--- vbcc-0.7.orig/debian/dirs
+++ vbcc-0.7/debian/dirs
@@ -0,0 +1 @@
+usr/bin
--- vbcc-0.7.orig/debian/vbcc.files
+++ vbcc-0.7/debian/vbcc.files
@@ -0,0 +1,4 @@
+/usr/bin
+/usr/lib/vbcc
+/usr/share/vbcc
+/usr/share/man
--- vbcc-0.7.orig/debian/README.Debian
+++ vbcc-0.7/debian/README.Debian
@@ -0,0 +1,11 @@
+vbcc for Debian
+---------------
+
+This is a Debianisation of Volker Barthelmann's vbcc compiler. The original
+upstream distribution site is:
+
+
http://www.compilers.de/vbcc/
+
+Note that this is version 0.7; the latest upstream version is 0.8.
+
+ -- David Given <
[email protected]>, Fri, 2 Nov 2001 20:59:17 +0000
--- vbcc-0.7.orig/debian/rules
+++ vbcc-0.7/debian/rules
@@ -0,0 +1,93 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=3
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+
+ autoconf
+ ./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
+
+ touch configure-stamp
+
+build: configure-stamp build-stamp
+build-stamp:
+ dh_testdir
+
+ mkdir -p bin
+ $(MAKE)
+
+ touch build-stamp
+
+clean: configure
+ dh_testdir
+ dh_testroot
+
+ if [ -f Makefile ]; then $(MAKE) clean; fi
+ rm -f Makefile config.cache config.log config.status
+ rm -f build-stamp configure-stamp
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ mkdir -p debian/tmp/usr/bin
+ mkdir -p debian/tmp/usr/lib/vbcc
+ cp bin/* debian/tmp/usr/lib/vbcc
+ mv debian/tmp/usr/lib/vbcc/vc debian/tmp/usr/bin
+
+ mkdir -p debian/tmp/usr/share/man/man1
+ cp vc.1 debian/tmp/usr/share/man/man1
+
+ cp -r share debian/tmp/usr
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_movefiles
+
+# dh_installdebconf
+ dh_installdocs
+ dh_installexamples
+ dh_installmenu
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_installinit
+ dh_installcron
+ dh_installman
+ dh_installinfo
+# dh_undocumented
+ dh_installchangelogs
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+# dh_makeshlibs
+ dh_installdeb
+# dh_perl
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
--- vbcc-0.7.orig/debian/vbcc.docs
+++ vbcc-0.7/debian/vbcc.docs
@@ -0,0 +1 @@
+doc
--- vbcc-0.7.orig/debian/copyright
+++ vbcc-0.7/debian/copyright
@@ -0,0 +1,98 @@
+This package was debianized by David Given <dg@hilfy> on
+Fri, 2 Nov 2001 20:59:17 +0000.
+
+It was downloaded from
http://www.compilers.de
+
+Upstream Author(s): Volker Barthelmann
+
+Copyright:
+
+vbcc compiler
+
+ vbcc is (c) in 1995-99 by Volker Barthelmann. The builtin preprocessor
+ (consisting of the files preproc.c and vbpp.h) is written and (c) by
+ Thorsten Schaaps. All other code is (c) by Volker Barthelmann.
+ vbcc may be freely redistributed as long as no modifications are made
+ and nothing is charged for it.
+ Non-commercial usage of vbcc is allowed without any restrictions.
+ Commercial usage needs my written consent.
+
+ Sending me money, gifts, postcards etc. would be very nice and may
+ encourage further development of vbcc, but is not legally or morally
+ necessary to use vbcc.
+
+vcpp preprocessor
+
+ The authors of this software are Christopher W. Fraser and
+ David R. Hanson.
+
+ Copyright (c) 1991,1992,1993,1994,1995 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 the lcc in whole or in part provided you
+ acknowledge its source and include this COPYRIGHT file.
+
+ 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, is subject to negotiation.
+
+Debianisation code and Z-machine code generator
+
+ This code is licensed under the MIT open source license.
+
+ Copyright (c) 2001, David Given
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
--- vbcc-0.7.orig/debian/changelog
+++ vbcc-0.7/debian/changelog
@@ -0,0 +1,22 @@
+vbcc (0.7-3) unstable; urgency=high
+
+ * Moved vc.1 from /usr/man to /usr/share/man to comply with the filesystem
+ standard. So *that's* why half my man pages are in /usr/share...
+
+ -- David Given <
[email protected]> Mon, 14 Jan 2002 12:11:39 +0000
+
+vbcc (0.7-2) unstable; urgency=high
+
+ * Danger, Will Robinson! Uninitialised variable! Fails horribly on OS X!
+
+ -- David Given <
[email protected]> Sat, 17 Nov 2001 23:39:17 +0000
+
+vbcc (0.7-1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- David Given <
[email protected]> Fri, 2 Nov 2001 20:59:17 +0000
+
+Local variables:
+mode: debian-changelog
+End:
--- vbcc-0.7.orig/debian/control
+++ vbcc-0.7/debian/control
@@ -0,0 +1,18 @@
+Source: vbcc
+Section: devel
+Priority: optional
+Maintainer: David Given <
[email protected]>
+Build-Depends: debhelper (>> 3.0.0)
+Standards-Version: 3.5.2
+
+Package: vbcc
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Lightweight retargetable optimising C compiler
+ vbcc is a free portable and retargetable ANSI C compiler which can generate
+ code for a wide variety of processors. It can perform any of a large range
+ of optimisations on the emitted code; in some areas it can produce better
+ code than gcc.
+ .
+ This version contains code generators for: alpha, c16x, i386, m68k, PowerPC,
+ and Infocom's Z-machine.
--- vbcc-0.7.orig/vc.1
+++ vbcc-0.7/vc.1
@@ -0,0 +1,135 @@
+.TH vc 1 "11 Nov 2001"
+.SH NAME
+vc \- front end to the vbcc compiler suite
+
+.SH SYNOPSIS
+.B vc
+.BI + "target"
+[
+.I options
+]
+[
+.I input-files
+]
+
+.SH DESCRIPTION
+.B vc
+is the front-end to the vbcc compiler suite. It should be reasonably compatible
+with the standard Unix
+.B cc
+program, with a few minor changes.
+.P
+vbcc is a cross-platform compiler. As a result it is necessary to tell the
+compiler which target to generate code for. This is done with the required
+.BI + "target"
+option. The following targets are supported:
+.TP
+.BR i386
+Intel 386 series.
+.TP
+.BR ppc
+Any Motorola PowerPC series processor.
+.TP
+.BR m68k
+Any Motorola 68000 series processor.
+.TP
+.BR alpha
+DEC's Alpha series.
+.TP
+.BR c16x
+The SAB C16X microprocessor.
+.TP
+.BR z
+Infocom's Z-machine.
+.P
+vbcc does not provide a complete toolchain, only the compiler. As a result, you
+will need the appropriate assembler and linker to use the code produced by
+vbcc. Unfortunately, vbcc cannot know which toolchain you are using, and as a
+result
+.B vc
+does not know how to assemble and link files.
+.P
+For more information on the code generators, descriptions of the
+platform-specific flags available, how to create configuration files, and
+detailed information on the more arcane options that
+.B vc
+supports, see
+.BR /usr/share/doc/vbcc/doc .
+
+.SH OPTIONS
+(Commonly used options only)
+
+.TP
+.BR -v
+verbose; print all commands
+.TP
+.BR -vv
+very verbose; display some internals as well
+.TP
+.BR -Ox
+optimisation level
+.TP
+.BI -o file
+save target as
+.I file
+(default for executables is a.out)
+.TP
+.BR -E
+do not compile, save the preprocessed C sources
+.TP
+.BR -S
+do not assemble, save the compiled files
+.TP
+.BR -SCS
+do not schedule, save the compiled files
+.TP
+.BR -c
+do not link, save the assembled files
+.TP
+.BR -k
+keep all intermediate files; by default all temporary files are removed
+.TP
+.BI -D string
+define a preprocessor symbol, e.g.
+.I -DAMIGA
+or
+.I -DCPU=68000
+.TP
+.BI -I path
+add the path to the include file search path
+.TP
+.BI -l lib
+link with the library
+.I lib
+.TP
+.B -nostdlib
+do not link with the standard libraries; useful only for experts
+.TP
+.B -notmpfile
+do not use names from tmpnam() for temporary files
+.TP
+.B -schedule
+do instruction scheduling (not supported in the Debian version)
+.P
+All other options are passed through to the compiler.
+
+.SH SEE ALSO
+The main vbcc documentation is in
+.IR /usr/share/doc/vbcc/doc .
+
+.SH AUTHORS
+Main compiler (C) 1995-1999 Volker Barthelmann; see
+.I vbcc.doc
+for license
+.P
+Preprocessor taken from the lcc distribution, with minor alterations.
+(C) 1991-1995 AT&T, Chris Fraser and David Hanson. See
+.I vcpp.doc
+for license and full details
+.P
+Z-machine code generator (C) 2001 David Given under the MIT license; see
+.I vbccz.doc
+for full license
+.P
+Additional code in the Debian version by David Given is in the public domain
+
--- vbcc-0.7.orig/machines/z/machine.dt
+++ vbcc-0.7/machines/z/machine.dt
@@ -0,0 +1,11 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BIEEEBE S32BIEEELE
+S64BIEEEBE S64BIEEELE
+S16BULE S16BUBE
--- vbcc-0.7.orig/machines/z/machine.h
+++ vbcc-0.7/machines/z/machine.h
@@ -0,0 +1,77 @@
+/* Z-machine code generator
+ * David Given
+ */
+
+#include "dt.h"
+
+/* Machine specific addressing-modes. Not used. */
+
+struct AddressingMode{
+ int never_used;
+};
+
+/* The number of registers we support. We don't really have any, but we
+ * use local variables instead; we have 14.
+ */
+
+#define MAXR 14
+
+/* Number of command-line options we accept. */
+
+#define MAXGF 6
+
+/* If this is set to zero vbcc will not generate ICs where the target operand
+ * is the same as the 2nd source operand. This can sometimes simplify the
+ * code-generator, but usually the code is better if the code-generator allows
+ * it.
+ */
+
+#define USEQ2ASZ 1
+
+/* The smallest and largest integer type that can be added to a pointer. */
+
+#define MINADDI2P INT
+#define MAXADDI2P INT
+
+/* Big-endian? */
+
+#define BIGENDIAN 1
+
+/* Little-endian? */
+
+#define LITTLEENDIAN 0
+
+/* If switch-statements should be generated as a sequence of SUB,TST,BEQ ICs
+ * rather than COMPARE,BEQ ICs set this to 1. This can yield better code on
+ * some machines.
+ */
+
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls with length
+ * known at compile-time will be inlined using an ASSIGN-IC if the size is less
+ * or equal to INLINEMEMCPY. The type used for the ASSIGN-IC will be
+ * UNSIGNED|CHAR. On the Z-machine, memcpy can be done in `hardware' with the
+ * @copy_table opcode, so always inline them if possible.
+ */
+
+#define INLINEMEMCPY 65536
+
+/* Do we want to pass parameters to functions in registers? */
+
+#define HAVE_REGPARMS
+
+/* If so, how many? Max 7 due to the architecture, but one is always xp. */
+
+#define NUM_REGPARMS 6
+
+/* This structure is used to keep track of where register parameters go. */
+
+struct reg_handle {
+ int reg;
+};
+
+/* Do we want to use zuint for size_t rather than the default zulong? */
+
+#define HAVE_INT_SIZET 1
+
--- vbcc-0.7.orig/machines/z/machine.c
+++ vbcc-0.7/machines/z/machine.c
@@ -0,0 +1,2742 @@
+/* z/machine.c
+ * Code generator for the Z-machine.
+ * (C) David Given 2001
+ */
+
+/* This code is licensed under the MIT open source license.
+ *
+ * Copyright (c) 2001, David Given
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* This code generator produces code for the Z-machine. The Z-machine is the
+ * highly peculiar virtual machine used for the old Infocom text adventures;
+ * these days, an extended form is still used in the interactive fiction genre
+ * of games. Usually, a dedicated compiler called Inform is used to generate
+ * code, but it would be nice to be able to use real C, so here we are.
+ *
+ * The Z-machine is (mostly) a semi-stack-based Harvard architecture machine.
+ * (Split code and data space, although they can share if you're clever. And
+ * mad.) It has no registers, but it does have procedure local variables which
+ * will do instead. It has a dedicated stack but as it's not accessible by
+ * ordinary memory it's not useful for C. It uses 8 and 16 bit words, so we'll
+ * have to emulate 32-bit arithmetic.
+ *
+ * For more information, including code for Inform, various interpreters, more
+ * documentation than you can shake a stick at, and the full technical reference
+ * for the Z-machine, check out the Interactive Fiction archive, at
+ *
http://www.ifarchive.org.
+ *
+ * Things to note: there is no Z-machine assembler. (Well, there's zasm, but it's
+ * really just a rumour.) Luckily, Inform has an assembler mode, where it'll
+ * generate raw Z-machine opcodes. Unluckily, it's horribly buggy... So we're
+ * going to have to generate Inform source, which seems at first to be rather
+ * silly, but as Inform is quite a simple compiler we can make sure that it's
+ * only going to generate the instructions we want it to generate.
+ */
+
+/* vbcc-mandated header. */
+
+#include "supp.h"
+static char FILE_[]=__FILE__;
+char cg_copyright[]="vbcc code-generator for Z-machine V0.0 (c) in 2001 by David Given";
+
+/* Command-line flags. */
+
+int g_flags[MAXGF] = {
+ STRINGFLAG,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+char *g_flags_name[MAXGF] = {
+ "module-name",
+ "trace-calls",
+ "trace-all",
+ "safe-branches",
+ "comment-ic",
+ "comment-misc"
+};
+union ppi g_flags_val[MAXGF];
+
+/* Type alignment. Much better code is generated if we can use even alignment.
+ */
+
+zlong align[16] = {
+ 0, /* 0: unused */
+ 1, /* 1: CHAR */
+ 2, /* 2: SHORT */
+ 2, /* 3: INT */
+ 2, /* 4: LONG */
+ 2, /* 5: FLOAT */
+ 2, /* 6: DOUBLE */
+ 2, /* 7: VOID */
+ 2, /* 8: POINTER */
+ 1, /* 9: ARRAY */
+ 1, /* 10: STRUCT */
+ 1, /* 11: UNION */
+ 1, /* 12: ENUM */
+ 1, /* 13: FUNKT */
+ 0, /* 14: unused */
+ 0, /* 15: unused */
+};
+
+/* Alignment that is valid for all types. */
+
+zlong maxalign = 2;
+
+/* Number of bits in a char. */
+
+zlong char_bit = 8;
+
+/* Sizes of all elementary types, in bytes. */
+
+zlong sizetab[16] = {
+ 0, /* 0: unused */
+ 1, /* 1: CHAR */
+ 2, /* 2: SHORT */
+ 2, /* 3: INT */
+ 4, /* 4: LONG */
+ 4, /* 5: FLOAT */
+ 8, /* 6: DOUBLE */
+ 0, /* 7: VOID */
+ 2, /* 8: POINTER */
+ 0, /* 9: ARRAY */
+ 0, /* 10: STRUCT */
+ 0, /* 11: UNION */
+ 2, /* 12: ENUM */
+ 0, /* 13: FUNKT */
+ 0, /* 14: unused */
+ 0, /* 15: unused */
+};
+
+/* Minimum and Maximum values each type can have.
+ */
+
+zlong t_min[32] = {
+ /* Signed: */
+ 0, /* 0: unused */
+ -128L, /* 1: CHAR */
+ -32768L, /* 2: SHORT */
+ -32768L, /* 3: INT */
+ -2147483647L, /* 4: LONG */
+ 0, /* 5: FLOAT */
+ 0, /* 6: DOUBLE */
+ 0, /* 7: VOID */
+ 0, /* 8: POINTER */
+ 0, /* 9: ARRAY */
+ 0, /* 10: STRUCT */
+ 0, /* 11: UNION */
+ 0, /* 12: ENUM */
+ 0, /* 13: FUNKT */
+ 0, /* 14: unused */
+ 0, /* 15: unused */
+ 0, /* 0: unused */
+ /* Unsigned: */
+ 0, /* 1: CHAR */
+ 0, /* 2: SHORT */
+ 0, /* 3: INT */
+ 0, /* 4: LONG */
+ 0, /* 5: FLOAT */
+ 0, /* 6: DOUBLE */
+ 0, /* 7: VOID */
+ 0, /* 8: POINTER */
+ 0, /* 9: ARRAY */
+ 0, /* 10: STRUCT */
+ 0, /* 11: UNION */
+ 0, /* 12: ENUM */
+ 0, /* 13: FUNKT */
+ 0, /* 14: unused */
+ 0, /* 15: unused */
+};
+zulong t_max[32] = {
+ /* Signed: */
+ 0, /* 0: unused */
+ 127UL, /* 1: CHAR */
+ 32767UL, /* 2: SHORT */
+ 32767UL, /* 3: INT */
+ 2147483647UL, /* 4: LONG */
+ 0, /* 5: FLOAT */
+ 0, /* 6: DOUBLE */
+ 0, /* 7: VOID */
+ 0, /* 8: POINTER */
+ 0, /* 9: ARRAY */
+ 0, /* 10: STRUCT */
+ 0, /* 11: UNION */
+ 0, /* 12: ENUM */
+ 0, /* 13: FUNKT */
+ 0, /* 14: unused */
+ 0, /* 15: unused */
+ 0, /* 0: unused */
+ /* Unsigned: */
+ 255UL, /* 1: CHAR */
+ 65535UL, /* 2: SHORT */
+ 65535UL, /* 3: INT */
+ 4294967295UL, /* 4: LONG */
+ 0, /* 5: FLOAT */
+ 0, /* 6: DOUBLE */
+ 0, /* 7: VOID */
+ 0, /* 8: POINTER */
+ 0, /* 9: ARRAY */
+ 0, /* 10: STRUCT */
+ 0, /* 11: UNION */
+ 0, /* 12: ENUM */
+ 0, /* 13: FUNKT */
+ 0, /* 14: unused */
+ 0, /* 15: unused */
+};
+
+/* Names of all the registers.
+ * We can have 16 local variables per routine. Var 0 is always the C stack
+ * pointer, xp. All the others can be used by the compiler. xp doesn't actually
+ * appear in the register map, so we get 15 main registers.
+ */
+
+char* regnames[] = {
+ "sp", /* vbcc doesn't use this, but we do */
+ "xp", "r0", "r1", "r2", "r3", "r4", "r5", "r6",
+ "r7", "r8", "r9", "r10", "r11", "r12"};
+#define XP 1
+#define USERREG 2
+
+/* The size of each register, in byes. */
+
+zlong regsize[] = {
+ 0,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2};
+
+/* Type needed to store each register. */
+
+struct Typ ityp = {INT};
+struct Typ* regtype[] = {
+ NULL,
+ &ityp, &ityp, &ityp, &ityp, &ityp, &ityp, &ityp, &ityp,
+ &ityp, &ityp, &ityp, &ityp, &ityp, &ityp};
+
+/* These registers are those dedicated for use by the backend. These ones will
+ * not be used by the code generator. */
+
+int regsa[] = {
+ 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0};
+
+/* Specifies which registers may be destroyed by function calls. As we're
+ * storing our registers in local variables so they're being automatically
+ * saved for us, none of them.
+ */
+
+int regscratch[] = {
+ 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0};
+
+/* Default state for register parameter passing. */
+
+struct reg_handle empty_reg_handle =
+ {USERREG};
+
+/* Prefix for labels. */
+
+static char* labelprefix = "L";
+
+/* Name of the current module; used for generating unique names for statics and
+ * the constant pool. */
+
+static char* modulename;
+
+/* Stack frame layout:
+ *
+ * --------------
+ * Arg 4 (Arguments being passed to this function)
+ * Arg 3
+ * Arg 2
+ * Arg 1
+ * -------------- xp + stackparamadjust + stackoffset
+ * Local 4 (This function's temp space)
+ * Local 3
+ * Local 2
+ * Local 1
+ * -------------- xp + stackparamadjust
+ * Arg 2 (Arguments this function has pushed to pass
+ * Arg 1 to a called function)
+ * -------------- xp
+ *
+ * Any area may be zero in size. (Although stackoffset is always at least 2 for
+ * some inadequately explained reason.)
+ */
+
+static int stackoffset;
+static int stackparamadjust;
+
+/* Represents something the Z-machine can use as an instruction operand. */
+
+struct zop {
+ int type;
+ union {
+ int reg;
+ zlong constant;
+ char* identifier;
+ } val;
+};
+
+enum {
+ ZOP_STACK,
+ ZOP_REG,
+ ZOP_CONSTANT,
+ ZOP_EXTERN,
+ ZOP_STATIC,
+ ZOP_CONSTANTADDR
+};
+
+/* Some useful zops. */
+
+struct zop zop_zero = {ZOP_CONSTANT, {constant: 0}};
+struct zop zop_xp = {ZOP_REG, {reg: XP}};
+struct zop zop_stack = {ZOP_STACK, 0};
+
+/* Temporaries used to store comparison register numbers. */
+
+static struct zop compare1;
+static struct zop compare2;
+
+/* Keeps track of whether we've emitted anything or not. Used to determine
+ * whether to emit the seperating ; or not. If it's 1, we haven't emitted
+ * anything. If it's -1, we're doing an array, so we need to emit a final (0)
+ * to finish it off if it's only one byte long. 0 for anything else. */
+
+static int virgin = 1;
+
+/* The current variable we're emitting data for. */
+
+struct variable {
+ int type;
+ union {
+ char* identifier;
+ int number;
+ } val;
+ zint offset;
+};
+
+struct variable currentvar;
+
+/* Inform can't emit variable references inside arrays. So when vbcc wants to
+ * put, say, the address of something in a global variable, we have to write it
+ * in later. A linked list of these structures keeps track of the items that
+ * need fixing up. */
+
+struct fixup {
+ struct fixup* next;
+ struct variable identifier;
+ struct variable value;
+ zlong offset;
+};
+
+static struct fixup* fixuplist = NULL;
+
+/* 32-bit values are stored in a constant pool, for simplicity. It's kept track
+ * of in this linked list. */
+
+struct constant {
+ struct constant* next;
+ int id;
+ zlong value;
+};
+
+static struct constant* constantlist = NULL;
+static int constantnum = 0;
+
+/* The function we're currently compiling. */
+
+static struct Var* function;
+
+/* Function prototypes. */
+
+static void emit_add(FILE* fp, struct zop* q1, struct zop* q2, struct zop* z);
+static void read_reg(FILE* fp, struct obj* obj, int typf, int reg);
+static int addconstant(zlong value);
+
+/* Emit debugging info. */
+
+static void debugemit(FILE* fp, char* fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (g_flags[5] & USEDFLAG)
+ vfprintf(fp, fmt, ap);
+ va_end(ap);
+}
+
+/* Do we need to emit a ; before the next thing? */
+
+static void reflower(FILE* fp)
+{
+ if (!virgin)
+ fprintf(fp, ";\n");
+ if (virgin == -1)
+ {
+ if (currentvar.offset == 1)
+ fprintf(fp, "(0)");
+ fprintf(fp, ";");
+ }
+ virgin = 0;
+}
+
+/* Extract the sign extended byte n of a value. */
+
+static char xbyte(zlong val, int byte)
+{
+ val <<= (sizeof(val)*8) - (byte*8) - 8;
+ val >>= (sizeof(val)*8) - 8;
+ return (unsigned char) val;
+}
+
+/* Extract the sign extended word n of a value. */
+
+static zshort xword(zlong val, int word)
+{
+ val <<= (sizeof(val)*8) - (word*16) - 16;
+ val >>= (sizeof(val)*8) - 16;
+ return (zshort) val;
+}
+
+/* Debug function: prints the text name of a type. */
+
+static void dump_type(FILE* fp, int typf)
+{
+ switch (typf)
+ {
+ case VOID: fprintf(fp, "VOID"); break;
+ case CHAR: fprintf(fp, "CHAR"); break;
+ case SHORT: fprintf(fp, "SHORT"); break;
+ case INT: fprintf(fp, "INT"); break;
+ case LONG: fprintf(fp, "LONG"); break;
+ case POINTER: fprintf(fp, "POINTER"); break;
+ case STRUCT: fprintf(fp, "STRUCT"); break;
+ case ARRAY: fprintf(fp, "ARRAY"); break;
+ case UNION: fprintf(fp, "UNION"); break;
+ case FUNKT: fprintf(fp, "FUNKT"); break;
+ default: fprintf(fp, "unknown %X", typf);
+ }
+}
+
+/* Debug function: outputs the obj. */
+
+static void dump_obj(FILE* fp, struct obj* obj, int typf)
+{
+ int f = obj->flags & (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ if (f == 0)
+ {
+ fprintf(fp, "[]");
+ return;
+ }
+
+ if (f & DREFOBJ)
+ fprintf(fp, "*");
+
+ if (f & VARADR)
+ fprintf(fp, "&");
+
+ if (f == KONST)
+ {
+ switch (typf & NU)
+ {
+ case CHAR:
+ fprintf(fp, "[char #%d]", obj->val.vchar);
+ break;
+
+ case UNSIGNED|CHAR:
+ fprintf(fp, "[uchar #%u]", obj->val.vuchar);
+ break;
+
+ case SHORT:
+ fprintf(fp, "[short #%d]", obj->val.vshort);
+ break;
+
+ case UNSIGNED|SHORT:
+ fprintf(fp, "[ushort #%u]", obj->val.vushort);
+ break;
+
+ case INT:
+ fprintf(fp, "[int #%d]", obj->val.vint);
+ break;
+
+ case UNSIGNED|INT:
+ fprintf(fp, "[uint #%d]", obj->val.vuint);
+ break;
+
+ case LONG:
+ fprintf(fp, "[long #%d]", obj->val.vlong);
+ break;
+
+ case UNSIGNED|LONG:
+ fprintf(fp, "[ulong #%u]", obj->val.vulong);
+ break;
+
+ case FLOAT:
+ fprintf(fp, "[float #%04X]", obj->val.vfloat);
+ break;
+
+ case DOUBLE:
+ fprintf(fp, "[double #%08X]", obj->val.vdouble);
+ break;
+
+ case POINTER:
+ fprintf(fp, "[pointer #%04X]", obj->val.vpointer);
+ break;
+ }
+ }
+ else if (f == REG)
+ fprintf(fp, "[reg %s]", regnames[obj->reg]);
+ else if (f == (REG|DREFOBJ))
+ fprintf(fp, "[deref reg %s]", regnames[obj->reg]);
+ //else if (f & VAR)
+ else
+ {
+ fprintf(fp, "[var ");
+ dump_type(fp, typf);
+ fprintf(fp, " %s", obj->v->identifier);
+
+ if ((obj->v->storage_class == AUTO) ||
+ (obj->v->storage_class == REGISTER))
+ {
+ zlong offset = obj->v->offset;
+ //if (offset < 0)
+ // offset = -(offset+maxalign);
+ fprintf(fp, " at fp%+d", offset);
+ }
+
+ fprintf(fp, "+%ld", obj->val.vlong);
+
+ if (f & REG)
+ fprintf(fp, " in %s", regnames[obj->reg]);
+ fprintf(fp, "]");
+ }
+}
+
+/* Debug function: outputs the ic, as a comment. */
+
+static void dump_ic(FILE* fp, struct IC* ic)
+{
+ char* p;
+
+ if (!ic)
+ return;
+
+ if (!(g_flags[4] & USEDFLAG))
+ return;
+
+ if (g_flags[2] & USEDFLAG)
+ fprintf(fp, "print \"");
+ else
+ fprintf(fp, "! ");
+
+ switch (ic->code)
+ {
+ case ASSIGN: p = "ASSIGN"; break;
+ case OR: p = "OR"; break;
+ case XOR: p = "XOR"; break;
+ case AND: p = "AND"; break;
+ case LSHIFT: p = "LSHIFT"; break;
+ case RSHIFT: p = "RSHIFT"; break;
+ case ADD: p = "ADD"; break;
+ case SUB: p = "SUB"; break;
+ case MULT: p = "MULT"; break;
+ case DIV: p = "DIV"; break;
+ case MOD: p = "MOD"; break;
+ case KOMPLEMENT: p = "KOMPLEMENT"; break;
+ case MINUS: p = "MINUS"; break;
+ case ADDRESS: p = "ADDRESS"; break;
+ case CALL: p = "CALL"; break;
+ case CONVCHAR: p = "CONVCHAR"; break;
+ case CONVSHORT: p = "CONVSHORT"; break;
+ case CONVINT: p = "CONVINT"; break;
+ case CONVLONG: p = "CONVLONG"; break;
+ case CONVFLOAT: p = "CONVFLOAT"; break;
+ case CONVDOUBLE: p = "CONVDOUBLE"; break;
+ case CONVPOINTER: p = "CONVPOINTER"; break;
+ case CONVUCHAR: p = "CONVUCHAR"; break;
+ case CONVUSHORT: p = "CONVUSHORT"; break;
+ case CONVUINT: p = "CONVUINT"; break;
+ case CONVULONG: p = "CONVULONG"; break;
+ case ALLOCREG: p = "ALLOCREG"; break;
+ case FREEREG: p = "FREEREG"; break;
+ case COMPARE: p = "COMPARE"; break;
+ case TEST: p = "TEST"; break;
+ case LABEL: p = "LABEL"; break;
+ case BEQ: p = "BEQ"; break;
+ case BNE: p = "BNE"; break;
+ case BLT: p = "BLT"; break;
+ case BGT: p = "BGT"; break;
+ case BLE: p = "BLE"; break;
+ case BGE: p = "BGE"; break;
+ case BRA: p = "BRA"; break;
+ case PUSH: p = "PUSH"; break;
+ case ADDI2P: p = "ADDI2P"; break;
+ case SUBIFP: p = "SUBIFP"; break;
+ case SUBPFP: p = "SUBPFP"; break;
+ case GETRETURN: p = "GETRETURN"; break;
+ case SETRETURN: p = "SETRETURN"; break;
+ case MOVEFROMREG: p = "MOVEFROMREG"; break;
+ case MOVETOREG: p = "MOVETOREG"; break;
+ case NOP: p = "NOP"; break;
+ default: p = "???";
+ }
+
+ fprintf(fp, "%s ", p);
+ dump_type(fp, ic->typf);
+ fprintf(fp, " ");
+
+ switch (ic->code)
+ {
+ case LABEL:
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BGT:
+ case BLE:
+ case BGE:
+ case BRA:
+ fprintf(fp, "%d", ic->typf);
+ goto epilogue;
+ }
+
+ dump_obj(fp, &ic->q1, ic->typf);
+ fprintf(fp, " ");
+ dump_obj(fp, &ic->q2, ic->typf);
+ fprintf(fp, " -> ");
+ dump_obj(fp, &ic->z, ic->typf);
+
+epilogue:
+ if (g_flags[2] & USEDFLAG)
+ fprintf(fp, "^\";\n");
+ else
+ fprintf(fp, "\n");
+}
+
+/* Initialise the code generator. This is called once. Returns 0 if things go
+ * wrong. */
+
+int init_cg(void)
+{
+ modulename = g_flags_val[0].p;
+ if (!modulename)
+ modulename = "";
+ return 1;
+}
+
+/* Returns the register in which variables of type typ are returned (or 0 if it
+ * can't be done). */
+
+int freturn(struct Typ *typ)
+{
+ int s = sizetab[typ->flags & NQ];
+ if ((typ->flags & NQ) == VOID)
+ return USERREG;
+ if ((s <= sizetab[INT]) && (s > 0))
+ return USERREG;
+ return 0;
+}
+
+/* Returns 1 if register reg can store variables of type typ. mode is set
+ * if the register is a pointer and the register is going to be dereferenced.
+ */
+
+int regok(int reg, int typf, int mode)
+{
+ int s = sizetab[typf & NQ];
+ if ((typf & NQ) == VOID)
+ return 1;
+ if ((s <= sizetab[INT]) && (s > 0))
+ return 1;
+ return 0;
+}
+
+/* Returns zero if the IC ic can be safely executed without danger of
+ * exceptions or similar things; for example, divisions or pointer dereferences
+ * are dangerous. This is used by the optimiser for code reordering.
+ */
+
+int dangerous_IC(struct IC *ic)
+{
+ /* Check for dereferences. */
+
+ if ((ic->q1.flags & DREFOBJ) ||
+ (ic->q2.flags & DREFOBJ) ||
+ (ic->z.flags & DREFOBJ))
+ return 0;
+
+ /* Division or modulo? */
+
+ if ((ic->code == DIV) ||
+ (ic->code == MOD))
+ return 0;
+
+ /* Safe, as far as we can tell. */
+
+ return 1;
+}
+
+/* Returns zero if the code for converting type p->ntyp to type typ is a noop.
+ */
+
+int must_convert(np p, int typ)
+{
+ int oldtype = p->ntyp->flags & NQ;
+ int newtype = typ & NQ;
+
+ /* ints and shorts are equivalent. */
+
+ if (oldtype == SHORT)
+ oldtype = INT;
+ if (newtype == SHORT)
+ newtype = INT;
+
+ /* Both the same type? */
+
+ if (oldtype == newtype)
+ return 0;
+
+#if 0
+ /* Converting two basic integers? */
+
+ if ((oldtype <= INT) && (newtype <= INT))
+ {
+ /* ... but char to short needs an AND. */
+
+ if ((oldtype == CHAR) && (newtype != CHAR))
+ return 1;
+ return 0;
+ }
+#endif
+
+ /* Pointer to/from int? */
+
+ if (((oldtype == INT) || (oldtype == POINTER)) &&
+ ((newtype == INT) || (newtype == POINTER)))
+ return 0;
+
+ /* Everything else needs code. */
+
+ return 1;
+}
+
+/* Ensure the output is aligned. A noop on the Z-machine. */
+
+void gen_align(FILE* fp, zlong align)
+{
+}
+
+/* Generate the label part of a variable definition. */
+
+void gen_var_head(FILE* fp, struct Var* var)
+{
+ if (var->storage_class == EXTERN)
+ debugemit(fp, "! Var %s %X\n", var->identifier, var->flags);
+ if (var->storage_class == STATIC)
+ debugemit(fp, "! Var static %ld %s %X\n", var->offset, var->identifier, var->flags);
+
+ /* We only want to emit records for genuinely defined variables. For
+ * some reason, TENTATIVE is defined for some of this. */
+
+ if ((var->storage_class == EXTERN) &&
+ !(var->flags & DEFINED) &&
+ !(var->flags & TENTATIVE))
+ return;
+
+ reflower(fp);
+ virgin = -1;
+ switch (var->storage_class)
+ {
+ case EXTERN:
+ /* This doesn't actually mean external linkage; it
+ * means a non-static global that may be referenced
+ * externally. */
+ fprintf(fp, "Array _%s ->\n",
+ var->identifier);
+ currentvar.type = EXTERN;
+ currentvar.val.identifier = strdup(var->identifier);
+ currentvar.offset = 0;
+ break;
+
+ case STATIC:
+ fprintf(fp, "Array STATIC_%s_%ld ->\n",
+ modulename, var->offset);
+ currentvar.type = STATIC;
+ currentvar.val.number = var->offset;
+ currentvar.offset = 0;
+ break;
+ }
+}
+
+/* Emit a certain number of bytes of bss data. No bss on the Z-machine,
+ * remember. */
+
+void gen_ds(FILE *fp, zlong size, struct Typ *typ)
+{
+ fprintf(fp, " %ld\n", size);
+ currentvar.offset += size;
+}
+
+/* Emit a certain number of bytes of initialised data. */
+
+void gen_dc(FILE *fp, int typf, struct const_list *p)
+{
+ switch (typf & NQ)
+ {
+ case CHAR:
+ fprintf(fp, " (%d)\n",
+ p->val.vuchar);
+ currentvar.offset += 1;
+ break;
+
+ case SHORT:
+ case INT:
+ reallyanint:
+ fprintf(fp, " (%d) (%d)\n",
+ xbyte(p->val.vint, 1),
+ xbyte(p->val.vint, 0));
+ currentvar.offset += 2;
+ break;
+
+ case LONG:
+ fprintf(fp, " (%d) (%d) (%d) (%d)\n",
+ xbyte(p->val.vlong, 3),
+ xbyte(p->val.vlong, 2),
+ xbyte(p->val.vlong, 1),
+ xbyte(p->val.vlong, 0));
+ currentvar.offset += 4;
+ break;
+
+ case POINTER:
+ if (!p->tree)
+ goto reallyanint;
+ {
+ struct fixup* fixup = malloc(sizeof(struct fixup));
+ struct obj* obj = &p->tree->o;
+ fixup->next = fixuplist;
+ fixuplist = fixup;
+ fixup->identifier = currentvar;
+
+ switch (obj->v->storage_class)
+ {
+ case EXTERN:
+ fixup->value.type = EXTERN;
+ fixup->value.val.identifier = strdup(obj->v->identifier);
+ break;
+
+ case STATIC:
+ fixup->value.type = STATIC;
+ fixup->value.val.number = obj->v->offset;
+ break;
+
+ default:
+ ierror(0);
+ }
+ fixup->value.offset = 0;
+ fixup->offset = obj->val.vlong;
+ fprintf(fp, " (0) (0)\n");
+ currentvar.offset += 2;
+ }
+ break;
+
+ default:
+ printf("type %d\n", typf);
+ ierror(0);
+ }
+}
+
+/* Returns the offset of the (STATIC or AUTO) given object. */
+
+zlong voff(struct obj* obj)
+{
+ zlong offset = obj->v->offset;
+ if (offset < 0)
+ offset = stackparamadjust + stackoffset - offset - maxalign;
+ else
+ offset += stackparamadjust;
+
+ offset += obj->val.vlong;
+ return offset;
+}
+
+/* When a varargs function is called, we need to find where the parameters are
+ * on the stack in order to make the __va_start magic variable work. This
+ * function does that. */
+
+static int find_varargs(void)
+{
+ int offset = 0;
+ struct reg_handle rh = empty_reg_handle;
+ struct struct_declaration* sd = function->vtyp->exact;
+ int stackalign;
+ int i;
+
+ for (i=0; i<sd->count; i++)
+ {
+ /* Ignore the parameter if it's been assigned a register. */
+
+ if ((*sd->sl)[i].reg != 0)
+ continue;
+
+ /* void shouldn't happen. */
+
+ if (((*sd->sl)[i].styp->flags & NQ) == VOID)
+ ierror(0);
+
+ /* Does the backend want to assign it to a register? */
+
+ if (reg_parm(&rh, (*sd->sl)[i].styp, 0))
+ continue;
+
+ /* Add on the size of this parameter. */
+
+ offset += sizetab[(*sd->sl)[i].styp->flags & NQ];
+
+ /* Stack align. */
+
+ stackalign = align[(*sd->sl)[i].styp->flags & NQ];
+ offset = ((offset+1) / stackalign) * stackalign;
+ }
+
+ return (offset + stackoffset);
+}
+
+/* Output the name of a global. */
+
+static void emit_identifier(FILE* fp, struct obj* obj)
+{
+ switch (obj->v->storage_class)
+ {
+ case STATIC:
+ fprintf(fp, "STATIC_%s_%ld",
+ modulename, obj->v->offset);
+ break;
+
+ case EXTERN:
+ fprintf(fp, "_%s", obj->v->identifier);
+ break;
+
+ default:
+ ierror(0);
+ }
+}
+
+/* Save a register. */
+
+static void write_reg(FILE* fp, struct obj* obj, int typf, int reg)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ /* Constant? */
+
+ if (flags == KONST)
+ ierror(0);
+
+ /* Dereference? */
+
+ if (flags & DREFOBJ)
+ goto dereference;
+
+ /* Register? */
+
+ if ((flags == REG) ||
+ ((flags & VAR) && (flags & REG) && (obj->v->storage_class == AUTO)) ||
+ ((flags & VAR) && (flags & REG) && (obj->v->storage_class == REGISTER)))
+ {
+ if (flags & DREFOBJ)
+ fprintf(fp, "\t@store%c %s 0 %s;\n",
+ ((typf & NQ) == CHAR) ? 'b' : 'w',
+ regnames[obj->reg], regnames[reg]);
+ else
+ {
+ struct zop in;
+ struct zop out;
+ in.type = ZOP_REG;
+ in.val.reg = reg;
+ out.type = ZOP_REG;
+ out.val.reg = obj->reg;
+ emit_add(fp, &in, &zop_zero, &out);
+ }
+#if 0
+ fprintf(fp, "\t@add %s 0 -> %s;\n",
+ regnames[reg], regnames[obj->reg]);
+#endif
+ return;
+ }
+
+ /* It must be a variable. */
+
+ switch (obj->v->storage_class)
+ {
+ case AUTO:
+ case REGISTER: /* Local variable */
+ {
+ zlong offset = voff(obj);
+
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@storeb xp 0%+ld %s;\n",
+ offset, regnames[reg]);
+ else
+ {
+ if (offset & 1)
+ {
+ struct zop c;
+ c.type = ZOP_CONSTANT;
+ c.val.constant = offset;
+ emit_add(fp, &zop_xp, &c, &zop_stack);
+ //fprintf(fp, "\t@add xp 0%+ld -> sp;\n", offset);
+ fprintf(fp, "\t@storew sp 0 %s;\n", regnames[reg]);
+ }
+ else
+ fprintf(fp, "\t@storew xp 0%+ld %s;\n",
+ offset >> 1, regnames[reg]);
+ }
+ return;
+ }
+
+ case EXTERN:
+ case STATIC:
+ /* Dereference object. */
+
+ if ((typf & NQ) == CHAR)
+ {
+ fprintf(fp, "\t@storeb ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld %s;\n",
+ obj->val.vlong, regnames[reg]);
+ }
+ else
+ {
+ if (obj->val.vlong & 1)
+ {
+ fprintf(fp, "\t@add ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> sp;\n",
+ obj->val.vlong);
+ fprintf(fp, "\t@storew sp 0 %s;\n",
+ regnames[reg]);
+ }
+ else
+ {
+ fprintf(fp, "\t@storew ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld %s;\n",
+ obj->val.vlong >> 1, regnames[reg]);
+ }
+ }
+ return;
+#if 0
+ case EXTERN: /* External linkage */
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@storeb _%s 0%+ld %s;\n",
+ obj->v->identifier, offset, regnames[reg]);
+ else
+ {
+
+ fprintf(fp, "\t@storew _%s 0 %s;\n",
+ obj->v->identifier, regnames[reg]);
+ return;
+
+ case STATIC: /* Static global */
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@storeb STATIC_%s_%ld 0%+ld %s;\n",
+ modulename, obj->v->offset, offset, regnames[reg]);
+ else
+ fprintf(fp, "\t@storew STATIC_%s_%ld 0 %s;\n",
+ modulename, obj->v->offset, regnames[reg]);
+ return;
+#endif
+
+ default:
+ ierror(0);
+ }
+
+ ierror(0); // Not reached
+dereference:
+ /* These are a *pain*.
+ *
+ * The first thing we need to do is to read the old contents of the
+ * memory cell, to work out the address we need to write to; and then
+ * do the write. Hurray for the Z-machine stack. */
+
+ obj->flags &= ~DREFOBJ;
+ read_reg(fp, obj, POINTER, 0);
+ fprintf(fp, "\t@store%c sp 0 %s;\n",
+ ((typf & NQ) == CHAR) ? 'b' : 'w',
+ regnames[reg]);
+}
+
+/* Move one register to another register. */
+
+static void move_reg(FILE* fp, int reg1, int reg2)
+{
+ struct zop r1;
+ struct zop r2;
+ r1.type = ZOP_REG;
+ r1.val.reg = reg1;
+ r2.type = ZOP_REG;
+ r2.val.reg = reg2;
+ emit_add(fp, &r1, &zop_zero, &r2);
+}
+/* Load a value into a zop. */
+
+static void read_reg(FILE* fp, struct obj* obj, int typf, int reg)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ /* The only thing you can do with a function is to take the address of
+ * it. */
+
+ if ((typf & NQ) == FUNKT)
+ flags &= ~DREFOBJ & ~VARADR;
+
+ /* Is this a memory dereference? */
+
+ if (flags & DREFOBJ)
+ goto dereference;
+
+ /* Constant? */
+
+ if (flags == KONST)
+ {
+ struct zop c;
+ struct zop r;
+ c.type = ZOP_CONSTANT;
+ //fprintf(fp, "\t@add ");
+ switch (typf & NQ)
+ {
+ case CHAR: c.val.constant = obj->val.vchar; break;
+ case UNSIGNED|CHAR: c.val.constant = obj->val.vuchar; break;
+ case SHORT: c.val.constant = obj->val.vshort; break;
+ case UNSIGNED|SHORT: c.val.constant = obj->val.vushort; break;
+ case POINTER: c.val.constant = obj->val.vpointer; break;
+ case INT: c.val.constant = obj->val.vint; break;
+ case UNSIGNED|INT: c.val.constant = obj->val.vuint; break;
+ default:
+ ierror(typf);
+ }
+ r.type = ZOP_REG;
+ r.val.reg = reg;
+ emit_add(fp, &c, &zop_zero, &r);
+ //fprintf(fp, " 0 -> %s;\n", regnames[reg]);
+ }
+ else if (flags == REG) /* Register? */
+ {
+ move_reg(fp, obj->reg, reg);
+ //fprintf(fp, "\t@add %s 0 -> %s;\n", regnames[obj->reg], regnames[reg]);
+ }
+ else if ((flags & REG) && ((typf & NQ) == FUNKT)) /* Function pointer? */
+ {
+ move_reg(fp, obj->reg, reg);
+ //fprintf(fp, "\t@add %s 0 -> %s;\n", regnames[obj->reg], regnames[reg]);
+ }
+ else
+ {
+ /* It must be a variable. */
+
+ switch (obj->v->storage_class)
+ {
+ case AUTO:
+ case REGISTER: /* Local variable */
+ if (flags & VARADR)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> %s;\n",
+ voff(obj), regnames[reg]);
+ }
+ else if (flags & REG)
+ {
+ move_reg(fp, obj->reg, reg);
+ //fprintf(fp, "\t@add %s 0 -> %s;\n",
+ // regnames[obj->reg], regnames[reg]);
+ }
+ else
+ {
+ zlong offset = voff(obj);
+
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@loadb xp 0%+ld -> %s;\n",
+ offset, regnames[reg]);
+ else
+ {
+ if (offset & 1)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> sp;\n", offset);
+ fprintf(fp, "\t@loadw sp 0 -> %s;\n", regnames[reg]);
+ }
+ else
+ fprintf(fp, "\t@loadw xp 0%+ld -> %s;\n",
+ offset >> 1, regnames[reg]);
+ }
+ }
+ break;
+
+ case STATIC:
+ case EXTERN: /* Global variable. Implicit dereference,
+ with the offset in obj->val.vlong. */
+
+ /* ...but functions are never dereferenced. */
+
+ if ((flags & VARADR) ||
+ ((typf & NQ) == FUNKT))
+ {
+ /* Fetch address of object. */
+
+ fprintf(fp, "\t@add ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> %s;\n",
+ obj->val.vlong, regnames[reg]);
+ }
+ else if (strcmp(obj->v->identifier, "__va_start") == 0)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> %s;\n",
+ find_varargs(), regnames[reg]);
+ }
+ else
+ {
+ /* Dereference object. */
+
+ if ((typf & NQ) == CHAR)
+ {
+ fprintf(fp, "\t@loadb ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> %s;\n",
+ obj->val.vlong, regnames[reg]);
+ }
+ else
+ {
+ if (obj->val.vlong & 1)
+ {
+ fprintf(fp, "\t@add ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> sp;\n",
+ obj->val.vlong);
+ fprintf(fp, "\t@loadw sp 0 -> %s;\n",
+ regnames[reg]);
+ }
+ else
+ {
+ fprintf(fp, "\t@loadw ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> %s;\n",
+ obj->val.vlong >> 1, regnames[reg]);
+ }
+ }
+ }
+ break;
+
+ default:
+ ierror(obj->v->storage_class);
+ }
+ }
+ return;
+
+dereference:
+ /* Do we need to dereference the thing we just fetched? */
+
+ /* Fetch the value to dereference. */
+ obj->flags &= ~DREFOBJ;
+ read_reg(fp, obj, POINTER, 0);
+
+ if (flags & DREFOBJ)
+ {
+ switch (typf & NQ)
+ {
+ case CHAR:
+ fprintf(fp, "\t@loadb sp 0 -> %s;\n",
+ regnames[reg], regnames[reg]);
+ break;
+
+ case SHORT:
+ case INT:
+ case POINTER:
+ case FUNKT:
+ fprintf(fp, "\t@loadw sp 0 -> %s;\n",
+ regnames[reg], regnames[reg]);
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ }
+}
+
+/* Returns the zop to use for an input parameter, pushing that parameter onto
+ * the stack if necessary. */
+
+static void push_value(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ if (flags == KONST)
+ {
+ op->type = ZOP_CONSTANT;
+ switch (typf & NU)
+ {
+ case CHAR: op->val.constant = obj->val.vchar; break;
+ case UNSIGNED|CHAR: op->val.constant = obj->val.vuchar; break;
+ case SHORT: op->val.constant = obj->val.vshort; break;
+ case UNSIGNED|SHORT: op->val.constant = obj->val.vushort; break;
+ case INT: op->val.constant = obj->val.vint; break;
+ case UNSIGNED|INT: op->val.constant = obj->val.vuint; break;
+ case POINTER: op->val.constant = obj->val.vpointer; break;
+ default:
+ fprintf(fp, "XXX !!! bad konst type %X\n", typf);
+ }
+ return;
+ }
+
+ /* The only thing you can do with a function is to take the address of it. */
+
+ if ((typf & NQ) == FUNKT)
+ flags &= ~DREFOBJ & ~VARADR;
+
+ /* This is used by the long code. The longop functions can only operate
+ * on pointers to longs; so if we need to pass in a constant, we have
+ * to stash it on the stack and return a pointer. */
+
+ if (flags == (KONST|VARADR))
+ {
+ op->type = ZOP_CONSTANTADDR;
+ op->val.constant = addconstant(obj->val.vlong);
+ return;
+ }
+
+ if (flags == REG)
+ {
+ debugemit(fp, "! zop reg %d\n", obj->reg);
+ op->type = ZOP_REG;
+ op->val.reg = obj->reg;
+ return;
+ }
+
+ if ((flags == (VAR|REG)) &&
+ ((obj->v->storage_class == AUTO) ||
+ (obj->v->storage_class == REGISTER)))
+ {
+ debugemit(fp, "! zop var reg %d\n", obj->reg);
+ op->type = ZOP_REG;
+ op->val.reg = obj->reg;
+ return;
+ }
+
+ if ((flags == (VAR|VARADR)) &&
+ (obj->v->storage_class == EXTERN) &&
+ (obj->v->offset == 0))
+ {
+ debugemit(fp, "! zop varaddr extern %s\n", obj->v->identifier);
+ op->type = ZOP_EXTERN;
+ op->val.identifier = obj->v->identifier;
+ return;
+ }
+
+ if ((flags == (VAR|VARADR)) &&
+ (obj->v->storage_class == STATIC) &&
+ (obj->v->offset == 0))
+ {
+ debugemit(fp, "! zop varaddr static %ld\n", obj->v->offset);
+ op->type = ZOP_STATIC;
+ op->val.constant = obj->v->offset;
+ return;
+ }
+
+ if ((flags & VAR) &&
+ ((obj->v->vtyp->flags & NQ) == FUNKT))
+ {
+ if (obj->v->storage_class == EXTERN)
+ {
+ op->type = ZOP_EXTERN;
+ op->val.identifier = obj->v->identifier;
+ }
+ else
+ {
+ op->type = ZOP_STATIC;
+ op->val.constant = obj->v->offset;
+ }
+ return;
+ }
+
+ read_reg(fp, obj, typf, 0);
+ op->type = ZOP_STACK;
+}
+
+/* Same as push_value(), but returns a zop for the *address* of the object, not
+ * the object itself. Used a lot by the long code. */
+
+static void push_addrof(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ if (obj->flags & DREFOBJ)
+ obj->flags &= ~DREFOBJ;
+ else
+ obj->flags |= VARADR;
+ push_value(fp, obj, POINTER, op);
+}
+
+/* Returns the zop to use for an output parameter. Unlike push_value, this does
+ * not emit a pop; that must be done later, if the return parameter is zero. */
+
+static void pop_value(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ /* We don't even *try* to handle dereferences here. */
+
+ if (flags & DREFOBJ)
+ goto stack;
+
+ if (flags == REG)
+ goto reg;
+
+ if ((flags == (VAR|REG)) &&
+ ((obj->v->storage_class == AUTO) ||
+ (obj->v->storage_class == REGISTER)))
+ goto reg;
+
+stack:
+ op->type = ZOP_STACK;
+ return;
+
+reg:
+ op->type = ZOP_REG;
+ op->val.reg = obj->reg;
+}
+
+/* Writes code for a zop. */
+
+static void emit_zop(FILE* fp, struct zop* op)
+{
+ switch (op->type)
+ {
+ case ZOP_STACK:
+ fprintf(fp, "sp");
+ return;
+
+ case ZOP_REG:
+ fprintf(fp, "%s", regnames[op->val.reg]);
+ return;
+
+ case ZOP_CONSTANT:
+ fprintf(fp, "0%+ld", (zshort)op->val.constant);
+ return;
+
+ case ZOP_EXTERN:
+ fprintf(fp, "_%s", op->val.identifier);
+ return;
+
+ case ZOP_STATIC:
+ fprintf(fp, "STATIC_%s_%ld",
+ modulename, op->val.constant);
+ return;
+
+ case ZOP_CONSTANTADDR:
+ fprintf(fp, "CONSTANT_%s_%ld",
+ modulename, op->val.constant);
+ return;
+
+ default:
+ ierror(op->type);
+ }
+}
+
+/* This is used in conjunction with pop_value(). pop_value() returns a zop that
+ * represents the return value for a function. If that return value is the
+ * stack, the value on the stack needs to be written back into memory. That's
+ * what this function does. */
+
+static void fin_zop(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ switch (op->type)
+ {
+ case ZOP_STACK:
+ write_reg(fp, obj, typf, 0);
+ return;
+
+ case ZOP_REG:
+ return;
+
+ default:
+ ierror(0);
+ }
+}
+
+/* Emit a basic ADD instruction.
+ * This routine tests for all the various special cases, of which there are
+ * many, and attempts to produce optimal code.
+ */
+
+static void emit_add(FILE* fp, struct zop* q1, struct zop* q2, struct zop* z)
+{
+ /* Sometimes we get ZOP_REG with reg=0. This actually means the stack. */
+
+ if ((q1->type == ZOP_REG) && (q1->val.reg == 0))
+ q1 = &zop_stack;
+ if ((q2->type == ZOP_REG) && (q2->val.reg == 0))
+ q2 = &zop_stack;
+ if ((z->type == ZOP_REG) && (z->val.reg == 0))
+ z = &zop_stack;
+
+ /* If q2 is a constant and 0, then this might be a register move of
+ * some kind. */
+
+ if ((q2->type == ZOP_CONSTANT) && (q2->val.constant == 0))
+ {
+ /* Left is a register? */
+ if (q1->type == ZOP_REG)
+ {
+ /* Right is a register? */
+ if (z->type == ZOP_REG)
+ {
+ /* They're the *same* register? */
+ if (q1->val.reg == z->val.reg)
+ {
+ /* No code need be emitted. */
+ return;
+ }
+
+ /* Emit a @store instruction. Unfortunately, I
+ * can't work out the syntax for Inform's
+ * @store opcode, so we emit a high-level
+ * assignment instead and let Inform work it
+ * out. */
+
+ fprintf(fp, "\t");
+ emit_zop(fp, z);
+ fprintf(fp, " = ");
+ emit_zop(fp, q1);
+ fprintf(fp, ";\n");
+ return;
+ }
+
+ /* Right is the stack? */
+ if (z->type == ZOP_STACK)
+ {
+ /* We're pushing the single parameter onto the
+ * stack. */
+
+ fprintf(fp, "\t@push ");
+ emit_zop(fp, q1);
+ fprintf(fp, ";\n");
+ return;
+ }
+ }
+
+ /* Left is the stack? */
+ if (q1->type == ZOP_STACK)
+ {
+ /* Right is a register? */
+ if (z->type == ZOP_REG)
+ {
+ /* We're popping the single parameter off the
+ * stack. */
+
+ fprintf(fp, "\t@pull ");
+ emit_zop(fp, z);
+ fprintf(fp, ";\n");
+ return;
+ }
+ }
+ }
+
+ /* Fall back on an ordinary @add. */
+
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, q1);
+ fprintf(fp, " ");
+ emit_zop(fp, q2);
+ fprintf(fp, " -> ");
+ emit_zop(fp, z);
+ fprintf(fp, ";\n");
+}
+
+/* Copy a value from one zop to another. This is not quite as simple as you
+ * might think, because there are a number of optimisation cases to take into
+ * account.
+ *
+ * NOTE: for simplicity, this function will never emit just a single
+ * instruction --- the assignment is always done via the stack. FIXME. */
+
+static void move_value(FILE* fp, struct obj* q1o, struct obj* zo, int typf)
+{
+ struct zop q1;
+ struct zop z;
+
+ pop_value(fp, zo, typf, &z);
+ push_value(fp, q1o, typf, &q1);
+ debugemit(fp, "! L=%d R=%d\n", q1.type, z.type);
+ /* In all cases except when push_value() and fin_zop() *both* emit
+ * code, we need to insert an assignment here. As they only emit code
+ * in the ZOP_STACK case... */
+ if ((q1.type != ZOP_STACK) || (z.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, zo, typf, &z);
+}
+
+/* Copy a 32-bit value from one obj to another. */
+
+static void move_long_value(FILE* fp, struct obj* q1, struct obj* z, int typf)
+{
+ int flags = q1->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+ struct zop q1z;
+ struct zop zz;
+
+ if (flags == KONST)
+ {
+ int hi = xword(q1->val.vlong, 1);
+ int lo = xword(q1->val.vlong, 0);
+
+ push_addrof(fp, z, POINTER, &zz);
+ fprintf(fp, "\t@call_vn __long_loadconst ");
+ emit_zop(fp, &zz);
+ fprintf(fp, " 0%+ld 0%+ld;\n", (short)hi, (short)lo);
+ return;
+ }
+
+ push_addrof(fp, z, POINTER, &zz);
+ push_addrof(fp, q1, POINTER, &q1z);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1z);
+ fprintf(fp, " ");
+ emit_zop(fp, &zz);
+ fprintf(fp, " 4;\n");
+}
+
+/* The code generator itself.
+ * This big, complicated, hairy and scary function does the work to actually
+ * produce the code. fp is the output stream, ic the beginning of the ic
+ * chain, func is a pointer to the actual function and stackframe is the size
+ * of the function's stack frame.
+ */
+
+void gen_code(FILE* fp, struct IC *ic, struct Var* func, zlong stackframe)
+{
+ int i;
+ struct zop q1;
+ struct zop q2;
+ struct zop z;
+ int code, typf; // ...of the IC under consideration
+
+ int c,t,lastcomp=0,reg;
+
+ function = func;
+
+ /* r0..r5 are always used for parameter passing. */
+
+ regused[2] = 1;
+ regused[3] = 1;
+ regused[4] = 1;
+ regused[5] = 1;
+ regused[6] = 1;
+ regused[7] = 1;
+
+ /* This is the offset of the stack frame, relative to the current stack
+ * pointer. */
+
+ stackoffset = stackframe;
+
+ /* No parameters pushed yet. */
+
+ stackparamadjust = 0;
+
+ reflower(fp);
+
+ if (func->storage_class == STATIC)
+ fprintf(fp, "[ STATIC_%s_%ld xp\n", modulename, func->offset);
+ else
+ fprintf(fp, "[ _%s xp\n", func->identifier);
+
+ /* Tell Inform what registers the function is using. */
+
+ for (i=1; i<=MAXR; i++)
+ {
+ //fprintf(fp, "! i=%d used %d scratch %d alloc %d\n",
+ // i, regused[i], regscratch[i], regsa[i]);
+ if (regused[i] && !regsa[i])
+ fprintf(fp, "\t%s\n", regnames[i]);
+ }
+ fprintf(fp, ";\n");
+
+ /* Trace the function name. */
+
+ if (g_flags[1] & USEDFLAG)
+ {
+ if (func->storage_class == STATIC)
+ fprintf(fp, "print \"STATIC_%s_%ld^\";\n", modulename, func->offset);
+ else
+ fprintf(fp, "print \"_%s^\";\n", func->identifier);
+ }
+
+ /* Adjust stack for locals. */
+
+ if (stackframe)
+ fprintf(fp, "\t@sub xp 0%+ld -> xp;\n", stackframe);
+ //if (stackoffset)
+ // fprintf(fp, "\txp = xp - %ld\n", stackframe);
+
+
+ /* Iterate through all ICs. */
+
+ for (; dump_ic(fp, ic), ic; ic=ic->next)
+ {
+ c=ic->code;t=ic->typf;
+ code = ic->code;
+ typf = ic->typf;
+
+ /* Do nothing for NOPs. */
+
+ if (code == NOP)
+ continue;
+
+ /* Has the stack been adjusted due to a call? */
+
+#if 0
+ if (stackcalladjustment)
+ {
+ if ((code != GETRETURN) &&
+ (code != FREEREG) &&
+ (code != ALLOCREG))
+ {
+ debugemit(fp, "! stack reset %d %d\n",
+ stackparamadjust, stackcallparamsize);
+ fprintf(fp, "\t@add xp %d -> xp;\n",
+ stackparamadjust+stackcallparamsize);
+ stackparamadjust = 0;
+ stackcallparamsize = 0;
+ stackcalladjustment = 0;
+ }
+ }
+#endif
+
+#if 0
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ fprintf(fp,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+ stackoffset+=notpopped;notpopped=0;
+ }
+ }
+#endif
+ /* These opcodes turn into other opcodes. */
+
+ switch (code)
+ {
+ case SUBPFP:
+ case SUBIFP:
+ code = SUB;
+ break;
+
+ case ADDI2P:
+ code = ADD;
+ break;
+ }
+
+ /* And now the big opcode switch. */
+
+ switch (code)
+ {
+ case ALLOCREG: /* Mark register in use */
+ regs[ic->q1.reg] = 1;
+ continue;
+
+ case FREEREG: /* Mark register not in use */
+ regs[ic->q1.reg] = 0;
+ continue;
+
+ case LABEL: /* Emit jump target */
+ fprintf(fp, ".%s%d;\n",
+ labelprefix, typf);
+ continue;
+
+ case BRA: /* Unconditional jump */
+ fprintf(fp, "\tjump %s%d;\n",
+ labelprefix, typf);
+ continue;
+
+ case GETRETURN: /* Read the last function call's return parameter */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ //if (ic->q2.val.vlong != 1)
+ // goto copy_struct;
+ /* fall through */
+ case SHORT:
+ case INT:
+ case POINTER:
+ write_reg(fp, &ic->z, typf, 2);
+ break;
+
+ /* Ignore the following; the
+ * front-end will automatically
+ * pass in an implicit
+ * parameter to the function
+ * containing the address of
+ * the return parameter, so
+ * GETRETURN ought to be a
+ * noop. */
+ case LONG:
+ case STRUCT:
+ case VOID:
+ case ARRAY:
+ break;
+#if 0
+ copy_struct:
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@copy_table xp ");
+ emit_zop(fp, &z);
+ fprintf(fp, " %ld;\n", szof(ic->z.v->vtyp));
+ break;
+#endif
+
+ default:
+ ierror(typf & NQ);
+ }
+ //fprintf(fp, "\tr0 = ");
+ //emit_object(fp, &ic->q1, typf);
+ //fprintf(fp, ";\n");
+ //write_reg(fp, &ic->z, typf, 2);
+ continue;
+
+ case SETRETURN: /* Set this function's return parameter */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ //if (ic->q2.val.vlong != 1)
+ // goto setreturn_copy_struct;
+ /* fall through */
+ case SHORT:
+ case INT:
+ case POINTER:
+ read_reg(fp, &ic->q1, typf, 2);
+ break;
+
+ case LONG:
+ case STRUCT:
+ case VOID:
+ case ARRAY:
+#if 0
+ setreturn_copy_struct:
+ fprintf(fp, "\t@add xp %ld -> sp;\n",
+ stackoffset);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " sp %ld;\n", szof(ic->q1.v->vtyp));
+ break;
+#endif
+
+ default:
+ ierror(typf & NQ);
+ }
+ //fprintf(fp, "\tr0 = ");
+ //emit_object(fp, &ic->q1, typf);
+ //fprintf(fp, ";\n");
+ continue;
+
+ case MINUS: /* Unary minus */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, typf, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@sub 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_addrof(fp, &ic->z, typf, &z);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vn __long_neg ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+
+ case KOMPLEMENT: /* Unary komplement */
+ /* INFORM BUG! */
+ /* The @not opcode doesn't work. We have to use a
+ * wrapper function instead. */
+
+ push_value(fp, &ic->q1, typf, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_2s __not ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ continue;
+
+ case MOVEFROMREG: /* Write a register to memory */
+ write_reg(fp, &ic->z, typf, ic->q1.reg);
+ continue;
+
+ case MOVETOREG: /* Read a register from memory */
+ read_reg(fp, &ic->q1, typf, ic->z.reg);
+ continue;
+
+ case ASSIGN: /* Move something to somewhere else */
+ debugemit(fp, "! ASSIGN size %d typf %d\n", ic->q2.val.vlong, typf & NQ);
+ switch (typf & NQ)
+ {
+ case CHAR:
+ if (ic->q2.val.vlong != 1)
+ goto assign_copy_struct;
+ /* fall through */
+ case SHORT:
+ case INT:
+ case POINTER:
+ move_value(fp, &ic->q1, &ic->z, typf);
+ break;
+
+ case LONG:
+ move_long_value(fp, &ic->q1, &ic->z, typf);
+ break;
+
+ case STRUCT:
+ case VOID:
+ case ARRAY:
+ assign_copy_struct:
+ push_addrof(fp, &ic->z, typf, &z);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0%+ld;\n", ic->q2.val.vlong);
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case ADDRESS: /* Fetch the address of something, always
+ AUTO or STATIC */
+ i = voff(&ic->q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@add xp 0%+ld -> ", i);
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ continue;
+
+ case PUSH: /* Push a value onto the stack */
+ fprintf(fp, "\t@sub xp 0%+ld -> xp;\n",
+ ic->q2.val.vlong);
+ //stackoffset += ic->q2.val.vlong;
+ stackparamadjust += ic->q2.val.vlong;
+
+ switch (ic->q2.val.vlong)
+ {
+ case 1:
+ push_value(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@storeb xp 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ case 2:
+ push_value(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@storew xp 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " xp 0%+ld;\n", ic->q2.val.vlong);
+ break;
+ }
+ continue;
+
+ case ADD: /* Add two numbers */
+ case SUB: /* Subtract two numbers */
+ case MULT: /* Multiply two numbers */
+ case DIV: /* Divide two numbers */
+ case MOD: /* Modulo two numbers */
+ case OR: /* Bitwise or */
+ case XOR: /* Bitwise xor */
+ case AND: /* Bitwise and */
+ case LSHIFT: /* Shift left */
+ case RSHIFT: /* Shift right */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case POINTER:
+ /* Second parameter first! */
+ push_value(fp, &ic->q2, typf, &q2);
+
+ if (code == RSHIFT)
+ {
+ fprintf(fp, "\t@sub 0 ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n");
+ q2.type = ZOP_STACK;
+ }
+
+ push_value(fp, &ic->q1, typf, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ //fprintf(fp, "\t");
+ //emit_object(fp, &ic->z, typf);
+ //fprintf(fp, " = ");
+ //emit_object(fp, &ic->q1, typf);
+ switch (code)
+ {
+ case ADD:
+ fprintf(fp, "\t@add ");
+ break;
+
+ case SUB:
+ fprintf(fp, "\t@sub ");
+ break;
+
+ case MULT:
+ fprintf(fp, "\t@mul ");
+ break;
+
+ case DIV:
+ if (typf & UNSIGNED)
+ fprintf(fp, "\t@call_vs __unsigned_div ");
+ else
+ fprintf(fp, "\t@div ");
+ break;
+
+ case MOD:
+ if (typf & UNSIGNED)
+ fprintf(fp, "\t@call_vs __unsigned_mod ");
+ else
+ fprintf(fp, "\t@mod ");
+ break;
+
+ case AND:
+ fprintf(fp, "\t@and ");
+ break;
+
+ case XOR:
+ fprintf(fp, "\t@call_vs __xor ");
+ break;
+
+ case OR:
+ fprintf(fp, "\t@or ");
+ break;
+
+ case LSHIFT:
+ case RSHIFT:
+ if (typf & UNSIGNED)
+ fprintf(fp, "\t@log_shift ");
+ else
+ fprintf(fp, "\t@art_shift ");
+ break;
+
+ default:
+ /* Should never get here! */
+ ierror(0);
+ }
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ //emit_object(fp, &ic->q2, typf);
+ break;
+
+ case LONG:
+ /* Destination parameter first! */
+
+ push_addrof(fp, &ic->z, typf, &z);
+ push_addrof(fp, &ic->q2, typf, &q2);
+ push_addrof(fp, &ic->q1, typf, &q1);
+
+ fprintf(fp, "\t@call_vn __long_");
+ switch (code)
+ {
+ case ADD:
+ fprintf(fp, "add");
+ break;
+
+ case SUB:
+ fprintf(fp, "sub");
+ break;
+
+ case MULT:
+ fprintf(fp, "mul");
+ break;
+
+ case DIV:
+ if (typf & UNSIGNED)
+ fprintf(fp, "unsigned_div");
+ else
+ fprintf(fp, "div");
+ break;
+
+ case MOD:
+ if (typf & UNSIGNED)
+ fprintf(fp, "unsigned_mod");
+ else
+ fprintf(fp, "mod");
+ break;
+
+ case AND:
+ fprintf(fp, "and");
+ break;
+
+ case XOR:
+ fprintf(fp, "xor");
+ break;
+
+ case OR:
+ fprintf(fp, "or");
+ break;
+
+ case LSHIFT:
+ fprintf(fp, "lsl");
+ break;
+
+ case RSHIFT:
+ if (typf & UNSIGNED)
+ fprintf(fp, "lsr");
+ else
+ fprintf(fp, "asr");
+ break;
+
+ default:
+ /* Should never get here! */
+ ierror(0);
+ }
+ fprintf(fp, " ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+
+ case CONVCHAR: /* Convert from char */
+ switch (typf & NU)
+ {
+ case CHAR:
+ case UNSIGNED|CHAR:
+ case UNSIGNED|SHORT:
+ case UNSIGNED|INT:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, CHAR, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@log_shift ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 8 -> sp;\n");
+ fprintf(fp, "\t@art_shift sp 0-8 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_fromchar");
+ emit_zop(fp, &z);
+ fprintf(fp, " ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+
+ case CONVUCHAR: /* Convert from unsigned char */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, UNSIGNED|CHAR, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, UNSIGNED|CHAR, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_fromint");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+
+ case CONVSHORT: /* Convert from short */
+ case CONVINT: /* Convert from int */
+ switch (typf & NU)
+ {
+ case CHAR:
+ case UNSIGNED|CHAR:
+ case UNSIGNED|SHORT:
+ case UNSIGNED|INT:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, INT, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_fromint ");
+ emit_zop(fp, &z);
+ fprintf(fp, " ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ case UNSIGNED|LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_loadconst ");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(typf);
+ }
+ continue;
+
+ case CONVUSHORT: /* Convert from unsigned short */
+ case CONVUINT: /* Convert from unsigned int */
+ case CONVPOINTER: /* Convert from pointer */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, INT, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_loadconst ");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+#if 0
+ case SHORT:
+ case INT:
+ fprintf(fp, "\t");
+ emit_object(fp, &ic->z, typf);
+ fprintf(fp, " = (");
+ emit_object(fp, &ic->q1, CHAR);
+ fprintf(fp, ") << 8 >> 8;\n");
+ break;
+#endif
+
+ default:
+ printf("%X\n", typf);
+ ierror(0);
+ }
+ continue;
+
+ case CONVULONG: /* Convert from unsigned long */
+ case CONVLONG: /* Convert from long */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ push_addrof(fp, &ic->q1, LONG, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@loadb ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 3 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case SHORT:
+ case INT:
+ push_addrof(fp, &ic->q1, LONG, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@loadw ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 1 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case COMPARE:
+ /* COMPARE is special. The next instruction is
+ * always a branch. The Z-machine does
+ * branches in the form:
+ *
+ * @j{e,g,l} <var1> <var2> [~]@<label>
+ *
+ * However, we don't know what short of branch
+ * to emit until the next instruction (which is
+ * the IC for a branch). So we have to stash
+ * the zops that we're using for the
+ * compare here, for use later. This is done
+ * using the globals compare1 and compare2.
+ */
+
+ switch (typf & NU)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case POINTER:
+ /* Second parameter first! */
+ push_value(fp, &ic->q2, typf, &compare2);
+ push_value(fp, &ic->q1, typf, &compare1);
+ break;
+
+ case UNSIGNED|CHAR:
+ case UNSIGNED|SHORT:
+ case UNSIGNED|INT:
+ /* Because the Z-machine only
+ * has signed comparisons, we
+ * need a dodgy algorithm to
+ * do this, which works as
+ * follows: in the signed
+ * domain, 0-7FFF compares
+ * greater than 8000-FFFF. In
+ * the unsigned domain, it's
+ * the other way around. So,
+ * by flipping the sign bits
+ * we do the logical
+ * equivalent of shifting the
+ * unsigned range up/down by
+ * 8000 which makes it fit
+ * the signed range. There.
+ * Did you understand that?
+ * Neither did I, the first
+ * few times it was explained
+ * to me. */
+ read_reg(fp, &ic->q2, typf, 0);
+ fprintf(fp, "\t@add sp $8000 -> sp;\n");
+ read_reg(fp, &ic->q1, typf, 0);
+ fprintf(fp, "\t@add sp $8000 -> sp;\n");
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_STACK;
+ break;
+
+ case LONG:
+ push_addrof(fp, &ic->q2, typf, &q2);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs __long_compare ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n");
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ case UNSIGNED|LONG:
+ push_addrof(fp, &ic->q2, typf, &q2);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs __long_unsigned_compare ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n");
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case TEST:
+ /* TEST is a special COMPARE. It takes one
+ * parameter and always tests it against 0; it
+ * is guaranteed to be followed by BNE or BEQ.
+ * */
+
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case POINTER:
+ push_value(fp, &ic->q1, typf, &compare1);
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ case LONG:
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs __long_compare ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ q2.type = ZOP_CONSTANTADDR;
+ q2.val.constant = addconstant(0);
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n", i);
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BGE:
+ case BLE:
+ case BGT:
+ {
+ static int branchlabel = 0;
+
+ fprintf(fp, "\t@j");
+ switch (code)
+ {
+ case BNE:
+ case BEQ: fprintf(fp, "e "); break;
+ case BLT:
+ case BGE: fprintf(fp, "l "); break;
+ case BGT:
+ case BLE: fprintf(fp, "g "); break;
+ }
+
+ emit_zop(fp, &compare1);
+ fprintf(fp, " ");
+ emit_zop(fp, &compare2);
+ fprintf(fp, " ?");
+
+ if (g_flags[3] & USEDFLAG)
+ {
+ if (!((code == BNE) || (code == BGE) || (code == BLE)))
+ fprintf(fp, "~");
+ fprintf(fp, "LL%d;\n", branchlabel);
+ fprintf(fp, "\tjump %s%d;\n", labelprefix, typf);
+ fprintf(fp, ".LL%d;\n", branchlabel++);
+ }
+ else
+ {
+ if ((code == BNE) || (code == BGE) || (code == BLE))
+ fprintf(fp, "~");
+ fprintf(fp, "%s%d;\n", labelprefix, typf);
+ }
+ continue;
+ }
+
+ case CALL:
+ {
+#if 0
+ /* Calculate the amount of stack to reserve for
+ * the return parameter. ints and smaller go in
+ * the return register. */
+
+ stackcallparamsize = szof(ic->q1.v->vtyp->next);
+ if (stackcallparamsize <= sizetab[INT])
+ stackcallparamsize = 0;
+
+ if (stackcallparamsize)
+ fprintf(fp, "\t@sub xp %d -> xp;\n",
+ stackcallparamsize);
+#endif
+
+ /* Is this actually an inline assembly function? */
+
+ if ((ic->q1.flags & VAR) &&
+ ic->q1.v->fi &&
+ ic->q1.v->fi->inline_asm)
+ {
+ /* Yes. Emit the assembly code. */
+
+ fprintf(fp, "%s", ic->q1.v->fi->inline_asm);
+ }
+ else
+ {
+ /* No; so emit a call. */
+
+ push_value(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs2 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " xp r0 r1 r2 r3 r4 r5 -> r0;\n");
+ }
+
+ //stackcalladjustment = 1;
+
+ /* If any parameters have been pushed, adjust
+ * the stack to pop them. */
+
+ if (stackparamadjust)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> xp;\n",
+ stackparamadjust);
+ //stackoffset -= stackparamadjust;
+ stackparamadjust = 0;
+ }
+ continue;
+ }
+
+ default:
+ ierror(code);
+ }
+
+ }
+
+ /* We really ought to tidy the stack up; but there's no need, because
+ * the old value of xp will be restored when the function exits. */
+
+ //if (stackframe)
+ // fprintf(fp, "\t@add xp %ld -> xp;\n", stackframe);
+
+ fprintf(fp, "\t@ret r0;\n");
+ fprintf(fp, "]\n");
+
+// function_bottom(fp, func, loff);
+}
+
+int shortcut(int code, int typ)
+{
+ return(0);
+}
+
+// Add a constant to the constant pool.
+
+static int addconstant(zlong value)
+{
+ struct constant* c;
+
+ /* Check to see if the constant's already in the pool. */
+
+ c = constantlist;
+ while (c)
+ {
+ if (c->value == value)
+ return c->id;
+ c = c->next;
+ }
+
+ /* It's not; add it. */
+
+ c = malloc(sizeof(struct constant));
+ c->next = constantlist;
+ c->id = constantnum++;
+ c->value = value;
+ constantlist = c;
+ return c->id;
+}
+
+void cleanup_cg(FILE *fp)
+{
+ struct fixup* fixup = fixuplist;
+
+ /* Have we actually emitted anything? */
+
+ if (!fp)
+ return;
+
+ reflower(fp);
+
+ /* Emit the constant pool. */
+
+ {
+ struct constant* constant = constantlist;
+
+ while (constant)
+ {
+ fprintf(fp, "Array CONSTANT_%s_%ld -->\n",
+ modulename, constant->id);
+ fprintf(fp, " 0%+ld 0%+ld;\n",
+ xword(constant->value, 1),
+ xword(constant->value, 0));
+ constant = constant->next;
+ }
+ }
+
+ /* Emit the code to initialise the data area. */
+
+ {
+ struct fixup* fixup = fixuplist;
+
+ fprintf(fp, "[ __init_vars_%s;\n", modulename);
+ while (fixup)
+ {
+ fprintf(fp, "\t@add 0%+ld ", fixup->offset);
+
+ switch (fixup->value.type)
+ {
+ case STATIC:
+ fprintf(fp, "STATIC_%s_%ld -> sp;\n",
+ modulename, fixup->value.val.number);
+ break;
+
+ case EXTERN:
+ fprintf(fp, "_%s -> sp;\n",
+ fixup->value.val.identifier);
+ break;
+
+ default:
+ ierror(0);
+ }
+
+ switch (fixup->identifier.type)
+ {
+ case STATIC:
+ fprintf(fp, "\t@storew STATIC_%s_%ld 0%+ld sp;\n",
+ modulename, fixup->identifier.val.number,
+ fixup->identifier.offset);
+ break;
+
+ case EXTERN:
+ fprintf(fp, "\t@storew _%s 0%+ld sp;\n",
+ fixup->identifier.val.identifier,
+ fixup->identifier.offset);
+ break;
+
+ default:
+ ierror(0);
+ }
+
+ fixup = fixup->next;
+ }
+ fprintf(fp, "];\n");
+ }
+}
+
+/* The code generator's asking us to pass a parameter in a register. */
+
+int reg_parm(struct reg_handle *rh, struct Typ *typ, int vararg)
+{
+ /* Vararg parameters never go in registers. */
+
+ if (vararg)
+ return 0;
+
+ /* Will the parameter fit? */
+
+ if (sizetab[typ->flags & NQ] > 2)
+ return 0;
+
+ /* Still enough registers? */
+
+ if (rh->reg >= NUM_REGPARMS+USERREG)
+ return 0;
+
+ return (rh->reg++);
+}
+
--- vbcc-0.7.orig/ic.c
+++ vbcc-0.7/ic.c
@@ -8,6 +8,8 @@
int do_arith(np,struct IC *,np,struct obj *);
+static void handle_reglist(struct regargs_list *,struct obj *);
+
void gen_test(struct obj *o,int t,int branch,int label)
/* Generiert ein test o, branch label und passt auf, dass */
/* kein TEST const generiert wird. */
@@ -732,13 +734,20 @@
ptyp.next=p->ntyp;
reg=reg_parm(®_handle,&ptyp,0);
if(!reg) ierror(0);
- sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,&ret_obj,reg);
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,&ret_obj,p->ntyp,reg);
+ if(optflags&2)
+ handle_reglist(rl,&ret_obj);
}else{
- sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,-1);
+ struct reg_handle reg_handle=empty_reg_handle;
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,0,-1);
+ if(optflags&2)
+ handle_reglist(rl,0);
}
}
#else
sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl);
+ if(optflags&2)
+ handle_reglist(rl,0);
#endif
if(!r) gen_IC(p->left,0,0);
if(!(p->left->o.flags&DREFOBJ)){
@@ -1068,8 +1077,45 @@
free(new);
p->o.flags=0;
}
+
+static void handle_reglist(struct regargs_list *nrl,struct obj *radr)
+{
+ struct IC *new;
+ /* Letztes Argument; jetzt in Register laden. */
+#ifdef HAVE_REGPARMS
+ int didradr=0;
+#endif
+ while(nrl){
+ new=mymalloc(ICS);
+ new->code=ASSIGN;
+ new->typf=nrl->v->vtyp->flags|VOLATILE;
+ new->q1.flags=VAR;
+ new->q1.v=nrl->v;
+ new->q1.val.vlong=l2zl(0L);
+ new->q2.flags=0;
+ new->q2.val.vlong=szof(nrl->v->vtyp);
+ new->z.flags=VAR;
+ new->z.val.vlong=l2zl(0L);
+ new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0);
+ new->z.v->reg=nrl->reg;
+ nrl->v=new->z.v;
+ add_IC(new);
+
#ifdef HAVE_REGPARMS
-zlong push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl,struct reg_handle *reg_handle,struct obj *radr,int rreg)
+ if(radr&&!didradr){
+ didradr=1;
+ }else{
+#endif
+ nrl->al->pushic=new;
+#ifdef HAVE_REGPARMS
+ }
+#endif
+ nrl=nrl->next;
+ }
+}
+
+#ifdef HAVE_REGPARMS
+zlong push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl,struct reg_handle *reg_handle,struct obj *radr,struct Typ *rtype,int rreg)
#else
zlong push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl)
#endif
@@ -1077,7 +1123,7 @@
/* auf den Stack. Es wird Integer-Erweiterung vorgenommen und float wird */
/* nach double konvertiert, falls kein Prototype da ist. */
{
- int t,reg,regpush,evaluated=0;
+ int t,reg,regpush,evaluated=0;struct Typ *ft;
struct IC *new;struct regargs_list *nrl;zlong sz,of;struct obj *arg;
#ifdef HAVE_REGPARMS
int stdreg;
@@ -1105,16 +1151,21 @@
if(!al->arg) ierror(0);
if(!sd) ierror(0);
if(n<sd->count){
- t=(*sd->sl)[n].styp->flags;sz=szof((*sd->sl)[n].styp);
+ ft=clone_typ((*sd->sl)[n].styp);sz=szof(ft);
+ t=ft->flags;
reg=(*sd->sl)[n].reg;
}else{
- t=al->arg->ntyp->flags;sz=szof(al->arg->ntyp);
+ ft=clone_typ(al->arg->ntyp);sz=szof(ft);
+ t=ft->flags;
}
- if((t&NQ)>=CHAR&&(t&NQ)<=LONG) {t=int_erw(t);sz=sizetab[t&NQ];}
+ if((t&NQ)>=CHAR&&(t&NQ)<=LONG) {t=int_erw(t);ft->flags=t;sz=sizetab[t&NQ];}
if((t&NQ)==FLOAT&&n>=sd->count) {t=DOUBLE;sz=sizetab[t];}
#ifdef HAVE_REGPARMS
}else{
- t=POINTER;sz=sizetab[POINTER];
+ ft=mymalloc(TYPS);
+ ft->flags=t=POINTER;
+ ft->next=clone_typ(rtype);
+ sz=sizetab[t];
}
#endif
if(reg<0) {reg=-reg;regpush=1;} else regpush=0;
@@ -1127,6 +1178,7 @@
convert(al->arg,t&NU);
evaluated=1;
new->q1=al->arg->o;
+ al->pushic=new;
}else
new->q1=*radr;
/* Parameteruebergabe ueber Stack. */
@@ -1152,9 +1204,9 @@
#endif
#ifdef HAVE_REGPARMS
if(radr){
- if(al) of=push_args(al,sd,0,rl,reg_handle,0,0); else of=l2zl(0L);
+ if(al) of=push_args(al,sd,0,rl,reg_handle,0,0,0); else of=l2zl(0L);
}else{
- if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0); else of=l2zl(0L);
+ if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0,0); else of=l2zl(0L);
}
#else
if(al->next) of=push_args(al->next,sd,n+1,rl); else of=l2zl(0L);
@@ -1171,7 +1223,7 @@
}else{
if(!evaluated){
gen_IC(al->arg,0,0);
- convert(al->arg,t&NU);
+ convert(al->arg,t);
evaluated=1;
}
arg=&al->arg->o;
@@ -1195,6 +1247,7 @@
new->q2.flags=new->z.flags=0;
new->q2.val.vlong=sz;
add_IC(new);
+ al->pushic=new;
if(!regpush) return(zladd(of,sz));
}
#endif
@@ -1225,31 +1278,8 @@
nrl->next=*rl;
nrl->reg=reg;
nrl->v=v;
+ nrl->al=al;
*rl=nrl;
-#ifdef HAVE_REGPARMS
- if(radr||(!radr&&rreg==-1))
-#else
- if(n==0)
-#endif
- {
- /* Letztes Argument; jetzt in Register laden. */
- for(;nrl;nrl=nrl->next){
- new=mymalloc(ICS);
- new->code=ASSIGN;
- new->typf=nrl->v->vtyp->flags|VOLATILE;
- new->q1.flags=VAR;
- new->q1.v=nrl->v;
- new->q1.val.vlong=l2zl(0L);
- new->q2.flags=0;
- new->q2.val.vlong=szof(nrl->v->vtyp);
- new->z.flags=VAR;
- new->z.val.vlong=l2zl(0L);
- new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0);
- new->z.v->reg=nrl->reg;
- nrl->v=new->z.v;
- add_IC(new);
- }
- }
return(of);
}else{
/* Nicht-optimierende Version. */
@@ -1281,6 +1311,13 @@
}else regs[reg]|=32;
}
new=mymalloc(ICS);
+#ifdef HAVE_REGPARMS
+ if(!radr){
+ al->pushic=new;
+ }
+#else
+ al->pushic=new;
+#endif
new->code=ASSIGN;
new->typf=t;
new->q1=*arg;
@@ -1520,6 +1557,9 @@
new->q1=p->left->o;
/* kleinere Typen als MINADDI2P erst in diesen wandeln */
if((new->typf&NQ)<MINADDI2P){convert(p->right,/*UNSIGNED|*/MINADDI2P);new->typf=/*UNSIGNED|*/MINADDI2P;}
+#ifdef MAXADDI2P
+ if((new->typf&NQ)>MAXADDI2P){convert(p->right,/*UNSIGNED|*/MAXADDI2P);new->typf=/*UNSIGNED|*/MAXADDI2P;}
+#endif
new->q2=p->right->o;
if(!dest&&(p->left->o.flags&SCRATCH)&®ok(new->q1.reg,POINTER,p->left->ntyp->next->flags&NU)){
new->z=p->left->o;
--- vbcc-0.7.orig/configure
+++ vbcc-0.7/configure
@@ -0,0 +1,1192 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=main.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says
[email protected].
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+# Check for programs.
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:531: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:561: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:612: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:644: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 655 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:660: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:686: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:691: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:700: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:719: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+
+# Check for header files.
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:754: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 769 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:775: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 786 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:792: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 803 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:809: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:834: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 839 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:847: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 864 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 882 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 903 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:914: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+
+# ...and output.
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
--- vbcc-0.7.orig/share/vbcc/conf/i386
+++ vbcc-0.7/share/vbcc/conf/i386
@@ -0,0 +1,8 @@
+-pp=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/i386/include -D__I386__ -+ %s %s %s
+-ppv=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/i386/include -D__I386__ -+ %s %s %s
+-cc=/usr/lib/vbcc/vbcci386 -quiet %s -o=%s %s -O=%ld
+-ccv=/usr/lib/vbcc/vbcci386 -I/usr/share/vbcc/arch/i386/include %s -o=%s %s -O=%ld
+-as=echo "Don't know how to assemble i386 code" 1>&2; exit 0
+-ld=echo "Don't know how to link i386 code" 1>&2; exit 0
+-rm=rm %s
+-rmv=rm %s
--- vbcc-0.7.orig/share/vbcc/conf/m68k
+++ vbcc-0.7/share/vbcc/conf/m68k
@@ -0,0 +1,8 @@
+-pp=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/m68k/include -D__M68K__ -+ %s %s %s
+-ppv=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/m68k/include -D__M68K__ -+ %s %s %s
+-cc=/usr/lib/vbcc/vbccm68k -quiet %s -o=%s %s -O=%ld
+-ccv=/usr/lib/vbcc/vbccm68k -I/usr/share/vbcc/arch/m68k/include %s -o=%s %s -O=%ld
+-as=echo "Don't know how to assemble m68k code" 1>&2; exit 0
+-ld=echo "Don't know how to link m68k code" 1>&2; exit 0
+-rm=rm %s
+-rmv=rm %s
--- vbcc-0.7.orig/share/vbcc/conf/alpha
+++ vbcc-0.7/share/vbcc/conf/alpha
@@ -0,0 +1,8 @@
+-pp=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/alpha/include -D__ALPHA__ -+ %s %s %s
+-ppv=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/alpha/include -D__ALPHAI386__ -+ %s %s %s
+-cc=/usr/lib/vbcc/vbccalpha -quiet %s -o=%s %s -O=%ld
+-ccv=/usr/lib/vbcc/vbccalpha -I/usr/share/vbcc/arch/alpha/include %s -o=%s %s -O=%ld
+-as=echo "Don't know how to assemble Alpha code" 1>&2; exit 0
+-ld=echo "Don't know how to link Alpha code" 1>&2; exit 0
+-rm=rm %s
+-rmv=rm %s
--- vbcc-0.7.orig/share/vbcc/conf/ppc
+++ vbcc-0.7/share/vbcc/conf/ppc
@@ -0,0 +1,8 @@
+-pp=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/ppc/include -D__PPC__ -+ %s %s %s
+-ppv=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/ppc/include -D__PPC__ -+ %s %s %s
+-cc=/usr/lib/vbcc/vbccppc -quiet %s -o=%s %s -O=%ld
+-ccv=/usr/lib/vbcc/vbccppc -I/usr/share/vbcc/arch/ppc/include %s -o=%s %s -O=%ld
+-as=echo "Don't know how to assemble PowerPC code" 1>&2; exit 0
+-ld=echo "Don't know how to link PowerPC code" 1>&2; exit 0
+-rm=rm %s
+-rmv=rm %s
--- vbcc-0.7.orig/share/vbcc/conf/z
+++ vbcc-0.7/share/vbcc/conf/z
@@ -0,0 +1,7 @@
+-pp=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/z/include -+ -D__Z__ %s %s %s
+-ppv=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/z/include -+ -D__Z__ %s %s %s
+-cc=/usr/lib/vbcc/vbccz -quiet %s -o=%s %s -O=%ld
+-ccv=/usr/lib/vbcc/vbccz %s -o=%s %s -O=%ld
+-as=cp %s %s
+-ld=echo "Don't know how to link Z-machine code" 1>&2; exit 0
+-rm=rm %s
--- vbcc-0.7.orig/share/vbcc/conf/c16x
+++ vbcc-0.7/share/vbcc/conf/c16x
@@ -0,0 +1,8 @@
+-pp=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/c16x/include -D__C16X__ -+ %s %s %s
+-ppv=/usr/lib/vbcc/vcpp -I/usr/share/vbcc/arch/c16x/include -D__C16X__ -+ %s %s %s
+-cc=/usr/lib/vbcc/vbccc16x -quiet %s -o=%s %s -O=%ld
+-ccv=/usr/lib/vbcc/vbccc16x -I/usr/share/vbcc/arch/c16x/include %s -o=%s %s -O=%ld
+-as=echo "Don't know how to assemble C16X code" 1>&2; exit 0
+-ld=echo "Don't know how to link C16X code" 1>&2; exit 0
+-rm=rm %s
+-rmv=rm %s
--- vbcc-0.7.orig/share/vbcc/arch/i386/include/stdarg.h
+++ vbcc-0.7/share/vbcc/arch/i386/include/stdarg.h
@@ -0,0 +1,24 @@
+/* stdarg.h
+ * vbcc is (c) in 1995-99 by Volker Barthelmann. All code is written by me
+ * and may be freely redistributed as long as no modifications are made
+ * and nothing is charged for it.
+ * Non-commercial usage of vbcc is allowed without any restrictions.
+ * Commercial usage needs my written consent.
+ *
+ * Sending me money, gifts, postcards etc. would of course be very nice
+ * and may encourage further development of vbcc, but is not legally or
+ * morally necessary to use vbcc.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+typedef unsigned char *va_list;
+
+#define va_start(ap, lastarg) ((ap) = (va_list)(&lastarg + 1))
+#define va_arg(ap, type) ((ap) += \
+ (sizeof(type)<sizeof(int)?sizeof(int):sizeof(type)), ((type *)(ap))[-1])
+#define va_end(ap) ((ap) = 0L)
+
+#endif
+
--- vbcc-0.7.orig/share/vbcc/arch/m68k/include/stdarg.h
+++ vbcc-0.7/share/vbcc/arch/m68k/include/stdarg.h
@@ -0,0 +1,24 @@
+/* alpha/m68k.h
+ * vbcc is (c) in 1995-99 by Volker Barthelmann. All code is written by me
+ * and may be freely redistributed as long as no modifications are made
+ * and nothing is charged for it.
+ * Non-commercial usage of vbcc is allowed without any restrictions.
+ * Commercial usage needs my written consent.
+ *
+ * Sending me money, gifts, postcards etc. would of course be very nice
+ * and may encourage further development of vbcc, but is not legally or
+ * morally necessary to use vbcc.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+typedef unsigned char *va_list;
+
+#define va_start(ap, lastarg) ((ap) = (va_list)(&lastarg + 1))
+#define va_arg(ap, type) ((ap) += \
+ (sizeof(type)<sizeof(int)?sizeof(int):sizeof(type)), ((type *)(ap))[-1])
+#define va_end(ap) ((ap) = 0L)
+
+#endif
+
--- vbcc-0.7.orig/share/vbcc/arch/alpha/include/stdarg.h
+++ vbcc-0.7/share/vbcc/arch/alpha/include/stdarg.h
@@ -0,0 +1,44 @@
+/* alpha/stdarg.h
+ * vbcc is (c) in 1995-99 by Volker Barthelmann. All code is written by me
+ * and may be freely redistributed as long as no modifications are made
+ * and nothing is charged for it.
+ * Non-commercial usage of vbcc is allowed without any restrictions.
+ * Commercial usage needs my written consent.
+ *
+ * Sending me money, gifts, postcards etc. would of course be very nice
+ * and may encourage further development of vbcc, but is not legally or
+ * morally necessary to use vbcc.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+typedef struct {
+ char *regbase;
+ char *membase;
+ int arg;
+} va_list;
+
+char *__va_start(void);
+int __va_fixargs(void);
+
+#define va_start(vl,dummy) \
+(vl.arg=__va_fixargs(),vl.regbase=__va_start(),vl.membase=vl.regbase+(6-vl.arg)*16)
+
+#define va_end(vl) (vl.regbase=vl.membase=0)
+
+#define __va_size(type) ((sizeof(type)+7)/8*8)
+#define va_arg(vl,type) \
+ ( \
+ ((__typeof(type)&15)<=8&&++vl.arg<=6) ? \
+ ( \
+ ((__typeof(type)&15)==5||(__typeof(type)&15)==6) ? \
+ (vl.regbase+=16,*(type *)(vl.regbase-8)) \
+ : \
+ (vl.regbase+=16,*(type *)(vl.regbase-16)) \
+ ) \
+ : \
+ (vl.membase+=__va_size(type),*(type *)(vl.membase-__va_size(type))) \
+ )
+
+#endif
--- vbcc-0.7.orig/share/vbcc/arch/ppc/include/stdarg.h
+++ vbcc-0.7/share/vbcc/arch/ppc/include/stdarg.h
@@ -0,0 +1,61 @@
+/* alpha/m68k.h
+ * vbcc is (c) in 1995-99 by Volker Barthelmann. All code is written by me
+ * and may be freely redistributed as long as no modifications are made
+ * and nothing is charged for it.
+ * Non-commercial usage of vbcc is allowed without any restrictions.
+ * Commercial usage needs my written consent.
+ *
+ * Sending me money, gifts, postcards etc. would of course be very nice
+ * and may encourage further development of vbcc, but is not legally or
+ * morally necessary to use vbcc.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+typedef struct {
+ int gpr;
+ int fpr;
+ char *regbase;
+ char *membase;
+} va_list;
+
+char *__va_start(void);
+char *__va_regbase(void);
+int __va_fixedgpr(void);
+int __va_fixedfpr(void);
+
+#define va_start(vl,dummy) \
+ ( \
+ vl.gpr=__va_fixedgpr(), \
+ vl.fpr=__va_fixedfpr(), \
+ vl.regbase=__va_regbase(), \
+ vl.membase=__va_start() \
+ )
+
+#define va_end(vl) (vl.regbase=vl.membase=0)
+
+#define __va_size(type) ((sizeof(type)+3)/4*4)
+#define va_arg(vl,type) \
+ (__typeof(type)&15)>8? \
+ (vl.membase+=__va_size(type),((type*)vl.membase)[-1]) \
+ : \
+ ( \
+ (((__typeof(type)&15)==5||(__typeof(type)&15)==6)) ? \
+ ( \
+ ++vl.fpr<=8 ? \
+ ((double*)(vl.regbase+32))[vl.fpr] \
+ : \
+ (vl.membase+=__va_size(type),((type*)vl.membase)[-1]) \
+ ) \
+ : \
+ ( \
+ ++vl.gpr<=8 ? \
+ ((int*)(vl.regbase+0))[vl.gpr] \
+ : \
+ (vl.membase+=__va_size(type),((type*)vl.membase)[-1]) \
+ ) \
+ ) \
+
+#endif
+
--- vbcc-0.7.orig/share/vbcc/arch/z/include/stdarg.h
+++ vbcc-0.7/share/vbcc/arch/z/include/stdarg.h
@@ -0,0 +1,38 @@
+/* z/stdarg.h
+ * Copyright (c) 2001, David Given
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+typedef char* va_list;
+extern va_list __va_start; /* magic */
+
+#define va_start(ap, lastarg) \
+ ((ap) = __va_start)
+#define va_arg(ap, type) \
+ (((ap) += (sizeof(type)<sizeof(int)) ? sizeof(int) : sizeof(type)), \
+ ((type*)ap)[-1])
+#define va_end(ap) ((ap) = 0)
+
+#endif
+
--- vbcc-0.7.orig/share/vbcc/arch/z/runtime.s
+++ vbcc-0.7/share/vbcc/arch/z/runtime.s
@@ -0,0 +1,508 @@
+! Z-machine C runtime
+! Copyright (c) 2001, David Given
+! All rights reserved.
+!
+! Permission is hereby granted, free of charge, to any person obtaining a
+! copy of this software and associated documentation files (the "Software"),
+! to deal in the Software without restriction, including without limitation
+! the rights to use, copy, modify, merge, publish, distribute, sublicense,
+! and/or sell copies of the Software, and to permit persons to whom the
+! Software is furnished to do so, subject to the following conditions:
+!
+! The above copyright notice and this permission notice shall be included in
+! all copies or substantial portions of the Software.
+!
+! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+! FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+! DEALINGS IN THE SOFTWARE.
+
+! There's an Inform bug that stops the @not opcode from assembling correctly,
+! so we have to use a conventional expression.
+
+[ __not q1;
+ return ~q1;
+];
+
+! And the Z-machine doesn't have xor. How bizarre.
+
+[ __xor q1 q2 t;
+ return (q1 & (~q2)) | ((~q1) & q2);
+];
+
+! Unsigned arithmetic is hard. These helper functions do it for us.
+! Thanks to Jay Foad for the algorithm for this.
+
+[ __unsigned_div q1 q2 t;
+ if (q1 == 0)
+ return q1;
+ else if (q2 == 0)
+ {
+ print "[zlibc error: division by zero in __unsigned_div]";
+ return 0;
+ }
+ else if (q2 == 1)
+ return q1;
+ else if ((q1 > 0) && (q2 > 0))
+ return q1/q2;
+
+ ! Optimisation query: given that when executing Z-machine instructions,
+ ! the decoding is by far the slowest part of the process, is it
+ ! useful to have these special cases?
+
+ !else if ((q1-32768) < (q2-32768))
+ ! return 0;
+
+ else if (q1 == q2)
+ return 1;
+ else if (q2 < 0)
+ {
+ ! If q2 is high, then the result can only be 0 or 1.
+ ! The only way it can be 1 is if q1 > q2.
+ return ((q1-32768) > (q2-32768));
+ }
+
+ ! Lose one bit of precision, and do the calculation.
+
+ @log_shift q1 0-1 -> t;
+ t = t / q2;
+ @log_shift t 1 -> t;
+
+ ! Now multiply back out and calculate the remainder. This tells
+ ! us how much to modify the result by, to restore lost precision.
+
+ !print "{", t, "}";
+ !print "[", (q1 - t*q2), ">", q2, "]";
+
+ if (((q1 - t*q2)-32768) >= (q2-32768))
+ t++;
+ return t;
+];
+
+[ __unsigned_mod q1 q2 t;
+ t = __unsigned_div(q1, q2) * q2;
+ return q1 - t;
+];
+
+! These wrapper functions do all the long arithmetic.
+
+Array __long_temp1 -> 4;
+Array __long_temp2 -> 4;
+Array __long_temp3 -> 4;
+
+[ __long_copy q1 z; ! z = q1
+ z-->0 = q1-->0;
+ z-->1 = q1-->1;
+];
+
+[ __long_loadconst z hi lo; ! z = hi.lo
+ z-->0 = hi;
+ z-->1 = lo;
+];
+
+[ __long_fromint z q1; ! z = (long)q1, with sign extension
+ z-->1 = q1;
+ if (q1 < 0)
+ z-->0 = -1;
+ else
+ z-->0 = 0;
+];
+
+[ __long_and q1 q2 z;
+ z-->0 = q1-->0 & q2-->0;
+ z-->1 = q1-->1 & q2-->1;
+];
+
+[ __long_or q1 q2 z;
+ z-->0 = q1-->0 | q2-->0;
+ z-->1 = q1-->1 | q2-->1;
+];
+
+[ __long_asr q1 q2 z s t;
+ if ((q2-->0 ~= 0) || (((q2-->1)-32768) > (31-32768)))
+ {
+ ! All bits shifted off; so we just propagate the sign.
+
+ if (q2-->0 & $8000)
+ {
+ z-->0 = -1;
+ z-->1 = -1;
+ }
+ else
+ {
+ z-->0 = 0;
+ z-->1 = 0;
+ }
+
+ return;
+ }
+
+ q2 = -(q2-->1 & $1F);
+ s = 16 + q2;
+
+ t = q1-->1;
+ @log_shift t q2 -> t;
+ z-->1 = t;
+
+ t = q1-->0;
+ @log_shift t s -> t;
+ z-->1 = z-->1 | t;
+
+ t = q1-->0;
+ @art_shift t q2 -> t;
+ z-->0 = t;
+];
+
+[ __long_lsr q1 q2 z s t;
+ if ((q2-->0 ~= 0) || ((q2-->1-32768) > (31-32768)))
+ {
+ ! All bits shifted off; the result is zero.
+
+ z-->0 = 0;
+ z-->1 = 0;
+ return;
+ }
+
+ q2 = -(q2-->1 & $1F);
+ s = 16 + q2;
+
+ t = q1-->1;
+ @log_shift t q2 -> t;
+ z-->1 = t;
+
+ t = q1-->0;
+ @log_shift t s -> t;
+ z-->1 = z-->1 | t;
+
+ t = q1-->0;
+ @log_shift t q2 -> t;
+ z-->0 = t;
+];
+
+[ __long_neg q1 z a b;
+ a = ~(q1-->0);
+ b = ~(q1-->1) + 1;
+ if (~~b)
+ a++;
+ z-->0 = a;
+ z-->1 = b;
+];
+
+[ __long_xor q1 q2 z a b;
+ a = q1-->0;
+ b = q2-->0;
+ z-->0 = (a & (~b)) | ((~a) & b);
+
+ a = q1-->1;
+ b = q2-->1;
+ z-->1 = (a & (~b)) | ((~a) & b);
+];
+
+[ __long_add q1 q2 z a b c cc;
+ ! Add the low word, and detect overflow.
+
+ a = q1-->1;
+ b = q2-->1;
+ c = a + b;
+ z-->1 = c;
+ @log_shift a 0-15 -> a;
+ @log_shift b 0-15 -> b;
+ @log_shift c 0-15 -> c;
+ cc = a;
+ if ((~~a) && b && (~~c))
+ cc = 1;
+ else if (a && b && (~~c))
+ cc = 0;
+
+ ! Add the high word, plus one if the low word overflowed.
+
+ z-->0 = q1-->0 + q2-->0 + cc;
+];
+
+[ __long_sub q1 q2 z a b c cc;
+ ! Subtract the low word, and detect overflow.
+
+ a = q1-->1;
+ b = q2-->1;
+ c = a - b;
+ z-->1 = c;
+ @log_shift a 0-15 -> a;
+ @log_shift b 0-15 -> b;
+ @log_shift c 0-15 -> c;
+
+ ! Carry table:
+ ! a b c c
+ ! 0 0 0 0
+ ! 0 0 1 1
+ ! 0 1 0 1
+ ! 0 1 1 1
+ ! 1 0 0 0
+ ! 1 0 1 0
+ ! 1 1 0 0
+ ! 1 1 1 1
+
+ cc = ~~a;
+ if ((~~a) && (~~b) && (~~c))
+ cc = 0;
+ else if (a && b && c)
+ cc = 1;
+
+ ! Subtract the high word, plus one if the low word overflowed.
+
+ z-->0 = q1-->0 - q2-->0 - cc;
+];
+
+! Algorithm converted from MIPS assembly, at:
+!
http://www.cz3.nus.edu.sg/~wangjs/CZ101/assembly-examples/divide.s
+[ __long_unsigned_divmod q1 q2 d r r1 r2 r3 r4 count t1 t2;
+ ! Check for division by zero.
+
+ if ((~~(q2-->0)) && (~~(q2-->1)))
+ {
+ print "[zlibc error: division by zero in __long_unsigned_divmod]";
+ return 0;
+ }
+
+ count = 0;
+ r1 = 0;
+ r2 = 0;
+ r3 = q1-->0;
+ r4 = q1-->1;
+ !print "[q1=", r3, " ", r4, " q2=", q2-->0, " ", q2-->1, " ";
+
+ do {
+ count++;
+
+ ! Shift r1..r4 left by one bit.
+
+ @log_shift r4 0-15 -> t1;
+ @log_shift r4 1 -> r4;
+
+ @log_shift r3 0-15 -> t2;
+ @log_shift r3 1 -> r3;
+ @or r3 t1 -> r3;
+
+ @log_shift r2 0-15 -> t1;
+ @log_shift r2 1 -> r2;
+ @or r2 t2 -> r2;
+
+ @log_shift r1 1 -> r1;
+ @or r1 t1 -> r1;
+
+ ! Subtract divisor from r1..r2.
+
+ __long_temp3-->0 = r1;
+ __long_temp3-->1 = r2;
+ __long_sub(__long_temp3, q2, __long_temp3);
+
+ ! Is the remainder non-negative?
+
+ if (__long_temp3-->0 >= 0)
+ {
+ ! Yes. Quotient gets a one; commit subtraction.
+
+ r1 = __long_temp3-->0;
+ r2 = __long_temp3-->1;
+
+ r4 = r4 | 1;
+ !print "1";
+ }
+ !else print "0";
+ ! Otherwise the quotient gets a zero and the subtraction is not
+ ! committed. No operation.
+ } until (count == 32);
+
+ ! Save results.
+
+ !print " r=", r1, " ", r2;
+ if (r)
+ {
+ r-->0 = r1;
+ r-->1 = r2;
+ }
+ !print " d=", r3, " ", r4, "]";
+ if (d)
+ {
+ d-->0 = r3;
+ d-->1 = r4;
+ }
+];
+
+[ __long_div q1 q2 z t sign;
+ ! Calculate final sign, and convert parameters to unsigned.
+
+ t = q1-->0;
+ if (t < 0)
+ sign = 1;
+ __long_temp1-->0 = t & $7FFF;
+ __long_temp1-->1 = q1-->1;
+
+ t = q2-->0;
+ if (t < 0)
+ sign = ~~sign;
+ __long_temp2-->0 = t & $7FFF;
+ __long_temp2-->1 = q2-->1;
+
+ ! Do the actual divide.
+
+ __long_unsigned_divmod(__long_temp1, __long_temp2, z, 0);
+
+ ! Adjust sign.
+
+ if (sign)
+ __long_neg(z);
+];
+
+[ __long_mod q1 q2 z t sign;
+ ! Calculate final sign, and convert parameters to unsigned.
+
+ t = q1-->0;
+ if (t < 0)
+ sign = 1;
+ __long_temp1-->0 = t & $7FFF;
+ __long_temp1-->1 = q1-->1;
+
+ t = q2-->0;
+ if (t < 0)
+ sign = ~~sign;
+ __long_temp2-->0 = t & $7FFF;
+ __long_temp2-->1 = q2-->1;
+
+ ! Do the actual modulo.
+
+ __long_unsigned_divmod(__long_temp1, __long_temp2, 0, z);
+
+ ! Adjust sign.
+
+ if (sign)
+ __long_neg(z);
+];
+
+[ __long_unsigned_div q1 q2 z;
+ __long_unsigned_divmod(q1, q2, z, 0);
+];
+
+[ __long_unsigned_mod q1 q2 z;
+ __long_unsigned_divmod(q1, q2, 0, z);
+];
+
+! Algorithm my own. Probably buggy (although it passes every test I've
+! thrown at it).
+[ __long_mul q1 q2 z a b c d aa bb cc dd sign t;
+ ! What we're doing here is long multiplication in base 256; so each
+ ! digit is a byte.
+ !
+ ! A B C D
+ ! * A' B' C' D'
+ ! = ---------------
+ ! AD' BD' CD' DD' +
+ ! BC' CC' DC' +
+ ! CB' DB' +
+ ! DA'
+ !
+ ! We need to add up the columns, remembering to overflow into the
+ ! next column. (Don't forget to make everything positive.)
+
+ if (q1->0 >= $80)
+ {
+ ! q1 is negative.
+ __long_neg(q1, __long_temp1);
+ q1 = __long_temp1;
+ sign = 1;
+ }
+
+ a = q1->0;
+ b = q1->1;
+ c = q1->2;
+ d = q1->3;
+
+ if (q2->0 >= $80)
+ {
+ ! q2 is negative.
+ __long_neg(q2, __long_temp1);
+ q2 = __long_temp1;
+ sign = ~~sign;
+ }
+
+ aa = q2->0;
+ bb = q2->1;
+ cc = q2->2;
+ dd = q2->3;
+
+ ! D column.
+
+ t = d*dd;
+ z->3 = t;
+ @log_shift t 0-8 -> t;
+
+ ! C column.
+
+ t = t + c*dd + d*cc;
+ z->2 = t;
+ @log_shift t 0-8 -> t;
+
+ ! B column.
+ t = t + b*dd + c*cc + d*bb;
+ z->1 = t;
+ @log_shift t 0-8 -> t;
+
+ ! A column.
+ t = t + a*dd + b*cc + c*bb + d*aa;
+ !t = t & $7F;
+ z->0 = t;
+
+ ! Apply sign bit.
+
+ if (sign)
+ __long_neg(z, z);
+
+ ! LongMul can't use the same output as one of its inputs.
+ !LongMul(__long_temp1, q1, q2);
+ !@copy_table __long_temp1 z 4;
+];
+
+[ __long_compare q1 q2 a b;
+ a = q1-->0;
+ b = q2-->0;
+ if (a == b)
+ {
+ a = q1-->1 - 32768;
+ b = q2-->1 - 32768;
+ }
+
+ if (a > b)
+ return 1;
+ if (a < b)
+ return -1;
+ return 0;
+];
+
+[ __long_unsigned_compare q1 q2 a b;
+ a = q1-->0 - 32768;
+ b = q2-->0 - 32768;
+ if (a == b)
+ {
+ a = q1-->1 - 32768;
+ b = q2-->1 - 32768;
+ }
+
+ if (a > b)
+ return 1;
+ if (a < b)
+ return -1;
+ return 0;
+];
+
+! And finally, the routine that calls a C function from Inform.
+
+Constant __c_stack_size 2048;
+Array __c_stack -> __c_stack_size;
+
+[ cinvoke func l0 l1 l2 l3 l4 l5 xp;
+ xp = __c_stack + __c_stack_size;
+ return func(xp, l0, l1, l2, l3, l4, l5);
+];
+
--- vbcc-0.7.orig/share/vbcc/arch/c16x/include/stdarg.h
+++ vbcc-0.7/share/vbcc/arch/c16x/include/stdarg.h
@@ -0,0 +1,18 @@
+/* alpha/c16x.h
+ * vbcc is (c) in 1995-99 by Volker Barthelmann. All code is written by me
+ * and may be freely redistributed as long as no modifications are made
+ * and nothing is charged for it.
+ * Non-commercial usage of vbcc is allowed without any restrictions.
+ * Commercial usage needs my written consent.
+ *
+ * Sending me money, gifts, postcards etc. would of course be very nice
+ * and may encourage further development of vbcc, but is not legally or
+ * morally necessary to use vbcc.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+#error stdarg.h is not supported on the C16X
+
+#endif
--- vbcc-0.7.orig/frontend/vc.c
+++ vbcc-0.7/frontend/vc.c
@@ -64,14 +64,17 @@
const char *config_name="vc.config";
const char *search_dirs[]={"","ENV:","VBCC:"};
char *ul="vlib:%s.lib";
+#define ASM_SUFFIX ".asm"
#elif defined(WINTEL)
const char *config_name="vc.cfg";
const char *search_dirs[]={"","%VCCFG%\\"};
char *ul="-l%s";
+#define ASM_SUFFIX ".asm"
#else
-const char *config_name="vc.config";
-const char *search_dirs[]={"","~/","/etc/"};
+const char *config_name="i386";
+const char *search_dirs[]={"/usr/share/vbcc/conf/", ""};
char *ul="-l%s";
+#define ASM_SUFFIX ".s"
#endif
/* String fuer die Default libraries */
@@ -345,7 +348,7 @@
}
/* MUST come before CCSRC-handling! */
if(j==SCSRC){
- file=add_suffix(file,".asm");
+ file=add_suffix(file,ASM_SUFFIX);
if(tfl==ASSRC&&(flags&OUTPUTSET)) file=destname;
sprintf(command,scname,oldfile,file);
if(tfl!=ASSRC) add_name(file,&first_scratch,&last_scratch);
@@ -355,7 +358,7 @@
file=add_suffix(file,".scs");
}else{
if(++j==tfl-1) file=namebuf;
- file=add_suffix(file,".asm");
+ file=add_suffix(file,ASM_SUFFIX);
}
if(tfl==j+1&&(flags&OUTPUTSET)) file=destname;
sprintf(command,ccname,oldfile,file,options,opt);
@@ -437,7 +440,7 @@
if(!strcmp(p,".c")) return PPSRC;
if(!strcmp(p,".i")) return CCSRC;
if(!strcmp(p,".s")) return ASSRC;
- if(!strcmp(p,".asm")) return ASSRC;
+ if(!strcmp(p,ASM_SUFFIX)) return ASSRC;
if(!strcmp(p,".scs")) return SCSRC;
if(!strcmp(p,".o")) return OBJ;
if(!strcmp(p,".obj")) return OBJ;
--- vbcc-0.7.orig/main.c
+++ vbcc-0.7/main.c
@@ -5,7 +5,7 @@
static char FILE_[]=__FILE__;
int endok=1;
-int line,errors;
+int line,errors=0;
char *multname[]={"","s"};
void raus(void)
--- vbcc-0.7.orig/doc/vbccz.doc
+++ vbcc-0.7/doc/vbccz.doc
@@ -0,0 +1,205 @@
+vbcc - C compiler (c) in 1995-2001 by Volker Barthelmann
+
+
+INTRODUCTION
+
+ vbcc is a free portable and retargetable ANSI C compiler.
+ It is clearly split into a target independant and a target dependant
+ part and supports emulating datatypes of the target machine on any
+ other machine so that it is possible to e.g. make a crosscompiler for
+ a 64bit machine on a 32bit machine.
+ This document only deals with the target dependant parts of the
+ Infocom Z-machine code generator.
+
+ This is a pre-alpha version!
+
+LEGAL
+
+ vbcc is (c) in 1995-99 by Volker Barthelmann. All code is written by me
+ and may be freely redistributed as long as no modifications are made
+ and nothing is charged for it.
+ Non-commercial usage of vbcc is allowed without any restrictions.
+ Commercial usage needs my written consent.
+
+ Sending me money, gifts, postcards etc. would of course be very nice
+ and may encourage further development of vbcc, but is not legally or
+ morally necessary to use vbcc.
+
+
+ The Z-machine code generator is licensed under the MIT open source license.
+
+ Copyright (c) 2001, David Given
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+ADDITIONAL OPTIONS FOR THIS VERSION
+
+ -module-name=<name>
+
+ Tells the code generator the C module name to use when emitting
+ code. This is used to generate identifiers for statics and
+ labels. If a program is made up of multiple modules, each
+ module should have a unique name.
+
+ If omitted, the compiled module must not be linked with any
+ other modules; i.e., omitting the module name is only suitable
+ for programs made up of a single source file. In this case the
+ BSS initialisation function is called __init_vars().
+
+ -trace-calls
+
+ Emit additional code that prints the function name into the
+ function prologue. This can be useful for tracing through code.
+
+ -trace-all
+
+ Emit additional code that prints vbcc's internal representation
+ of each instruction before emitting the Z-machine code for that
+ instruction. This can be useful for tracing, but is primarily
+ used to debug the code generator.
+
+ -safe-branches
+
+ Attempts to work around an Inform bug that causes relative
+ branches in very long source functions to be incorrectly
+ generated. (The Z-machine has an upper limit to the offset
+ that can be put in a relative branch, but Inform does not test
+ for this. If that limit is reached, Inform will happily
+ generate incorrect code.)
+
+ -comment-ic
+ -comment-misc
+
+ Emit various comments in the output assembly that shows what
+ the code generator is doing. These is completely useless to
+ anyone who isn't debugging the code generator.
+
+SOME INTERNALS
+
+ This code generator produces files suitable for assembly with the Inform
+ Z-machine compiler.
+
+ It implements:
+
+ 8-bit signed and unsigned chars
+ 16-bit signed and unsigned shorts and ints
+ 32-bit signed and unsigned longs
+ No floating point (may be included at a future date)
+
+ 32-bit arithmetic is emulated and may be very slow.
+
+ All the standard ANSI C semantics are implemented, or at least should be.
+ This includes but is not limited to static data, BSS, stack allocation,
+ passing and returning structures to functions, varargs, etc.
+
+ The compiled code expects to be linked and run in a particular manner.
+ Inform does not use a conventional link stage, which means that certain
+ contortions must be done to make the vbcc compiled code to work. A wrapper
+ Inform source file is needed that references the vbcc compiled code, sets
+ up the BSS, and runs the C. For example, say we have a C source file that
+ provides a function main(), called helloworld.c. We would need the following
+ Inform file:
+
+ #include "/usr/share/vbcc/arch/runtime.s"
+ #include "helloworld.o"
+
+ [ Initialise;
+ __init_vars_helloworld();
+ cinvoke(_main);
+ ];
+
+ The C file world be compiled as follows:
+
+ vc +z -module-name=helloworld -c helloworld.c
+
+ And then the Inform file:
+
+ inform helloworld.inf
+
+ Each module is provided with a function that sets up that module's BSS.
+ This is called __init_vars_<modulename>, and must be called prior to
+ running any code in that module.
+
+ /usr/share/vbcc/arch/runtime.s is provided with the code generator (if you
+ are not using a binary package, it will be in share/vbcc/arch/runtime.s in
+ the source directory), and contains helper functions for working around
+ Inform bugs, providing extra functionality (the Z-machine has no xor
+ instruction), and unsigned and 32-bit arithmetic helper functions. It also
+ sets up a 2kB call stack.
+
+ The cinvoke() Inform function should be used to call C code from Inform
+ code. It sets up the stack and forwards parameters on. The return value of
+ the C function is then passed back out of cinvoke(). Note that 32-bit
+ parameters are not supported in cinvoke(), and cinvoke() is not reentrant
+ (it must not be called from Inform code called from C code called with
+ cinvoke()).
+
+ No libc is provided with the compiler. If you require a libc, the game
+ _Silicon Castles_ comes with an extremely minimalist libc that may be
+ useful.
+
+ The Z-machine is not implemented as a particularly normal register-based
+ processor. As a result, the code generator is a bit odd in places. The
+ Z-machine's local variables are used in place of registers. These are
+ referred to here as xp and r0..r12.
+
+ xp is the C stack pointer. The Z-machine's own stack is not memory mapped
+ and so is useless from the C point of view. As a result, the C stack is
+ held in main memory; it is set up by the cinvoke() function. It should be
+ borne in mind that this means that both stacks will need adjusting for a
+ longjmp() implementation.
+
+ r0 to r5 are used for parameter passing when calling functions, but at all
+ other times all the registers are used for scratch space. The Z-machine
+ automatically saves all the locals when making procedure calls, so
+ parameters are returned on the Z-machine stack.
+
+STDARG
+
+ #ifndef __STDARG_H
+ #define __STDARG_H
+
+ #ifdef __Z__
+ typedef char* va_list;
+ extern va_list __va_start; /* magic */
+
+ #define va_start(ap, lastarg) \
+ ((ap) = __va_start)
+ #define va_arg(ap, type) \
+ (((ap) += (sizeof(type)<sizeof(int)) ? sizeof(int) : sizeof(type)), \
+ ((type*)ap)[-1])
+ #define va_end(ap) ((ap) = 0)
+ #endif
+
+ #endif /* __STDARG_H */
+
+KNOWN PROBLEMS
+
+ I'm sure there are some in the compiler, but nothing's bitten me yet. The
+ main problems are caused by the fact that vbcc generates really weird
+ Z-machine code that stresses Inform and the interpreters in ways that have
+ never been tested before. I've found at least two major interpreter bugs;
+ some versions of nitfol think that -32760 > 32760, and some versions of Zip
+ think that $FF00 asr 8 != $FFFF. There are some Inform bugs that generate
+ bogus code, too.
+
+David Given
[email protected]
+
--- vbcc-0.7.orig/configure.in
+++ vbcc-0.7/configure.in
@@ -0,0 +1,19 @@
+# configure.in
+# vbcc for Unix autoconf file
+
+# Check we're in the right directory.
+
+AC_INIT(main.c)
+
+# Check for programs.
+
+AC_PROG_CC
+
+# Check for header files.
+
+AC_HEADER_STDC
+
+# ...and output.
+
+AC_OUTPUT(Makefile)
+
--- vbcc-0.7.orig/Makefile.in
+++ vbcc-0.7/Makefile.in
@@ -0,0 +1,183 @@
+# The usual settings.
+
+CC = gcc
+CFLAGS = -O2 -g -fsigned-char
+TARGETDIR= machines/$(TARGET)
+INCLUDES = -I. -Imachines/$(TARGET)
+LIBS =
+
+# These are the available targets.
+
+TARGETS = \
+ alpha \
+ c16x \
+ i386 \
+ m68k \
+ ppc \
+ z
+
+# C file compilation rules.
+
+COMPILE = $(CC) $(CFLAGS) $(INCLUDES)
+%.o: %.c
+ $(COMPILE) -c -o $@ $<
+
+# Top-level rules.
+
+all: compilers frontend vcpp
+
+clean: compilers-clean frontend-clean vcpp-clean
+
+# === The front-end ==========================================================
+
+VCOBJS = \
+ frontend/vc.o
+
+bin/vc: $(VCOBJS)
+ $(CC) $(LIBS) $(VCOBJS) -o $@
+
+.PHONY: frontend
+frontend: bin/vc
+
+.PHONY: frontend-clean
+frontend-clean:
+ $(RM) $(VCOBJS)
+ $(RM) bin/vc
+
+# === The preprocessor =======================================================
+
+VCPPOBJS = \
+ vcpp/cpp.o \
+ vcpp/eval.o \
+ vcpp/getopt.o \
+ vcpp/hideset.o \
+ vcpp/include.o \
+ vcpp/lex.o \
+ vcpp/macro.o \
+ vcpp/nlist.o \
+ vcpp/tokens.o \
+ vcpp/unix.o
+
+bin/vcpp: $(VCPPOBJS)
+ $(CC) $(LIBS) $(VCPPOBJS) -o $@
+
+.PHONY: vcpp
+vcpp: bin/vcpp
+
+.PHONY: vcpp-clean
+vcpp-clean:
+ $(RM) $(VCPPOBJS)
+ $(RM) bin/vcpp
+
+# === The compilers ==========================================================
+
+.PHONY: compilers
+compilers:
+ for target in $(TARGETS); do \
+ $(MAKE) TARGET=$$target compiler.$$target; \
+ done
+
+.PHONY: compilers-clean
+compilers-clean: dtgen-clean
+ for target in $(TARGETS); do \
+ $(MAKE) TARGET=$$target compiler-clean.$$target; \
+ done
+
+# Build the dtgen program.
+
+DTGENOBJECTS = \
+ datatypes/dtgen.o
+
+datatypes/dtgen.o: datatypes/dtgen.c datatypes/datatypes.h datatypes/dtconv.h
+
+dtgen: $(DTGENOBJECTS)
+ $(CC) $(DTGENOBJECTS) -o $@ $(LIBS)
+
+.PHONY: dtgen-clean
+dtgen-clean:
+ $(RM) dtgen $(DTGENOBJECTS)
+
+# Build a generic compiler.
+
+BOBJECTS = \
+ $(TARGETDIR)/main.o \
+ $(TARGETDIR)/vars.o \
+ $(TARGETDIR)/declaration.o \
+ $(TARGETDIR)/parse_expr.o \
+ $(TARGETDIR)/type_expr.o \
+ $(TARGETDIR)/ic.o \
+ $(TARGETDIR)/machine.o \
+ $(TARGETDIR)/statements.o \
+ $(TARGETDIR)/preproc.o \
+ $(TARGETDIR)/supp.o \
+ $(TARGETDIR)/dt.o
+
+$(TARGETDIR)/main.o: main.c vbc.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/vars.o: vars.c vbc.h supp.h $(TARGETDIR)/machine.h errors.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/declaration.o: declaration.c vbc.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/parse_expr.o: parse_expr.c vbc.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/type_expr.o: type_expr.c vbc.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/ic.o: ic.c vbc.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/statements.o: statements.c vbc.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/preproc.o: preproc.c vbpp.h supp.h vbc.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/supp.o: supp.c supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/machine.o: $(TARGETDIR)/machine.c $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/dt.o: $(TARGETDIR)/dt.c $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $< -Idatatypes
+
+FOBJECTS = \
+ $(BOBJECTS) \
+ $(TARGETDIR)/opt.o \
+ $(TARGETDIR)/av.o \
+ $(TARGETDIR)/rd.o \
+ $(TARGETDIR)/regs.o \
+ $(TARGETDIR)/flow.o \
+ $(TARGETDIR)/cse.o \
+ $(TARGETDIR)/cp.o \
+ $(TARGETDIR)/loop.o \
+ $(TARGETDIR)/alias.o
+
+$(TARGETDIR)/opt.o: opt.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/av.o: av.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/rd.o: rd.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/regs.o: regs.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/flow.o: flow.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/cse.o: cse.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/cp.o: cp.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/loop.o: loop.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+$(TARGETDIR)/alias.o: alias.c opt.h supp.h $(TARGETDIR)/machine.h $(TARGETDIR)/dt.h
+ $(COMPILE) -c -o $@ $<
+
+$(TARGETDIR)/dt.h: dtgen
+ ./dtgen $(TARGETDIR)/machine.dt $(TARGETDIR)/dt.h $(TARGETDIR)/dt.c
+
+bin/vbcc$(TARGET): $(TARGETDIR)/dt.h $(FOBJECTS)
+ $(CC) $(FOBJECTS) -o bin/vbcc$(TARGET) $(LIBS)
+
+.PHONY: compiler.$(TARGET)
+compiler.$(TARGET): bin/vbcc$(TARGET)
+
+.PHONY: compiler-clean.$(TARGET)
+compiler-clean.$(TARGET):
+ $(RM) $(FOBJECTS) bin/vbcc$(TARGET)
+ $(RM) $(TARGETDIR)/dt.h $(TARGETDIR)/dt.c
+
+
--- vbcc-0.7.orig/vbc.h
+++ vbcc-0.7/vbc.h
@@ -34,8 +34,9 @@
#endif
struct argument_list{
- np arg;
- struct argument_list *next;
+ np arg;
+ struct argument_list *next;
+ struct IC *pushic;
};
@@ -91,12 +92,13 @@
extern void gen_IC(np,int,int),convert(np,int),gen_label(int);
extern void savescratch(int,struct IC *,int);
struct regargs_list{
- struct regargs_list *next;
- int reg;
- struct Var *v;
+ struct regargs_list *next;
+ struct argument_list *al;
+ int reg;
+ struct Var *v;
};
#ifdef HAVE_REGPARMS
-extern zlong push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **,struct reg_handle *,struct obj *,int);
+extern zlong push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **,struct reg_handle *,struct obj *,struct Typ *,int);
#else
extern zlong push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **);
#endif
--- vbcc-0.7.orig/datatypes/dtgen.c
+++ vbcc-0.7/datatypes/dtgen.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <stdint.h>
struct dtlist {char *spec,*descr;} dts[]={
#include "datatypes.h"
@@ -39,6 +40,7 @@
char *nt[TYPECNT+1];
FILE *fin,*cout,*hout;
int crosscompiler;
+int endian;
void *mymalloc(size_t size)
{
@@ -50,6 +52,17 @@
return p;
}
+int getendian(void)
+{
+ union {
+ int32_t i;
+ int8_t b[4];
+ } u;
+
+ u.i = 1;
+ return u.b[3] ? 'B' : 'L';
+}
+
int askyn(void)
{
char in[8];
@@ -84,12 +97,13 @@
cnv[type]=-1;
return 1;
}else{
- printf("Does your system/compiler support a type implemented as\n%s?\n",dts[i].descr);
- if(askyn()){
- dt[type]=i;
- nt[type]=asktype();
- have[i]=type;
- cnv[type]=-1;
+ int e = dts[i].descr[0];
+ if ((e == ' ') || (e == endian))
+ {
+ dt[type] = i;
+ nt[type] = dts[i].descr + 1;
+ have[i] = type;
+ cnv[type] = -1;
return 1;
}else{
have[i]=-2;
@@ -111,12 +125,13 @@
cnv[type]=j;
return 2;
}else{
- printf("Does your system/compiler support a type implemented as\n%s?\n",dts[i].descr);
- if(askyn()){
- dt[type]=i;
- nt[type]=asktype();
- have[i]=type;
- cnv[type]=j;
+ int e = dts[i].descr[0];
+ if ((e == ' ') || (e == endian))
+ {
+ dt[type] = i;
+ nt[type] = dts[i].descr + 1;
+ have[i] = type;
+ cnv[type] = j;
return 2;
}else{
have[i]=-2;
@@ -179,8 +194,10 @@
if(!hout){ printf("Could not open <%s> for output!\n",argv[2]);exit(EXIT_FAILURE);}
cout=fopen(argv[3],"w");
if(!hout){ printf("Could not open <%s> for output!\n",argv[3]);exit(EXIT_FAILURE);}
- printf("Are you building a cross-compiler?\n");
- crosscompiler=askyn();
+// printf("Are you building a cross-compiler?\n");
+// crosscompiler=askyn();
+ crosscompiler = 1;
+ endian = getendian();
for(i=1;i<=TYPECNT;i++){
fgets(spec,127,fin);
/* printf("Specs for z%s:\n%s\n",typen[i],spec); */
@@ -198,6 +215,7 @@
}
}
fprintf(hout,"\n\n/* Machine generated file. DON'T TOUCH ME! */\n\n\n");
+ fprintf(hout,"#include <stdint.h>\n");
fprintf(cout,"\n\n/* Machine generated file. DON'T TOUCH ME! */\n\n\n");
fprintf(cout,"#include \"dt.h\"\n\n");
for(i=1;i<=TYPECNT;i++){
--- vbcc-0.7.orig/datatypes/datatypes.h
+++ vbcc-0.7/datatypes/datatypes.h
@@ -1,36 +1,36 @@
/* elementary data types currently known to vbcc */
/* unsigned 8bit byte */
-"S8BU", "standard unsigned 8bit byte",
+"S8BU", " int8_t",
/* signed 8bit byte */
-"S8BS", "standard 2-complement 8bit byte",
+"S8BS", " uint8_t",
/* typical unsigned integers, big-endian */
-"S16BUBE", "standard 8bit-byte-based unsigned 16bit word, big-endian",
-"S32BUBE", "standard 8bit-byte-based unsigned 32bit word, big-endian",
-"S64BUBE", "standard 8bit-byte-based unsigned 64bit byte, big-endian",
+"S16BUBE", "Buint16_t",
+"S32BUBE", "Buint32_t",
+"S64BUBE", "Buint64_t",
/* typical unsigned integers, little-endian */
-"S16BULE", "standard 8bit-byte-based unsigned 16bit word, little-endian",
-"S32BULE", "standard 8bit-byte-based unsigned 32bit word, little-endian",
-"S64BULE", "standard 8bit-byte-based unsigned 64bit byte, little-endian",
+"S16BULE", "Luint16_t",
+"S32BULE", "Luint32_t",
+"S64BULE", "Luint64_t",
/* typical signed integers, big-endian */
-"S16BSBE", "standard 8bit-byte-based 2-complement 16bit word, big-endian",
-"S32BSBE", "standard 8bit-byte-based 2-complement 32bit word, big-endian",
-"S64BSBE", "standard 8bit-byte-based 2-complement 64bit word, big-endian",
+"S16BSBE", "Bint16_t",
+"S32BSBE", "Bint32_t",
+"S64BSBE", "Bint64_t",
/* typical signed integers, little-endian */
-"S16BSLE", "standard 8bit-byte-based 2-complement 16bit word, little-endian",
-"S32BSLE", "standard 8bit-byte-based 2-complement 32bit word, little-endian",
-"S64BSLE", "standard 8bit-byte-based 2-complement 64bit word, little-endian",
+"S16BSLE", "Lint16_t",
+"S32BSLE", "Lint32_t",
+"S64BSLE", "Lint64_t",
/* typical IEEE-floats, big-endian */
-"S32BIEEEBE", "standard 8bit-byte-based 32bit IEEE floating-point, big-endian",
-"S64BIEEEBE", "standard 8bit-byte-based 64bit IEEE floating-point, big-endian",
+"S32BIEEEBE", "Bfloat",
+"S64BIEEEBE", "Bdouble",
/* typical IEEE-floats, little-endian */
-"S32BIEEELE", "standard 8bit-byte-based 32bit IEEE floating-point, little-endian",
-"S64BIEEELE", "standard 8bit-byte-based 64bit IEEE floating-point, little-endian",
+"S32BIEEELE", "Lfloat",
+"S64BIEEELE", "Ldouble",