Browse Source

Initial commit from latest tar.gz file

Godzil 6 years ago
commit
d735aca251
100 changed files with 31139 additions and 0 deletions
  1. 3 0
      INSTALL
  2. 37 0
      Makefile
  3. 20 0
      bin/Makefile
  4. 13 0
      common-gtc.mk
  5. 11 0
      common.mk
  6. 20 0
      configure
  7. 55 0
      doc/building.html
  8. 56 0
      doc/cmdline.html
  9. 83 0
      doc/credits.html
  10. 14 0
      doc/examples.html
  11. 210 0
      doc/extensions.html
  12. 57 0
      doc/faq.html
  13. 51 0
      doc/glossary.html
  14. 41 0
      doc/index.html
  15. 1 0
      doc/layout/default.css
  16. 89 0
      doc/layout/simple.css
  17. 354 0
      doc/license-gpl2.html
  18. 14 0
      doc/missing.html
  19. 33 0
      doc/oncalc.html
  20. 27 0
      doc/preprocessor.html
  21. 65 0
      doc/specificities.html
  22. 32 0
      doc/version.html
  23. 29 0
      doc/windows.html
  24. 96 0
      gtc/Makefile
  25. 87 0
      gtc/Makefile.orig
  26. 114 0
      gtc/script/mkprotos.rb
  27. 4 0
      gtc/src/Makefile
  28. 201 0
      gtc/src/all.c
  29. 816 0
      gtc/src/analyze.c
  30. 102 0
      gtc/src/bin2calc.c
  31. 548 0
      gtc/src/c.h
  32. 303 0
      gtc/src/cglbdec.h
  33. 675 0
      gtc/src/cmain.c
  34. 1657 0
      gtc/src/decl.c
  35. 378 0
      gtc/src/define.h
  36. 150 0
      gtc/src/error.c
  37. 58 0
      gtc/src/error.h
  38. 2157 0
      gtc/src/expr.c
  39. 169 0
      gtc/src/expr.h
  40. 74 0
      gtc/src/ffplib.h
  41. 24 0
      gtc/src/flashend.c
  42. 210 0
      gtc/src/flashhdr.c
  43. 301 0
      gtc/src/flashhdr.h
  44. 471 0
      gtc/src/func.c
  45. 352 0
      gtc/src/gen.h
  46. 3536 0
      gtc/src/gen68k.c
  47. 174 0
      gtc/src/genffp.c
  48. 1248 0
      gtc/src/genstmt.c
  49. 718 0
      gtc/src/getasm.c
  50. 2293 0
      gtc/src/getsym.c
  51. 43 0
      gtc/src/gtdevcomm.c
  52. 44 0
      gtc/src/gtdevcomm.h
  53. 2259 0
      gtc/src/gtpack/gtpack.c
  54. 99 0
      gtc/src/gtpack/packhead.h
  55. 108 0
      gtc/src/gtpack/revtools.h
  56. 48 0
      gtc/src/gtpack/tt.h
  57. 49 0
      gtc/src/gtpack/ttunpack.h
  58. 53 0
      gtc/src/gtpack/ttversion.h
  59. 22 0
      gtc/src/identity.h
  60. 434 0
      gtc/src/init.c
  61. 96 0
      gtc/src/intexpr.c
  62. 532 0
      gtc/src/memmgt.c
  63. 887 0
      gtc/src/optimize.c
  64. 3017 0
      gtc/src/out68k_as.c
  65. 71 0
      gtc/src/out68k_exe.h
  66. 53 0
      gtc/src/pch.h
  67. 1291 0
      gtc/src/peep68k.c
  68. 572 0
      gtc/src/preproc.c
  69. 329 0
      gtc/src/protos.h
  70. 446 0
      gtc/src/reg68k.c
  71. 182 0
      gtc/src/searchkw.c
  72. 23 0
      gtc/src/securecommdef.h
  73. 952 0
      gtc/src/stmt.c
  74. 91 0
      gtc/src/sunpack.c
  75. 343 0
      gtc/src/symbol.c
  76. 247 0
      gtc/src/trees.c
  77. 98 0
      gtc/src/vcg.c
  78. 8 0
      gtc/src/version.h
  79. 24 0
      h/Makefile
  80. 0 0
      h/all
  81. 1 0
      h/legacy/README
  82. 67 0
      h/legacy/ezgen
  83. 42 0
      h/legacy/ezgensc
  84. 1 0
      h/legacy/genle
  85. 4 0
      h/legacy/inclgen
  86. 1 0
      h/legacy/include
  87. 340 0
      h/processed/COPYING
  88. BIN
      h/processed/assert.89t
  89. BIN
      h/processed/compat.89t
  90. BIN
      h/processed/default.89t
  91. BIN
      h/processed/doors.89t
  92. BIN
      h/processed/extgraph.89t
  93. BIN
      h/processed/gen.89t
  94. BIN
      h/processed/nostub.89t
  95. BIN
      h/processed/patch.89t
  96. BIN
      h/processed/std.89t
  97. BIN
      h/processed/tigcclib.89t
  98. BIN
      h/processed/ttunpack.89t
  99. BIN
      h/processed/xupak.89t
  100. 31 0
      h/script/strip.pl

+ 3 - 0
INSTALL

@@ -0,0 +1,3 @@
+Quick install: type "./configure && make -j && sudo make install".
+
+More information is available in "doc/building.html".

+ 37 - 0
Makefile

@@ -0,0 +1,37 @@
+SUBSYSTEMS = tools bin h pch gtc ti68k
+INSTALLABLE_SUBSYSTEMS = h pch gtc
+all: $(addprefix all-,$(SUBSYSTEMS))
+	@echo 1>&2
+	@echo 1>&2 '-- Compilation successful!'
+	@echo 1>&2 '   You may use the calculator binaries now (e.g. for the TI-89 in ti68k/bin-89).'
+	@echo 1>&2 '   Or if you want to go ahead and install the cross-compiler, just type "make install".'
+	@echo 1>&2
+install: $(addprefix all-,$(SUBSYSTEMS)) $(addprefix install-,$(INSTALLABLE_SUBSYSTEMS))
+	@echo 1>&2
+	@echo 1>&2 '-- Cross-compiler install successful!'
+	@echo 1>&2 '   You should now be able to compile by typing "gtc myprogram.c".'
+	@echo 1>&2 '   Remember that the calculator binaries are available, e.g. for the TI-89 in ti68k/bin-89.'
+	@echo 1>&2
+clean: $(addprefix clean-,$(SUBSYSTEMS))
+distclean: $(addprefix distclean-,$(SUBSYSTEMS))
+scratchclean: $(addprefix scratchclean-,$(SUBSYSTEMS))
+distclean scratchclean:
+	$(RM) config.mk
+
+all-bin: all-tools
+all-h: all-bin
+all-pch: all-bin
+all-gtc: all-bin
+all-ti68k: all-bin all-h all-pch
+$(addprefix install-,$(INSTALLABLE_SUBSYSTEMS)): $(addprefix all-,$(INSTALLABLE_SUBSYSTEMS))
+
+all-%:
+	$(MAKE) -C $(patsubst all-%,%,$@) all
+install-%:
+	$(MAKE) -C $(patsubst install-%,%,$@) install
+clean-%:
+	$(MAKE) -C $(patsubst clean-%,%,$@) clean
+distclean-%:
+	$(MAKE) -C $(patsubst distclean-%,%,$@) distclean
+scratchclean-%:
+	$(MAKE) -C $(patsubst scratchclean-%,%,$@) scratchclean

+ 20 - 0
bin/Makefile

@@ -0,0 +1,20 @@
+include ../platform.mk
+vpath ../tools
+
+PROGRAMS = obj2ti$(BIN_SUFFIX) pchmaker$(BIN_SUFFIX) txt89t$(BIN_SUFFIX) dat89y$(BIN_SUFFIX)
+
+all: $(PROGRAMS)
+
+clean:
+distclean:
+	$(RM) $(PROGRAMS)
+scratchclean: distclean
+
+obj2ti$(BIN_SUFFIX): ../tools/obj2ti/obj2ti$(BIN_SUFFIX)
+	cp $< $@
+pchmaker$(BIN_SUFFIX): ../tools/pchmaker/pchmaker$(BIN_SUFFIX)
+	cp $< $@
+txt89t$(BIN_SUFFIX): ../tools/txt89t/txt89t$(BIN_SUFFIX)
+	cp $< $@
+dat89y$(BIN_SUFFIX): ../tools/dat89y/dat89y$(BIN_SUFFIX)
+	cp $< $@

+ 13 - 0
common-gtc.mk

@@ -0,0 +1,13 @@
+# This Makefile is used for source codes that depend on the GTC code tree.
+# It is expected that the current working directory is of the form src/xxx/yyy.
+#
+# Note that GTC itself may need more C defines to be compiled, but they will
+# only be required in .c files, not .h files, so they are not defined here.
+
+include ../../common.mk
+include ../../config.mk
+
+GTC_SOURCE = ../../gtc/src
+GTC_HEADERS = $(GTC_SOURCE)/*.h
+
+CFLAGS = $(DEFAULT_CFLAGS) -I$(GTC_SOURCE) $(GTC_ARCH_DEFINES)

+ 11 - 0
common.mk

@@ -0,0 +1,11 @@
+# This Makefile is used for all source codes that must build binaries.
+
+DEFAULT_CFLAGS = -O2 -s
+
+ifndef CC
+ifeq (,$(shell which gcc 2>&1 >/dev/null))
+CC=gcc
+else
+CC=cc
+endif
+endif

+ 20 - 0
configure

@@ -0,0 +1,20 @@
+#!/bin/sh
+rm -f config.mk
+touch config.mk
+if [ "x$1" = "x--prefix" ]; then
+    if test -z "$2"; then
+	echo "missing argument to $1" 1>&2; exit 1
+    fi
+    echo "using prefix $2..."
+    echo "prefix=$2" >> config.mk
+    shift 2
+else
+    deflt_prefix=/usr/local
+    echo "using default prefix $deflt_prefix..."
+    echo "prefix=$deflt_prefix" >> config.mk
+fi
+if test "$1"; then
+    echo "error: too many arguments" 1>&2; exit 1
+fi
+echo "GTC_ARCH_DEFINES = -DNDEBUG -DMC68000 -DCPU_DEFINED -DPC -DUNIXOID -DAS -DASM -DPCH -DREGPARM -DBCDFLT -DNOFLOAT -DVCG" >> config.mk
+echo configuration OK ! 1>&2

+ 55 - 0
doc/building.html

@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>Building GTC - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>Building GTC</h1>
+<p>If you use Windows or TI calculators you don't need to build GTC yourself as 
+there are already precompiled versions available.</p>
+<p>If you use Unix-like operating systems (Linux, Mac OS X...) you will have to 
+follow these instructions to build GTC yourself.</p>
+<div class='toc'><div class='toctop'><div class='tocbot'><div class='toc-content'>
+<b>Contents:</b><ul>
+  <li><a href='#Building.the.binaries'>Building the binaries</a></li>
+  <li><a href='#Rebuilding.a.modified.GTC'>Rebuilding a modified GTC</a></li>
+  <li><a href='#Notes.for.developers'>Notes for developers</a></li>
+</ul>
+</div></div></div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Building.the.binaries'></a>Building the binaries</h1><div class='c1in'><hr class='hr1in' />
+<p>You should need no special package apart from GNU make and a C/C++ compiler to 
+build GTC. On Windows you will need Cygwin.</p>
+<p>Just type</p>
+<p><code>./configure &amp;&amp; make &amp;&amp; sudo make install</code></p>
+<p>(replace<span class='widespace'>&#32;</span><code>make</code><span class='widespace'>&#32;</span>with<span class='widespace'>&#32;</span><code>make -j</code><span class='widespace'>&#32;</span>to take advantage of multiprocessor systems).</p>
+<p>By default GTC will be installed in<span class='widespace'>&#32;</span><code>/usr/local</code>. If you want to install it in 
+a different directory (for example if you don't have administrator rights), use 
+the following command:</p>
+<p><code>./configure --prefix $HOME/my_directory &amp;&amp; make install</code></p>
+</div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Rebuilding.a.modified.GTC'></a>Rebuilding a modified GTC</h1><div class='c1in'><hr class='hr1in' />
+<p>The above instructions are designed to only recompile platform-dependent files 
+and as such have minimal dependencies.</p>
+<p>If you want to modify precompiled data such as the precompiled headers you will 
+need extra packages like Perl and possibly Ruby.</p>
+</div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Notes.for.developers'></a>Notes for developers</h1><div class='c1in'><hr class='hr1in' />
+<p>The Makefiles follow these conventions:</p>
+<ul><li><span class='widespace'>&#32;</span><code>make clean</code><span class='widespace'>&#32;</span>cleans up intermediary files, but not final files.
+</li><li><span class='widespace'>&#32;</span><code>make distclean</code><span class='widespace'>&#32;</span>cleans up intermediary files and any platform-dependent
+ files.
+</li><li><span class='widespace'>&#32;</span><code>make scratchclean</code><span class='widespace'>&#32;</span>cleans up everything that can be rebuilt. Note: use
+ with care, as if you don't have the right tools installed you are not going 
+ to be able to rebuild GTC.
+</li></ul>
+<p>All Makefiles are designed to be safely used with parallel compilation.
+</div></div></p></div>
+</body>
+</html>

File diff suppressed because it is too large
+ 56 - 0
doc/cmdline.html


+ 83 - 0
doc/credits.html

@@ -0,0 +1,83 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>Information - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>Information</h1>
+<div class='toc'><div class='toctop'><div class='tocbot'><div class='toc-content'>
+<b>Contents:</b><ul>
+  <li><a href='#Credits.and.licensing'>Credits and licensing</a>
+  <ul>
+    <li><a href='#Standard.library'>Standard library</a></li>
+    <li><a href='#Compiler.core'>Compiler core</a></li>
+    <li><a href='#Compression.routines'>Compression routines</a></li>
+    <li><a href='#Object.file.import'>Object file import</a></li>
+    <li><a href='#Thanks'>Thanks</a></li>
+  </ul></li>
+  <li><a href='#Contact'>Contact</a></li>
+</ul>
+</div></div></div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Credits.and.licensing'></a>Credits and licensing</h1><div class='c1in'><hr class='hr1in' />
+<p>GTC is composed of three separate parts: the GTC compiler, the GTC IDE and the
+GTC standard library. You are free to use these parts separately or in
+combination.</p>
+<p>You can redistribute or modify GTC freely for non-commercial use, as long as
+you also redistribute the modified source and comply with the licenses of the
+components you choose to distribute: you cannot redistribute the GTC standard
+library if you fail to comply with the terms of the <a href='license-gpl2.html#GNU.General.Public.License'>GNU General Public
+License</a>, version 2 (GPL). In addition you may redistribute the GTC standard
+library under the terms of the GPL license, without restriction on commercial
+use.</p>
+<p>Excluding the standard library, the main author of GTC is Paul Froissart,
+however GTC would not have been possible without building upon the work of
+the following contributors.</p>
+<div class='c2'>
+<hr class='hr2' /><h2 class='heading'><a name='Standard.library'></a>Standard library</h2><div class='c2in'><hr class='hr2in' />
+<p>The GTC standard library is a simple recompilation of old versions of the TIGCC
+library, adapted for usage of a different calling convention. As such it is
+licensed under the terms of the <a href='license-gpl2.html#GNU.General.Public.License'>GNU General Public License</a>, with an
+exception allowing linking of the library with external programs, and
+redistribution of the linked programs notwithstanding the provisions of the
+GPL.</p>
+<p>The TIGCC library was written by Zeljko Juric, Thomas Nussbaumer, Sebastian
+Reichelt, Kevin Kofler and other contributors to the
+<a href='http://tigcc.ticalc.org/'> TIGCC project</a>.</p>
+</div></div>
+<div class='c2'>
+<hr class='hr2' /><h2 class='heading'><a name='Compiler.core'></a>Compiler core</h2><div class='c2in'><hr class='hr2in' />
+<p>The GTC compiler is based on the 68000 and i386 C compiler III.1 by Christoph
+van Wuellen (1989-1991), itself based on the 68000 compiler by Matthew Brandt
+(1984-1986).</p>
+</div></div>
+<div class='c2'>
+<hr class='hr2' /><h2 class='heading'><a name='Compression.routines'></a>Compression routines</h2><div class='c2in'><hr class='hr2in' />
+<p>The<span class='widespace'>&#32;</span><code>-exe</code><span class='widespace'>&#32;</span>mode is based on the PuCrunch algorithm written by Pasi <em>Albert</em> Ojala, and adapted for use on TI calculators by Thomas Nussbaumer.</p>
+</div></div>
+<div class='c2'>
+<hr class='hr2' /><h2 class='heading'><a name='Object.file.import'></a>Object file import</h2><div class='c2in'><hr class='hr2in' />
+<p>The code to import<span class='widespace'>&#32;</span><code>.o</code><span class='widespace'>&#32;</span>files is based on<span class='widespace'>&#32;</span><code>obj2ti</code><span class='widespace'>&#32;</span>written by Julien Muchembled and further modified by Sebastian Reichelt and Kevin Kofler.</p>
+</div></div>
+<div class='c2'>
+<hr class='hr2' /><h2 class='heading'><a name='Thanks'></a>Thanks</h2><div class='c2in'><hr class='hr2in' />
+<p>Some people provided significant help without contributing code to the project.</p>
+<p>Thanks to Olivier Armand for his FlashAppy patch: since TI has stopped signing 
+Flash applications this is absolutely vital to GTC.</p>
+<p>Thanks to vince from the Ti-Fr team for his generous hosting.</p>
+<p>Thanks to all the testers who helped uncover bugs.</p>
+</div></div>
+</div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Contact'></a>Contact</h1><div class='c1in'><hr class='hr1in' />
+<p>You will find the latest versions and online documentation on the GTC website:</p>
+<p><a href='http://gtc.ti-fr.com/'> http://gtc.ti-fr.com/</a></p>
+<p>Please use the <a href='http://gtc.ti-fr.com/feedback/'> feedback form</a> to submit bugs or 
+comments.
+</div></div></p></div>
+</body>
+</html>

+ 14 - 0
doc/examples.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>GTC examples - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>GTC examples</h1>
+<p>You will find</p></div>
+</body>
+</html>

File diff suppressed because it is too large
+ 210 - 0
doc/extensions.html


File diff suppressed because it is too large
+ 57 - 0
doc/faq.html


+ 51 - 0
doc/glossary.html

@@ -0,0 +1,51 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>Glossary - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>Glossary</h1>
+<div class='toc'><div class='toctop'><div class='tocbot'><div class='toc-content'>
+<b>Contents:</b><ul>
+        <li><a href='#68000'>68000</a></li>
+        <li><a href='#a68k'>a68k</a></li>
+        <li><a href='#AMS'>AMS</a></li>
+        <li><a href='#Assembly'>Assembly</a></li>
+        <li><a href='#TIGCC'>TIGCC</a></li>
+      </ul>
+</div></div></div></div>
+<div class='c1'>
+<div class='c2'>
+<div class='c3'>
+<div class='c4'>
+<hr class='hr4' /><h4 class='heading'><a name='68000'></a>68000</h4><div class='c4in'><hr class='hr4in' />
+<p>The type of processor included in TI-89 and above calculators.</p>
+</div></div>
+<div class='c4'>
+<hr class='hr4' /><h4 class='heading'><a name='a68k'></a><a href='glossary.html#a68k'><code>a68k</code></a></h4><div class='c4in'><hr class='hr4in' />
+<p>The traditional (and popular) assembler for TI calculators. It is currently 
+distributed as part of TIGCC.</p>
+</div></div>
+<div class='c4'>
+<hr class='hr4' /><h4 class='heading'><a name='AMS'></a>AMS</h4><div class='c4in'><hr class='hr4in' />
+<p>AMS (Advanced Mathematics Software) is the operating system of TI calculators. 
+It is stored in the Flash ROM.</p>
+</div></div>
+<div class='c4'>
+<hr class='hr4' /><h4 class='heading'><a name='Assembly'></a>Assembly</h4><div class='c4in'><hr class='hr4in' />
+<p>The native language of the 68000 processor.</p>
+</div></div>
+<div class='c4'>
+<hr class='hr4' /><h4 class='heading'><a name='TIGCC'></a>TIGCC</h4><div class='c4in'><hr class='hr4in' />
+<p>The largest C compiler available for TI calculators. It's a patched GCC 
+compiler and for this reason is only available for PC platforms.
+</div></div>
+</div></div>
+</div></div>
+</div></div></p></div>
+</body>
+</html>

File diff suppressed because it is too large
+ 41 - 0
doc/index.html


+ 1 - 0
doc/layout/default.css

@@ -0,0 +1 @@
+@import url(simple.css);

+ 89 - 0
doc/layout/simple.css

@@ -0,0 +1,89 @@
+body {
+    background-color: white;
+    color: black;
+    font-family: georgia, verdana, sans-serif;
+    padding-bottom: 2em;
+    font-size-adjust: 0.5;
+}
+p {
+    text-align: justify;
+    line-height: 130%;
+}
+pre {
+    margin-left: 2em;
+}
+/*.widespace {
+    margin: 0.1em;
+}*/
+a {
+    color:#0000b0;
+    text-decoration:none;
+}
+a:hover {
+    color:#6060ff;
+    text-decoration:underline;
+}
+h1,h2,h3,h4,h5,h6,
+h1 a,h2 a,h3 a,h4 a,h5 a,h6 a {
+    color:#25b;
+}
+h1 {
+    margin-top: 1.5em;
+    margin-bottom: 0;
+}
+h2 {
+    margin-top: 1.5em;
+}
+.hr1in {
+    height: 1px;
+    background-color: #999; /* used by FF */
+    color: #999; /* used by IE */
+    border: 0;
+}
+.hr1,.hr2,.hr3,.hr4,.hr5,.hr6 {
+    display: none;
+}
+.hr0in {
+    height: 1px;
+    background-color: #7a7;
+    border: 0;
+}
+.hr0in,.hr2in,.hr3in,.hr4in,.hr5in,.hr6in {
+    display: none;
+}
+.c0 {
+    width: 700px;
+}
+/*
+.c0 {
+    width: 700px;
+    margin-left: auto;
+    margin-right: auto;
+    text-align: center;
+}
+    */
+.c1 {
+    text-align: left; 
+}
+.toc {
+    font-size: 95%;
+    margin-top: 1em;
+    margin-left: 2em;
+    padding: 0.2em;
+    border: 1px dotted black;
+}
+.toc ul {
+    /*list-style-type: circle;*/
+}
+.toc ul ul ul {
+    /*list-style-type: ;*/
+}
+.toc ul ul ul ul {
+    display: none;
+}
+code a {
+    font-weight: bold;
+}
+a.invalidlink {
+    color: #900000;
+}

+ 354 - 0
doc/license-gpl2.html

@@ -0,0 +1,354 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>GNU General Public License - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>GNU General Public License</h1>
+<pre>
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    &lt;one line to give the program's name and a brief idea of what it does.&gt;
+    Copyright (C) &lt;year&gt;  &lt;name of author&gt;
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type <code>show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type </code>show c' for details.
+
+The hypothetical commands <code>show w' and </code>show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than <code>show w' and </code>show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  &lt;signature of Ty Coon&gt;, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+</pre></div>
+</body>
+</html>

+ 14 - 0
doc/missing.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>Missing entry - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>Missing entry</h1>
+<p>Sorry, this entry has not been written yet!</p></div>
+</body>
+</html>

File diff suppressed because it is too large
+ 33 - 0
doc/oncalc.html


+ 27 - 0
doc/preprocessor.html

@@ -0,0 +1,27 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>The C preprocessor - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>The C preprocessor</h1>
+<div class='toc'><div class='toctop'><div class='tocbot'><div class='toc-content'>
+<b>Contents:</b><ul>
+  <li><a href='#Preprocessor.directives'>Preprocessor directives</a>
+  <ul>
+    <li><a href='#.23define'>#define</a></li>
+  </ul></li>
+</ul>
+</div></div></div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Preprocessor.directives'></a>Preprocessor directives</h1><div class='c1in'><hr class='hr1in' /><div class='c2'>
+<hr class='hr2' /><h2 class='heading'><a name='.23define'></a><a href='preprocessor.html#.23define'><code>#define</code></a></h2><div class='c2in'><hr class='hr2in' />
+<p>...
+</div></div>
+</div></div></p></div>
+</body>
+</html>

File diff suppressed because it is too large
+ 65 - 0
doc/specificities.html


+ 32 - 0
doc/version.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>History - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>History</h1>
+<div class='toc'><div class='toctop'><div class='tocbot'><div class='toc-content'>
+<b>Contents:</b><ul>
+  <li><a href='#Version.history'>Version history</a></li>
+  <li><a href='#To.do'>To do</a></li>
+</ul>
+</div></div></div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Version.history'></a>Version history</h1><div class='c1in'><hr class='hr1in' /><ul><li> 0.90.2:
+</li><ul><li> fix IDE behaviour when catalog symbol limit is reached
+</li><li> small compiler fixes:
+</li><ul><li> proper error message when converting from union type to another type
+</li><li> reject duplicate member names in struct or union declarations
+</li></ul></ul><li> 0.90.1: first public release
+</li></ul></div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='To.do'></a>To do</h1><div class='c1in'><hr class='hr1in' /><ul><li> Implement command-line interface in on-calc version.
+</li><li> Improve the pre-compiled header format to handle the full up-to-date TIGCC library.
+</li><li> Add a true linker.
+</li></ul></div></div></div>
+</body>
+</html>

+ 29 - 0
doc/windows.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+<head>
+	<title>Windows-specific features - GTC documentation</title>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+	<link rel='stylesheet' type='text/css' href='layout/default.css' />
+</head>
+<body>
+<p><a href='index.html'>◄ Back to index</a></p>
+<div class='c0'>
+<h1>Windows-specific features</h1>
+<p><b>Warning</b>: the Windows version does not have a graphical interface yet, so 
+you should only use it if you know how to run programs from the command line.</p>
+<div class='toc'><div class='toctop'><div class='tocbot'><div class='toc-content'>
+<b>Contents:</b><ul>
+  <li><a href='#Getting.started.with.the.Windows.compiler'>Getting started with the Windows compiler</a></li>
+</ul>
+</div></div></div></div>
+<div class='c1'>
+<hr class='hr1' /><h1 class='heading'><a name='Getting.started.with.the.Windows.compiler'></a>Getting started with the Windows compiler</h1><div class='c1in'><hr class='hr1in' />
+<p><em>Legal notice: the<span class='widespace'>&#32;</span><code>Include</code><span class='widespace'>&#32;</span>directory is subject to the <a href='license-gpl2.html#GNU.General.Public.License'>GNU General Public License</a>, which grants you a number of rights. You may choose not to install it, but it will prevent you from using the TIGCC Library.</em></p>
+<p>To install GTC just extract<span class='widespace'>&#32;</span><code>gtc.exe</code><span class='widespace'>&#32;</span>and the<span class='widespace'>&#32;</span><code>Include</code><span class='widespace'>&#32;</span>directory to any 
+directory. You should add that directory to your Windows path (Control Panel → 
+System → Advanced → Environment Variables, and modify the PATH variable).</p>
+<p>Now you can invoke<span class='widespace'>&#32;</span><code>gtc</code><span class='widespace'>&#32;</span>on the command-line, for more information see <a href='cmdline.html#GTC.Command-line.options'>GTC 
+Command-line options</a>.
+</div></div></p></div>
+</body>
+</html>

+ 96 - 0
gtc/Makefile

@@ -0,0 +1,96 @@
+VPATH = src
+
+ifndef DEBUG_FLAG
+CCBASEFLAGS=-O2 -Wall -Wno-unused-functions
+LDFLAGS=-s
+else
+CCBASEFLAGS=-g -Wall -Wno-switch -DDEBUGGING
+LDFLAGS=
+endif
+ifdef MINGW32
+ifeq (Cygwin,$(shell uname -o))
+CCBASEFLAGS += -mno-cygwin
+LDFLAGS     += -mno-cygwin
+endif
+endif
+include ../config.mk
+include ../platform.mk
+CDEFINES=$(GTC_ARCH_DEFINES) -DINCL_PATH=\"$(prefix)/share/gtc/include\"
+CFLAGS=$(CCBASEFLAGS) $(CDEFINES)
+SOURCEFILES=$(wildcard src/*.c src/*.h src/gtpack/*)
+HEADERS=$(wildcard src/*.h)
+OBJFILES=\
+	analyze.o \
+	bin2calc.o \
+	cmain.o \
+	decl.o \
+	expr.o \
+	func.o \
+	gen68k.o \
+	genffp.o \
+	genstmt.o \
+	getasm.o \
+	getsym.o \
+	init.o \
+	intexpr.o \
+	memmgt.o \
+	optimize.o \
+	out68k_as.o \
+	peep68k.o \
+	preproc.o \
+	reg68k.o \
+	searchkw.o \
+	stmt.o \
+	sunpack.o \
+	symbol.o \
+
+
+.PHONY: all clean install
+
+all:	gtc
+
+clean:
+	$(RM) $(OBJFILES) src/tags
+distclean: clean
+	$(RM) gtc$(BIN_SUFFIX)
+scratchclean: distclean
+
+install: gtc
+	mkdir -p $(prefix)/bin
+	install gtc $(prefix)/bin/gtc
+
+splint:
+	splint \
+		-nestcomment -paramuse -nullassign -initallelements -fullinitblock \
+		+charint +boolint -boolops +ptrnegate -shiftnegative \
+		-nullret -retvalint -retvalother \
+		-noeffect \
+		-globstate -mustfreeonly -mustfreefresh -onlytrans -statictrans -observertrans -dependenttrans -temptrans -branchstate \
+		$(CDEFINES) $(OBJFILES:%.o=%.c)
+	# -nestcomment     is for '//#define foo bar /* this is a comment */'
+	# -paramuse        is for unused func params
+	# -nullassign      is for 'int x CGLOB;'
+	# -initallelements is for 'int x[5] CGLOBL;'
+	# -fullinitblock   is for 'TI_SHORT x CGLOBL;'
+	# +charint         is for 'char c = 2+1;' or 'if (c < 2+1)'
+	# +boolint         is for 'int z = (x==y);'
+	# -boolops         is for 'ptr && x'
+	# +ptrnegate       is for '!ptr'
+	# -shiftnegative   is for '1 << my_int' where 'my_int' has no known range
+	# -noeffect        is for '(void)0'
+	# -nullret         is for 'return NULL;' without '/*@null@*/' annotation
+	# -retvalint       is for 'myfunc(x);' without subsequent cast to void
+	# -retvalother     is for 'myfunc(x);' without subsequent cast to void
+
+src/protos.h: src/*.c
+	ruby -e '' && perl -e '' && (grep "^[^/\#*} 	].*(.*{" src/*.c | perl -pe 's/ {/;/ or die $$_' | perl -pe '$$m=$$_;s/\/\*.*?\*\// /g;/(\w+)\(/ or die $$_;print "$$1:";$$_=$$m' | perl -pe 's/\bTYP\b/struct typ/g;s/\bSYM\b/struct sym/g;s/\bTABLE\b/struct stab/g;s/\bHTABLE\b/struct hstab/g;s/\bSTACK_IMAGE\b/struct _stackimg/g;s/\bREGS_IMAGE\b/struct _regsimg/g;s/\b_pc_bcd\b/struct _pc_bcd_s/g' | sort | uniq | ruby script/mkprotos.rb > $@) || echo 1>&2 "warning: unable to rebuild 'protos.h'"
+
+gtc: $(SOURCEFILES)
+	$(MAKE) gtc-rebuild
+
+#$(OBJFILES): $(HEADERS)
+gtc-rebuild: $(OBJFILES)
+	$(CC) -o gtc $(LDFLAGS) $(OBJFILES)
+
+%.o: %.c vcg.c error.c *.h gtpack/*.h Makefile config.mk
+	$(CC) -c $(CFLAGS) $<

+ 87 - 0
gtc/Makefile.orig

@@ -0,0 +1,87 @@
+VPATH = src
+
+ifndef DEBUG_FLAG
+CCBASEFLAGS=-O2 -Wimplicit
+LDFLAGS=-s
+else
+CCBASEFLAGS=-g -Wall
+LDFLAGS=
+endif
+ifdef MINGW32
+ifeq (Cygwin,$(shell uname -o))
+CCBASEFLAGS += -mno-cygwin
+LDFLAGS     += -mno-cygwin
+endif
+endif
+include ../config.mk
+include ../platform.mk
+CDEFINES=$(GTC_ARCH_DEFINES) -DINCL_PATH=\"$(prefix)/share/gtc/include\"
+CFLAGS=$(CCBASEFLAGS) $(CDEFINES)
+OBJFILES=\
+	analyze.o \
+	cmain.o \
+	decl.o \
+	expr.o \
+	func.o \
+	gen68k.o \
+	genffp.o \
+	genstmt.o \
+	getasm.o \
+	getsym.o \
+	init.o \
+	intexpr.o \
+	memmgt.o \
+	optimize.o \
+	out68k_as.o \
+	peep68k.o \
+	preproc.o \
+	reg68k.o \
+	searchkw.o \
+	stmt.o \
+	sunpack.o \
+	symbol.o \
+	ttbin2asm.o \
+
+
+.PHONY: all clean install
+
+all:	gtc
+
+clean:
+	$(RM) $(OBJFILES) src/tags
+distclean: clean
+	$(RM) gtc$(BIN_SUFFIX)
+scratchclean: distclean
+
+install: gtc
+	mkdir -p $(prefix)/bin
+	install gtc $(prefix)/bin/gtc
+
+splint:
+	splint \
+		-nestcomment -paramuse -nullassign -initallelements -fullinitblock \
+		+charint +boolint -boolops +ptrnegate -shiftnegative \
+		-nullret -retvalint -retvalother \
+		-noeffect \
+		-globstate -mustfreeonly -mustfreefresh -onlytrans -statictrans -observertrans -dependenttrans -temptrans -branchstate \
+		$(CDEFINES) $(OBJFILES:%.o=%.c)
+	# -nestcomment     is for '//#define foo bar /* this is a comment */'
+	# -paramuse        is for unused func params
+	# -nullassign      is for 'int x CGLOB;'
+	# -initallelements is for 'int x[5] CGLOBL;'
+	# -fullinitblock   is for 'TI_SHORT x CGLOBL;'
+	# +charint         is for 'char c = 2+1;' or 'if (c < 2+1)'
+	# +boolint         is for 'int z = (x==y);'
+	# -boolops         is for 'ptr && x'
+	# +ptrnegate       is for '!ptr'
+	# -shiftnegative   is for '1 << my_int' where 'my_int' has no known range
+	# -noeffect        is for '(void)0'
+	# -nullret         is for 'return NULL;' without '/*@null@*/' annotation
+	# -retvalint       is for 'myfunc(x);' without subsequent cast to void
+	# -retvalother     is for 'myfunc(x);' without subsequent cast to void
+
+gtc: $(OBJFILES)
+	$(CC) -o gtc $(LDFLAGS) $(OBJFILES)
+
+%.o: %.c vcg.c error.c *.h gtpack/*.h Makefile config.mk
+	$(CC) -c $(CFLAGS) $<

+ 114 - 0
gtc/script/mkprotos.rb

@@ -0,0 +1,114 @@
+#!/usr/bin/ruby
+
+class String
+    def scan_for_structenum(target)
+	scan(/(struct\s+\w+)/) do
+	    target[$1] = true
+	end
+	scan(/enum\((\w+)\)/) do
+	    target["enum #$1"] = true
+	end
+    end
+end
+
+class FuncDef
+    attr_accessor :name,:files,:proto,:referenced
+    def initialize(name,files,proto)
+	@name = name
+	@files = files
+	@proto = proto
+	@referenced = []
+    end
+    def to_s
+	(files.length==1 ? files[0] : "{"+files.join(",")+"}")+":#{name} [[#{proto}]]"
+    end
+    def inspect
+	"{{FuncDef #{to_s}}}"
+    end
+    def compatible?(oth)
+	name==oth.name && proto==oth.proto
+    end
+    def static?
+	proto =~ /^\bstatic\b/
+    end
+end
+
+funcs = {}
+structenum = {}
+
+while x=gets
+    if x !~ /^(\w+):(.*?):(.*)$/
+	throw x
+    else
+	func = FuncDef.new($1,[$2],$3)
+	if !func.static?
+	    func.proto.scan_for_structenum(structenum)
+	    name = func.name
+	    if funcs[name]
+		if funcs[name].compatible?(func)
+		    funcs[name].files += func.files
+		else
+		    $stderr.puts "conflict between #{funcs[name]} and #{func}"
+		    throw :conflict
+		end
+	    else
+		funcs[name] = func
+	    end
+	end
+    end
+end
+
+banlist = %w(debug isidch isalnum isdigit isspace unary declare nl Compile err_int warn_int error_do AP_app AP_about sUnpack)
+banlist.each do |name|
+    funcs.delete(name)
+end
+
+class Union
+    include Enumerable
+    def initialize(*sets)
+	@sets = sets
+    end
+    def each
+	@sets.each do |set|
+	    set.each do |item|
+		yield item
+	    end
+	end
+    end
+end
+
+Union.new(Dir['**/*.c']).each do |path|
+    File.open(path) do |f|
+	words = Hash.new 0
+	f.each do |line|
+	    line.scan(/\w+/) do |word|
+		if funcs[word]
+		    words[word] += 1
+		end
+	    end
+	end
+	words.each do |word,count|
+	    if funcs[word].files != [path]
+		funcs[word].referenced << path
+	    end
+	end
+    end
+end
+
+
+puts "// Auto-generated file, do not edit!"
+puts
+puts "#ifndef PROTOS_H_"
+puts "#define PROTOS_H_"
+puts
+structenum.keys.sort.each do |decl|
+    puts "#{decl};"
+end
+puts
+funcs.each do |name,func|
+    if !func.referenced.empty? || func.files!=["src/out68k_as.c"]
+	puts func.proto
+    end
+end
+puts
+puts "#endif"

+ 4 - 0
gtc/src/Makefile

@@ -0,0 +1,4 @@
+all:
+
+tags: *.c *.h
+	ctags *.c *.h

+ 201 - 0
gtc/src/all.c

@@ -0,0 +1,201 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) main file
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define DECLARE
+#define FLASH_VERSION
+#define GTDEV
+#include	"define.h"
+#ifdef OPTIMIZE_BSS
+register void *bssdata asm("a5");
+#endif
+#define dseg() while (0)
+#define cseg() while (0)
+#define nl() while (0)
+#define compound_done getsym
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+#include	"flashhdr.h"
+#ifdef GTDEV
+#include "GtDevComm.h"
+#endif
+#include	"flashhdr.c"
+
+#ifndef debug
+void debug(int c) {
+	printf("%c ",c);
+	ngetchx();
+}
+#endif
+
+#undef exit
+#define exit(k) asm(" move.l exit_a7,%sp\n rts")
+extern char *curname;
+extern void fatal(char *s) __attribute__ ((noreturn));
+
+#include "out68k_as.c"
+
+#include "decl.c"
+#include "expr.c"
+#ifdef ASM
+#include "getasm.c"
+#endif
+#include "getsym.c"
+#include "init.c"
+#include "intexpr.c"
+//#include "memmgt.c"	// xalloc is common to both modules
+#include "preproc.c"
+#include "searchkw.c"
+#include "stmt.c"
+#include "symbol.c"
+
+void *exit_a7 CGLOB;
+#if 0
+void _exit(int code) {
+	clean_up();
+	printf("\nerror code %d",code);
+	while (!kbhit());
+	asm(" move.l exit_a7,%sp; rts");
+//	exit(0);
+}
+#endif
+
+void _noreturn assert_terminated();
+#ifdef GTDEV
+void fatal(char *message) {
+	clean_up();
+	msg_process(message, ET_FATAL, "", "", -1, -1);
+	exit(0);
+	assert_terminated();
+}
+#else
+void fatal(char *message) {
+	clean_up();
+	msg2("Fatal error!\n%s\n", message);
+//	msg("There may be a syntax error or a compiler bug.\n");
+//	while (!kbhit());
+	ngetchx();
+	asm(" move.l exit_a7,%sp; rts");
+	assert_terminated();
+//	exit(0);
+}
+#endif
+
+void fatal(char *s) __attribute__ ((noreturn));
+
+#define mk_node near_mk_node
+#define mk_icon near_mk_icon
+struct enode *mk_node(enum(e_node) nt, struct enode *v1, struct enode *v2) {
+/*
+ * build an expression node with a node type of nt and values v1 and v2.
+ */
+	struct enode   *ep;
+	ep = (struct enode *) xalloc((int) sizeof(struct enode), ENODE+MK_NODE);
+	ep->nodetype = nt;
+	ep->etype = bt_void;
+	ep->esize = -1;
+	ep->v.p[0] = v1;
+	ep->v.p[1] = v2;
+	return ep;
+}
+
+struct enode *mk_icon(long i) {
+/*
+ * build an expression node forming an integer constant
+ */
+	struct enode   *ep;
+//	ep = (struct enode *) xalloc((int) sizeof(struct enode), ENODE+MK_ICON);
+	ep = (struct enode *) xalloc((int) sizeof(struct xcon), ENODE+MK_ICON);
+	ep->nodetype = en_icon;
+	ep->etype = bt_void;
+#ifdef NO_CALLOC
+	ep->esize = 0;
+#endif
+	ep->v.i = i;
+	return ep;
+}
+
+#include "analyze.c"
+#include "func.c"
+#include "gen68k.c"
+#include "genffp.c"
+#include "genstmt.c"
+#include "memmgt.c"	// xalloc is common to both modules
+#include "optimize.c"
+#include "peep68k.c"
+#include "reg68k.c"
+
+/* this is reimplemented because old versions of TIGCC didn't check for _F_WRIT */
+void my_fclose(FILE *f) {
+	if (f->flags&_F_WRIT)
+		HeapRealloc(f->handle,*(unsigned short*)f->base+2);
+	HeapUnlock(f->handle);
+	free(f);
+}
+
+asm("bcopy:\n"
+"	move.w (12,%sp),-(%sp)\n"
+"	clr.w -(%sp)\n"
+"	move.l (8,%sp),-(%sp)\n"
+"	move.l (16,%sp),-(%sp)\n"
+"	movea.l 0xC8,%a0\n"
+"	movea.l (%a0,0x26A*4),%a0\n"
+"	jsr (%a0)                  /* memcpy */\n"
+"	lea (%sp,12),%sp\n"
+"	rts\n"
+
+"__mulsi3:\n"
+"	move.l (4,%sp),%d1\n"
+"	move.l (8,%sp),%d2\n"
+"	move.l %d2,%d0\n"
+"	mulu %d1,%d0\n"
+"	swap %d2\n"
+"	mulu %d1,%d2\n"
+"	swap %d1\n"
+"	mulu (10,%sp),%d1\n"
+"	add.w %d1,%d2\n"
+"	swap %d2\n"
+"	clr.w %d2\n"
+"	add.l %d2,%d0\n"
+"	rts\n"
+
+"__modsi3:\n"
+"	move.w #0x2A9*4,%d2        /* _ms32s32 */\n"
+"	bra.s __div_entry\n"
+"__divsi3:\n"
+"	move.w #0x2A8*4,%d2        /* _ds32s32 */\n"
+"	bra.s __div_entry\n"
+"__umodsi3:\n"
+"	move.w #0x2A9*4,%d2        /* _mu32u32 */\n"
+"	bra.s __div_entry\n"
+"__udivsi3:\n"
+"	move.w #0x2A8*4,%d2        /* _du32u32 */\n"
+"	bra.s __div_entry\n"
+"	nop\n"
+"__div_entry:\n"
+"	move.l (4,%sp),%d1\n"
+"	move.l (8,%sp),%d0\n"
+"	movea.l 0xC8,%a0\n"
+"	movea.l (%a0,%d2.w),%a0\n"
+"	jsr (%a0)\n"
+"	move.l %d1,%d0\n"
+"	rts");
+
+#include	"cmain.c"
+
+#include	"flashend.c"
+// vim:ts=4:sw=4

+ 816 - 0
gtc/src/analyze.c

@@ -0,0 +1,816 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * analyzer
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+//#undef OPT_ROMCALLS
+
+/*
+ * this module will step through the parse tree and find all optimizable
+ * expressions. at present these expressions are limited to expressions that
+ * are valid throughout the scope of the function. the list of optimizable
+ * expressions is:
+ *
+ * constants
+ * global and static addresses
+ * auto addresses
+ * contents of auto addresses.
+ *
+ * contents of auto addresses are valid only if the address is never referred to
+ * without dereferencing.
+ *
+ * scan will build a list of optimizable expressions which opt1 will replace
+ * during the second optimization pass.
+ */
+
+void scan(struct snode *block);
+void repcse(struct snode *block);
+
+#define INIT_EXEC_COUNT 16
+FILE		   *list CGLOB;
+int 			regs_used CGLOB;
+struct enode   *regexp[REGEXP_SIZE] CGLOBL;
+xstatic unsigned int exec_count CGLOB;
+xstatic struct cse *olist CGLOB;		/* list of optimizable expressions */
+
+int equalnode(struct enode *node1, struct enode *node2) {
+/*
+ * equalnode will return 1 if the expressions pointed to by node1 and node2
+ * are equivalent.
+ */
+	if (node1 == 0 || node2 == 0)
+		return 0;
+	if (node1->nodetype != node2->nodetype)
+		return 0;
+	switch (node1->nodetype) {
+#ifndef AS
+	  case en_labcon:
+		  /* FALLTHROUGH  -  HACK : v.i==(long)v.ensp */
+	  case en_icon:
+#else
+	  case en_labcon:
+		return (node1->v.enlab == node2->v.enlab);
+	  case en_icon:
+#endif
+	  case en_autocon:
+	  case en_tempref: // note: this one is not necessary when doing CSE, but can be useful in gen68k.c
+		/*infunc("chk_curword")
+			if (node2->v.i=(long)(char)0xCD)
+				bkpt();*/
+		return (node1->v.i == node2->v.i);
+	  case en_nacon:
+		return (!strcmp(node1->v.ensp, node2->v.ensp));
+	  case en_ref:
+	  case en_fieldref:
+		return equalnode(node1->v.p[0], node2->v.p[0]);
+	  default:
+		return 0;
+	}
+}
+
+
+static struct cse *searchnode(struct enode *node) {
+/*
+ * searchnode will search the common expression table for an entry that
+ * matches the node passed and return a pointer to it.
+ * the top level of equalnode is code inline here for speed
+ */
+	register struct cse *csp;
+	register struct enode *ep;
+	if (node == 0)
+		return 0;
+	csp = olist;
+	while (csp != 0) {
+		ep = csp->exp;
+		if (ep != 0 && node->nodetype == ep->nodetype) {
+			switch (node->nodetype) {
+			  case en_icon:
+#ifndef AS
+			  case en_labcon:
+#endif
+			  case en_autocon:
+				if (node->v.i == ep->v.i)
+					return csp;
+				break;
+#ifndef AS
+			  case en_nacon:
+				if (!strcmp(node->v.ensp, ep->v.ensp))
+					return csp;
+				break;
+#endif
+#ifdef AS
+			  case en_labcon:
+			  case en_nacon:
+				if (node->v.enlab == ep->v.enlab)
+					return csp;
+				break;
+#endif
+			  case en_ref:
+				if (equalnode(node->v.p[0], ep->v.p[0])) {
+					/* 05/09/03: added check for size ; struct or unions
+					 *           won't work either since Gen68k needs their address
+					 */
+					if (node->esize != ep->esize || bt_aggregate(node->etype))
+						csp->voidf=1;
+					return csp;
+				}
+				break;
+			}
+		}
+		csp = csp->next;
+	}
+	return 0;
+}
+
+struct enode *copynode(struct enode *node) {
+/*
+ * copy the node passed into a new enode so it wont get corrupted during
+ * substitution.
+ */
+	struct enode   *temp;
+	if (node == 0)
+		return 0;
+	temp = (struct enode *) xalloc((int) sizeof(struct enode), ENODE+COPYNODE);
+	*temp = *node;
+	return temp;
+}
+
+
+
+static struct cse *enternode(struct enode *node, int duse) {
+/*
+ * enternode will enter a reference to an expression node into the common
+ * expression table. duse is a flag indicating whether or not this reference
+ * will be dereferenced.
+ */
+	struct cse	   *csp;
+	if ((csp = searchnode(node)) == 0) {		/* add to tree */
+		csp = (struct cse *) xalloc((int) sizeof(struct cse), CSE+ENTERNODE);
+		csp->next = olist;
+#ifdef NO_CALLOC
+		csp->uses = 0;
+		csp->duses = 0;
+		csp->voidf = 0;
+#endif
+		csp->exp = copynode(node);
+		olist = csp;
+		if (bt_aggregate(node->etype))
+			csp->voidf++;
+	} else {
+		/*
+		 * Integer constants may be in the table with different sizes -- keep
+		 * the maximum size
+		 */
+		if (node->nodetype == en_icon && node->esize > csp->exp->esize)
+			csp->exp->esize = node->esize;
+	}
+/*	infunc("chk_curword")
+		if (node->nodetype != en_icon && node->esize==1)
+			bkpt();*/
+#ifdef REGALLOC_FOR_SIZE
+#define exec_count INIT_EXEC_COUNT
+#endif
+	csp->uses+=exec_count;
+	if (duse)
+		csp->duses+=exec_count;
+#ifdef REGALLOC_FOR_SIZE
+#undef exec_count
+#endif
+	return csp;
+}
+
+static struct cse *voidauto(struct enode *node) {
+/*
+ * voidauto will void an auto dereference node which points to the same auto
+ * constant as node.
+ */
+	struct cse	   *csp;
+	csp = olist;
+	while (csp != 0) {
+		if (csp->exp->nodetype==en_ref && equalnode(node, csp->exp->v.p[0])) {
+			if (csp->voidf)
+				return 0;
+			csp->voidf = 1;
+			return csp;
+		}
+		csp = csp->next;
+	}
+	return 0;
+}
+
+void scanexpr(struct enode *node, int duse) {
+/*
+ * scanexpr will scan the expression pointed to by node for optimizable
+ * subexpressions. when an optimizable expression is found it is entered into
+ * the tree. if a reference to an autocon node is scanned the corresponding
+ * auto dereferenced node will be voided. duse should be set if the
+ * expression will be dereferenced.
+ */
+	struct cse	   *csp, *csp1;
+	if (node == 0)
+		return;
+	switch (node->nodetype) {
+	  case en_nacon:
+#ifdef FLINE_RC
+		if (fline_rc && node->v.ensp &&
+			node->v.ensp[1]=='R' && node->v.ensp[0]=='_' &&
+			!memcmp(node->v.ensp+2,"OM_CALL_",8))
+			break;
+#endif
+		/*@fallthrough@*/
+	  case en_labcon:
+#ifndef NO_ICONST_SCAN
+	  case en_icon:
+#endif
+		(void) enternode(node, duse);
+		break;
+	  case en_autocon:
+		/*
+		 * look if the dereferenced use of the node is in the list, remove it
+		 * in this case
+		 */
+		if ((csp = voidauto(node)) != 0) {
+			csp1 = enternode(node, duse);
+			csp1->duses += csp->uses;
+		} else if (duse>=0)				// don't enter it otherwise (we can already access it)
+			(void) enternode(node, duse);
+		break;
+
+	  case en_ref:
+	  case en_fieldref:
+		if (node->v.p[0]->nodetype == en_autocon) {
+			/*infunc("ChargerAdressesData")
+				bkpt();*/
+			{
+			int first = (searchnode(node) == 0);
+/*			infunc("chk_curword") if (node->v.p[0]->v.i==(long)(char)0xCD)
+				bkpt();*/
+			csp = enternode(node, duse);
+			/*
+			 * take care: the non-derereferenced use of the autocon node may
+			 * already be in the list. In this case, set voidf to 1
+			 */
+			if (searchnode(node->v.p[0]) != 0) {
+				csp->voidf = 1;
+				scanexpr(node->v.p[0], 1);
+			} else if (first) {
+				/* look for register nodes */
+				int 			i = 0;
+				XLST_TYPE		j = (XLST_TYPE)node->v.p[0]->v.i, *p;
+				p=reglst; while (i < regptr) {
+					if (*p++ == j) {
+						csp->voidf--;	/* this is not in auto_lst */
+//						if (regalloc[i]>=0) csp->reg=regalloc[i];
+						csp->uses += 256 * INIT_EXEC_COUNT * (100 - i);
+						//csp->duses += 30 * (100 - i);	// so we know we don't always need an areg
+						break;
+					}
+					++i;
+				}
+				/* set voidf if the node is not in autolst */
+				csp->voidf++;
+				i = autoptr;
+				p=autolst;
+				while (i--)
+					if (*p++ == j) {
+						csp->voidf--;
+						break;
+					}
+				/*
+				 * even if that item must not be put in a register,
+				 * it is legal to put its address therein
+				 */
+				if (csp->voidf)
+					scanexpr(node->v.p[0], 1);
+			}
+			}
+#ifdef OPT_ROMCALLS
+		} else if (node->v.p[0]->nodetype == en_icon && node->v.p[0]->v.i == 0xC8) {
+			enternode(node, 1);
+#endif
+		} else {
+			scanexpr(node->v.p[0], 1);
+		}
+		break;
+	  case en_uminus:
+	  case en_compl:
+	  case en_ainc:
+	  case en_adec:
+	  case en_not:
+	  case en_cast:
+	  case en_deref:
+		scanexpr(node->v.p[0], duse);
+		break;
+	  case en_alloca:
+		scanexpr(node->v.p[0], 0);
+		break;
+	  case en_asadd:
+	  case en_assub:
+	  case en_add:
+	  case en_sub:
+#ifndef NO_IMPROVED_CSE_SCAN
+		if (duse) {
+			if (node->v.p[0]->etype==bt_pointer
+				|| (node->v.p[1]->etype!=bt_pointer && node->v.p[0]->esize==4)
+				|| (node->v.p[1]->esize!=4)) {
+					if (node->v.p[1]->nodetype!=en_icon)
+						scanexpr(node->v.p[0], 1),
+						scanexpr(node->v.p[1], 0);
+					else
+						scanexpr(node->v.p[0], -1);
+			} else scanexpr(node->v.p[0], 0), scanexpr(node->v.p[1], 1);
+		} else
+#endif
+			scanexpr(node->v.p[0], 0), scanexpr(node->v.p[1], 0);
+/*		scanexpr(node->v.p[0], duse);	// why ??
+		scanexpr(node->v.p[1], duse);*/
+		break;
+	  case en_mul:
+	  case en_div:
+	  case en_lsh:
+	  case en_rsh:
+	  case en_mod:
+	  case en_and:
+	  case en_or:
+	  case en_xor:
+	  case en_lor:
+	  case en_land:
+	  case en_eq:
+	  case en_ne:
+	  case en_gt:
+	  case en_ge:
+	  case en_lt:
+	  case en_le:
+	  case en_asmul:
+	  case en_asdiv:
+	  case en_asmod:
+	  case en_aslsh:
+	  case en_asrsh:
+	  case en_asand:
+	  case en_asor:
+	  case en_asxor:
+	  case en_cond:
+	  case en_void:
+	  case en_assign:
+		scanexpr(node->v.p[0], 0);
+		scanexpr(node->v.p[1], 0);
+		break;
+	  case en_fcall:
+		scanexpr(node->v.p[0], 1);
+		scanexpr(node->v.p[1], 0);
+		break;
+	  case en_compound:
+		scan(node->v.st);
+		break;
+	}
+}
+
+void scan(struct snode *block) {
+/*
+ * scan will gather all optimizable expressions into the expression list for
+ * a block of statements.
+ */
+	while (block != 0) {
+		unsigned int old=exec_count;
+		switch (block->stype) {
+		  case st_return:
+		  case st_expr:
+			opt4(&block->exp);
+			scanexpr(block->exp, 0);
+			break;
+		  case st_loop:
+			opt4(&block->exp);
+			scanexpr(block->exp, 0);
+			exec_count*=block->count;
+			scanexpr(block->exp->v.p[0],0);	// increase desirability of counter reg allocation
+			scan(block->s1);
+			if (block->v2.e) {
+				opt4(&block->v2.e);
+				scanexpr(block->v2.e, 0);
+			}
+			break;
+		  case st_while:
+		  case st_do:
+			exec_count*=block->count;
+			exec_count++;
+			opt4(&block->exp);
+			scanexpr(block->exp, 0);
+			exec_count--;
+			scan(block->s1);
+			break;
+		  case st_for:
+			opt4(&block->exp);
+			scanexpr(block->exp, 0);
+			exec_count*=block->count;
+			opt4(&block->v1.e);
+			scanexpr(block->v1.e, 0);
+			scan(block->s1);
+			opt4(&block->v2.e);
+			scanexpr(block->v2.e, 0);
+			break;
+		  case st_if:
+			opt4(&block->exp);
+			scanexpr(block->exp, 0);
+			exec_count=(unsigned int)(((unsigned long)exec_count*(unsigned long)block->count+32768)>>16);
+			scan(block->s1);
+			exec_count=old-exec_count;
+			scan(block->v1.s);
+			break;
+		  case st_switch:
+			opt4(&block->exp);
+			scanexpr(block->exp, 0);
+			exec_count>>=1;
+			scan(block->v1.s);
+			break;
+		  case st_case:
+		  case st_default:
+			scan(block->v1.s);
+			break;
+		  case st_compound:
+		  case st_label:
+			scan(block->s1);
+			break;
+		}
+		block = block->next;
+		exec_count=old;
+	}
+}
+
+unsigned long desire(struct cse *csp) {
+/*
+ * returns the desirability of optimization for a subexpression.
+ */
+#ifdef INFINITE_REGISTERS
+	return 4294967295;
+#endif
+	if (csp->voidf || (csp->exp->nodetype == en_icon &&
+//					   (unsigned int)csp->exp->v.i+8 <= 16))
+					   csp->exp->v.i < 16 && csp->exp->v.i >= 0))
+		return 0;
+#ifdef REGPARM_OLD
+			{ struct enode *ep;
+	if (csp->exp->nodetype == en_ref && (ep=csp->exp->v.p[0])->nodetype == en_autocon
+		&& ep->v.i>0 && (ep->v.i&REG_PARAMS))
+		return 10000000;	// if it's a register param, then it *must* be in a long-live reg
+			}
+#endif
+	if (g_lvalue(csp->exp))
+		return 2 * csp->uses;
+	return csp->uses;
+}
+
+void bsort(struct cse **list) {
+/*
+ * bsort implements a bubble sort on the expression list.
+ */
+	struct cse	   *csp1, *csp2;
+	csp1 = *list;
+	if (csp1 == 0 || csp1->next == 0)
+		return;
+	bsort(&(csp1->next));
+	while (csp1 != 0 && (csp2 = csp1->next) != 0 && desire(csp1) < desire(csp2)) {
+		*list = csp2;
+		csp1->next = csp2->next;
+		csp2->next = csp1;
+		list = &(csp2->next);
+	}
+}
+
+#ifdef REGPARM_OLD
+extern struct typ *head;
+#define parm_val (_parm_val+1)
+XLST_TYPE	_parm_val[1+MAX_DATA+1+MAX_ADDR+1];
+int			parm_reg[MAX_DATA+1+MAX_ADDR+1];
+#endif
+void allocate(void) {
+/*
+ * allocate will allocate registers for the expressions that have a high
+ * enough desirability.
+ */
+	struct cse	   *csp;
+	struct enode   *exptr/*,*ep*/;
+	reg_t			datareg, addreg;
+#ifdef AREG_AS_DREG
+	int				areg_possible;
+#endif
+	unsigned int	mask, rmask;
+	struct amode   *ap, *ap2;
+//#define __DEBUG__
+/*#ifdef __DEBUG__
+	int i=0;*
+#endif*/
+	regs_used = 0;
+	datareg = MAX_DATA+1;
+	addreg = MAX_ADDR+1 + AREGBASE;
+	mask = 0;
+	rmask = 0;
+	bsort(&olist);				/* sort the expression list */
+	csp = olist;
+/*	infunc("play")
+		bkpt();*/ //autoptr=0,regptr=0;
+	while (csp != 0) {
+/*#ifdef __DEBUG__
+	infunc("play")
+		if (i++==2) {
+			csp->voidf=1;
+			regs_used++;
+			rmask = rmask | (1 << (15 - datareg));
+			mask = mask | (1 << datareg);
+			datareg++;
+		}
+#endif*/
+/*
+ * If reg_option is not true, the 'desire' value must be at least
+ * 5000, which I hope can only be achieved by the 'register' attribute
+ */
+		if (desire(csp) < 3*INIT_EXEC_COUNT || (!reg_option && desire(csp) < 5000))
+			csp->reg = -1;
+#ifndef AREG_AS_DREG
+		else if (csp->duses &&
+#else
+		else if ((areg_possible=
+#endif
+				/* && (csp->duses * 3) > csp->uses */
+				addreg <
+							#ifdef USE_LINK
+										FRAMEPTR
+							#else
+										STACKPTR - uses_link
+							#endif
+			/*
+			 * integer constants may have different types
+			 */
+				 && (csp->exp->nodetype == en_icon
+			/*
+			 * the types which are fine in address registers
+			 */
+				 || (csp->exp->etype == bt_short ||
+					 csp->exp->etype == bt_long ||
+					 csp->exp->etype == bt_ulong ||
+					 csp->exp->etype == bt_pointer))
+#ifndef AREG_AS_DREG
+					)
+#else
+					) && csp->duses)
+#endif
+			csp->reg = addreg++;
+		else if (datareg < AREGBASE && csp->exp->nodetype!=en_autocon)
+			csp->reg = datareg++;
+#ifdef AREG_AS_DREG
+		else if (areg_possible)
+			csp->reg = addreg++;
+#endif
+		else
+			csp->reg = -1;
+/*		infunc("chk_curword")
+			if (csp->reg==AREGBASE+2 || csp->reg==AREGBASE+3 || csp->reg==4)
+				bkpt();*/
+		if (csp->reg IS_VALID) {
+			regexp[reg_t_to_regexp(csp->reg)] = csp->exp;
+			regs_used++;
+			rmask = rmask | (1 << (15 - csp->reg));
+			mask = mask | (1 << csp->reg);
+		}
+		csp = csp->next;
+	}
+#ifdef ADD_REDUNDANCY
+	if (regs_used>=6) {	/* >=6 : won't increase the push/pop time very much */
+		mask = 0x7CF8, rmask = 0x1F3E;
+		regs_used = 10;
+	/* (note that we could use less than 6 as a threshold, but the benefit lies around
+	    +0.5% while the runtime cost is rather high for such functions)
+	   (note too that the benefit for the optimization with threshold 6 is around 0.5%
+	    only, but it is so inexpensive that we really can afford it :] ) */
+	}
+#endif
+	if (mask != 0) {
+		g_code(op_movem, 4, mk_rmask(rmask), push_am);
+#ifdef ICODE
+		if (icode_option)
+			fprintf(icode, "\t$regpush %04x\n", rmask);
+#endif
+	}
+	save_mask = mask;
+	csp = olist;
+	while (csp != 0) {
+		if (csp->reg IS_VALID) {	/* see if preload needed */
+			exptr = csp->exp;
+#ifdef REGPARM_OLD
+			/* the following code works since REGPARM's are always
+			 * handled first -- their desire() is highest */
+			if (exptr->nodetype==en_ref && (ep=exptr->v.p[0])->nodetype==en_autocon
+				&& ep->v.i>0 && (ep->v.i&REG_PARAMS)) {
+				ap = mk_reg(ep->v.i>>REG_PARAMLOG);
+				ap2 = mk_reg(csp->reg);
+				g_code(op_move, (int) exptr->esize, ap, ap2);
+			} else
+#endif
+			if (exptr->nodetype!=en_ref
+#ifdef OPT_ROMCALLS
+				|| exptr->v.p[0]->nodetype!=en_autocon
+#endif
+#ifdef REGPARM
+				|| ((XLST_TYPE)exptr->v.p[0]->v.i >= -reg_size)) {
+#else
+				|| ((XLST_TYPE)exptr->v.p[0]->v.i > 0)) {
+#endif
+				initstack();
+				ap = g_expr(exptr, F_ALL | F_SRCOP);
+				ap2 = mk_reg(csp->reg);
+				g_code(op_move, (int) exptr->esize, ap, ap2);
+				freeop(ap);
+#ifdef ICODE
+				if (icode_option) {
+					fprintf(icode, "$reg ");
+					if (csp->reg < AREGBASE)
+						fprintf(icode, "D%d\n", csp->reg);
+					else
+						fprintf(icode, "A%d\n", csp->reg - AREGBASE);
+					g_icode(exptr);
+				}
+#endif
+			}
+		}
+		csp = csp->next;
+	}
+}
+
+#ifdef NO_EXTENDED_AUTOS
+void repexpr(struct enode *node) {
+#else
+#define repexpr(node) _repexpr(&(node))
+void _repexpr(struct enode **ep) {
+	struct enode *node=*ep;
+#endif
+/*
+ * repexpr will replace all allocated references within an expression with
+ * tempref nodes.
+ */
+	struct cse	   *csp;
+	if (node == 0)
+		return;
+	switch (node->nodetype) {
+	  case en_icon:
+	  case en_nacon:
+	  case en_labcon:
+	  case en_autocon:
+		if ((csp = searchnode(node)) != 0) {
+			if (csp->reg > 0) {
+				node->nodetype = en_tempref;
+				node->v.i = csp->reg;
+			}
+		}
+		break;
+	  case en_ref:
+	  case en_fieldref:
+		if ((csp = searchnode(node)) != 0) {
+			if (csp->reg > 0) {
+				node->nodetype = en_tempref;
+				node->v.i = csp->reg;
+			} else
+				repexpr(node->v.p[0]);
+		} else
+			repexpr(node->v.p[0]);
+		break;
+	  case en_uminus:
+	  case en_not:
+	  case en_compl:
+	  case en_ainc:
+	  case en_adec:
+	  case en_cast:
+	  case en_deref:
+	  case en_alloca:
+		repexpr(node->v.p[0]);
+		break;
+	  case en_add:
+		if (node->v.p[0]->nodetype==en_autocon && node->v.p[1]->nodetype==en_icon) {
+			/**ep=mk_icon(node->v.p[0]->v.i+node->v.p[1]->v.i);
+			(*ep)->nodetype=en_autocon;
+			(*ep)->etype=bt_pointer;
+			(*ep)->esize=4;*/
+			node->v.p[0]->v.i+=node->v.p[1]->v.i;
+			*ep=node->v.p[0];
+			return;
+		}
+		/*@fallthrough@*/
+	  case en_sub:
+	  case en_mul:
+	  case en_div:
+	  case en_mod:
+	  case en_lsh:
+	  case en_rsh:
+	  case en_and:
+	  case en_or:
+	  case en_xor:
+	  case en_land:
+	  case en_lor:
+	  case en_eq:
+	  case en_ne:
+	  case en_lt:
+	  case en_le:
+	  case en_gt:
+	  case en_ge:
+	  case en_cond:
+	  case en_void:
+	  case en_asadd:
+	  case en_assub:
+	  case en_asmul:
+	  case en_asdiv:
+	  case en_asor:
+	  case en_asxor:
+	  case en_asand:
+	  case en_asmod:
+	  case en_aslsh:
+	  case en_asrsh:
+	  case en_fcall:
+	  case en_assign:
+		repexpr(node->v.p[0]);
+		repexpr(node->v.p[1]);
+		break;
+	  case en_compound:
+		repcse(node->v.st);
+		break;
+	}
+}
+
+void repcse(struct snode *block) {
+/*
+ * repcse will scan through a block of statements replacing the optimized
+ * expressions with their temporary references.
+ */
+	while (block != 0) {
+		switch (block->stype) {
+		  case st_return:
+		  case st_expr:
+			repexpr(block->exp);
+			break;
+		  case st_loop:
+			repexpr(block->exp);
+			repcse(block->s1);
+			repexpr(block->v2.e);
+			break;
+		  case st_while:
+		  case st_do:
+			repexpr(block->exp);
+			repcse(block->s1);
+			break;
+		  case st_for:
+			repexpr(block->exp);
+			repexpr(block->v1.e);
+			repcse(block->s1);
+			repexpr(block->v2.e);
+			break;
+		  case st_if:
+			repexpr(block->exp);
+			repcse(block->s1);
+			repcse(block->v1.s);
+			break;
+		  case st_switch:
+			repexpr(block->exp);
+			repcse(block->v1.s);
+			break;
+		  case st_case:
+		  case st_default:
+			repcse(block->v1.s);
+			break;
+		  case st_compound:
+		  case st_label:
+			repcse(block->s1);
+			break;
+		}
+		block = block->next;
+	}
+}
+
+void opt1(struct snode *block) {
+/*
+ * opt1 is the externally callable optimization routine. it will collect and
+ * allocate common subexpressions and substitute the tempref for all
+ * occurrances of the expression within the block.
+ *
+ */
+	if (!opt_option)
+		return;
+	olist = 0;
+	exec_count = INIT_EXEC_COUNT;
+	scan(block);				/* collect expressions */
+	allocate(); 				/* allocate registers */
+	repcse(block);				/* replace allocated expressions */
+}
+// vim:ts=4:sw=4

+ 102 - 0
gtc/src/bin2calc.c

@@ -0,0 +1,102 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * binary to TI calculator format conversion
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "define.h"
+#include "gtpack/gtpack.c"
+
+// This structure comes from ttools.
+typedef struct {
+    char          signature[8]; // "**TI92P*" or "**TI89**"
+    unsigned char fill1[2];     // 01 00
+    char          folder[8];    // folder name
+    char          desc[40];     // ---- not used ----
+    unsigned char fill2[6];     // 01 00 52 00 00 00
+    char          name[8];      // varname
+    unsigned char type[4];      // 0C 00 00 00
+    unsigned char size[4];      // complete file size (including checksum)
+    unsigned char fill3[6];     // A5 5A 00 00 00 00
+    unsigned char datasize[2];  // data size
+} TI_FILE_HDR;
+
+
+static void put_little_endian(unsigned char *dest, unsigned long val, int len) {
+    while (len--) {
+	*dest++ = (unsigned char)(val&0xFF);
+	val >>= 8;
+    }
+}
+static void put_big_endian(unsigned char *dest, unsigned long val, int len) {
+    dest += len;
+    while (len--) {
+	*--dest = (unsigned char)(val&0xFF);
+	val >>= 8;
+    }
+}
+
+char *create_ti_file(int calc,int tigl_type,char *name,char *folder,char *content,unsigned long content_size,unsigned long *ti_file_size) {
+    TI_FILE_HDR h;
+    memset(&h, 0, sizeof h);
+    memcpy(h.signature, "********", 8);
+#define sig(x) memcpy(h.signature+2,x,sizeof(x)-1)
+    switch (calc) {
+	case 0:
+	    sig("TI89");
+	    break;
+	case 1:
+	    sig("TI92P");
+	    break;
+	case 2:
+	    sig("TI92P");
+	    break;
+	default:
+	    fatal("unknown calc type");
+    }
+#undef sig
+    h.fill1[0] = 1;
+    strncpy(h.folder, folder?folder:"main", 8);
+    h.fill2[0] = 1; h.fill2[2] = 0x52;
+    strncpy(h.name, name, 8);
+    h.type[0] = tigl_type; h.type[2] = 3;
+    h.fill3[0] = 0xA5; h.fill3[1] = 0x5A;
+    {
+	unsigned long oncalc_size = 88+content_size+2;
+	put_little_endian(h.size, oncalc_size, 4);
+    }
+    put_big_endian(h.datasize, content_size, 2);
+
+    if (content_size>=65520)
+	fatal("TIOS variables can't be more than 65520 bytes long.");
+
+    {
+	char *ret = malloc(sizeof(h)+content_size+2);
+	if (!ret)
+	    fatal("Memory");
+	if (ti_file_size)
+	    *ti_file_size = sizeof(h)+content_size+2;
+	memcpy(ret, &h, sizeof(h));
+	memcpy(ret+sizeof(h), content, content_size);
+	{
+	    unsigned int crc = h.datasize[0]+h.datasize[1];
+	    unsigned long n = content_size;
+	    while (n--)
+		crc += 0xff & (unsigned char)*content++;
+	    put_little_endian(ret+sizeof(h)+content_size, crc, 2);
+	}
+	return ret;
+    }
+}

+ 548 - 0
gtc/src/c.h

@@ -0,0 +1,548 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * C
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef C_H
+#define C_H
+#ifdef PC
+	#ifdef SHORT_INT
+	#undef int
+	#endif
+	#include <stddef.h>
+	//#include <times.h>
+	#include <stdio.h>
+	#ifdef SHORT_INT
+	#define int short
+	#endif
+#else
+	#include "define.h"
+#endif
+//#warning hey hey!
+#include "error.h"
+
+#ifdef CPU_DEFINED
+#undef CPU_DEFINED
+#endif
+
+#ifdef MC68000
+#define MC680X0
+#ifdef CPU_DEFINED
+error, define only one target CPU!
+#endif
+#define CPU_DEFINED
+#define LIST_NAME  "gtclist.txt"
+#define ICODE_NAME "gtcicode.txt"
+#endif
+
+#ifdef MC68010
+#define MC680X0
+#ifdef CPU_DEFINED
+error, define only one target CPU!
+#endif
+#define CPU_DEFINED
+#define LIST_NAME  "gtclist.txt"
+#define ICODE_NAME "gtcicode.txt"
+#endif
+
+#ifdef MC68020
+#define MC680X0
+#ifdef CPU_DEFINED
+error, define only one target CPU!
+#endif
+#define CPU_DEFINED
+#define LIST_NAME  "gtclist.txt"
+#define ICODE_NAME "gtcicode.txt"
+#endif
+
+#ifdef MC68030
+#define MC680X0
+#ifdef CPU_DEFINED
+error, define only one target CPU!
+#endif
+#define CPU_DEFINED
+#define LIST_NAME  "gtclist.txt"
+#define ICODE_NAME "gtcicode.txt"
+#endif
+
+#ifdef MC68040
+#define MC680X0
+#ifdef CPU_DEFINED
+error, define only one target CPU!
+#endif
+#define CPU_DEFINED
+#define LIST_NAME  "gtclist.txt"
+#define ICODE_NAME "gtcicode.txt"
+#endif
+
+#ifdef	INTEL_486
+#ifndef INTEL_386
+#define INTEL_386
+#endif
+#endif
+
+#ifdef INTEL_386
+#ifdef CPU_DEFINED
+#error define only one target CPU!
+#endif
+#define CPU_DEFINED
+#define LIST_NAME  "c386.list"
+#define ICODE_NAME "c386.icode"
+/*
+ * if FUNCS_USE_387 is defined, extra library calls are generated if the
+ * nofpu option is in effect that allows to use code generated by
+ * this compiler to be linked with functions that return values
+ * on the 387 stack
+ */
+#define FUNCS_USE_387
+#endif
+
+#ifndef CPU_DEFINED
+#error target CPU type must be defined
+#endif
+
+/* the tokens returned from lexical analysis */
+
+/* assumptions about the order :
+ *  none currently (beware of is_lang_ext though) */
+enum e_sym {
+	// 0x00
+	cconst, iconst, lconst, uconst, ulconst, sconst, rconst, plus, minus,
+	// 0x09
+	divide, lshift, rshift, modop, eq, neq, lt, leq, gt,
+	// 0x12
+	geq, assign, asplus, asminus, astimes, asdivide, asmodop,
+	asuparrow,
+	// 0x1A
+	aslshift, asrshift, asand, asor, autoinc, autodec, hook, compl,
+	// 0x22
+	comma, colon, semicolon, uparrow, openbr, closebr, begin, end,
+	// 0x2A
+	closepa, pointsto, dot, lor, land, not, or, and,
+	// 0x32
+	star, openpa, id, kw_int, kw_char, kw_short, kw_long,
+	kw_void, kw_float, kw_double, kw_struct, kw_union,
+	kw_enum, kw_unsigned, kw_signed, kw_auto, kw_extern,
+	kw_const, kw_volatile,
+	// 0x45
+	kw_register, kw_typedef, kw_static, kw_goto, kw_return,
+	kw_sizeof, kw_break, kw_continue, kw_if, kw_else, kw_for,
+	kw_do, kw_while, kw_switch, kw_case, kw_default,
+	// 0x55
+	eof,
+	// ANSI extensions
+	kw_typeof, dots, kw_alloca,
+	// GTC extensions
+	kw_loop, kw_until, kw_count, kw_eval,	// (lang extensions)
+	kw_defined, kw_incbin, kw_softcast, kw_c,
+	// GNU C extensions
+	kw_asm, kwb_constant_p, kw_attr,
+	// ASM keywords
+	kw_dreg, kw_areg, sharp,
+#ifdef OLD_AMODE_INPUT
+	kw_offs_end,
+#endif
+	kw_instr,
+};
+#define is_lang_ext(__st) (__st>=kw_loop && __st<=kw_eval)
+
+/* storage classes */
+
+enum e_sc {
+	sc_static, sc_auto, sc_global, sc_external, sc_type, sc_const,
+	sc_member, sc_label, sc_ulabel, sc_typedef, sc_parms, sc_parms2,
+	sc_define, sc_vamac
+};
+
+/* basic data types */
+
+#ifndef BCDFLT
+#define bt_size(__x) ((__x)<bt_long?((__x)<bt_short?1:2):4)
+#define float_size 4
+#else
+#ifdef DOUBLE
+#define bt_size(__x) ((__x)<bt_long?((__x)<bt_short?1:2):((__x)==bt_double?10:4))
+#define float_size !!! CAUTION, VARIES BETWEEN DOUBLE AND FLOAT !!!
+#else
+#define bt_size(__x) ((__x)<bt_long?((__x)<bt_short?1:2):((__x)==bt_float?10:4))
+#define float_size 10
+#endif
+#endif
+#define bt_uns(__x) ((__x)&1)
+#define bt_integral(__x) ((__x)<=bt_ulong)
+#ifndef DOUBLE
+#define bt_bcd bt_float
+#define bt_double bt_float
+#define tp_double tp_float
+#define bt_scalar(__x) ((__x)<=bt_double)
+#else
+#define bt_bcd bt_double
+#endif
+#ifdef NOBCDFLT
+#undef bt_bcd
+#endif
+#define bt_comparable(__x) ((__x)<=bt_pointer)
+#ifndef NOBCDFLT
+#define bt_aggregate(__x) ((__x)==bt_bcd || (__x)>=bt_struct)
+#else
+#define bt_aggregate(__x) ((__x)>=bt_struct)
+#endif
+#define bt_uncastable(__x) ((__x)>=bt_struct)
+#define iscomparable(tp) bt_comparable((tp)->type)
+#define isscalar(tp) bt_scalar((tp)->type)
+#define integral(tp) bt_integral((tp)->type)
+#define isaggregate(tp) bt_aggregate((tp)->type)
+enum e_bt {
+	bt_char, bt_uchar, bt_short, bt_ushort,
+	bt_long, bt_ulong, bt_float,
+#ifdef DOUBLE
+	bt_double,
+#endif
+	bt_pointer,
+	bt_func,
+	bt_void, bt_bitfield,
+	bt_struct, bt_union,
+};
+
+/* these form the string literal pool */
+
+struct slit {
+	struct slit    *next;
+	char		   *str;
+	short			label;
+	short			len;
+};
+
+/* a symbol table */
+struct stab {
+	int				hash;
+	struct sym	   *head;
+	struct sym	   *tail;
+};
+/* important points for reconsidering N_HASH value :
+  - a HTABLE is about 8*N_HASH -byte long
+  - each imbricated 'compound()' call takes the space of 2 HTABLEs on the stack
+   (512 bytes with N_HASH=32, thus allowing only 20 imbricated compound stmts)
+  - there are 6 static HTABLEs, 7 if AS is defined (but could be improved with malloc() / BSS)
+  - N_HASH = 1 << HASH_LOG */
+#define N_HASH 32
+#define N_HASH_AND "31"
+#define HASH_LOG 5
+typedef struct hstab {
+	int				hash;
+	struct htab {
+		struct sym	   *head;
+		struct sym	   *tail;
+	}				h[N_HASH];
+} HTABLE;
+
+/* structure defining a data type */
+
+struct typ {
+	struct stab 	lst;
+	struct typ	   *btp;
+#ifdef LISTING
+	char		   *sname;
+#endif
+	long			size;
+	enum(e_bt)		type;
+/*
+ * The following six chars may be unsigned -- no harm.
+ * They could be ints without restriction -- this is to save memory
+ */
+	/*
+	 * val_flag is normally 0, except for:
+	 * - type==bt_pointer: set to 1 if it's an array, to 0 if it's a pointer
+	 * - type==bt_func: always set to 1
+	 *   (passing a function is like passing an array, we should actually be passing a pointer;
+	 *   and like an array, we do not want cond_deref() to build an en_ref node)
+	 * - type==bt_integral: set to 1 to indicate an enum (this feature is currently unused)
+	 */
+	char			val_flag;
+
+	char			st_flag;	// is the type already stored globally?
+	char			const_flag;	// is it a 'const' type?
+	char			vol_flag;	// is it a 'volatile' type?
+	char			bit_width;
+	char			bit_offset;
+};
+#ifdef REGPARM
+#define rp_dn bit_width
+#define rp_an bit_offset
+#endif
+
+/* a symbol table entry */
+
+struct sym {
+	char		   *name;
+	struct sym	   *prev;
+	struct sym	   *next;
+	struct typ	   *tp;
+	union {
+		long			i;
+		unsigned long	u;
+		int				splab;
+		char		   *s;
+	}				value;
+	enum(e_sc)		storage_class;
+	int 			used;	// note:
+							// - for 'normal' symbols (C variables), this belongs to {-1,0,1}
+							// - for preprocessor symbols, the lower 8 bits is the number of arguments to the macro
+							//   and the higher 8 bits are described in enum(e_ppsymflags) below
+};
+enum e_ppsymflags {
+	PPSYM_UNDER_EXPANSION = 0x8000,	// set if we are currently expanding this symbol (avoid recursive expansion)
+#ifdef ASM
+	PPSYM_ASM_KEYWORD = 0x4000,		// set if this an ASM reserved keyword ('move', 'b', 'w', 'l', 'd7', 'sp')
+	PPSYM_DEFINED_IN_ASM = 0x2000,	// set if this symbol was defined inside an asm{} statement
+#endif
+};
+
+#define SYM 	struct sym
+#define TYP 	struct typ
+#define TABLE	struct stab
+
+#ifdef PC
+#define MAX_ERROR_COUNT 1
+#else
+#define MAX_ERROR_COUNT 1
+#endif
+#define MAX_STRLEN		1500
+#define MAX_ID_LEN		50
+#ifdef OLD_MACRO
+#define MAX_MAC_LEN 	800
+#define LINE_LENGTH (1800+MAX_MAC_LEN+1)
+#else
+#define LINE_LENGTH (1800+1)
+#endif
+#define MAX_PARAMS		20
+#define REG_LIST		20
+#define AUTO_LIST		100
+
+#define ERR_SYNTAX		0		/* general error */
+#define ERR_ILLCHAR 	1		/* illegal character */
+#define ERR_FPCON		2		/* illegal floating-point constant */
+#define ERR_ILLTYPE 	3		/* illegal type */
+#define ERR_UNDEFINED	4		/* undefined identifier */
+#define ERR_FIELD		5		/* no field allowed here */
+#define ERR_PUNCT		6		/* expected symbol not found */
+#define ERR_IDEXPECT	7		/* identifier expected */
+#define ERR_NOINIT		8		/* initialization invalid */
+#define ERR_INCOMPLETE	9		/* incomplete struct/union/enum declaration */
+#define ERR_ILLINIT 	10		/* illegal initialization */
+#define ERR_INITSIZE	11		/* too many initializers */
+#define ERR_ILLCLASS	12		/* illegal storage class */
+#define ERR_BLOCK		13		/* function body expected */
+#define ERR_NOPOINTER	14		/* pointer type expected */
+#define ERR_NOFUNC		15		/* function type expected */
+#define ERR_NOMEMBER	16		/* struct/union member expected */
+#define ERR_LVALUE		17		/* l-value required */
+#define ERR_DEREF		18		/* error dereferencing a pointer */
+#define ERR_MISMATCH	19		/* type mismatch error */
+#define ERR_EXPREXPECT	20		/* expression expected */
+#define ERR_WHILEXPECT	21		/* 'while' expected in do-loop */
+#define ERR_ENUMVAL 	22		/* enum value out of range */
+#define ERR_DUPCASE 	23		/* duplicate case label */
+#define ERR_LABEL		24		/* undefined label */
+//#define ERR_PREPROC 	25		/* preprocessing error */
+#define ERR_ARG 		26		/* declared Argument missing */
+#define ERR_WIDTH		27		/* illegal field width */
+#define ERR_INTEXPR 	28		/* illegal constant integer expression */
+#define ERR_CAST		29		/* error doing a cast */
+#define ERR_INTEGER 	30		/* integer-valued type expected */
+#define ERR_CASTCON 	31		/* error casting a constant */
+#define ERR_REDECL		32		/* illegal redeclaration */
+//#define ERR_PARMS		33		/* error while scanning a parameter list */
+#define ERR_FTYPE		34		/* bad host type for bit fields */
+#define ERR_INCLFILE	35		/* #include: no include file specified */
+#define ERR_CANTOPEN	36		/* can't open include file */
+#define ERR_DEFINE		37		/* wrong #define */
+#define ERR_CUSTOM		38		/* #error */
+#define ERR_DUPSYM	 	39		/* duplicate symbol */
+#define ERR_CONSTEXPECT	40		/* constant expression expected */
+#define ERR_OUTRANGE 	41		/* value out of range */
+#define ERR_TOOMPARAMS	42		/* too many parameters to function */
+#define ERR_TOOFPARAMS	43		/* too few parameters to function */
+#define ERR_CASERANGE 	44		/* invalid case range */
+#define ERR_UNEXPECTEOF	45		/* unexpected end of file */
+#define ERR_OTH			46		/* (custom error) */
+#define ERR_SYS			47		/* (system limitation) */
+#define ERRA_INVALIDREL 48		/* invalid relocation in expression */
+
+/* alignment sizes */
+
+#ifdef MC68000
+/*
+ * MC68000 is a 16-bit processor. Word alignment is OK in all cases
+ */
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		2
+#define AL_POINTER		2
+#define AL_FLOAT		2
+#define AL_DOUBLE		2
+#define AL_STRUCT		2
+#define AL_FUNC 		2
+
+#define AL_DEFAULT		2		/* alignment suitable for all types */
+#endif /* MC68000 */
+
+#ifdef MC68010
+/*
+ * MC68010 is a 16-bit processor. Word alignment is OK in all cases
+ */
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		2
+#define AL_POINTER		2
+#define AL_FLOAT		2
+#define AL_DOUBLE		2
+#define AL_STRUCT		2
+#define AL_FUNC 		2
+
+#define AL_DEFAULT		2		/* alignment suitable for all types */
+#endif /* MC68010 */
+
+#ifdef MC68020
+/*
+ * perhaps not necessary, but useful: 32-bit alignment for 32-bit types
+ */
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		4
+#define AL_POINTER		4
+#define AL_FLOAT		4
+#define AL_DOUBLE		4
+#define AL_STRUCT		4
+#define AL_FUNC 		4
+
+#define AL_DEFAULT		4		/* alignment suitable for all types */
+#endif /* MC68020 */
+
+#ifdef MC68030
+/*
+ * perhaps not necessary, but useful: 32-bit alignment for 32-bit types
+ */
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		4
+#define AL_POINTER		4
+#define AL_FLOAT		4
+#define AL_DOUBLE		4
+#define AL_STRUCT		4
+#define AL_FUNC 		4
+
+#define AL_DEFAULT		4		/* alignment suitable for all types */
+#endif /* MC68030 */
+
+#ifdef MC68040
+/*
+ * perhaps not necessary, but useful: 32-bit alignment for 32-bit types
+ */
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		4
+#define AL_POINTER		4
+#define AL_FLOAT		4
+#define AL_DOUBLE		4
+#define AL_STRUCT		4
+#define AL_FUNC 		4
+
+#define AL_DEFAULT		4		/* alignment suitable for all types */
+#endif /* MC68040 */
+
+#ifdef INTEL_386
+/*
+ * perhaps not necessary, but useful: 32-bit alignment for 32-bit types
+ */
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		4
+#define AL_POINTER		4
+#define AL_FLOAT		4
+#define AL_DOUBLE		4
+#define AL_STRUCT		4
+#define AL_FUNC 		4
+
+#define AL_DEFAULT		4		/* alignment suitable for all types */
+#endif /* INTEL_386 */
+
+
+#ifdef SPARC
+#define AL_CHAR 		1
+#define AL_SHORT		2
+#define AL_LONG 		4
+#define AL_POINTER		4
+#define AL_FLOAT		4
+#define AL_DOUBLE		8
+#define AL_STRUCT		8
+#define AL_FUNC 		4
+
+#define AL_DEFAULT		8		/* alignment suitable for all types */
+#endif /* SPARC */
+
+
+int 		   *_xalloc(int);
+struct sym	   *search();
+struct sym	   *gsearch();
+char		   *strsave();
+TYP 		   *expression();
+TYP 		   *exprnc();
+TYP 		   *cast_op();
+TYP 		   *mk_type();
+long			intexpr();
+int 			getch();
+//void			error();
+void			getsym();
+void			needpunc();
+void			initsym();
+void			append();
+long			strip_icon();
+long			push_param();
+void			do_warning(char *,...);
+
+struct sym *symremove();
+void getidstr();
+void skipspace();
+void msg(char *s);
+
+void rel_local();
+void rel_global();
+void clean_up();
+
+void out_init();
+void out_close();
+void do_compile();
+void initpch();
+void closepch();
+
+void insert(SYM *sp,HTABLE *table);
+
+#ifdef DUAL_STACK
+extern void *dualstack;
+extern void *ds_currentlo,*ds_currenthi;
+void ds_allocatleast(unsigned int size);
+void ds_free(void);
+#define ds_remaining (unsigned int)((char *)ds_currenthi-(char *)dualstack)
+#define ds_ensure(size) ((ds_remaining>=(size) ? 0 : ds_allocatleast(size),0), dualstack)
+#define ds_pop(target) (void)((target)!=ds_currentlo ? (dualstack = (target)) : ds_free(),0)
+#ifdef PC
+#define ds_update(ptr) (void)(dualstack=(ptr),dualstack+=(-(size_t)dualstack)&3,0)
+#else
+#define ds_update(ptr) (void)(dualstack=(ptr),1&(short)(long)dualstack ? ++dualstack,0 : 0,0)
+#endif
+#define ds_var(type) (type)dualstack
+#define DS_BSIZE 6000 // we set aside 6 kb for each stack block
+#endif
+#endif
+// vim:ts=4:sw=4

+ 303 - 0
gtc/src/cglbdec.h

@@ -0,0 +1,303 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * C global declarations
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef CGLBDEC_H
+#define CGLBDEC_H
+#ifdef PC
+#define outstr stderr
+#define msg(s) fprintf(outstr,s)
+#define msg2(s,a) fprintf(outstr,s,a)
+#define msg3(s,a,b) fprintf(outstr,s,a,b)
+#define msg4(s,a,b,c) fprintf(outstr,s,a,b,c)
+#define msg5(s,a,b,c,d) fprintf(outstr,s,a,b,c,d)
+#define msg6(s,a,b,c,d,e) fprintf(outstr,s,a,b,c,d,e)
+#define vmsg(s,va) vfprintf(outstr,s,va)
+#else
+#define msg printf
+#define msg2(s,a) printf(s,a)
+#define msg3(s,a,b) printf(s,a,b)
+#define msg4(s,a,b,c) printf(s,a,b,c)
+#define msg5(s,a,b,c,d) printf(s,a,b,c,d)
+#define msg6(s,a,b,c,d,e) printf(s,a,b,c,d,e)
+#undef vcbprintf
+#define vcbprintf ({register long __a=32+*(long*)(*(long*)0xC8+0x14C); \
+  (void(*)(void(*)(char,void**),void**,char*,void*))(__a+*(short*)__a);})
+#define vmsg(s,va) vcbprintf((void(*)(char,void**))fputchar,NULL,s,va)
+#endif
+
+#define int_bits 16
+#define tp_int tp_short
+#define tp_uint tp_ushort
+#define fpu_option 0
+#define short_option 1
+#ifdef LISTING
+#define list_option 1
+#else
+#define list_option 0
+#endif
+#define reg_option 1
+#define opt_option 1
+#define warn_option 1
+#define trans_option 0
+#ifdef ICODE
+#define icode_option 1
+#else
+#define icode_option 0
+#endif
+enum e_xt {
+	X_MID_DECL=0x1, X_COMP_STRING=0x2, X_LANG_EXT=0x4,
+};
+#define flags_fullgtc -1 /* all flags, even those that break compatibility */
+#define flags_basegtc (X_MID_DECL|X_COMP_STRING) /* all flags, except those that break compatibility */
+#define flags_cplusplus X_MID_DECL
+#define flags_ansi 0
+extern int		flags;
+#ifdef SPEED_OPT
+extern int		speed_opt_value;
+extern int		default_speed_opt_value;
+#endif
+extern int		verbose;
+#ifdef PC
+enum {
+	VERBOSITY_PRINT_SEARCH_DIRS=0x1,
+	VERBOSITY_PRINT_INCLUDES=0x2,
+};
+extern int		verbosity;
+#endif
+
+extern FILE    *input, *list, *output;
+extern char *outputname,*calcname;
+extern char proj_file[];
+extern char export_pfx[]; extern short_size export_pfx_len;
+#ifdef ICODE
+extern FILE    *icode;
+#endif
+extern int		nextlabel;
+extern int		lastch;
+extern enum(e_sym) lastst;
+#ifdef PC
+extern enum(e_sym) cached_sym;
+#else
+extern enum(e_sym) _cached_sym;
+#endif
+extern int		cached_flag;
+extern char 	lastid[MAX_ID_LEN+1];
+extern int		lastcrc;
+extern int		lastreg;
+extern struct sym *lastsp;
+extern char 	laststr[MAX_STRLEN + 1];
+extern int		lstrlen;
+extern unsigned long ival;
+#ifndef NOFLOAT
+extern double	rval;
+#endif
+
+extern HTABLE	gsyms, lsyms, labsyms, gtags, ltags;
+
+extern struct slit *strtab;
+extern struct slit *datatab;
+extern XLST_TYPE 	lc_auto;
+extern XLST_TYPE 	reg_size;
+extern XLST_TYPE 	max_scratch;
+extern XLST_TYPE 	act_scratch;
+extern long 	lc_bss; 		/* local bss counter */
+extern int		global_flag;
+extern int		global_strings;
+extern int		temp_mem,temp_local,min_temp_mem;
+extern int		asm_flag,asm_xflag,asm_zflag;
+extern int		nostub_mode;
+extern int		exestub_mode;
+#ifdef MC680X0
+extern unsigned int save_mask;		/* register save mask */
+#endif
+extern char    *declid;
+extern int		nparms;
+extern int		store_lst;
+extern int		pch_init;
+extern int		middle_decl;
+extern char    *names[MAX_PARAMS];
+extern int		bit_offset; 	/* the actual offset */
+extern int		bit_width;		/* the actual width */
+extern int		bit_next;		/* offset for next variable */
+extern int		decl1_level;
+
+#ifdef ASM
+extern struct ocode *asm_head;
+#endif
+#ifdef AS
+extern struct ocode *scope_head;
+#else
+#ifdef ASM
+extern struct ocode *peep_head;
+#endif
+#endif
+
+#ifdef FLINE_RC
+extern int fline_rc;
+#endif
+
+//extern int	  list_option;
+//extern int	  short_option;
+//extern int		opt_option;
+//extern int	  trans_option;
+//extern int		warn_option;
+//extern int	fpu_option;
+//extern int	reg_option;
+//#ifdef ICODE
+//extern int		icode_option;
+//#endif
+extern TYP	   *ret_type;
+
+extern int		regptr;
+extern XLST_TYPE reglst[REG_LIST];
+extern int		autoptr;
+extern XLST_TYPE autolst[AUTO_LIST];
+
+extern struct enode *init_node;
+#ifdef MID_DECL_IN_EXPR
+extern struct enode *md_expr;
+extern struct typ	*md_type;
+#endif
+
+#ifdef VERBOSE
+extern struct tms tms_buf;
+extern long 	decl_time, parse_time, opt_time, gen_time, flush_time;
+#endif							/* VERBOSE */
+
+extern readonly TYP		tp_void, tp_long, tp_ulong, tp_char, tp_uchar;
+extern readonly TYP		tp_short, tp_ushort, tp_float;
+extern readonly TYP		tp_econst, tp_string, tp_void_ptr, tp_int, tp_uint, tp_func;
+extern readonly TYP		tp_double;
+
+//extern int	  int_bits;
+
+#ifdef MC680X0
+extern readonly struct amode push, pop;
+#define push_am (struct amode *)&push
+#define pop_am (struct amode *)&pop
+#endif
+/*extern int uses_structassign;*/
+extern int regs_used;
+extern int pushed;
+extern int is_leaf_function, uses_link;
+#ifdef INTEL_386
+extern int edi_used, esi_used, ebx_used;
+#endif
+
+extern int		lineno,lineid,lastch;
+extern int		prevlineid,cached_lineid;
+
+extern int err_force_line,err_cur_line,err_assembly;
+
+#ifdef DECLARE
+extern TYP	   *head, *tail;
+
+extern int		total_errors;
+
+/*extern FILE	  *input,
+				*list,
+				*output,
+				*bin;*/
+
+//extern long	  ival;
+extern double	rval;
+
+extern SYM			   *lasthead;
+extern struct slit	   *strtab;
+extern struct slit	   *datatab;
+extern int			   lc_static;
+//extern int			 lc_auto;
+extern struct snode    *bodyptr;
+extern int			   global_flag;
+//extern int			 save_mask; 		 /* register save mask */
+extern SYM				*func_sp;
+
+extern TYP *lastexpr_tp;
+extern int lastexpr_size, lastexpr_type;
+#endif
+extern struct amode *lastexpr_am;
+extern int	need_res;
+
+extern SYM *func_sp;
+
+#ifdef TWIN_COMPILE
+extern int twinc_necessary;
+extern int *twinc_info,*twinc_prev;
+#endif
+
+SYM *search(char *na, int crc, HTABLE *tab);
+void dodecl(enum(e_sc) defclass);
+int eq_type(TYP *tp1, TYP *tp2);
+
+#ifndef integral
+int integral(TYP *tp);
+#endif
+int isshort(struct enode *node);
+int isbyte(struct enode *node);
+
+int radix36(char c);
+
+int equal_address();
+
+int crcN(char *na);
+
+#ifdef ASM
+void asm_getsym();
+#endif
+
+extern HTABLE defsyms;
+
+#define MAX_IF_DEPTH 50
+extern int ifdepth,ifreldepth,ifskip,ifsd;
+extern int ifcount[MAX_IF_DEPTH];
+extern int ifval[MAX_IF_DEPTH];
+#endif
+
+#ifndef PCHS_MODES
+#define PCHS_MODES
+enum { PCHS_ADD=1, PCHS_UNLOAD=-1 };
+#endif
+
+#ifdef USE_MEMMGT
+/*
+ * Memory is allocated in blocks of 4 kb, which form a linked list
+ */
+
+#define BLKLEN 4096
+
+#ifndef BLK_STRUCT
+#define BLK_STRUCT
+struct blk {
+	char			m[BLKLEN];	/* memory area */
+	struct blk	   *next;
+};
+#endif
+
+#define NIL_BLK ((struct blk *)0)
+
+extern int		glbsize,	/* size left in current global block */
+				locsize,	/* size left in current local block */
+				glbindx,	/* global index */
+				locindx;	/* local index */
+
+extern int		glbmem,locmem;
+
+extern struct blk *locblk,	/* pointer to local block list */
+				*glbblk;		/* pointer to global block list */
+
+void tmp_use();
+void tmp_free();
+#endif
+// vim:ts=4:sw=4

+ 675 - 0
gtc/src/cmain.c

@@ -0,0 +1,675 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * main entry point
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define CMAIN_C
+#define DECLARE
+
+#ifdef PC
+#ifdef _WIN32
+#define DIR_SEPARATOR '\\'
+#define ENVPATH_SEPARATOR ';'
+#else
+#ifdef UNIXOID
+#define DIR_SEPARATOR '/'
+#define ENVPATH_SEPARATOR ':'
+#else
+#error Please define a directory and a $PATH separator for your platform.
+#endif
+#endif
+#endif
+
+#ifdef PC
+/*
+#define memcmp memcmp2
+#define strcmp stricmp
+//#define strlen strlen2
+#define abs abs2
+#define _rotl _rotl2
+#define _rotr _rotr2
+//#include	<signal.h>
+
+// --> what was this crap ???
+*/
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include <assert.h>
+#endif
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+extern char *curname;
+
+#ifdef SPEED_OPT
+int default_speed_opt_value CGLOB;
+#endif
+
+static void openfile();
+static void closefile();
+static void initialize_files();
+static void close_files();
+#ifdef LISTING
+static			summary();
+#endif
+
+#ifdef PC
+void fatal(char *s);
+#else
+void fatal(char *s) __attribute__ ((noreturn));
+#endif
+
+#ifdef PC
+#ifndef debug
+void debug(int c) {
+	fprintf(stderr,"debug step '%c'\n",c);
+}
+#endif
+#ifdef EXCEPTION_MGT
+static void exception(int sig) {
+	msg2("\n\nSIGNAL %d -- TERMINATING.\n", sig);
+	fatal("EXCEPTION");
+}
+#endif
+#define _exit __exit
+int pause_on_error=0;
+void _exit(int code) {
+	clean_up();
+	if (pause_on_error)
+		getchar();
+	exit(code);
+}
+#endif
+
+char export_pfx[20]; short_size export_pfx_len;
+
+#ifdef TWIN_COMPILE
+int twinc_necessary CGLOB;
+int *twinc_info CGLOB,*twinc_info0 CGLOB,*twinc_prev CGLOB,*twinc_prev0 CGLOB;
+#endif
+
+#ifdef PC
+	char *calcfolder=0;
+	static char _calcfolder[100];
+	char *outputname=0,*calcname=0;
+	static char _calcname[100];
+	
+	#include <ctype.h>
+	#include <time.h>
+	#if 0
+	void TempName(char *dest) {
+		int i;
+		srand(clock());
+		*dest++='~';
+		*dest++='g';
+		*dest++='t';
+		*dest++='c';
+		for (i=0;i<4;i++)
+			*dest++='0'+(rand()*10)/(RAND_MAX+1);
+		strcpy(dest,".tmp");
+	}
+	#endif
+
+	/* warning: duplicated in getsym.c! */
+	enum OptionModes { optn_parse=0, optn_global_init, optn_global_init_post, optn_preproc_init };
+	size_t option_parse(size_t listc,char **listv,enum(OptionModes) ex_mode);
+	void option_parse_all(enum(OptionModes) ex_mode);
+
+	char *incfolders[10] CGLOBL;
+	size_t incfoldernum CGLOB;
+
+	size_t optnc,optnmax; char **optnv;
+	size_t filec,filemax; char **filev;
+
+#define LST_INIT(lst,len) (lst##c=0, lst##max=(len), lst##v=alloca((len)*sizeof(*lst##v)))
+#define LST_ADD(lst,val) (lst##c>=lst##max?exit(EXIT_FAILURE):(void)0, lst##v[lst##c++]=(val))
+
+	void cmdline_parse(size_t argc, char **argv) {
+		size_t i;
+		int force_files = 0;
+		for (i=1; i<argc; ) {
+			size_t listc = argc-i, skip;
+			char **listv = &argv[i];
+			char *arg = listv[0];
+			if (!force_files && arg[0] == '-') {
+				if (!strcmp(arg,"--")) {
+					force_files = 1;
+					i++;
+				} else {
+					if ((skip = option_parse(listc,listv,optn_parse))) {
+						size_t j;
+						for (j=0; j<skip; j++)
+							LST_ADD(optn,listv[j]);
+						i+=j;
+					} else {
+						msg2("Invalid option '%s', ignoring option.\n", arg);
+						i++;
+					}
+				}
+			} else {
+				LST_ADD(file,arg);
+				i++;
+			}
+		}
+	}
+
+	void search_installdir(char *exe_name) {
+		char *gtcpath=alloca(strlen(exe_name)+40);
+		strcpy(gtcpath,exe_name);
+		if (strrchr(gtcpath,DIR_SEPARATOR)) strrchr(gtcpath,DIR_SEPARATOR)[1]=0;	// strip 'gtc.exe'
+		else {
+	#if 0
+			gtcpath="";	// 'gtc.exe' is in the current folder... (this assumption is OK under Win9x)
+	#else
+			// things don't stop here as WinXP sets argv[0] to be 'gtc.exe' if it is in the
+			// PATH environment variable... (and the same goes for Unixoids)
+			char *path=getenv("PATH");
+			while ((gtcpath="",path)) {
+				char *limit=strchr(path,ENVPATH_SEPARATOR),*base_limit=limit; char *buf;
+				FILE *fp;
+				if (!limit) limit=path+strlen(path);
+				if (path[0]=='"' && path[limit-path-1]=='"')
+					path++,limit--;
+				gtcpath=alloca(limit-path+2);
+				memcpy(gtcpath,path,(size_t)(limit-path)); gtcpath[limit-path]=DIR_SEPARATOR; gtcpath[limit-path+1]=0;
+				buf=alloca(strlen(gtcpath)+sizeof("gtc.exe"));
+				strcpy(buf,gtcpath);
+				strcat(buf,"gtc.exe");
+				if ((fp=fopen(buf,"rb"))) {
+					fclose(fp);
+					break;
+				}
+		#ifndef _WIN32
+				strcpy(buf,gtcpath);
+				strcat(buf,"gtc");
+				if ((fp=fopen(buf,"rb"))) {
+					fclose(fp);
+					break;
+				}
+		#endif
+				path = base_limit ? base_limit+1 : NULL;
+			}
+		}
+	#endif
+		{
+		char *incl_cmd=malloc(sizeof("-I")-1+strlen(gtcpath)+sizeof("include"));
+		assert(incl_cmd!=0);
+		strcpy(incl_cmd,"-I");
+		strcat(incl_cmd,gtcpath);
+		strcat(incl_cmd,"include");
+		LST_ADD(optn,incl_cmd);
+		}
+	}
+
+	int main(int _argc, char **argv) {
+		size_t argc = (size_t)_argc;
+		LST_INIT(optn,argc+10);
+		LST_INIT(file,argc+10);
+	#ifdef UNIXOID
+		pause_on_error=0;
+	#endif
+
+		// initialize optn* and file*
+		cmdline_parse(argc, argv);
+		search_installdir(argv[0]);
+	#ifdef INCL_PATH
+		LST_ADD(optn,"-I"INCL_PATH);
+	#endif
+
+		// now setup options
+		//	defaults
+		calcfolder=NULL; outputname=NULL; calcname=NULL;
+		tp_econst = tp_int;
+		tp_econst.val_flag=1;
+		//	user-defined options
+		option_parse_all(optn_global_init);
+		option_parse_all(optn_global_init_post);
+
+		if (verbosity&VERBOSITY_PRINT_SEARCH_DIRS)
+			verbose_print_searchdirs();
+
+	#ifdef TWIN_COMPILE
+		twinc_info0=0;
+		do {
+			twinc_prev0=twinc_prev=twinc_info0;
+			twinc_info=twinc_info0=malloc(100000);
+			twinc_necessary=0;
+	#endif
+			initialize_files();
+			out_init();
+/*			initsym();
+			getch();
+			getsym();
+			compile();*/
+			initpch();
+			{
+				size_t optnc_save = optnc; // for twin compilation
+				size_t i;
+				for (i=0; i<filec; i++) {
+					if (i==1)	// the current version of the library needs it :(
+						LST_ADD(optn,"-D__SECONDARY_FILE__");
+					openfile(i);
+					do_compile();
+					closefile();
+				}
+				optnc = optnc_save;
+			}
+			closepch();
+		#ifdef LISTING
+			if (list_option)
+				summary();
+			else
+				/* This emits all the global and external directives */
+				list_table(&gsyms, 0);
+		#endif
+		#ifdef VERBOSE
+			msg("\n -- %d errors found.\n", total_errors);
+		#endif
+			out_close();
+	//		rel_global();	in out_close()
+			close_files();
+	#ifdef TWIN_COMPILE
+			if (twinc_prev0) free(twinc_prev0);
+		} while (twinc_necessary);
+		free(twinc_info0);
+	#endif
+	#ifdef VERBOSE
+		decl_time -= parse_time;
+		parse_time -= gen_time + flush_time;
+		gen_time -= opt_time;
+		msg("Times: %6ld + %6ld + %6ld + %6ld + %6ld\n",
+				decl_time, parse_time, opt_time, gen_time, flush_time);
+	#endif
+		if (total_errors > 0)
+			_exit(1);
+		if (temp_mem)
+			printf("TEMP MEM LEAK\n"), temp_mem=0;
+		return 0;
+	}
+#else /* !defined(PC) */
+#ifdef OPTIMIZE_BSS
+	#define PRI_MAIN
+		void _zmain(void);
+		#include "identity.h"
+		int has_error CGLOB;
+	#ifndef GTDEV
+		void _main(void) {
+			bssdata=malloc(BSS_SIZE);
+			if (!bssdata) return;
+			memset(bssdata,0,BSS_SIZE);
+			has_error=1;
+			asm("movem.l d0-d7/a0-a4/a6,-(a7)");	/* do not include 'a5' :o */
+			_zmain();
+			asm("movem.l (a7)+,d0-d7/a0-a4/a6");
+			bssdata=identity(bssdata);	/* volatilize 'bssdata' =) */
+			if (bssdata) {	/* in case 'input' or 'output' couldn't be opened... */
+				if (bin) free(bin);
+				fclose(output);
+				fclose(input);
+				free(bssdata);
+			}
+		}
+	#else
+		void _main(void) {
+			ST_helpMsg("Please use the IDE to compile.");
+			ngetchx();
+		}
+	#endif
+	#ifdef GTDEV
+		void _gtdevmain(void) {
+			has_error=1;
+			asm("movem.l d0-d7/a0-a4/a6,-(a7)");	/* do not include 'a5' :o */
+			_zmain();
+			asm("movem.l (a7)+,d0-d7/a0-a4/a6");
+			bssdata=identity(bssdata);	/* volatilize 'bssdata' =) */
+			if (bssdata) {	/* in case 'input' or 'output' couldn't be opened... */
+				if (bin) free(bin);
+				fclose(output);
+				fclose(input);
+			}
+		}
+	#endif
+	void _zmain(void) {
+#else
+	void _main(void) {
+#endif
+		int n;
+	#ifndef GTDEV
+		clrscr();
+	#endif
+//		__HALT;
+/*		tp_econst = tp_int;
+		tp_econst.val_flag=1;*/
+	#ifndef PRI_MAIN
+	#ifdef OPTIMIZE_BSS
+		bssdata=malloc(BSS_SIZE);
+		if (!bssdata) return;
+		memset(bssdata,0,BSS_SIZE);
+	#endif
+	#endif
+
+	#ifndef GTDEV
+	#define in_file "in"
+	#ifdef AS
+	#define out_file "outbin"
+	#else
+	#define out_file "out"
+	#endif
+	#endif
+		if (!(input=fopen(in_file,"r"))) goto quit;
+	#ifdef AS
+		if (!(output=fopen(out_file,"wb"))) { fclose(input); quit: free(bssdata); bssdata=0; return; }
+	#else
+		if (!(output=fopen(out_file,"w"))) { fclose(input); quit: free(bssdata); bssdata=0; return; }
+	#endif
+
+		/*********************************************************
+		 * [!BUG-SOURCE!] THE FOLLOWING LINE IS FAIRLY GORE SO   *
+		 *  *ANY* MODIFICATION WHATSOEVER TO _MAIN (OR EVEN ANY  *
+		 *  COMPILER UPDATE...) MIGHT BREAK COMPATIBILITY!       *
+		 *                                                       */
+	#ifndef GTDEV
+		/**/  asm("lea 12(%sp),%a0\n	move.l %a0,exit_a7");  /**/
+	#else
+		/**/  asm("lea  4(%sp),%a0\n	move.l %a0,exit_a7");  /**/
+	#endif
+		/*                                                       *
+		 *********************************************************/
+		out_init();
+		initpch();
+		strcpy(export_pfx,strrchr(in_file,'\\')?:in_file);
+		strcat(export_pfx,"__"); export_pfx_len=strlen(export_pfx);
+		do_compile();
+		closepch();
+		debug('E');
+		out_close();
+		debug('Q');
+//		rel_global();	in out_close()
+		if (ferror(output)) fatal("Memory");
+	#ifndef PRI_MAIN
+		fclose(output);
+		fclose(input);
+	#endif
+	#ifndef GTDEV
+		if (temp_mem) printf("TEMP MEM LEAK\n"), temp_mem=0;
+	#endif
+/*		if (total_errors > 0) { printf("\nThere were errors."); while (!kbhit()); }
+		else*/ {
+	#ifdef PRI_MAIN
+			has_error=0;
+	#endif
+	#ifndef GTDEV
+			FILE *fp=fopen("gtcerr","wb");
+			if (fp) {
+				fputc(0,fp);
+				fputc(POSINT_TAG,fp);
+				fclose(fp);
+			}
+			printf("\nsuccess");
+			n=4000;
+			while (n-- && !kbhit());
+			if (kbhit()) ngetchx();
+	#endif
+		}
+	#ifndef PRI_MAIN
+	#ifdef OPTIMIZE_BSS
+		free(bssdata);
+	#endif
+	#endif
+	}
+#endif /* !defined(PC) */
+
+
+#ifdef PC
+int forbid_bss=0;
+
+char *fill_calcvar(char *buffer, char *input) {
+	int i=0;
+	while (*input) {
+		char c=tolower(*input++);
+		if (c=='-' || c==' ' || c=='.')
+			c='_';
+		if (isalnum(c) && i<8)
+			buffer[i++] = c;
+	}
+	buffer[i]=0;
+	if (!buffer[0])
+		fatal("bad calculator variable name");
+	return buffer;
+}
+
+// Takes as an input the list of remaining arguments, returning:
+// * 0: can't parse the option
+// * n>0: the option was parsed successfully, n = number of arguments
+//		to skip for this option
+size_t option_parse(size_t listc,char **listv,enum(OptionModes) ex_mode) {
+	char *s = listv[0];
+	size_t value = 1; // number of arguments read so far
+	char *next_chunk, *_next_chunk;
+	#define strscmp(s,t) (next_chunk=_next_chunk="", strcmp(s,t))
+	#define strbcmp(s,t) (next_chunk=_next_chunk=s+strlen(t), strncmp(s,t,strlen(t)))
+	// get_next_chunk is only necessary if you want to handle options split into several arguments
+	#define get_next_chunk() \
+			do { \
+				next_chunk = *_next_chunk ? _next_chunk : listc > value ? listv[value++] : NULL; \
+				if (!next_chunk) return 0; \
+			} while (0)
+
+	// PURELY SYNTACTIC TRANSFORMATIONS
+	if (!strscmp(s,"-exe"))
+		s = "-DEXE_OUT";
+
+	// STANDALONE OPTIONS (strscmp)
+	if (!strscmp(s,"-o")) {
+		get_next_chunk();
+		if (ex_mode==optn_global_init)
+			outputname = next_chunk;
+	} else if (!strscmp(s,"-v")) {
+#ifdef PC
+		verbose=1;
+#endif
+#ifdef PC
+	} else if (!strscmp(s,"-print-search-dirs")) {
+		verbosity|=VERBOSITY_PRINT_SEARCH_DIRS;
+	} else if (!strscmp(s,"-print-includes")) {
+		verbosity|=VERBOSITY_PRINT_INCLUDES;
+#endif
+	} else if (!strscmp(s,"-mno-bss")) {
+		if (ex_mode==optn_global_init)
+			forbid_bss=1;
+	} else if (!strcmp(s,"-O2")) {
+		default_speed_opt_value = 1;
+	} else if (!strcmp(s,"-O3")) {
+		default_speed_opt_value = 3;
+	} else if (!strcmp(s,"-Os")) {
+		default_speed_opt_value = -1;
+	// CHUNKED OPTIONS (strbcmp)
+	} else if (!strbcmp(s,"-I")) {
+		get_next_chunk();
+		if (ex_mode==optn_global_init)
+			if (incfoldernum<sizeof(incfolders)/sizeof(*incfolders))
+				incfolders[incfoldernum++] = next_chunk;
+	} else if (!strbcmp(s,"--std-include=")) {
+		get_next_chunk();
+		if (ex_mode==optn_global_init_post)
+			if (incfoldernum<sizeof(incfolders)/sizeof(*incfolders))
+				incfolders[incfoldernum++] = next_chunk;
+	} else if (!strbcmp(s,"-D")) {
+		if (ex_mode==optn_preproc_init) {
+			struct sym *sp = (SYM *)xalloc((int)sizeof(SYM), _SYM);
+			char *name = next_chunk;
+			char *name_end = strchr(name,'=');
+			if (!name_end)
+				name_end = name+strlen(name);
+			sp->name = (char *)xalloc(name_end-name+1, STR);
+			memcpy(sp->name, name, (size_t)(name_end-name));
+			sp->name[name_end-name] = 0;
+			sp->value.s = *name_end ? name_end+1 : "1";
+			insert(sp,&defsyms);
+		}
+	// LONG OPTIONS
+	} else if (!strbcmp(s,"--")) {
+		// STANDALONE OPTIONS (strscmp)
+		if (!strscmp(s,"--nobss")) {
+			if (ex_mode==optn_global_init)
+				forbid_bss=1;
+		// CHUNKED OPTIONS (strbcmp)
+		} else if (!strbcmp(s,"--folder=")) {
+			if (ex_mode==optn_global_init)
+				calcfolder = fill_calcvar(_calcfolder,next_chunk);
+		} else if (!strbcmp(s,"--output=")) {
+			if (ex_mode==optn_global_init)
+				calcname = fill_calcvar(_calcname,next_chunk);
+		// ERROR
+		} else
+			return 0;
+	// ERROR
+	} else
+		return 0;
+	return value;
+	#undef get_next_chunk
+	#undef strbcmp
+	#undef strscmp
+}
+void option_parse_all(enum(OptionModes) ex_mode) {
+	size_t i;
+	for (i=0; i<optnc; )
+		i += option_parse(optnc-i, &optnv[i], ex_mode);
+}
+
+static char _outputname[300];
+char proj_file[300];
+#ifdef PC
+char tempname[20];
+#endif
+static void openfile(size_t idx) {
+	if (!(input = fopen(curname=filev[idx], "r"))) {
+		msg2("can't open input file '%s'\n",curname);
+		_exit(2);
+	}
+}
+static void closefile() {
+	fclose(input);
+}
+// obtain the last part delimited by the character c
+// (e.g. "xxx/yyy/zzz" -> "zzz", and "zzz" -> "zzz")
+static char *strlast(char *s,char c) {
+	char *t = strrchr(s,c);
+	return t ? t+1 : s;
+}
+
+static void initialize_files() {
+	if (filec < 1) {
+		msg("no input file specified!\n");
+		_exit(2);
+	}
+
+	if (!outputname) {
+		outputname = _outputname;
+		strncpy(outputname,filev[0],sizeof(_outputname)-1);
+		outputname[sizeof(_outputname)-1]=0;
+		if (strrchr(outputname,'.'))
+			*strrchr(outputname,'.')=0;
+	}
+	strncpy(proj_file,outputname,sizeof(proj_file)-4-1);
+	proj_file[sizeof(proj_file)-4-1]=0;
+	strcat(proj_file,".gtc");
+
+	if (!calcname) {
+		char *zcalcname;
+		calcname = outputname;
+		calcname = strlast(calcname,'\\');	// for Windows
+		calcname = strlast(calcname,'/');	// for Unix
+		zcalcname = alloca(strlen(calcname)+1);
+		strcpy(zcalcname,calcname);
+		if (strrchr(zcalcname,'.'))
+			*strrchr(zcalcname,'.')=0;
+		calcname = fill_calcvar(_calcname,zcalcname);
+	}
+	strcpy(export_pfx,calcname);
+	strcat(export_pfx,"__"); export_pfx_len=strlen(export_pfx);
+#ifndef AS
+	{
+		char *buffer=alloca(strlen(outputname)+strlen(".asm")+1);
+		sprintf(buffer,"%s.asm",outputname);
+		if (!(output = fopen(buffer, "w"))) {
+			msg("can't open output file\n");
+			_exit(2);
+		}
+	}
+#endif
+#ifdef LISTING
+	if (list_option && (list = fopen(LIST_NAME, "w")) == 0) {
+		msg("can't open listfile\n");
+		_exit(1);
+	}
+#endif
+#ifdef ICODE
+	if (icode_option && ((icode = fopen(ICODE_NAME, "w")) == 0)) {
+		msg("can't open icode file\n");
+		_exit(1);
+	}
+#endif
+}
+#endif
+
+#ifdef LISTING
+static void summary(void) {
+//	if (gsyms.head != NULL) {
+		fprintf(list, "\f\n *** global scope symbol table ***\n\n");
+		list_table(&gsyms, 0);
+//	}
+//	if (gtags.head != NULL) {
+		fprintf(list, "\n *** structures and unions ***\n\n");
+		list_table(&gtags, 0);
+//	}
+}
+#endif
+
+#ifdef PC
+static void close_files(void) {
+#ifdef LISTING
+		if (list_option)
+		fclose(list);
+#endif
+#ifdef ICODE
+	if (icode_option)
+		fclose(icode);
+#endif
+}
+#endif
+
+#ifdef PC
+void fatal(char *message) {
+	debug('f');
+	clean_up();
+	msg2("Fatal error!\n%s\n", message);
+#ifdef PC
+	fflush(outstr);
+	if (pause_on_error)
+		getchar();
+	exit(EXIT_FAILURE);
+#else
+//	while (!kbhit());
+	ngetchx();
+	exit(0);
+#endif
+}
+#endif
+// vim:ts=4:sw=4

+ 1657 - 0
gtc/src/decl.c

@@ -0,0 +1,1657 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * misc declarations
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define DECLARE
+#define USE_MEMMGT
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+static struct typ *save_type(struct typ *tp);
+static int declbegin(enum(e_sym) st);
+static void declenum(struct hstab *table);
+static void decl2(void);
+static void declstruct(enum(e_bt) ztype);
+static void enumbody(struct hstab *table);
+static void structbody(struct typ *tp, enum(e_bt) ztype);
+long auto_init(long offs,TYP *typ,TYP **tpp,int brace_level,int offmod,int stroff);
+void doinit(struct sym *sp, int align);
+
+TYP 		   *head CGLOB, *tail CGLOB;
+int 			regptr CGLOB;
+XLST_TYPE		reglst[REG_LIST] CGLOBL;
+int				regalloc[REG_LIST];
+int 			autoptr CGLOB;
+XLST_TYPE		autolst[AUTO_LIST] CGLOBL;
+int 			global_flag CGLOB,global_strings CGLOB;
+int 			asm_flag CGLOB,asm_xflag CGLOB,asm_zflag CGLOB;
+char		   *declid CGLOB;
+int				store_lst CGLOB;
+#ifdef NEW_ATTR
+TI_SHORT		func_attr CGLOBL;
+#endif
+#ifdef MID_DECL
+int				middle_decl CGLOB;
+#endif
+
+#ifdef LISTING
+#define LP 0,
+#else
+#define LP
+#endif
+
+readonly TYP	tp_void = {{0, 0}, 0, LP 1, bt_void, 0, 1};// 1 and not -1 as previously defined
+readonly TYP	tp_long = {{0, 0}, 0, LP 4, bt_long, 0, 1};
+readonly TYP	tp_ulong = {{0, 0}, 0, LP 4, bt_ulong, 0, 1};
+readonly TYP	tp_char = {{0, 0}, 0, LP 1, bt_char, 0, 1};
+readonly TYP	tp_uchar = {{0, 0}, 0, LP 1, bt_uchar, 0, 1};
+readonly TYP	tp_short = {{0, 0}, 0, LP 2, bt_short, 0, 1};
+readonly TYP	tp_ushort = {{0, 0}, 0, LP 2, bt_ushort, 0, 1};
+#ifndef NOFLOAT
+#ifndef BCDFLT
+readonly TYP	tp_float = {{0, 0}, 0, LP 4, bt_float, 0, 1};
+#else
+readonly TYP	tp_float = {{0, 0}, 0, LP 10, bt_float, 0, 1};
+#endif
+#ifdef INTEL_386
+readonly TYP	tp_double = {{0, 0}, 0, LP 8, bt_double, 0, 1};
+#endif
+#endif
+readonly TYP	tp_constchar = {{0, 0}, LP 0, 1, bt_char, 0, 1, 1};
+readonly TYP	tp_string = {{0, 0}, (TYP *)&tp_constchar, LP 4, bt_pointer, 0, 1};
+readonly TYP	tp_void_ptr = {{0, 0}, (TYP *)&tp_void, LP 4, bt_pointer, 0, 1};
+readonly TYP	tp_econst = {{0, 0}, 0, LP 2, bt_ushort, 1, 1};	// tp_uint + val_flag=1
+//readonly TYP	  tp_int, tp_uint;
+readonly TYP	tp_func = {{0, 0}, (TYP *)&tp_int, LP 4, bt_func, 1, 1};
+//int			  int_bits;
+
+extern int		glblabel;
+
+/* variables for function parameter lists */
+int		nparms CGLOB;
+char    *names[MAX_PARAMS] CGLOBL;
+
+/* variable for bit fields */
+int		bit_offset CGLOB; 	/* the actual offset */
+int		bit_width CGLOB;		/* the actual width */
+int		bit_next CGLOB;		/* offset for next variable */
+int		decl1_level CGLOB;
+
+int stringlit(char *s, int len) {
+/*
+ * mk_ s a string literal and return its label number.
+ * 'len' should not include the terminating zero
+ */
+	struct slit    *lp;
+	char		   *p;
+	int 			l, local_global = global_flag;
+	global_flag = 0;			/* always allocate from local space. */
+	lp=strtab;
+	while (lp!=0) {
+		if (len==(l=lp->len)) {
+			char *a=s,*b=lp->str;
+			while (l--)
+				if (*a++!=*b++)
+					goto stringlit_not_same;
+			return lp->label;
+		}
+	stringlit_not_same:
+		lp=lp->next;
+	}
+	lp = (struct slit *) xalloc((int) sizeof(struct slit), SLIT+STRINGLIT);
+	lp->label = global_strings?nxtglabel():nxtlabel();
+	p = lp->str = (char *) xalloc((int) len, STR+STRINGLIT);
+	lp->len = len;
+	while (len--)
+		*p++ = *s++;
+	lp->next = strtab;
+	strtab = lp;
+	global_flag = local_global;
+	return lp->label;
+}
+#ifdef USE_DATALIT
+int datalit(char *s, int len) {
+/*
+ * mk_ s a data literal and return its label number.
+ */
+	struct slit    *lp;
+	char		   *p;
+	int 			l, local_global = global_flag;
+	global_flag = 0;			/* always allocate from local space. */
+	lp=datatab;
+	while (lp!=0) {
+		if (len==(l=lp->len)) {
+			char *a=s,*b=lp->str;
+			while (l--)
+				if (*a++!=*b++)
+					goto datalit_not_same;
+			return lp->label;
+		}
+	datalit_not_same:
+		lp=lp->next;
+	}
+	lp = (struct slit *) xalloc((int) sizeof(struct slit), SLIT+STRINGLIT);
+	lp->label = global_strings?nxtglabel():nxtlabel();
+	p = lp->str = (char *) xalloc((int) len, STR+STRINGLIT);
+	lp->len = len;
+	while (len--)
+		*p++ = *s++;
+	lp->next = datatab;
+	datatab = lp;
+	global_flag = local_global;
+	return lp->label;
+}
+#endif
+
+char *litlate(char *s) {
+	char *p, *q, m;
+	int string=0;
+	while (isspace(*s)) s++;
+	q = p = (char *)xalloc((int)strlen(s) + 1, STR+LITLATE);
+	while ((*p++=m=*s++) && m!='\n')
+		if (p-2>=q && p[-2]=='\\') {}
+		else if (m=='"') string=~string;
+		else if (m=='/' && !string) {
+			if (*s=='/') {
+				p[-1]=' ', *p++=0; break;
+			} else if (*s=='*') {
+				p--; if (!isspace(p[-1])) *p++=' ';
+				s+=2;	/* since / * / isn't a valid comment */
+				while (*s && (*s++!='/' || s[-2]!='*'));
+			}
+		}
+	if (m) *--p=0;
+	if (string) return 0;	/* invalid if quotes are unbalanced */
+	return q;
+}
+
+static long imax(long i, long j) {
+	return (i > j) ? i : j;
+}
+
+char *strsave(char *s) {
+	char *p, *q;
+	q = p = (char *)xalloc((int)strlen(s) + 1, STR+STRSAVE);
+	while ((*p++ = *s++));
+	return q;
+}
+
+TYP *copy_type(TYP *s) {
+	TYP 		   *tp;
+	tp = (TYP *) xalloc((int) sizeof(TYP), _TYP);
+	*tp = *s;
+	//memcpy(tp, s, sizeof(TYP));
+	return tp;
+}
+
+TYP *mk_type(enum(e_bt) bt, int siz) {
+	TYP 		   *tp;
+	tp = (TYP *) xalloc((int) sizeof(TYP), _TYP+MK_TYPE);
+	tp->size = siz;
+	tp->type = bt;
+	tp->st_flag = global_flag;
+#ifdef NO_CALLOC
+#ifdef LISTING
+	tp->sname = 0;
+#endif
+	tp->btp = 0;
+	tp->lst.tail = tp->lst.head = 0; tp->lst.hash = 0;
+	tp->val_flag = tp->const_flag = tp->vol_flag = 0;
+	tp->bit_width = 0;
+#endif
+	return tp;
+}
+
+TI_SHORT process_attr();
+void decl(HTABLE *table) {		/* table is used only for enum members */
+//	struct sym	   *sp;
+
+	/*
+	 * at top level, 'int' is changed to 'short' or 'long'
+	 */
+
+	switch (lastst) {
+	  case kw_void:
+		head = tail = (TYP *)&tp_void;
+		getsym();
+		break;
+	  case kw_char:
+		head = tail = (TYP *)&tp_char;
+		getsym();
+		break;
+	  case kw_short:
+		getsym();
+		if (lastst == kw_unsigned) {
+			getsym();
+			head = tail = (TYP *)&tp_ushort;
+		} else {
+			if (lastst == kw_signed) getsym();
+			head = tail = (TYP *)&tp_short;
+		}
+		if (lastst == kw_int)
+			getsym();
+		break;
+	  case kw_int:
+		head = tail = (TYP *)&tp_int;
+		getsym();
+		break;
+	  case kw_long:
+		getsym();
+		if (lastst == kw_unsigned) {
+			getsym();
+			head = tail = (TYP *)&tp_ulong;
+		} else {
+			if (lastst == kw_signed) getsym();
+			head = tail = (TYP *)&tp_long;
+		}
+		if (lastst == kw_int)
+			getsym();
+		break;
+	  case kw_unsigned:
+		getsym();
+		switch (lastst) {
+		  case kw_long:
+			getsym();
+			head = tail = (TYP *)&tp_ulong;
+			if (lastst == kw_int)
+				getsym();
+			break;
+		  case kw_char:
+			getsym();
+			head = tail = (TYP *)&tp_uchar;
+			break;
+		  case kw_short:
+			getsym();
+			head = tail = (TYP *)&tp_ushort;
+			if (lastst == kw_int)
+				getsym();
+			break;
+		  case kw_int:
+			getsym();
+		  default:
+			head = tail = (TYP *)&tp_uint;
+			break;
+		}
+		break;
+	  case kw_signed:
+		getsym();
+		switch (lastst) {
+		  case kw_long:
+			getsym();
+			head = tail = (TYP *)&tp_long;
+			if (lastst == kw_int)
+				getsym();
+			break;
+		  case kw_char:
+			getsym();
+			head = tail = (TYP *)&tp_char;
+			break;
+		  case kw_short:
+			getsym();
+			head = tail = (TYP *)&tp_short;
+			if (lastst == kw_int)
+				getsym();
+			break;
+		  case kw_int:
+			getsym();
+		  default:
+			head = tail = (TYP *)&tp_int;
+			break;
+		}
+		break;
+	  case kw_const:
+		getsym();
+		decl(table);
+		head = copy_type(head);
+		head->const_flag = 1;
+		tail = head;
+		break;
+	  case kw_volatile:
+		getsym();
+		decl(table);
+		head = copy_type(head);
+		head->vol_flag = 1;
+		tail = head;
+		break;
+	  case kw_typeof:
+		getsym();
+		needpunc(openpa);
+		{ struct enode *en;
+		/*tmp_use(); -> TODO, but copy_type must be global/local*/
+		head = copy_type(expression(&en));
+		/*tmp_free();*/ }
+		head->const_flag = head->vol_flag = 0;
+		tail = head;
+		needpunc(closepa);
+		break;
+	  case id:
+		if (lastsp != 0 &&
+			lastsp->storage_class == sc_typedef)
+			/* type identifier */
+		{
+			/* BUGGY/FIXME!!! I swapped these two lines, but I can't figure out why
+			 * they had to be */
+			head = tail = lastsp->tp;
+			getsym();
+			break;
+		}
+		/* else fall through */
+	  case openpa:
+	  case star:
+		/* default type is int */
+		head = tail = (TYP *)&tp_int;
+		break;
+#ifndef NOFLOAT
+	  case kw_float:
+#ifndef DOUBLE
+	  case kw_double:
+#endif
+		head = tail = (TYP *)&tp_float;
+		getsym();
+		break;
+#ifdef DOUBLE
+	  case kw_double:
+		head = tail = (TYP *)&tp_double;
+		getsym();
+		break;
+#endif
+#endif
+	  case kw_enum:
+		getsym();
+		declenum(table);
+		break;
+	  case kw_struct:
+		getsym();
+		declstruct(bt_struct);
+		break;
+	  case kw_union:
+		getsym();
+		declstruct(bt_union);
+		break;
+	  case kw_attr:
+		func_attr=process_attr();
+		decl(table);
+		break;
+	}
+	if (lastst==kw_volatile) {
+		head = copy_type(head);
+		head->vol_flag = 1;
+		tail = head;
+		getsym();
+	}
+}
+
+#ifdef PC
+TI_SHORT unset_attr={-1,-1};
+TI_SHORT stkparm_attr={0,0};
+TI_SHORT regparm_attr={2,1};
+#define attr_isset(v) ((v).hi!=(unsigned char)-1)
+#else
+#define unset_attr -1
+#define stkparm_attr 0
+#define regparm_attr 0x0201
+#define attr_isset(v) ((int)(v) IS_VALID)
+#endif
+
+TI_SHORT process_attr() {
+#ifdef DEFAULT_STKPARM
+#ifndef NEW_ATTR
+	unsigned char rp_dn=0,rp_an=0;
+#endif
+#define DEFLT_ATTR stkparm_attr
+#else
+#ifndef NEW_ATTR
+	unsigned char rp_dn=2,rp_an=1;
+#endif
+#define DEFLT_ATTR regparm_attr
+#endif
+#ifdef NEW_ATTR
+	unsigned char rp_dn=-1,rp_an=-1;
+#endif
+	getsym();
+	needpunc(openpa);
+	{
+		int n=1;
+		do {
+			if (lastst==openpa) n++;
+			else if (lastst==closepa) n--;
+			else if (lastst==id) {
+#ifdef REGPARM
+				if (lastid[0]=='_' && lastid[1]=='_')
+					memmove(lastid,lastid+2,MAX_ID_LEN-2),lastid[strlen(lastid)-2]=0;
+				if (!strcmp(lastid,"stkparm"))
+					rp_dn=0, rp_an=0;
+				else if (!strcmp(lastid,"aregparm"))
+					rp_dn=3, rp_an=2;
+				else if (!strcmp(lastid,"regparm")) {
+					getsym();
+					if (lastst==openpa) {
+						getsym();
+						if (lastst!=iconst) error(ERR_SYNTAX);
+						else {
+							rp_dn = rp_an = (char)ival;
+							getsym();
+							if (lastst==comma) {
+								getsym();
+								if (lastst==iconst)
+									rp_an = (char)ival, getsym();
+							}
+						}
+						if (rp_dn>CONVENTION_MAX_DATA+1 || rp_an>CONVENTION_MAX_ADDR+1)
+							error(ERR_OUTRANGE), rp_dn=0, rp_an=0;
+						if (lastst!=closepa) uerr(ERR_PUNCT,')');
+					} else { rp_dn=2; rp_an=1; goto nxt_attr; }
+				}
+#endif
+			} else if (lastst!=comma)
+				uerr(ERR_PUNCT,')');
+			getsym();
+		nxt_attr:
+			(void)0;
+		} while (n>0);
+	}
+#ifdef PC
+	{
+	TI_SHORT ret;
+	ret.hi=rp_dn;
+	ret.lo=rp_an;
+	return ret;
+	}
+#else
+	return (rp_dn<<8)+(rp_an);
+#endif
+}
+
+void decl1(void) {
+/* handles *, :, ... */
+	TYP 		   *temp1, *temp2, *temp3, *temp4;
+	decl1_level++;
+	switch (lastst) {
+	  case id:
+		declid = strsave(lastid);
+		getsym();
+		if (lastst != colon) {
+			decl2();
+			break;
+		}
+		/* FALLTHROUGH */
+	  case colon:
+		getsym();
+		if (decl1_level != 1)
+			error(ERR_FIELD);
+		if (head->type != tp_int.type && head->type != tp_uint.type)
+#if 0
+			error(ERR_FTYPE);
+#else
+			uwarn("field type should be unsigned or int");
+#endif
+		bit_width = (int)intexpr();
+		bit_offset = bit_next;
+		if (bit_width < 0 || bit_width > int_bits) {
+			error(ERR_WIDTH);
+			bit_width = 1;
+		}
+		if (bit_width == 0 || bit_offset + bit_width > int_bits)
+			bit_offset = 0;
+		bit_next = bit_offset + bit_width;
+		break;
+	  case star:
+		temp1 = mk_type(bt_pointer, 4);
+		temp1->btp = head;
+		head = temp1;
+		if (tail == NULL)
+			tail = head;
+		getsym();
+		decl1();
+		break;
+	  case openpa: {
+#ifndef NEW_ATTR
+		short attr=DEFLT_ATTR;
+#endif
+		getsym();
+		temp1 = head;
+		temp2 = tail;
+		head = tail = NULL;
+		decl1();
+#ifndef NEW_ATTR
+		if (lastst==kw_attr)
+			attr=process_attr();
+#endif
+		needpunc(closepa);
+		temp3 = head;
+		temp4 = tail;
+		head = temp1;
+		tail = temp2;
+		decl2();
+#ifndef NEW_ATTR
+#ifdef REGPARM
+		assert(sizeof(short)==sizeof(TI_SHORT));
+		if (*(short *)&head->rp_dn==DEFLT_ATTR)
+			*(short *)&head->rp_dn=attr;
+#endif
+#endif
+		if (temp4 != NULL) {
+			temp4->btp = head;
+			if (temp4->type == bt_pointer &&
+				temp4->val_flag != 0 && head != NULL)
+				temp4->size = (long)((int)head->size)*((int)temp4->size);
+			head = temp3;
+		}
+	   } break;
+#ifdef NEW_ATTR
+	  case kw_attr:
+		func_attr=process_attr();
+		decl1();
+		break;
+#endif
+/*	  case kw_attr:
+		process_attr();*/
+		/* FALL THROUGH */
+	  case kw_const:
+		getsym();
+		head = copy_type(head);
+		head->const_flag = 1;
+		tail = head;
+		decl1();
+		break;
+	  case kw_volatile:
+		getsym();
+		head = copy_type(head);
+		head->vol_flag = 1;
+		tail = head;
+		decl1();
+		break;
+	  default:
+		decl2();
+		break;
+	}
+	decl1_level--;
+	/*
+	 * Any non-bitfield type resets the next offset
+	 */
+	if (bit_width IS_INVALID)
+		bit_next = 0;
+}
+
+#ifdef REGPARM
+#if 0
+short count_dn_an(struct enode *plist,int rp_dn,int rp_an) {
+	int true_dn=0,true_an=0;
+	int nr=rp_dn+rp_an,np=0,n;
+	int list[16],*p;
+	struct enode *ep=plist;
+	while (ep) np++, ep=ep->v.p[1];
+	/* first, push stack params while all the temp registers are free */
+	while (np>nr) np--,plist = plist->v.p[1];
+	/* store the last params so we can examinate them in the correct order */
+	n=np; while (n--) list[n]=plist->v.p[0]->etype-bt_pointer, plist=plist->v.p[1];
+	/* now, get the real # of regs */
+	p=list;
+	n=np; while (n--) {
+		if ((!*p++ && rp_an) || !rp_dn)
+			true_an++, rp_an--;
+		else true_dn++, rp_dn--;
+	}
+#ifdef PC
+	return (true_dn)+(true_an<<8);
+#else
+	return (true_dn<<8)+(true_an);
+#endif
+}
+#endif
+#endif
+
+#ifndef NO_VARARG_FUNC
+char variable_arg_name[]="__vararg__";
+#define is_variable_arg(sp) ((sp)->name==variable_arg_name)
+#define mk_variable_arg(sp) ((sp)->name=variable_arg_name)
+#endif
+
+static long declare(HTABLE *table, enum(e_sc) al, long ilc, enum(e_bt) ztype, int regflag);
+static void decl2(void) {
+/* Handles __attribute__, [*] (for arrays) and (*) (for functions) */
+	TYP 		   *temp1,*temp2;
+	long			i;
+	switch (lastst) {
+	  case openbr:
+		getsym();
+		if (lastst == closebr)
+			i = 0;
+		else
+			i = intexpr();
+		needpunc(closebr);
+		if (lastst == openbr)
+			decl2();
+		temp1 = mk_type(bt_pointer, 0);
+		temp1->val_flag = 1;
+		temp1->btp = head;
+		if (head != 0)
+			temp1->size = i * head->size;
+		else
+			temp1->size = i;
+		head = temp1;
+		if (tail == NULL)
+			tail = head;
+		decl2();
+		break;
+	  case openpa:
+		getsym();
+		temp1 = mk_type(bt_func, 4);
+		temp1->val_flag = 1;
+		temp1->btp = head;
+		temp1->lst.head=temp1->lst.tail=0; temp1->lst.hash=0;
+		head = temp1;
+		if (tail == NULL)
+			tail = head;
+		temp2 = tail;
+		if (lastst == kw_void) {
+			getcache(-1);
+			if (cached_sym == closepa)
+				getsym();
+		}
+		if (lastst == closepa)
+			getsym();
+		else {
+			TABLE *tp;
+			struct sym *sp;
+			char *func_name;
+			long slc;
+			int regflag;
+			int old_nparms;
+			int old_middle_decl=middle_decl,old_store_lst=store_lst;
+//			int old_regptr=regptr,old_autoptr=autoptr;
+#ifdef NO_PROTO
+			if (nparms != 0)	// (void(*)(myparam1...))myfunc() *was* invalid
+				error(ERR_PARMS);
+#endif
+#ifdef REGPARM
+#ifdef DEFAULT_STKPARM
+			head->rp_dn=0; head->rp_an=0;
+#else
+			head->rp_dn=2; head->rp_an=1;
+#endif
+#endif
+			/*if (lineid==32)
+				bkpt();*/
+			tp=(TABLE *)temp1;
+			old_nparms=nparms;
+			func_name = declid;
+			slc=34560;
+			store_lst=pch_init?0:global_flag;
+			/*
+			 * Basically 'store_lst' is always equal to 1, except in two cases:
+			 * - declaring a function inside a PCH initialization (pch_init!=0)
+			 * - prototyping a function (global_flag==0)
+			 * because we don't want the parameters of those functions to mess
+			 * with the function we are declaring.
+			 *
+			 * In all the other cases, we reset 'regptr'/'autoptr' when
+			 * parsing the declaration of the function (starting from the
+			 * parameter list, of course).
+			 */
+			if (store_lst) {
+				regptr = 0;
+				autoptr = 0;
+			}
+			middle_decl=0;
+			while (1) {
+				if (nparms >= MAX_PARAMS)
+					uerrsys("too many params");
+				regflag = 3;
+				switch (lastst) {
+				case kw_typedef: case kw_static: case kw_auto: case kw_extern:
+						error(ERR_ILLCLASS);
+						return;
+				case kw_register:
+						regflag = 4;
+						getsym();
+						goto do_pdecl;
+				case id:
+				/*
+				 * If it is a typedef identifier, fall through & do the declaration.
+				 */
+						if (!(sp = lastsp) || sp->storage_class != sc_typedef) {
+							names[nparms++] = strsave(lastid);
+							getsym();
+							break;
+						}
+				case kw_char: case kw_short: case kw_unsigned: case kw_long:
+				case kw_struct: case kw_union: case kw_enum: case kw_void:
+				case kw_float: case kw_double: case kw_int: case kw_typeof:
+				case kw_signed: case kw_const: case kw_volatile:
+do_pdecl:
+					slc+=declare((HTABLE *)tp, sc_parms2, slc, bt_struct, regflag);
+					if (isaggregate(head))
+						func_attr=stkparm_attr;	/* force the function to be stkparm... */
+					names[nparms++] = declid;
+					break;
+				/*case closepa:
+					getsym();
+					return;	*/
+				case dots:
+					getsym();
+#ifdef NO_VARARG_FUNC
+					tp->head=tp->tail=NULL;
+#else
+					func_attr=stkparm_attr;	/* force the function to be stkparm... */
+					{
+						SYM *sp=(SYM *)xalloc(sizeof(SYM),_SYM);
+						mk_variable_arg(sp);
+						append(&sp,(HTABLE *)tp);
+						goto args_done;
+					}
+#endif
+					break;
+				default:
+					error(ERR_SYNTAX);
+				}
+				if (lastst == comma) getsym();
+				else break;
+			}
+		args_done:
+			store_lst=old_store_lst;
+			middle_decl=old_middle_decl;
+			needpunc(closepa);
+			head = temp1;
+			tail = temp2;
+			if (lastst != begin && (!nparms || !castbegin(lastst)))
+				nparms=old_nparms;
+			declid=func_name;
+		}
+#ifdef NEW_ATTR
+		*(TI_SHORT *)&head->rp_dn=DEFLT_ATTR;
+#endif
+		if (lastst==kw_attr)
+#ifdef REGPARM
+			*(TI_SHORT *)&head->rp_dn=
+#endif
+				process_attr();
+#ifdef NEW_ATTR
+		if (attr_isset(func_attr))
+			*(TI_SHORT *)&head->rp_dn=func_attr, func_attr=unset_attr;
+#endif
+/*#ifdef REGPARM
+		if (head->rp_dn || head->rp_an)
+			*(short *)&(head->rp_dn)=count_dn_an(
+#endif*/
+		break;
+/*		if (lastst == kw_void) {
+			getsym();
+			if (lastst != closepa)
+				error(ERR_PARMS);
+		}
+		if (lastst == closepa)
+			getsym();
+		else {
+			if (nparms != 0)
+				error(ERR_PARMS);
+			if (lastst != id) {
+				while (lastst != closepa) {
+					names[nparms++] = strsave(lastid);
+				}
+			} else while (lastst == id) {
+				if (nparms >= MAX_PARAMS)
+					fatal("MAX_PARAMS");
+				names[nparms++] = strsave(lastid);
+				getsym();
+				if (lastst == comma)
+					getsym();
+			}
+			needpunc(closepa);
+		}
+		break;*/
+	}
+}
+
+int alignment(TYP *tp) {
+	switch (tp->type) {
+	  case bt_uchar:
+	  case bt_char:
+		return AL_CHAR;
+	  case bt_ushort:
+	  case bt_short:
+		return AL_SHORT;
+	  case bt_ulong:
+	  case bt_long:
+		return AL_LONG;
+	  case bt_pointer:
+		if (tp->val_flag)
+			return alignment(tp->btp);
+		else
+			return AL_POINTER;
+	  case bt_func:
+		return AL_FUNC;
+	  case bt_float:
+		return AL_FLOAT;
+#ifdef DOUBLE
+	  case bt_double:
+		return AL_DOUBLE;
+#endif
+	  case bt_struct:
+	  case bt_union:
+		return AL_STRUCT;
+	  case bt_void:
+		return 1;
+	  default:
+		ierr(ALIGNMENT,1);
+		return 0; // does not happen
+	}
+}
+
+xstatic long old_nbytes CGLOB;
+	/* should be in declare(), but SConvert would put it in the text */
+	/*  segment, preventing it from being modified */
+static long declare(HTABLE *table, enum(e_sc) al, long ilc, enum(e_bt) ztype, int regflag) {
+/*
+ * process declarations of the form:
+ *
+ * <type>		<decl>, <decl>...;
+ *
+ * leaves the declarations in the symbol table pointed to by table and returns
+ * the number of bytes declared. al is the allocation type to assign, ilc is
+ * the initial location counter. if al is sc_member then no initialization
+ * will be processed. ztype should be bt_struct for normal and in structure
+ * declarations and sc_union for in union declarations.
+ *
+ * regflag values:
+ *	   -2:		union  component
+ *	   -1:		struct component
+ *		0:		static, global, extern
+ *		1:		auto
+ *		2:		register auto
+ *		3:		argument
+ *		4:		register argument
+ */
+	struct sym				 *sp, *sp1;
+	TYP 									 *dhead;
+	long											nbytes;
+	int 											func_flag;
+	int 											no_append;
+	nbytes = 0;
+	decl(table);
+	dhead = head;
+	for (;;) {
+		declid = 0;
+		bit_width = -1;
+		decl1();
+#ifdef MID_DECL
+		if (middle_decl && !declid && lastst==closepa)
+			return 0;
+		/*				if (middle_decl)
+						bkpt();*/
+#endif
+		if (!declid && al == sc_member)
+			declid = "__unnamed__";
+		if (declid != 0) {		/* otherwise just struct tag
+								 * or unnamed argument in func prototype... */
+			if (head->size == 0 && head->type == bt_pointer
+					&& al == sc_typedef) {
+				uwarn("typedef with null size");
+			}
+#ifdef LISTING
+			if (al==sc_typedef)	/* hack to display structs' real names */
+				head->sname = declid;
+#endif
+			func_flag = 0;
+			if (head->type == bt_func &&
+					(lastst == begin || (nparms > 0 && castbegin(lastst)))) {
+				func_flag = 1;
+				concat((TABLE *)&lsyms,(TABLE *)head);
+			}
+			sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+_DECLARE);
+			sp->name = declid;
+			sp->storage_class = (al==sc_parms2) ? sc_auto : al;
+#ifdef NO_CALLOC
+			sp->used = 0;
+#endif
+
+			if (head->type != bt_func && bit_width > 0 && bit_offset > 0) {
+				/*
+				 * share the storage word with the previously defined field
+				 */
+				nbytes = old_nbytes - ilc;
+			}
+			old_nbytes = ilc + nbytes;
+			while ((ilc + nbytes) % alignment(head))
+				nbytes++;
+			//printf("%s: %d\n",sp->name,al);
+			if (al==sc_global) {/* don't store value.i (else pb w/ value.splab) */}
+			else if (al == sc_static)
+#ifdef AS
+				sp->value.splab=0/*nxtglabel()*/;//->this will be done in genstorage()
+#else
+			sp->value.i = nxtglabel();
+#endif
+			else if (ztype == bt_union)
+				sp->value.i = ilc;
+			else if (al != sc_auto)
+				sp->value.i = ilc + nbytes;
+			else
+				sp->value.i = -(ilc + nbytes + head->size);
+
+			/*
+			 * The following code determines possible candidates for register
+			 * variables. Note that 'sp->value.i' could be modified later on,
+			 * but only when auto_init()ing an array/struct/union; and these
+			 * structures are excluded from here (except for arguments to the
+			 * function with type array: they are really pointers).
+			 */
+			if (store_lst)
+				switch (head->type) {
+					case bt_pointer:
+						if (head->val_flag && regflag < 3)
+							break;
+						/* FALLTHROUGH */
+					case bt_char:
+					case bt_uchar:
+					case bt_short:
+					case bt_ushort:
+					case bt_long:
+					case bt_ulong:
+					case bt_float:
+#ifdef DOUBLE
+					case bt_double:
+#endif
+						switch (regflag) {
+							case 1:
+							case 3:
+								if (autoptr < AUTO_LIST)
+									autolst[autoptr++] = sp->value.i;
+								break;
+							case 2:
+							case 4:
+								if (regptr < REG_LIST)
+									reglst[regptr++] = sp->value.i;
+								break;
+						}
+				}
+
+			if (bit_width IS_INVALID) {
+				sp->tp = head;
+			} else {
+				sp->tp = (struct typ *) xalloc((int) sizeof(struct typ),
+						_TYP+_DECLARE);
+				*(sp->tp) = *head;
+				sp->tp->type = bt_bitfield;
+				sp->tp->size = tp_int.size;
+				sp->tp->bit_width = (char)bit_width;
+				sp->tp->bit_offset = (char)bit_offset;
+			}
+			/*
+			 * The following stuff deals with inconsistencies in the
+			 * C syntax and semantics, namely the scope of locally
+			 * declared functions and its default storage class (extern,
+			 * not auto) etc.
+			 */
+			no_append = 0;
+			/*
+			 * The flag no_append will be set if some stuff is forwarded to the
+			 * global symbol table here and thus should not be repeated in the local
+			 * symbol table
+			 */
+
+			/*
+			 * extern function definitions with function body are global
+			 */
+			if (func_flag && sp->storage_class == sc_external)
+				sp->storage_class = sc_global;
+			/*
+			 * global function declarations without function body are external
+			 */
+			if (sp->tp->type == bt_func && sp->storage_class == sc_global
+					&& !func_flag) {
+				sp->storage_class = sc_external;
+			}
+			/*
+			 * [auto] int test() is not an auto declaration, it should be
+			 * external
+			 */
+			if (sp->tp->type == bt_func && sp->storage_class == sc_auto) {
+				/*
+				 * althouh the following if-statement is not necessary since
+				 * this check is performed in append() anyway, it saves
+				 * global storage if the functions has previously been
+				 * defined.
+				 */
+				if ((sp1 = search(sp->name, -1, &gsyms)) == 0) {
+					/* put entry in the global symbol table */
+					++global_flag;
+					sp1 = (struct sym *) xalloc((int) sizeof(struct sym),
+							_SYM+_DECLARE);
+					sp1->name = strsave(sp->name);
+					sp1->storage_class = sc_external;
+					sp1->tp = save_type(sp->tp);
+#ifdef NO_CALLOC
+					sp1->used = 0;
+#endif
+					append(&sp1, &gsyms);
+					--global_flag;
+				} else {
+					/* already defined in global symbol table */
+					if (!eq_type(sp->tp, sp1->tp))
+						uerr(ERR_REDECL,sp->name);
+				}
+				no_append = 1;
+				sp = sp1;
+			}
+			/*
+			 * static local function declarations should be put in the
+			 * global symbol table to retain the compiler generated
+			 * label number
+			 */
+			if (sp->tp->type == bt_func && sp->storage_class == sc_static
+					&& table == &lsyms) {
+				if (!(sp1 = search(sp->name, -1, &gsyms))) {
+					/* put it into the global symbol table */
+					++global_flag;
+					sp1 = (struct sym *) xalloc((int) sizeof(struct sym),
+							_SYM+_DECLARE);
+					sp1->name = strsave(sp->name);
+					sp1->storage_class = sc_static;
+					sp1->tp = save_type(sp->tp);
+					sp1->value.i = sp->value.i;
+#ifdef NO_CALLOC
+					sp1->used = 0;
+#endif
+					append(&sp1, &gsyms);
+					--global_flag;
+				} else {
+					if (!eq_type(sp->tp, sp1->tp))
+						uerr(ERR_REDECL,sp->name);
+				}
+				no_append = 1;
+				sp = sp1;
+			}
+			if (ztype == bt_union)
+				nbytes = imax(nbytes, sp->tp->size);
+			else if (al != sc_external)
+				nbytes += sp->tp->size;
+			if (!no_append)
+				if (al == sc_member)
+					insert(sp, table);
+				else
+					append(&sp, table);
+			if (func_flag) {
+				/* function body follows */
+				int local_nparms = nparms;
+				ret_type = sp->tp->btp;
+				if (!global_flag)
+					error(ERR_SYNTAX);
+				nparms = 0;
+				funcbody(sp, names, local_nparms);
+				return nbytes;
+			}
+			if ((al == sc_global || al == sc_static) &&
+					sp->tp->type != bt_func && sp->used IS_VALID)
+				doinit(sp, alignment(head));
+			else if (lastst == assign) {
+				if (regflag == 1 || regflag == 2) {
+					long old=sp->tp->size;
+					getsym();
+#ifdef MID_DECL_IN_EXPR
+#error fix needed here...
+#endif
+					{struct enode *bak=init_node;
+						init_node=NULL;
+						old-=auto_init(sp->value.i,sp->tp,&sp->tp,0,0,-1);
+						old-=old&1;
+						if (old<0) {
+							struct enode *en=init_node;
+							sp->value.i+=old;
+							if (en!=NULL) {
+								while (en->nodetype!=en_assign) {
+									struct enode *en2=en/*en_void*/->v.p[1]/*en_assign*/
+										->v.p[0]/*en_ref*/->v.p[0]/*en_autocon/en_add*/;
+									if (en2->nodetype==en_add)
+										en2=en2->v.p[0];
+									en2->v.i += old;
+									en=en->v.p[0];
+								}
+								en/*en_assign*/->v.p[0]/*en_ref*/
+									->v.p[0]/*en_autocon*/->v.i += old;
+							}
+							nbytes-=old;
+						}
+						if (bak) {
+							if (init_node)
+								init_node=mk_node(en_void,bak,init_node);
+							else
+								init_node=bak;
+						}
+					}
+				} else {
+					error(ERR_ILLINIT);
+					doinit(sp, alignment(head));
+				}
+				/* just a small check, it was proposed that I should make it */
+				/*if (sp->tp->size == 0 && sp->storage_class != sc_external
+				  && sp->storage_class != sc_typedef
+				  && !(head->type == bt_pointer && head->val_flag)
+				  && regflag < 3) {
+				  uwarn("declaration with null size");
+				  }*/
+			}
+		} else if (al==sc_parms2) {		/* in 'if (declid != 0)' ... */
+			sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+_DECLARE);
+			sp->name="";
+			sp->tp=head;
+			append(&sp,table);
+		}
+		if (al == sc_parms2
+#ifdef MID_DECL
+				|| middle_decl
+#endif
+		   ) return nbytes;
+		else if (lastst == semicolon)
+			break;
+		needpunc(comma);
+		if (declbegin(lastst) == 0)
+			break;
+		head = dhead;
+	}
+	getsym();
+	return nbytes;
+}
+
+static int declbegin(enum(e_sym) st) {
+		return (st == star || st == id || st == openpa ||
+				st == openbr || st == colon);
+}
+
+static void declenum(HTABLE *table) {
+		struct sym				 *sp;
+		TYP 									 *tp;
+		if (lastst == id) {
+				if ((sp = search(lastid, lastcrc, &ltags)) == 0 &&
+						(sp = search(lastid, lastcrc, &gtags)) == 0) {
+						sp = (struct sym *) xalloc((int) sizeof(struct sym),
+							_SYM+DECLENUM);
+						if (short_option)
+								sp->tp = mk_type(bt_ushort, 2);
+						else
+								sp->tp = mk_type(bt_ulong, 4);
+						sp->storage_class = sc_type;
+						sp->name = strsave(lastid);
+#ifdef LISTING
+						sp->tp->sname = sp->name;
+#endif
+#ifdef NO_CALLOC
+						sp->used = 0;
+#endif
+						getsym();
+						if (lastst != begin)
+								error(ERR_INCOMPLETE);
+						else {
+								if (global_flag)
+										append(&sp, &gtags);
+								else
+										append(&sp, &ltags);
+								getsym();
+								enumbody(table);
+						}
+				} else getsym();
+				head = sp->tp;
+		} else {
+				if (short_option)
+						tp = mk_type(bt_ushort, 2);
+				else
+						tp = mk_type(bt_ulong, 4);
+				if (lastst != begin)
+						error(ERR_INCOMPLETE);
+				else {
+						getsym();
+						enumbody(table);
+				}
+				head = tp;
+		}
+}
+
+static void enumbody(HTABLE *table) {
+	long			evalue;
+	struct sym	   *sp;
+	evalue = 0;
+	while (lastst == id) {
+		sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+ENUMBODY);
+		sp->value.i = evalue++;
+		sp->name = strsave(lastid);
+		sp->storage_class = sc_const;
+		sp->tp = (TYP *)&tp_econst;
+		append(&sp, table);
+		getsym();
+		if (lastst == assign) {
+			getsym();
+			evalue = sp->value.i = intexpr();
+			evalue++;
+		}
+		if (short_option && (sp->value.i < -32768 || sp->value.i > /*32767*/65535))
+			error(ERR_ENUMVAL);
+		if (lastst == comma)
+			getsym();
+		else if (lastst != end)
+			break;
+	}
+	needpunc(end);
+}
+
+static void declstruct(enum(e_bt) ztype) {
+/*
+ * declare a structure or union type. ztype should be either bt_struct or
+ * bt_union.
+ *
+ * References to structures/unions not yet declared are allowed now. The
+ * declaration has to be done before the structure is used the first time
+ */
+	struct sym	   *sp;
+	TYP 		   *tp;
+	if (lastst == id) {
+		if ((sp = search(lastid, lastcrc, &ltags)) == 0 &&
+			(sp = search(lastid, lastcrc, &gtags)) == 0) {
+			sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+DECLSTRUCT);
+			sp->name = strsave(lastid);
+			sp->tp = mk_type(ztype, 0);
+			sp->storage_class = sc_type;
+#ifdef LISTING
+			sp->tp->sname = sp->name;
+#endif
+			if (global_flag)
+				append(&sp, &gtags);
+			else
+				append(&sp, &ltags);
+		}
+		if (sp->tp->lst.head != 0)
+			getsym();
+		else {
+			getsym();
+			/* allow, e.g. struct x *p; before x is defined */
+			if (lastst == begin) {
+				getsym();
+				structbody(sp->tp, ztype);
+			}
+		}
+		head = sp->tp;
+	} else {
+		tp = mk_type(ztype, 0);
+		if (lastst != begin)
+			error(ERR_INCOMPLETE);
+		else {
+			getsym();
+			structbody(tp, ztype);
+		}
+		head = tp;
+	}
+}
+
+static void structbody(TYP *tp, enum(e_bt) ztype) {
+	long			slc;
+	slc = 0;
+	bit_next = 0;
+	while (lastst != end) {
+		if (ztype == bt_struct)
+			slc += declare((HTABLE *)&(tp->lst), sc_member, slc, ztype, -1);
+		else
+			slc = imax(slc, declare((HTABLE *)&tp->lst, sc_member, 0l, ztype, -2));
+	}
+	/*
+	 * consider alignment of structs in arrays...
+	 */
+#if AL_DEFAULT==2
+	slc+=(slc&1);
+#else
+	if (slc % AL_DEFAULT != 0)
+		slc += AL_DEFAULT - (slc % AL_DEFAULT);
+#endif
+	tp->size = slc;
+	getsym();
+	bit_next = 0;
+}
+
+extern char linein[LINE_LENGTH];
+extern char *lptr;
+#ifdef VCG
+extern int vcg_lvl;
+#endif
+static int nologo=0;
+void compile(void) {
+/*
+ * main compiler routine. this routine parses all of the declarations using
+ * declare which will call funcbody as functions are encountered.
+ */
+#ifdef VERBOSE
+		time_t			ltime;
+#endif
+
+	debugcls();
+#ifdef PC
+	if (!verbose)
+		nologo=1;
+#endif
+	if (!nologo)
+#ifdef PC
+		msg(
+			"        ---  GTC C compiler  ---        \n\n"
+			" © 2001-2004 by Paul Froissart\n\n"),nologo++;
+#else
+#ifndef GTDEV
+		msg("GTC compiler - © 2001-2004\n by Paul Froissart\n"),nologo++;
+#endif
+#endif
+
+#ifdef VERBOSE
+	times(&tms_buf);
+	ltime = tms_buf.tms_utime;
+#endif
+
+	strtab = 0;
+	lc_bss = 0;
+	debug('1');
+	hashinit(&gsyms);
+	hashinit(&gtags);
+	hashinit(&lsyms);
+	hashinit(&ltags);
+	hashinit(&labsyms);
+	debug('6');
+	nextlabel = 1;
+	store_lst = 1;
+	asm_flag = 0;
+	asm_xflag = 0;
+	asm_zflag = 0;
+	nparms = 0;
+	func_sp = NULL;
+#ifdef DUAL_STACK
+	{
+		// create a 16-byte 'leak' (which will be freed in rel_global(), though)
+		// to avoid perpetual malloc()/free() of the dualstack
+		ds_ensure(16);
+		{
+		char *ptr = ds_var(char *);
+		ds_update(ptr+16);
+		}
+	}
+#endif
+#ifdef VCG
+	vcg_lvl=VCG_MAX;
+#endif
+	getch();
+	getsym();
+	debug('7');
+	while (lastst != eof) {
+		extern int got_sym;
+		got_sym = 0;
+		dodecl(sc_global);
+#if 0
+		if (lastst != eof)		/* what the heck is this??? am I doing a mistake    */
+			getsym();			/*  when I disable it? how come I find it only now? */
+#elif 1	/* UPDATE : the former seems to be a (missed) fix for the infinite loop *
+		 * when a particular kind of syntax error occurred. This is now fixed. */
+		if (!got_sym)
+			uerr(ERR_SYNTAX);
+#endif
+	}
+#ifdef VERBOSE
+	times(&tms_buf);
+	decl_time += tms_buf.tms_utime - ltime;
+#endif
+	debug('8');
+	dumplits();
+	debug('9');
+}
+
+#ifdef VCG
+extern struct ocode *vcg_peep_head[];
+#endif
+void dodecl(enum(e_sc) defclass) {
+		long slc = 0;
+		struct sym *sp;
+		int regflag;
+		for (;;) {
+				regflag = 1;
+				switch (lastst) {
+				case kw_register:
+						regflag = 2;
+						getsym();
+						if (defclass != sc_auto && defclass != sc_parms)
+								error(ERR_ILLCLASS);
+						goto do_decl;
+				case kw_auto:
+						getsym();
+						if (defclass != sc_auto)
+								error(ERR_ILLCLASS);
+						goto do_decl;
+				case kw_asm:
+						if (!global_flag) /* more secure than 'if (defclass != sc_global)' ? */
+							return;			// so that while (x) { asm(...); ... }
+						getsym();			// works (as in-line asm)
+#ifdef ASM
+						if (lastst != begin) {
+#endif
+	#ifndef AS
+							if (lastst != openpa)
+	#endif
+								error(ERR_SYNTAX);
+	#ifndef AS
+							else {
+								getsym();
+								if (lastst != sconst)
+									error(ERR_SYNTAX);
+								put_code(_op_asm,0,(struct amode *)strsave(laststr),NIL_AMODE);
+								getsym();
+								needpunc(closepa);
+								needpunc(semicolon);
+							}
+	#endif
+#ifdef ASM
+						} else {
+							int glob = global_flag;
+					#ifdef AS
+							struct ocode *sh = scope_head;
+							int nextlab = nextlabel;
+					#endif
+							global_flag = 0;
+#ifdef PCH
+							push_local_mem_ctx();	/* because global_flag=0 is possible inside
+													 *  a function */
+#endif
+					#ifdef AS
+							put_align2();
+							scope_head = 0;
+							scope_init();
+					#endif
+							asm_flag++;
+							asm_head = 0;
+							asm_getsym();
+							while (getasm_main());
+							asm_flag--;
+							needpunc(end);
+							needpunc(semicolon);
+							if (strtab)
+								dumplits();
+					#ifdef AS
+							scope_head = asm_head;
+							scope_flush();
+							nextlabel = nextlab;
+							scope_head = sh;
+							local_clean();
+					#else
+						#ifdef VCG
+							vcg_peep_head[vcg_lvl] = asm_head;
+						#else
+							peep_head = asm_head;
+						#endif
+							flush_peep();
+					#endif
+#ifdef PCH
+							pop_local_mem_ctx();
+#else
+							rel_local();			/* release local symbols */
+#endif
+							global_flag = glob;
+						}
+#endif
+						break;
+				case id:
+				/*
+				 * If it is a typedef identifier, do the declaration.
+				 */
+						if ((sp = lastsp) != 0 && sp->storage_class == sc_typedef)
+								goto do_decl;
+						/* else fall through */
+						/*
+						 * If defclass == sc_global (we are outside any function), almost
+						 * anything can start a declaration, look, e.g. mined:
+						 * (*escfunc(c))() ,,almost anything'' is not exact: id (no
+						 * typedef id), star, or openpa.
+						 */
+				case openpa:
+				case star:
+						if (defclass == sc_global)
+								goto do_decl;
+						return;
+						/* else fall through to declare  */
+				case kw_char:
+				case kw_short:
+				case kw_unsigned:
+				case kw_long:
+				case kw_struct:
+				case kw_union:
+				case kw_enum:
+				case kw_void:
+				case kw_float:
+				case kw_double:
+				case kw_int:
+				case kw_typeof:
+				case kw_attr:
+				case kw_signed: case kw_const: case kw_volatile:
+do_decl:
+						if (defclass == sc_global)
+								(void) declare(&gsyms, sc_global, 0l, bt_struct, 0);
+						else if (defclass == sc_auto)
+								lc_auto +=
+								declare(&lsyms, sc_auto, lc_auto, bt_struct, regflag);
+						else			/* defclass == sc_parms (parameter decl.) */
+								slc +=
+								declare(&lsyms, sc_auto, slc, bt_struct, regflag + 2);
+						break;
+				case kw_static:
+						getsym();
+						if (defclass == sc_member)
+								error(ERR_ILLCLASS);
+						if (defclass == sc_auto)
+								(void) declare(&lsyms, sc_static, 0l, bt_struct, 0);
+						else
+								(void) declare(&gsyms, sc_static, 0l, bt_struct, 0);
+						break;
+				case kw_typedef:
+						getsym();
+						if (defclass == sc_member)
+								error(ERR_ILLCLASS);
+						if (defclass == sc_auto)
+								(void) declare(&lsyms, sc_typedef, 0l, bt_struct, 0);
+						else
+								(void) declare(&gsyms, sc_typedef, 0l, bt_struct, 0);
+						break;
+				case kw_extern:
+						getsym();
+						if (defclass == sc_member)
+								error(ERR_ILLCLASS);
+						if (defclass == sc_auto)
+								(void) declare(&lsyms, sc_external, 0l, bt_struct, 0);
+						else
+								(void) declare(&gsyms, sc_external, 0l, bt_struct, 0);
+						break;
+				default:
+						return;
+				}
+		}
+}
+
+int eq_type(TYP *tp1, TYP *tp2) {
+/*
+ * This is used to tell valid from invalid redeclarations
+ */
+	if (tp1 == 0 || tp2 == 0)
+		return 0;
+
+	if (tp1 == tp2)
+		return 1;
+
+	if (tp1->type != tp2->type)
+		return 0;
+
+	if (tp1->type == bt_pointer)
+		return eq_type(tp1->btp, tp2->btp);
+	if (tp1->type == bt_func) {
+		SYM *sp=tp1->lst.head,*sp2=tp2->lst.head;
+		if (!sp || !sp2)	// one is only a prototype : OK
+			return eq_type(tp1->btp, tp2->btp);
+		while (sp && sp2) {
+			/*
+			 * in vararg funcs we can have sp->tp==sp2->tp==NULL, but
+			 * eq_type(NULL,NULL) is 0 hence the first check
+			 */
+			if (sp->tp!=sp2->tp && !eq_type(sp->tp,sp2->tp))
+				return 0;
+			sp=sp->next; sp2=sp2->next;
+		}
+		if (sp || sp2) return 0;	// != # of args
+		return eq_type(tp1->btp, tp2->btp);
+	}
+	if (tp1->type == bt_struct || tp1->type == bt_union)
+		return (tp1->lst.head == tp2->lst.head);
+
+	return 1;
+}
+
+int indir_num(TYP *tp) {
+	int n=0;
+	while (tp->type == bt_pointer || tp->type == bt_func) {
+		n++;
+		tp=tp->btp;
+	}
+	return n;
+}
+
+static TYP *save_type(TYP *tp) {
+	TYP 		   *ret_tp;
+/* the type structure referenced by tp may be in local tables.
+   Copy it to global tables and return a pointer to it.
+ */
+	if (tp->st_flag)
+		return tp;
+	++global_flag;
+	ret_tp = (TYP *) xalloc((int) sizeof(TYP), _TYP+SV_TYPE);
+
+/* copy TYP structure */
+	*ret_tp = *tp;
+	ret_tp->st_flag = 1;
+
+	if (tp->type == bt_func || tp->type == bt_pointer)
+		ret_tp->btp = save_type(tp->btp);
+
+	if (tp->type == bt_struct || tp->type == bt_union) {
+		/*
+		 * It consumes very much memory to duplicate the symbol table, so we
+		 * don't do it. I think we needn't do it if it is in local tables, so
+		 * this warning is perhaps meaningless.
+		 */
+//		uwarn("didn't copy local struct/union in save_type");
+		ret_tp->lst.tail = ret_tp->lst.head = 0; ret_tp->lst.hash = 0;
+	}
+	--global_flag;
+	return ret_tp;
+}
+// vim:ts=4:sw=4

+ 378 - 0
gtc/src/define.h

@@ -0,0 +1,378 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * #define's
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+//#define SHOWSTEP
+
+#ifndef DEFINE_H
+#define DEFINE_H
+#if 0
+	#ifdef PC
+	#define debugcls() (void)0
+	#define debugf printf
+	#else
+	#define debugcls clrscr
+	extern int progr;
+	#define debugf(f...) (printf(f),progr_process(func_sp?func_sp->name:0,curname,progr),ngetchx())
+	#endif
+	#define debugfq printf
+#else
+	#define debugcls() (void)0
+	#if defined(PC) && !defined(__GNUC__)
+	/*@unused@*/ static void debugf(char *s,...) {}
+	/*@unused@*/ static void debugfq(char *s,...) {}
+	#else
+	#define debugf(f...) (void)0
+	#define debugfq(f...) (void)0
+	#endif
+#endif
+#if !defined(PC) || !defined(DEBUGGING)
+#define enum(tp) unsigned int // some compilers make enums signed, make them happy
+#else
+#define enum(tp) enum tp // we want nice debugging output
+#endif
+#define IS_VALID >=0
+#define IS_INVALID <0
+#define nxtlabel() (short)(nextlabel++)
+#ifdef AS
+	#define nxtglabel() (short)(glblabel++)
+#else
+	#define nxtglabel() (short)(nextlabel++)
+#endif
+#define local(__l) (__l>=0)
+#define global(__l) (((unsigned short)__l)<0xC000) // only valid if !local(__l)
+#define external(__l) (((unsigned short)__l)>=0xC000)
+#ifdef PC
+#define splbl(__sp) (__sp->value.splab?__sp->value.splab:(__sp->value.splab=label(__sp->name)))
+#else
+#define splbl(__sp) (__sp->value.splab?:(__sp->value.splab=label(__sp->name)))
+#endif
+#ifdef PC
+#define TWIN_COMPILE
+#endif
+#define DUAL_STACK	// save space on the stack by allocating on a temporary buffer just the size we need
+#ifdef PC
+#define OBJ_OUT
+#endif
+
+//#define INFINITE_REGISTERS // compile for a virtual machine with an arbitrarily high number of registers
+#ifdef DISABLE_OPTS
+#undef VCG
+#endif
+#define USE_WORDS_IN_SWITCH // use dc.w instead of dc.l in 'real' switch statements
+#define NEW_ATTR	// allows TI-GCC-like attribute declaration
+#ifdef PC
+#ifndef DISABLE_OPTS
+#define ADV_OPT		// is it worth the extra exe size & comp time ? => disabled on-calc
+#endif
+#endif
+#ifdef VCG
+#define GENERATE_ROL_ROR	// optimize (x<<12)|(x>>4) into a ror; depends on VCG because commutativity is not tested
+#endif
+//#define NO_ICONST_SCAN
+//#define ALTERNATE_HOOK
+#define OPT_ROMCALLS	// assumes that *(void **)0xC8 is never modified
+//#define DEFAULT_STKPARM
+#define TWOBYTE_ARRAY_EXTRA_OPT	// {add.w d3,a0;add.w d3,a0} instead of
+								// {move.w d3,d0;add.w d0,d0;add.w d0,a0}
+//#define AREG_AS_DREG	// some fine-tune should be done before this switch provides any benefit
+#define PREFER_POS_VALUES	// allows for better CSE collection (seems like there's a bug in
+							//  Optimize which is fixed or reduced by this switch too...)
+#define ADVANCED_TEMP_REGS	// to be fit one day in Gen68k in order to optimize free temp regs
+#if 0
+#define ADVANCED_MEMORY_MOVE	// optimize contiguous sequences of move's (< auto_init/g_fcall)
+								// (rather time-consuming, for very low consequences...
+								//   => disabled, even on PC)
+#endif
+#ifdef PC	// only valid on PC!
+#define REQ_MGT	// enable required files management
+#endif
+#define MULTIFILE	// enable multiple file support
+#define OPTIMIZED_AINCDEC_TEST	// allows for dbf too
+#define LONG_ADDS_IN_AREG	// so that lea can be used rather than addi.l
+//#define NO_OFFSET_AUTOCON	// useless as of now
+#define ADD_REDUNDANCY	// increases compression ratios at the cost of function-overhead speed
+#define REGALLOC_FOR_SIZE
+//#define HARDCORE_FOR_UNPACKED_SIZE	// favour size wherever possible, with little improvement
+								// of packed size and even more probably regression (lsl.w #2...)
+#define SPEED_OPT
+//#define speed_opt_value 1	// we may add n instruction before the bra (1 : useful for dbf)
+//#define G_CAST2	// this might remove some op_ext's : to be tested
+#define RAM_CALLS	// support for RAM_CALLs
+#ifdef PC
+#define FLINE_RC	// support for F-Line ROM_CALLs
+#endif
+#define SHORT_STRUCT_PASSING	// allows HSym to be defined as a structure
+#ifdef PC
+#define EXE_OUT		// output an EXE program (implementation incomplete)
+#endif
+#define NO_SECURE_POINTERS	// assert that all array accesses are less than 32kb
+//#define POP_OPT	// still buggy as of now
+#define NO_TRIVIAL_CASTS	// suppresses trivial en_cast's ; might add bugs, but not certain
+#define NO_VERYTRIVIAL_CASTS // suppresses obvious en_cast's ; was already there, but possibly buggy
+#define MID_DECL	// allows for powerful middle decl handler
+#define MINIMAL_SIZES	// so that (long)x>>(char)y won't be converted to (long)x>>(long)y
+//#define USE_SWAP_FOR_SHIFT16	// use op_swap wherever possible for shifts (buggy, FIXME)
+#define AUTOINIT_PAD	// pad auto_init statements ('side' requires this, for example)
+#define MACRO_PPDIR
+#define MEXP_SUPPORTS_PCH	// this is mandatory for TiGccLib's RR_* support.
+							//  The way speed is affected I don't know, but perhaps it's
+							//  faster with this option enabled... (slightly more PCH
+							//  searches, very slightly fewer HTable searches)
+							// Some tests should be performed about this.
+// TODO:
+// - add FAVOUR_RELATIVE_BSS directive so that once a BSS is CSE'd, all other BSS
+//  refer to it rather than to the classical BSS (what's more, CSE::scan should favour
+//  such optimizations by doing some sort of most_used_BSS_cse->desire += (other_BSS_cse's)>>1)
+//   This would allow for intensive use of BSS :)
+// - add RELATIVE_CSE directive so that when constantly using mylib__0000+2,
+//  CSE searches for all mylib__0000 occurrences and finds out that it's better to use
+//  mylib__0000+2 (replacing should take this into a count)
+//   -- but complicated and not *that* useful...
+#if !defined(NONSTD_MACRO_CONCAT) && !defined(NONSTD_MACRO_CONCAT_V2)
+#define STD_MACRO_CONCAT
+#endif
+#define EXT_AS_ID	// enabled since the dirty getch() management of .b/.w/.l is no more necessary
+#if defined(NOFLOAT) || !defined(BCDFLT)
+#define NOBCDFLT
+#endif
+#ifndef AS
+#ifdef AS92p
+#define FORBID_TABLES
+#endif
+#endif
+#define push_local_mem_ctx() { int _locsize=locsize,_locindx=locindx; \
+	struct blk *_locblk=locblk; locblk=0; locsize=0
+#define pop_local_mem_ctx() rel_local(); locsize=_locsize; locindx=_locindx; locblk=_locblk; }
+#define put_align(__a) put_align2()
+#ifdef VCG
+#define VCG_MAX 5
+#endif
+#ifdef EXE_OUT
+#ifdef PC
+//#ifndef _DEBUG
+#define SIZE_STATS	// include statistics to determine the part of code generated from C code
+//#endif
+#endif
+#endif
+#ifdef FLASH_VERSION
+#define HAS_CMDLINE_EXTENSION
+#endif
+#ifdef BIGSTACK
+	#define XLST_TYPE long
+	#define REG_PARAMS 0xF000
+	#define REG_PARAMLOG 12
+#else
+	#define XLST_TYPE int
+	/* limits the param size to 2 kb - not much of a problem ;) */
+	#define REG_PARAMS 0x7800
+	#define REG_PARAMLOG 11
+#endif
+#ifndef HAS_TI_SHORT
+#ifdef PC
+typedef struct {
+	unsigned char x0,x1,x2,x3;
+} TI_LONG;
+typedef struct {
+	unsigned char hi,lo;
+} TI_SHORT;
+#else
+typedef unsigned long TI_LONG;
+typedef unsigned short TI_SHORT;
+#endif
+#ifdef PC
+extern unsigned long _w2ul(TI_LONG *p);
+extern unsigned short _w2us(TI_SHORT *p);
+#define w2ul(x) _w2ul(&(x))
+#define w2us(x) _w2us(&(x))
+#else
+#define w2ul(x) (x)
+#define w2us(x) (x)
+#endif
+#endif
+#ifndef NOFLOAT
+#ifndef PC
+#ifndef BCDFLT
+#define double long
+#endif
+#endif
+#endif
+#ifndef NOBCDFLT
+#define BCDLEN 8
+typedef struct bcd {
+	unsigned short exponent;
+	unsigned char mantissa[BCDLEN];
+} BCD;
+#endif
+#ifdef PC
+	#define infunc(f) if (!strcmp(func_sp->name,f))
+	#define bkpt() printf("")
+	#define DB_POSSIBLE
+	#define DEBUG 1
+	#ifdef SHORT_INT
+		#define int short
+	#endif
+	#ifdef CMAIN_C
+		long alloc[3][0xE000];
+	#else
+		extern long alloc[][0xE000];
+	#endif
+	enum myEnum {
+		ANONYMOUS=0, COPYNODE=1, ENTERNODE=2, STRINGLIT=3, LITLATE=4,
+			STRSAVE=5, MK_TYPE=6, _DECLARE=7, DECLENUM=8, ENUMBODY=9,
+			DECLSTRUCT=0xA, SV_TYPE=0xB, MK_NODE=0xC, MK_ICON=0xD,
+			NAMEREF=0xE, FUNCBODY=0xF, MK_INT=0x10, MK_SCRATCH=0x11,
+			MK_LABEL=0x12, MK_IMMED=0x13, MK_OFFSET=0x14, COPY_ADDR=0x15,
+			G_DEREF=0x16, G_EXPR=0x17, MK_REG=0x18, MK_MASK=0x19,
+			MK_STRLAB=0x1A, GENLOOP=0x1B, G_CODE=0x1C, G_LABEL=0x1D,
+			DODEFINE=0x1E, G_PUSH=0x1F, TEMP_DATA=0x20, TEMP_ADDR=0x21,
+			SYMBOL=0x22, REF_ADD=0x23, LAB_ADD_REF=0x24, RT_ADD_REF=0x25,
+		ENODE=0x1000, CSE=0x2000, SLIT=0x3000, STR=0x4000, _TYP=0x5000,
+			_SYM=0x6000, AMODE=0x7000, OCODE=0x8000, _TABLE=0x9000,
+			SNODE=0xA000, _TAB=0xB000, _REF=0xC000, _RT=0xD000,
+	};
+	#define xalloc(s,c) (alloc[temp_mem?2:!!global_flag][(c)]+=(s)+((s)&1),_xalloc(((s)+3)&-4))
+	#define _FILE(x)
+	#define dseg() while (0)
+	#define cseg() while (0)
+	#define compound_done getsym
+	#ifdef _MSC_VER
+		#pragma warning (disable : 4033 4013 4716 4715 4133)
+		#pragma warning (disable : 4996) // strcpy/fopen/... are declared deprecated in VC++ 2005 :D
+		#ifdef SHORT_INT
+			#pragma warning (disable : 4305 4244 4761)
+		#endif
+	#endif
+	#ifdef SHORT_INT
+		#undef int
+	#endif
+	#define debug(x) ((void)0)
+	#include <memory.h>
+	#include <string.h>
+	#include <stdio.h>
+	#include <stdlib.h>
+	#include <ctype.h>
+	#ifndef _MSC_VER
+	#ifndef __MINGW32__
+	#include <alloca.h>
+	#else
+	#include <malloc.h>
+	#endif
+	#else
+	#define alloca _alloca
+	#endif
+	#ifdef SHORT_INT
+		#define int short
+	#endif
+	#ifndef max
+		#define max(a,b) ((a)>(b)?(a):(b))
+	#endif
+    #define getline getline_gtc
+	typedef size_t short_size;
+#else
+	#define infunc(f) if (0)
+	#define bkpt() {}
+	#define DB_POSSIBLE
+	#define DEBUG 0
+	#define xalloc(__s,__c) _xalloc(__s+(__s&1))
+	//#define _FILE(x) asm(".ascii \""x"\";.even");
+	#define _FILE(__x)
+	#define cached_sym (int)_cached_sym
+	#define AS92p
+	#ifndef CMAIN_C
+		#define NOSTUB
+		#define _rom_call(type,args,ind) (*(type(**)args)(*(long*)0xC8+0x##ind*4))
+	#else
+		#include	"lib_map.h"
+		#define USE_KERNEL
+		//#define USE_FULL_LONGMUL_PATCH
+		//#define USE_FULL_LONGDIV_PATCH
+		int _ti89;
+	#endif
+	#ifndef gtc_compiled
+		#include <tigcclib.h>
+	#else
+		#define FILE void
+		#define NULL (void *)0
+	#endif
+	#undef off
+	//#define stkparm
+  #ifndef FLASH_VERSION
+	#define debug(x) ((void)0)
+	#undef clrscr
+	#define clrscr gtcrt__0000
+	#undef printf
+	#define printf gtcrt__0001
+	#undef vcbprintf
+	#define vcbprintf gtcrt__0002
+	#undef fopen
+	#define fopen gtcrt__0008
+	FILE *fopen(const char *,const char *);
+	#undef fclose
+	#define fclose gtcrt__0009
+	#undef fputc
+	#define fputc gtcrt__000a
+	int fputc(int,FILE *);
+	#undef fgetc
+	#define fgetc gtcrt__000b
+	#undef fwrite
+	#define fwrite gtcrt__000c
+	int fwrite(void *,int,int,FILE *);
+	#undef fputs
+	#define fputs gtcrt__0010
+	#undef fgets
+	#define fgets gtcrt__0011
+	char *fgets(char *,int,FILE *);
+	#undef fprintf
+	#define fprintf gtcrt__0014
+  #else
+	#define debug(x) ((void)0)	// for flash ver
+    #undef fclose
+    #define fclose my_fclose // fix buggy fclose
+	void my_fclose(FILE *f);
+	#define OPTIMIZE_BSS
+	#define BSS_SIZE 8192
+  #endif	/* FLASH_VERSION */
+
+  typedef short short_size;
+
+	//#undef printf
+	//#undef fputchar
+	//#define printf print
+	//#define printf(f...) (((void(*)(void*,char*,...))prtf)(fputchar,##f))
+	//#define fputchar ((short(*)(char))ptch)
+#endif
+#ifndef FLASH_VERSION
+	#define CGLOB =0
+	#define CGLOBL ={0}
+	#define xstatic static
+	#define readonly
+#else
+	#define CGLOB
+	#define CGLOBL
+	#define xstatic
+	#define readonly const
+#endif
+
+#include "protos.h"
+#ifndef nl
+  void nl(void);
+#endif
+#ifndef PC
+char *__attribute__((stkparm)) sUnpack(char *in,char *out,char *dic);
+#else
+char *sUnpack(char *in,char *out,char *dic);
+#endif
+#endif
+// vim:ts=4:sw=4

+ 150 - 0
gtc/src/error.c

@@ -0,0 +1,150 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * error handling
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+/*#include "define.h"
+#include "c.h"
+#include "cglbdec.h"*/
+#include <stdarg.h>
+#include <setjmp.h>
+
+extern int pause_on_error;
+
+#ifndef GTDEV
+//#ifdef PC
+void _err_attr err_int(int m) {
+	clean_up();
+	msg2("\nAn internal error occurred (error ID #%04d)\n"
+		"Please report this bug to paul.froissart@libertysurf.fr\n",m);
+#ifdef PC
+	fflush(outstr);
+	if (pause_on_error)
+		getchar();
+	exit(16);
+#else
+	ngetchx();
+	exit(0);
+#endif
+}
+void err_usr(int m,...) {
+	va_list args;
+	va_start(args,m);
+#ifdef PC
+	if (verbose)
+#endif
+		msg("\nCompilation error:\n");
+	if (err_force_line IS_INVALID && err_assembly)
+		err_force_line=err_cur_line;
+	locate();
+	if (m==ERR_OTH) {
+		char *s=va_arg(args,char *);
+		vmsg(s,args);
+	} else
+		vmsg((char *)__err[m],args);
+	msg("\n");
+	va_end(args);
+	clean_up();
+#ifdef PC
+	fflush(outstr);
+	if (pause_on_error)
+		getchar();
+	exit(16);
+#else
+	ngetchx();
+	exit(0);
+#endif
+}
+void _err_attr warn_int(int m) {
+	msg2("\nAn unexpected event occurred (event ID #%04d)\n"
+		"It might be possible to continue, but the generated code may "
+		"contain bugs.\nDo you want to continue [y/n]?",m);
+#ifdef PC
+	fflush(outstr);
+	if ((pause_on_error && (msg("\nn\n"),1)) || getchar()=='n') {
+		clean_up();
+		exit(16);
+	}
+	msg("\n");
+#else
+	while (!kbhit());
+	if (ngetchx()=='n') {
+		clean_up();
+		exit(0);
+	} else msg("\n");
+#endif
+}
+void warn_usr(char *s,...) {
+	va_list args;
+	va_start(args,s);
+	locate();
+	msg("warning: ");
+	vmsg(s,args);
+	msg("\n");
+	va_end(args);
+}
+//#endif
+#else
+void _err_attr error_do(char *msg,int type) {
+	char _func[100],file[40];
+	char *func=0;
+	int line,chr=0;
+	if (func_sp) strcpy(func=_func,func_sp->name);
+	strcpy(file,curname);
+	if (err_force_line IS_INVALID && err_assembly)
+		err_force_line=err_cur_line;
+	if (err_force_line IS_VALID)
+		line=err_force_line;
+	else line=lineno,chr=0/*to be improved*/;
+	if (et_iserror(type))
+		clean_up();
+	msg_process(msg,type,func,file,line,chr);
+	if (et_iserror(type))
+		exit(0);
+}
+void _noreturn assert_terminated();
+asm("assert_terminated:\n rts\n");
+void _err_attr err_int(int m) {
+	char b[30];
+	sprintf(b,"error ID #%04d",m);
+	error_do(b,ET_INTERNAL_FAILURE);
+	assert_terminated();
+}
+void err_usr(int m,...) {
+	va_list args;
+	va_start(args,m);
+	char b[200];
+	if (m==ERR_OTH) {
+		char *s=va_arg(args,char *);
+		vsprintf(b,s,args);
+	} else
+		vsprintf(b,(char *)__err[m],args);
+	va_end(args);
+	error_do(b,ET_ERROR);
+	assert_terminated();
+}
+void _err_attr warn_int(int m) {
+	char b[30];
+	sprintf(b,"event ID #%04d",m);
+	error_do(b,ET_INTERNAL_WARNING);
+}
+void warn_usr(char *s,...) {
+	va_list args;
+	va_start(args,s);
+	char b[200];
+	vsprintf(b,s,args);
+	va_end(args);
+	error_do(b,ET_WARNING);
+}
+#endif
+// vim:ts=4:sw=4

+ 58 - 0
gtc/src/error.h

@@ -0,0 +1,58 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * error handling
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define error(x) uerr(x)
+#define ierr(f,n) err_int(((FUNC_##f)<<8)+n)
+#define uerr err_usr
+#define uerrc(m) uerr(ERR_OTH,m)
+#define uerrc2(m,a) uerr(ERR_OTH,m,a)
+#define uerrc3(m,a,b) uerr(ERR_OTH,m,a,b)
+#define uerrsys(m) uerr(ERR_SYS,m)
+#define iwarn(f,n) warn_int(((FUNC_##f)<<8)+n)
+#define uwarn warn_usr
+
+#ifdef PC
+#define _noreturn
+#define _err_attr
+#else
+#define _noreturn __attribute__((noreturn))
+#define _err_attr
+//#define _err_attr __attribute__((regparm(1)))
+#endif
+
+void _noreturn              fatal(char *message);
+void _noreturn _err_attr	err_int(int e);
+void _noreturn				err_usr(int e,...);
+void _err_attr				warn_int(int w);
+void						warn_usr(char *w,...);
+
+// rules for adding new items : add them *ALWAYS* at the end
+enum {
+	FUNC_NONE=0,
+	
+/*$01*/	FUNC_ALIGNMENT, FUNC_MK_LEGAL, FUNC_COPY_ADDR, FUNC_G_DEREF, FUNC_G_UNARY,
+/*$06*/	FUNC_G_ADDSUB, FUNC_G_DIV, FUNC_G_MOD, FUNC_G_MUL, FUNC_G_HOOK, FUNC_G_ASADD,
+/*$0C*/	FUNC_G_ASXOR, FUNC_G_ASSHIFT, FUNC_G_ASMUL, FUNC_G_ASDIV, FUNC_G_ASMOD, FUNC_G_AINCDEC,
+/*$12*/	FUNC_G_PARMS, FUNC_REGPARM, FUNC_FUNC_RESULT, FUNC_G_CAST, FUNC_G_EXPR, FUNC_G_COMPARE,
+/*$18*/	FUNC_TRUEJP, FUNC_FALSEJP, FUNC_GENLOOP, FUNC_GENRETURN, FUNC_GENSTMT, FUNC_ADD_CODE, 
+/*$1E*/	FUNC_ASM_GETSYM, FUNC_LISTING, FUNC_OPT0, FUNC_PASS3, FUNC_UNINIT_TEMP, __FUNC_UNUSED1,
+/*$24*/	FUNC_G_CODE, FUNC_PEEP_DELETE, FUNC_G_PUSH, FUNC_G_POP, FUNC_CHECKSTACK, FUNC_TEMP_DATA, 
+/*$2A*/	FUNC_TEMP_ADDR, FUNC_FREEOP, FUNC_DOOPER, FUNC_PEEP_LABEL, FUNC_BBLK_INIT,
+
+/*$2F*/	FUNC_LINK_MISPL, FUNC_TABLE_HASH,
+/*$31*/	FUNC_WARN_LC_STK,
+
+};
+// vim:ts=4:sw=4

+ 2157 - 0
gtc/src/expr.c

@@ -0,0 +1,2157 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * expressions
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define DECLARE
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifndef NOFLOAT
+#include	"ffplib.h"
+#endif
+#ifdef PC
+#ifdef SHORT_INT
+#undef int
+#endif
+#include		<ctype.h>
+#ifdef SHORT_INT
+#define int short
+#endif
+#else
+#include "define.h"
+#endif
+
+long inittype();
+
+unsigned char sizeof_flag CGLOB;
+unsigned char id_are_zero CGLOB;
+#ifdef MID_DECL_IN_EXPR
+struct enode	 *md_expr CGLOB;
+struct typ		 *md_type CGLOB;
+#endif
+/*
+ * expression evaluation
+ *
+ * this set of routines builds a parse tree for an expression. no code is
+ * generated for the expressions during the build, this is the job of the
+ * codegen module. for most purposes expression() is the routine to call. it
+ * will allow all of the C operators. for the case where the comma operator
+ * is not valid (function parameters for instance) call exprnc().
+ *
+ * each of the routines returns a pointer to a describing type structure. each
+ * routine also takes one parameter which is a pointer to an expression node
+ * by reference (address of pointer). the completed expression is returned in
+ * this pointer. all routines return either a pointer to a valid type or NULL
+ * if the hierarchy of the next operator is too low or the next symbol is not
+ * part of an expression.
+ */
+
+static TYP *primary();
+static TYP *unary();
+static TYP *multops();
+static TYP *addops();
+#ifndef isscalar
+static int isscalar();
+#endif
+TYP *force_cast_op();
+
+int not_lvalue(struct enode *node) {
+	while (node->nodetype==en_cast) node=node->v.p[0];
+	return node->nodetype-en_ref;
+}
+
+struct enode *mk_node(enum(e_node) nt, struct enode *v1, struct enode *v2) {
+/*
+ * build an expression node with a node type of nt and values v1 and v2.
+ */
+	struct enode   *ep;
+	ep = (struct enode *) xalloc((int) sizeof(struct enode), ENODE+MK_NODE);
+	ep->nodetype = nt;
+	ep->etype = bt_void;
+	ep->esize = -1;
+	ep->v.p[0] = v1;
+	ep->v.p[1] = v2;
+	return ep;
+}
+
+struct enode *mk_icon(long i) {
+/*
+ * build an expression node forming an integer constant
+ */
+	struct enode   *ep;
+/*	if (i==0x4E0003)
+		__HALT;*/
+/*	if (global_flag && !temp_mem)
+		printf("gfdiog");*/
+//	ep = (struct enode *) xalloc((int) sizeof(struct enode), ENODE+MK_ICON);
+	ep = (struct enode *) xalloc((int) sizeof(struct xcon), ENODE+MK_ICON);
+	ep->nodetype = en_icon;
+	ep->etype = bt_void;
+#ifdef NO_CALLOC
+	ep->esize = 0;
+#endif
+	ep->v.i = i;
+	return ep;
+}
+
+TYP *deref(struct enode **node, TYP *tp) {
+/*
+ * build the proper dereference operation for a node using the type pointer
+ * tp.
+ */
+	switch (tp->type) {
+	  case bt_void:
+	  case bt_char:
+	  case bt_uchar:
+	  case bt_short:
+	  case bt_ushort:
+	  case bt_long:
+	  case bt_pointer:
+	  case bt_ulong:
+	  case bt_struct:
+	  case bt_union:
+	  case bt_float:
+#ifdef DOUBLE
+	  case bt_double:
+#endif
+		*node = mk_node(en_ref, *node, NIL_ENODE);
+		(*node)->etype = tp->type;
+		(*node)->esize = tp->size;
+		break;
+	  case bt_bitfield:
+		*node = mk_node(en_fieldref, *node, NIL_ENODE);
+		(*node)->bit_width = tp->bit_width;
+		(*node)->bit_offset = tp->bit_offset;
+		/*
+		 * maybe it should be 'unsigned'
+		 */
+		(*node)->etype = tp_int.type;
+		(*node)->esize = tp_int.size;
+		tp = (TYP *)&tp_int;
+		break;
+	  default:
+		error(ERR_DEREF);
+		break;
+	}
+	return tp;
+}
+
+TYP *cond_deref(struct enode **node, TYP *tp) {
+	TYP 		   *tp1;
+	/*
+	 * dereference the node if val_flag is zero. If val_flag is non_zero and
+	 * tp->type is bt_pointer (array reference), set the size field to the
+	 * pointer size (if this code is not executed on behalf of a sizeof
+	 * operator)
+	 */
+
+/*	infunc("chk_curword")
+		bkpt();*/
+	if (tp->val_flag == 0)
+		return deref(node, tp);
+	if (tp->type == bt_pointer && sizeof_flag == 0) {
+		tp1 = tp->btp;
+		tp = mk_type(bt_pointer, 4);
+		tp->btp = tp1;
+	}
+	return tp;
+}
+
+TYP *nameref(struct enode **node) {
+/*
+ * nameref will build an expression tree that references an identifier. if
+ * the identifier is not in the global or local symbol table then a
+ * look-ahead to the next character is done and if it indicates a function
+ * call the identifier is coerced to an external function name. non-value
+ * references generate an additional level of indirection.
+ */
+	struct sym	   *sp;
+	TYP 		   *tp;
+	sp = lastsp;
+	if (sp == 0) {
+		getcache(id);
+		if (cached_sym == openpa && !cached_flag) {
+			uwarn("function '%s' not defined; assuming extern returning int", lastid);
+			++global_flag;
+			sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+NAMEREF);
+			sp->tp = (TYP *)&tp_func;
+			sp->name = strsave(lastid);
+			sp->storage_class = sc_external;
+			append(&sp, &gsyms);
+			--global_flag;
+			tp = (TYP *)&tp_func;
+			*node = mk_node(en_nacon, NIL_ENODE, NIL_ENODE);
+			(*node)->v.ensp = sp->name;
+#ifdef AS
+			(*node)->v.enlab = splbl(sp);
+#endif
+			sp->used = 1;
+			(*node)->etype = bt_pointer;
+			(*node)->esize = 4;
+			if (asm_zflag) (*node)->etype = bt_ulong;
+		} else {
+			if (lastid[0]=='_' && lastid[1]=='R' && !strncmp(lastid+3,"M_CALL_",7)) {
+				++global_flag;
+				sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+NAMEREF);
+				sp->tp = (TYP *)&tp_void_ptr;
+				sp->name = strsave(lastid);
+				sp->storage_class = sc_external;
+				append(&sp, &gsyms);
+				--global_flag;
+				goto ok_sp;
+			} else {
+				if (!asm_xflag) {
+					tp = 0;
+					uerr(ERR_UNDEFINED,lastid);
+				} else {
+					tp = (TYP *)&tp_ulong;
+					*node = mk_node(en_nacon, NIL_ENODE, NIL_ENODE);
+					(*node)->v.ensp = strsave(lastid);
+		#ifdef AS
+					(*node)->v.enlab = label(lastid);
+		#endif
+					(*node)->etype = bt_ulong;
+					(*node)->esize = 4;
+				}
+			}
+		}
+	} else {
+	  ok_sp:
+		if ((tp = sp->tp) == 0) {
+			uerr(ERR_UNDEFINED,lastid);
+			return 0;			/* guard against untyped entries */
+		}
+		switch (sp->storage_class) {
+		  case sc_static:
+			*node = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+#ifdef AS
+			(*node)->v.enlab = splbl(sp);
+#else
+			(*node)->v.enlab = sp->value.i;
+#endif
+			(*node)->etype = bt_pointer;
+			(*node)->esize = 4;
+			break;
+		  case sc_global:
+		  case sc_external:
+			*node = mk_node(en_nacon, NIL_ENODE, NIL_ENODE);
+			(*node)->v.ensp = sp->name;
+#ifdef AS
+			(*node)->v.enlab = splbl(sp);
+#endif
+			sp->used = 1;
+			(*node)->etype = bt_pointer;
+			(*node)->esize = 4;
+			break;
+		  case sc_const:
+			*node = mk_icon((long) sp->value.i);
+			(*node)->etype = tp_econst.type;
+			(*node)->esize = tp_econst.size;
+			break;
+		  default:				/* auto and any errors */
+			if (sp->storage_class != sc_auto)
+				error(ERR_ILLCLASS);
+			*node = mk_node(en_autocon, NIL_ENODE, NIL_ENODE);
+			(*node)->v.i = sp->value.i;
+			(*node)->etype = bt_pointer;
+			(*node)->esize = 4;
+/*			infunc("chk_curword")
+				if (sp->value.i==(long)(char)0xCF)
+					bkpt();*/
+/*			infunc("chk_curword")
+				if (*(long *)node==0x7b4bf8)
+					bkpt();*/
+			break;
+		}
+		if (asm_zflag) {
+			if ((*node)->etype == bt_pointer)
+				(*node)->etype = bt_ulong;
+			if (tp->type == bt_pointer || tp->type == bt_struct || tp->type == bt_union)
+				tp = (TYP *)&tp_ulong;
+		} else tp = cond_deref(node, tp);
+	}
+	getsym();
+	return tp;
+}
+
+#ifndef NO_VARARG_FUNC
+extern char variable_arg_name[];
+#define is_variable_arg(sp) ((sp)->name==variable_arg_name)
+#define mk_variable_arg(sp) ((sp)->name=variable_arg_name)
+#endif
+
+struct enode *parmlist(SYM *f) {
+/*
+ * parmlist will build a list of parameter expressions in a function call and
+ * return a pointer to the last expression parsed. since parameters are
+ * generally pushed from right to left we get just what we asked for...
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp;
+	ep1 = 0;
+	if (lastst != closepa)
+		for (;;) {
+			tp = exprnc(&ep2);		/* evaluate a parameter */
+			if (tp == 0)
+				error(ERR_EXPREXPECT);
+#ifdef INTEL_386
+			/* trap struct assigns */
+			if (isaggregate(tp))
+				uses_structassign=1;
+#endif
+			/*
+			 * do the default promotions
+			 */
+			if (f) {
+				if (tp->const_flag && f->tp->type==bt_pointer && !f->tp->btp->const_flag)
+					uwarn("read-only arg might be modified by function");
+				tp = cast_op(&ep2, tp, f->tp);
+			}
+#ifndef NOFLOAT
+#ifdef DOUBLE
+			if (tp->type == bt_float)
+				tp = cast_op(&ep2, tp, (TYP *)&tp_double);
+#endif
+#endif
+			if (short_option) {
+				if (tp->type == bt_char || tp->type == bt_uchar)
+					(void) cast_op(&ep2, tp, (TYP *)&tp_short);
+			} else {
+				if (tp->type == bt_uchar || tp->type == bt_char ||
+						tp->type == bt_short || tp->type == bt_ushort)
+					(void) cast_op(&ep2, tp, (TYP *)&tp_long);
+			}
+			ep1 = mk_node(en_void, ep2, ep1);
+			if (lastst != comma)
+				break;
+			getsym();
+			if (f && !(f=f->next)) error(ERR_TOOMPARAMS);
+#ifndef NO_VARARG_FUNC
+			if (f && is_variable_arg(f)) f=NULL;	// switch to K&R mode for variable args...
+#endif
+		}
+	if (f && f->next && !is_variable_arg(f->next)) error(ERR_TOOFPARAMS);
+	return ep1;
+}
+
+int castbegin(enum(e_sym) st) {
+/*
+ * return 1 if st in set of [ kw_char, kw_short, kw_long, kw_float,
+ * kw_double, kw_struct, kw_union ] CVW change: or kw_void CVW change: or an
+ * type identifier
+ */
+	if (st == kw_char || st == kw_short || st == kw_int ||
+		st == kw_long || st == kw_float || st == kw_double ||
+		st == kw_struct || st == kw_union || st == kw_unsigned ||
+		st == kw_void || st == kw_enum || st == kw_typeof ||
+		st == kw_signed || st == kw_const || st == kw_volatile)
+		return 1;
+	if (st == id && lastsp != 0 &&
+		lastsp->storage_class == sc_typedef)
+		return 1;
+	return 0;
+}
+
+static TYP *primary(struct enode **node) {
+/*
+ * primary will parse a primary expression and set the node pointer returning
+ * the type of the expression parsed. primary expressions are any of:
+ * id
+ * constant
+ * string
+ * ( expression )
+ * primary[ expression ]
+#ifndef OLD_PRIOR
+ * primary++
+ * primary--
+#endif
+ * primary.id
+ * primary->id
+ * primary( parameter list )
+ * -- or just a semicolon, yields empty expression --
+ *
+ */
+	struct enode   *pnode, *qnode, *rnode;
+	struct sym	   *sp;
+	TYP 		   *tptr;
+	TYP 		   *tp1,*tp2;
+	switch (lastst) {
+
+	  case id:
+		if (id_are_zero) {
+			pnode = mk_icon(0l);
+			tptr = (TYP *)&tp_long;			// dans #if, le type par défaut est 'long'
+			pnode->etype = tp_long.type;
+			pnode->esize = tp_long.size;
+			getsym();
+			break;
+		}
+		tptr = nameref(&pnode);
+		if (tptr == 0)
+			break;
+		/*
+		 * function names alone are pointers to functions.
+		 * If followed by '(', the reference is stripped off
+		 * later.
+		 */
+		if (tptr->type == bt_func) {
+		   tp1 = mk_type(bt_pointer, 4);
+		   tp1->btp = tptr;
+		   tptr = tp1;
+		}
+		break;
+	  case iconst:
+	  case uconst:
+	  case lconst:
+	  case ulconst:
+		pnode = mk_icon(0l);
+		pnode->v.i = ival;
+		if (lastst == uconst) {
+			tptr = (TYP *)&tp_uint;
+			pnode->etype = tp_uint.type;
+			pnode->esize = tp_uint.size;
+		} else if (lastst == lconst) {
+			tptr = (TYP *)&tp_long;
+			pnode->etype = bt_long;
+			pnode->esize = 4;
+		} else if (lastst == ulconst) {
+			tptr = (TYP *)&tp_ulong;
+			pnode->etype = bt_ulong;
+			pnode->esize = 4;
+		} else {
+			tptr = (TYP *)&tp_int;
+			pnode->etype = tp_int.type;
+			pnode->esize = tp_int.size;
+		}
+		getsym();
+		break;
+#ifndef NOFLOAT
+	  case rconst:
+		tptr = (TYP *)&tp_double;
+		pnode = mk_node(en_fcon, NIL_ENODE, NIL_ENODE);
+		pnode->v.f = rval;
+		pnode->etype = tp_double.type;
+		pnode->esize = tp_double.size;
+		getsym();
+		break;
+#endif
+	  case sconst:
+		if (sizeof_flag) {
+			tptr = mk_type(bt_pointer, 0);
+			tptr->size = lstrlen + 1;
+			tptr->btp = (TYP *)&tp_char;
+			tptr->val_flag = 1;
+		} else
+			tptr = (TYP *)&tp_string;
+		pnode = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+		if (sizeof_flag == 0)
+			pnode->v.enlab = stringlit(laststr, lstrlen);
+		pnode->etype = bt_pointer;
+		pnode->esize = 4;
+		getsym();
+		break;
+	  case kw_softcast:
+		getsym();
+		if (!castbegin(lastst)) {
+			error(ERR_SYNTAX);
+			tptr = 0; // just to avoid a compiler warning =)
+		} else {
+			struct typ *local_head = head, *local_tail=tail;
+			decl((HTABLE *)NULL);	/* do cast declaration */
+			decl1();
+			tptr = head;
+			needpunc(closepa);
+			if (!(tp1 = unary(&pnode))) {
+				error(ERR_IDEXPECT);
+				tptr = 0;
+			} else
+				/* do the cast */
+				tptr = cast_op(&pnode, tp1, tptr);
+			head = local_head;
+			tail = local_tail;
+		}
+		break;
+	  case openpa:
+		getsym();
+		if (!castbegin(lastst)) {
+			if (lastst==begin) {	/* compound expression */
+				struct snode *snp;
+				struct enode *old_init_node = init_node;
+				int old_middle_decl = middle_decl;
+				getsym();
+				init_node = 0;
+				middle_decl = 0;
+				snp = compound(0);
+				init_node = old_init_node;
+				middle_decl = old_middle_decl;
+				tptr = lastexpr_tp;
+				pnode = mk_node(en_compound, (struct enode *)snp, NIL_ENODE);
+				pnode->etype=lastexpr_type;
+				pnode->esize=lastexpr_size;
+			} else tptr = expression(&pnode);
+			needpunc(closepa);
+		} else {				/* cast operator or middle declaration */
+			struct typ *local_head = head, *local_tail=tail;
+#ifdef MID_DECL_IN_EXPR
+			struct enode *old_md_expr = md_expr;
+			struct typ *old_md_type = md_type;
+			md_expr = 0;
+			middle_decl++;
+			dodecl(sc_auto);		/* if it's a real cast, same as decl(NULL);decl1(); */
+			middle_decl--;
+#else
+			decl((HTABLE *)NULL);	/* do cast declaration */
+			decl1();
+#endif
+			tptr = head;
+			needpunc(closepa);
+#ifdef MID_DECL_IN_EXPR
+			if ((pnode = md_expr))
+				tptr = md_type;	/* we can't use head since parsing md_expr might change it */
+			md_expr = old_md_expr;
+			md_type = old_md_type;
+			if (pnode)
+				break;
+#endif
+			if (lastst==begin) {	/* cast constructor */
+				int lab=nxtlabel();
+				TYP *tp=tptr;
+				nl();
+				dseg();
+				put_align(alignment(tptr));
+				put_label(lab);
+				inittype(tp,&tp);
+				pnode = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+				pnode->v.enlab=lab;
+				pnode->etype=bt_pointer;
+				pnode->esize=4;
+				tptr=cond_deref(&pnode,tp);
+			} else if ((tp1 = unary(&pnode)) == 0) {
+				error(ERR_IDEXPECT);
+				tptr = 0;
+			} else {
+				/* do the cast */
+				tptr = force_cast_op(&pnode, tp1, tptr);
+			}
+			head = local_head;
+			tail = local_tail;
+		}
+		break;
+	  default:
+		tptr=0;
+		break;
+	}
+	if (tptr == 0)
+		return 0;
+	for (;;) {
+		switch (lastst) {
+		  case openbr:			/* build a subscript reference */
+			getsym();
+/*
+ * a[b] is defined as *(a+b), such exactly one of (a,b) must be a pointer
+ * and one of (a,b) must be an integer expression
+ */
+			if (tptr->type == bt_pointer) {
+				tp2 = expression(&rnode);
+				tp1 = tptr;
+			} else {
+				tp2 = tptr;
+				rnode = pnode;
+				tp1 = expression(&pnode);
+				tptr = tp1;
+			}
+
+/*
+ * now, pnode and tp1 describe the pointer,
+ *		rnode and tp2 describe the integral value
+ */
+
+			if (tptr->type != bt_pointer)
+				error (ERR_NOPOINTER);
+			else
+				tptr = tptr->btp;
+
+			if (tptr->size==1) {	/* doing this : 1) saves RAM; 2) allows file_ESI[filesize] */
+				cast_op(&rnode, tp2, (TYP *)&tp_long);	/*			(even with fast_array on)  */
+				cast_op(&rnode, (TYP *)&tp_long, tp1);
+				qnode=rnode;
+			} else {
+				qnode = mk_icon((long) tptr->size);
+	#ifdef NO_SECURE_POINTERS
+				qnode->etype = bt_short;
+				qnode->esize = 2;
+	#else
+				qnode->etype = bt_long;
+				qnode->esize = 4;
+	#endif
+	/*
+	 * qnode is the size of the referenced object
+	 */
+	#ifdef NO_SECURE_POINTERS
+				cast_op(&rnode, tp2, (TYP *)&tp_short);
+	#else
+				cast_op(&rnode, tp2, (TYP *)&tp_long);
+	#endif
+				/*
+				 * we could check the type of the expression here...
+				 */
+	#ifdef NO_SECURE_POINTERS
+				qnode = mk_node(en_mul, qnode, rnode);
+				qnode->etype = bt_short;
+				qnode->esize = 2;
+				cast_op(&qnode, (TYP *)&tp_short, (TYP *)&tp_long);
+				cast_op(&qnode, (TYP *)&tp_long, tp1);
+	#else
+				qnode = mk_node(en_mul, qnode, rnode);
+				qnode->etype = bt_long;
+				qnode->esize = 4;
+				cast_op(&qnode, (TYP *)&tp_long, tp1);
+	#endif
+			}
+			pnode = mk_node(en_add, pnode, qnode);
+//			pnode = mk_node(en_add, qnode, pnode);
+			pnode->etype = bt_pointer;
+			pnode->esize = 4;
+			tptr = cond_deref(&pnode, tptr);
+			needpunc(closebr);
+			break;
+		  case pointsto:
+			if (tptr->type != bt_pointer)
+				error(ERR_NOPOINTER);
+			else
+				tptr = tptr->btp;
+			/*
+			 * tptr->type should be bt_struct or bt_union tptr->val_flag
+			 * should be 0 the ref node will be stripped off in a minute
+			 */
+			tptr = cond_deref(&pnode, tptr);
+			/*
+			 * fall through to dot operation
+			 */
+		  case dot:
+			getsym();			/* past -> or . */
+			if (lastst != id)
+				error(ERR_IDEXPECT);
+			else {
+				if (tptr->type!=bt_struct && tptr->type!=bt_union)
+					uerrc("not a structure/union");
+				{
+				TABLE *tab=&tptr->lst;
+				long offs=0;
+			search_again:
+				sp = search(lastid, lastcrc, (HTABLE *)tab);
+				if (sp == 0) {
+					sp = search("__unnamed__", -1, (HTABLE *)tab);
+					if (!sp || (sp->tp->type!=bt_union && sp->tp->type!=bt_struct))
+						uerr(ERR_NOMEMBER,lastid);
+					else {
+						offs += sp->value.i;
+						tab = &sp->tp->lst;
+						goto search_again;
+					}
+				} else {
+					/* strip off the en_ref node on top */
+					if (lvalue(pnode))
+						pnode = pnode->v.p[0];
+					else {
+						pnode = mk_node(en_deref, pnode, NIL_ENODE);
+						pnode->etype = bt_pointer;
+						pnode->esize = 4;
+					}
+					tptr = sp->tp;
+					qnode = mk_icon((long) (offs+sp->value.i));
+					qnode->etype = bt_long;
+					qnode->esize = 4;
+					pnode = mk_node(en_add, pnode, qnode);
+					pnode->etype = bt_pointer;
+					pnode->esize = 4;
+					tptr = cond_deref(&pnode, tptr);
+				}
+				}
+				getsym();		/* past id */
+			}
+			break;
+		  case openpa:			/* function reference */
+#ifdef ASM
+#ifndef OLD_AMODE_INPUT
+			if (asm_zflag) goto fini;
+#endif
+#endif
+			getsym();
+			/*
+			 *	the '*' may be ommitted with pointers to functions
+			 *	we have included another indirection (see above, case id:)
+			 */
+			if (tptr->type == bt_pointer)
+				tptr = tptr->btp;
+			if (tptr->type != bt_func)
+				error(ERR_NOFUNC);
+
+			/*
+			 * This hack lets us remember that this function itself calls
+			 * other functions.
+			 * The code generator might use this information to generate
+			 * safer register-pop-off code.
+			 */
+			is_leaf_function = 0;
+
+			pnode = mk_node(en_fcall, pnode, parmlist(tptr->lst.head));
+#ifdef REGPARM
+			pnode->rp_dn = tptr->rp_dn;
+			pnode->rp_an = tptr->rp_an;
+#endif
+			tptr = tptr->btp;
+			pnode->etype = tptr->type;
+			pnode->esize = tptr->size;
+			needpunc(closepa);
+			break;
+		  case autoinc:
+		  case autodec:
+			if (g_lvalue(pnode)) {
+				qnode = mk_icon((tptr->type==bt_pointer?(long)tptr->btp->size:1L));
+				pnode = mk_node(lastst==autoinc?en_ainc:en_adec, pnode, qnode);
+				pnode->etype = tptr->type;
+				pnode->esize = tptr->size;
+			} else
+				error(ERR_LVALUE);
+			getsym();
+			break;
+		  default:
+			goto fini;
+		}
+	}
+fini:
+	*node = pnode;
+	return tptr;
+}
+
+static TYP *unary(struct enode **node) {
+/*
+ * unary evaluates unary expressions and returns the type of the expression
+ * evaluated. unary expressions are any of:
+ *
+ * primary
+#ifdef OLD_PRIOR
+ * primary++
+ * primary--
+#endif
+ * !unary
+ * ~unary
+ * ++unary
+ * --unary
+ * -unary
+ * *unary
+ * &unary
+ * (typecast)unary
+ * sizeof(typecast)
+ * sizeof unary
+ *
+ */
+	TYP 		   *tp, *tp1;
+	struct enode   *ep1, *ep2;
+	int 			flag;
+//	long			i;
+	flag = 0;
+	switch (lastst) {
+	  case autodec:
+		flag = 1;
+		/* fall through to common increment */
+	  case autoinc:
+		getsym();
+		tp = unary(&ep1);
+		if (tp == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		if (g_lvalue(ep1)) {
+			if (tp->type == bt_pointer)
+				ep2 = mk_icon((long) tp->btp->size);
+			else {
+				ep2 = mk_icon(1l);
+				if (!integral(tp))
+					error(ERR_INTEGER);
+			}
+
+			ep2->etype = bt_long;
+			ep2->esize = 4;
+			ep1 = mk_node(flag ? en_assub : en_asadd, ep1, ep2);
+			ep1->etype = tp->type;
+			ep1->esize = tp->size;
+		} else
+			error(ERR_LVALUE);
+		break;
+	  case minus:
+		getsym();
+		tp = unary(&ep1);
+		if (tp == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		ep1 = mk_node(en_uminus, ep1, NIL_ENODE);
+		ep1->etype = tp->type;
+		ep1->esize = tp->size;
+		break;
+	  case not:
+		getsym();
+		tp = unary(&ep1);
+		if (tp == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		if (!bt_comparable(tp->type))
+			uerrc("cannot test expression");
+		ep1 = mk_node(en_not, ep1, NIL_ENODE);
+		tp = (TYP *)&tp_int;
+		ep1->etype = tp_int.type;
+		ep1->esize = tp_int.size;
+		break;
+	  case compl:
+		getsym();
+		tp = unary(&ep1);
+		if (tp == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		ep1 = mk_node(en_compl, ep1, NIL_ENODE);
+		ep1->etype = tp->type;
+		ep1->esize = tp->size;
+		if (!integral(tp))
+			error(ERR_INTEGER);
+		break;
+	  case star:
+		getsym();
+		tp = unary(&ep1);
+		if (tp == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		if (tp->type!=bt_pointer)
+			error(ERR_DEREF);
+		else
+			tp = tp->btp;
+		tp = cond_deref(&ep1, tp);
+		break;
+	  case and:
+		getsym();
+		/*if (lineid==0x216)
+			bkpt();*/
+		tp = unary(&ep1);
+		if (tp == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		if (lvalue(ep1)) {	/* TODO: adapt this to g_lvalue */
+/*			if (ep1->nodetype==en_cast	*/
+			ep1 = ep1->v.p[0];
+			tp1 = mk_type(bt_pointer, 4);
+			tp1->st_flag = 0;
+			tp1->btp = tp;
+			tp = tp1;
+		} else if (tp->type == bt_pointer && tp->btp->type == bt_func) {
+			uwarn("'&' operator ignored");
+		} else
+			error(ERR_LVALUE);
+		break;
+	  case kw_c: {
+		int zf=asm_zflag;
+		asm_zflag=0;
+		getsym();
+		needpunc(openpa);
+		tp=expression(&ep1);
+		asm_zflag=zf;
+		needpunc(closepa);
+	   } break;
+	  case kw_defined:
+		skipspace();
+		{ int parenth=0;
+		if (lastch=='(') getch(),parenth=1;
+		skipspace();
+		if ((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z')
+			|| lastch=='_' || lastch=='$') {
+			getidstr();
+			ep1=mk_icon((long)!!search(lastid,lastcrc,&defsyms));
+			tp = (TYP *)&tp_int;
+			ep1->etype = tp_int.type;
+			ep1->esize = tp_int.size;
+			getsym();
+		} else {
+			error(ERR_IDEXPECT);
+			tp = 0; // just to avoid a compiler warning =)
+		}
+		if (parenth)
+			needpunc(closepa);
+		}
+		break;
+	  case kwb_constant_p:
+		getsym();
+		needpunc(openpa);
+		if (!expression(&ep1)) error(ERR_EXPREXPECT);
+		needpunc(closepa);
+		opt0(&ep1);
+		ep1=mk_icon((long)(ep1->nodetype==en_icon || ep1->nodetype==en_fcon));
+		tp = (TYP *)&tp_int;
+		ep1->etype = tp_int.type;
+		ep1->esize = tp_int.size;
+		break;
+	  case kw_alloca:
+		getsym();
+		needpunc(openpa);
+		if (!(tp=expression(&ep1))) error(ERR_EXPREXPECT);
+		needpunc(closepa);
+		uses_link = 1;
+		cast_op(&ep1,tp,(TYP *)&tp_short);
+		ep1 = mk_node(en_alloca,ep1,NIL_ENODE);
+		tp = (TYP *)&tp_void_ptr;
+		ep1->etype = tp_void_ptr.type;
+		ep1->esize = tp_void_ptr.size;
+		break;
+	  case kw_sizeof:
+		getsym();
+		if (lastst == openpa) {
+			flag = 1;
+			getsym();
+		}
+		if (flag && castbegin(lastst)) {
+			/*
+			 * save head and tail, since we may be called from inside decl
+			 * imagine: int x[sizeof(...)];
+			 */
+			tp = head;
+			tp1 = tail;
+			decl((HTABLE *) 0);
+			decl1();
+			if (head != 0) {
+				ep1 = mk_icon((long) head->size);
+				/*
+				 * Guard against the size of not-yet-declared struct/unions
+				 */
+				if (head->size ==  0) {
+					uwarn("sizeof(item) = 0");
+				}
+			} else
+				ep1 = mk_icon(1l);
+			head = tp;
+			tail = tp1;
+		} else {
+/*
+ * This is a mess.
+ * Normally, we treat array names just as pointers, but with sizeof,
+ * we want to get the real array size.
+ * sizeof_flag != 0 tells cond_deref not to convert array names to pointers
+ */
+			sizeof_flag++;
+			tp = unary(&ep1);
+			sizeof_flag--;
+			if (tp == 0) {
+				error(ERR_SYNTAX);
+				ep1 = mk_icon(1l);
+			} else
+				ep1 = mk_icon((long) tp->size);
+		}
+/*		if (short_option && ep1->v.i > 65535)
+			do_warning("'sizeof' value greater than 65535\n");*/
+		tp = (TYP *)&tp_uint;
+		ep1->etype = tp_uint.type;
+		ep1->esize = tp_uint.size;
+		if (flag)
+			needpunc(closepa);
+		break;
+	  default:
+		tp = primary(&ep1);
+		break;
+	}
+	*node = ep1;
+	return tp;
+}
+
+#ifndef NO_TYPE_STR
+int type_str_pos CGLOB;
+typedef char type_str_content_type[32];
+type_str_content_type type_str_content[4];
+char *type_str(TYP *tp) {
+	char *p,*q;
+	int n;
+	switch (tp->type) {
+	  case bt_char:
+		return "char";
+	  case bt_uchar:
+		return "unsigned char";
+	  case bt_short:
+		return "short";
+	  case bt_ushort:
+		return "unsigned short";
+	  case bt_long:
+		return "long";
+	  case bt_ulong:
+		return "unsigned long";
+	  case bt_float:
+		return "float";
+#ifdef DOUBLE
+	  case bt_double:
+		return "double";
+#endif
+	  case bt_void:
+		return "void";
+	  case bt_struct:
+#ifdef LISTING
+		if (tp->sname) return tp->sname;
+#endif
+		return "<struct>";
+	  case bt_union:
+		return "<union>";
+	  case bt_func:
+		return "<func>";
+	  case bt_bitfield:
+		return "<bitfield>";
+	  case bt_pointer:
+		n=type_str_pos;
+		q=p=type_str(tp->btp);
+		if (n==type_str_pos) {
+			type_str_pos++;
+			strcpy(type_str_content[n],p);
+			q=p=type_str_content[n];
+			while (*p++);
+			p[-1]=' '; *p++=0;
+		} else while (*p++);
+		if (!tp->val_flag) p[-1]='*';
+		else p[-1]='[',*p++=']';
+		*p=0;
+		return q;
+	}
+	return "<unknown>";
+}
+#endif
+
+TYP *forcefit(struct enode **node1, TYP *tp1, struct enode **node2, TYP *tp2) {
+/*
+ * forcefit will coerce the nodes passed into compatible types and return the
+ * type of the resulting expression.
+ */
+	/* cast short and char to int */
+	if (short_option) {
+		if (tp1->type == bt_char || tp1->type == bt_uchar)
+			tp1 = cast_op(node1, tp1, (TYP *)&tp_short);
+		if (tp2->type == bt_char || tp2->type == bt_uchar)
+			tp2 = cast_op(node2, tp2, (TYP *)&tp_short);
+	} else {
+		if (tp1->type == bt_char || tp1->type == bt_uchar ||
+			tp1->type == bt_short || tp1->type == bt_ushort)
+			tp1 = cast_op(node1, tp1, (TYP *)&tp_long);
+
+		if (tp2->type == bt_char || tp2->type == bt_uchar ||
+			tp2->type == bt_short || tp2->type == bt_ushort)
+			tp2 = cast_op(node2, tp2, (TYP *)&tp_long);
+	}
+
+#ifndef NOFLOAT
+	/* cast float to double */
+#ifdef DOUBLE
+	if (tp1->type == bt_float)
+		tp1 = cast_op(node1, tp1, (TYP *)&tp_double);
+	if (tp2->type == bt_float)
+		tp2 = cast_op(node2, tp2, (TYP *)&tp_double);
+#endif
+
+	if (tp1->type == bt_double && isscalar(tp2))
+		tp2 = cast_op(node2, tp2, (TYP *)&tp_double);
+	else if (tp2->type == bt_double && isscalar(tp1))
+		tp1 = cast_op(node1, tp1, (TYP *)&tp_double);
+#endif
+
+	if (tp1->type == bt_ulong && isscalar(tp2))
+		tp2 = cast_op(node2, tp2, tp1);
+	else if (tp2->type == bt_ulong && isscalar(tp1))
+		tp1 = cast_op(node1, tp1, tp2);
+
+	if (tp1->type == bt_long && isscalar(tp2))
+		tp2 = cast_op(node2, tp2, tp1);
+	else if (tp2->type == bt_long && isscalar(tp2))
+		tp1 = cast_op(node1, tp1, tp2);
+
+	if (tp1->type == bt_ushort && isscalar(tp2))
+		tp2 = cast_op(node2, tp2, tp1);
+	else if (tp2->type == bt_ushort && isscalar(tp2))
+		tp1 = cast_op(node1, tp1, tp2);
+
+	if (isscalar(tp1) && isscalar(tp2))
+		return (tp1);
+
+	/* pointers may be combined with integer constant 0 */
+	if (tp1->type == bt_pointer && (*node2)->nodetype == en_icon &&
+		(*node2)->v.i == 0)
+		return tp1;
+	if (tp2->type == bt_pointer && (*node1)->nodetype == en_icon &&
+		(*node2)->v.i == 0)
+		return tp2;
+
+	if (tp1->type == bt_pointer && tp2->type == bt_pointer)
+		return tp1;
+
+	/* report mismatch error */
+
+	uerr(ERR_MISMATCH,type_str(tp1),type_str(tp2));
+	return tp1;
+}
+
+TYP *forceft2(struct enode **node1, TYP *tp1, struct enode **node2, TYP *tp2) {
+/*
+ * ,,forcefit'' for comparisons:
+ * When comparing two char's, it is not necessary to cast
+ * both of them to long in advance
+ *
+ * Perhaps not strictly K&R, but more efficient.
+ * If you don't like it, use forcefit in ALL cases
+ */
+
+	/* short cut: */
+	if (tp1->type == tp2->type)
+		return tp1;
+
+	/* comparison with integer constant */
+
+	if ((*node1)->nodetype == en_icon) {
+		struct enode  **node = node1;
+		TYP 		   *tp = tp1;
+		node1 = node2;
+		tp1 = tp2;
+		node2 = node;
+		tp2 = tp;
+	}
+	opt4(node2);
+	if ((*node2)->nodetype == en_icon) {
+		long			val = (*node2)->v.i;
+		enum(e_bt)		typ1 = tp1->type;
+		if ((typ1 == bt_char && -128 <= val && val <= 127) ||
+			(typ1 == bt_uchar && 0 <= val && val <= 255) ||
+			(typ1 == bt_short && -32768 <= val && val <= 32767) ||
+			(typ1 == bt_ushort && 0 <= val && val <= 65535) ||
+			(typ1 == bt_pointer && val == 0))
+			return cast_op(node2, tp2, tp1);
+	}
+
+	switch (tp1->type) {
+		/* Type of first operand */
+	  case bt_char:
+	  case bt_uchar:
+		switch (tp2->type) {
+		  case bt_char:
+		  case bt_uchar:
+			(void) cast_op(node1, tp1, (TYP *)&tp_short);
+			return cast_op(node2, tp2, (TYP *)&tp_short);
+		  case bt_short:
+		  case bt_long:
+		  case bt_ushort:
+		  case bt_ulong:
+		  case bt_float:
+#ifdef DOUBLE
+		  case bt_double:
+#endif
+			return cast_op(node1, tp1, tp2);
+		}
+		break;
+	  case bt_short:
+	  case bt_ushort:
+		switch (tp2->type) {
+		  case bt_char:
+		  case bt_uchar:
+			return cast_op(node2, tp2, tp1);
+		  case bt_ushort:
+			if (short_option)
+			   return cast_op (node1, tp1, (TYP *)&tp_ushort);
+			else {
+			   (void) cast_op (node1, tp1, (TYP *)&tp_long);
+			   return cast_op (node2, tp2, (TYP *)&tp_long);
+			}
+		  case bt_short:
+			if (short_option)
+				return cast_op(node2, tp2, (TYP *)&tp_ushort);
+			else {
+			   (void) cast_op (node1, tp1, (TYP *)&tp_long);
+			   return cast_op (node2, tp2, (TYP *)&tp_long);
+			}
+		  case bt_long:
+		  case bt_ulong:
+		  case bt_float:
+#ifdef DOUBLE
+		  case bt_double:
+#endif
+			return cast_op(node1, tp1, tp2);
+		}
+		break;
+	  case bt_long:
+	  case bt_ulong:
+		switch (tp2->type) {
+		  case bt_char:
+		  case bt_uchar:
+		  case bt_short:
+		  case bt_ushort:
+			return cast_op(node2, tp2, tp1);
+		  case bt_long:
+			return cast_op(node2, tp2, tp1);
+		  case bt_ulong:
+			return cast_op(node1, tp1, tp2);
+		  case bt_float:
+#ifdef DOUBLE
+		  case bt_double:
+#endif
+			return cast_op(node1, tp1, tp2);
+		}
+		break;
+	  case bt_float:
+#ifdef DOUBLE
+	  case bt_double:
+#endif
+		switch (tp2->type) {
+		  case bt_char:
+		  case bt_uchar:
+		  case bt_short:
+		  case bt_ushort:
+		  case bt_long:
+		  case bt_ulong:
+		  case bt_float:
+			return cast_op(node2, tp2, tp1);
+#ifdef DOUBLE
+		  case bt_double:
+			return cast_op(node1, tp1, tp2);
+#endif
+		}
+		break;
+		/*
+		 * pointers are equivalent to function names
+		 */
+	  case bt_pointer:
+		if (tp2->type == bt_func)
+			return cast_op(node2, tp2, tp1);
+		break;
+	  case bt_func:
+		if (tp2->type == bt_pointer)
+			return cast_op(node1, tp1, tp2);
+		break;
+	}
+	uerr(ERR_MISMATCH,type_str(tp1),type_str(tp2));
+	return 0;
+}
+
+#ifndef isscalar
+static int isscalar(TYP *tp) {
+/*
+ * this function returns true when the type of the argument is a scalar type
+ * (enum included)
+ */
+/*	return tp->type == bt_char ||
+		tp->type == bt_uchar ||
+		tp->type == bt_ushort ||
+		tp->type == bt_short ||
+		tp->type == bt_long ||
+		tp->type == bt_ulong ||
+		tp->type == bt_float ||
+		tp->type == bt_double; */
+	return bt_scalar(tp->type);
+}
+#endif
+
+static TYP *multops(struct enode **node) {
+/*
+ * multops parses the multiply priority operators. the syntax of this group
+ * is:
+ *
+ * unary multop * unary multop / unary multop % unary
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp1, *tp2;
+	enum(e_sym)		oper;
+	tp1 = unary(&ep1);
+	if (tp1 == 0)
+		return 0;
+	while (lastst == star || lastst == divide || lastst == modop) {
+		oper = lastst;
+		getsym();				/* move on to next unary op */
+/*		if (lineid==77)
+			bkpt();*/
+		tp2 = unary(&ep2);
+		if (tp2 == 0) {
+			error(ERR_IDEXPECT);
+			*node = ep1;
+			return tp1;
+		}
+#ifdef INTEL_386
+		tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+#endif
+		switch (oper) {
+		  case star:
+				/*{extern SYM *func_sp;
+				if (!strcmp(func_sp->name,"bonus"))
+					printf("gjio");}*/
+/*					if (lineid==1189)
+						bkpt();*/
+				tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+#ifndef NOFLOAT
+//#warning STUDY ME!!!
+//			  uwarn("!!! study this !!!");
+//			if (tp1->type==bt_float || tp2->type==bt_float)
+//				tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+//			else
+#endif
+#ifdef MC68000
+//			{
+//				tp1 = cast_op(&ep1, tp1, (TYP *)&tp_long);
+//				tp2 = cast_op(&ep2, tp2, (TYP *)&tp_long);
+//			}
+#endif
+			ep1 = mk_node(en_mul, ep1, ep2);
+#ifndef NOFLOAT
+			if (tp1->type!=bt_float)
+#endif
+#ifdef MC68000
+//			tp1 = (TYP *)&tp_long;
+#endif
+/*			if (bt_integral(tp1->type)) {
+				if (bt_uns(tp1->type)) tp1=(TYP *)&tp_ulong;
+				else tp1=(TYP *)&tp_long;
+			}*/
+			break;
+		  case divide:
+		  case modop:
+#ifndef NOFLOAT
+			if (tp1->type==bt_float || tp2->type==bt_float)
+				tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+			else
+#endif
+#ifdef MC68000
+			{
+#ifdef OLD_STUPID_DIVIDE	/* !!! n'importe quoi !!! */
+				tp1 = cast_op(&ep1, tp1, (TYP *)&tp_long);
+				if (tp2->type==bt_long || tp2->type==bt_ulong) {
+					ep1 = mk_node(oper==divide?en_div:en_mod, ep1, ep2);
+					tp1 = (TYP *)&tp_long;
+					break;
+				}
+				tp2 = cast_op(&ep2, tp2, (TYP *)&tp_short);
+#else
+				tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+#endif
+			}
+#endif
+			ep1 = mk_node(oper==divide?en_div:en_mod, ep1, ep2);
+#ifdef OLD_STUPID_DIVIDE	/* !!! n'importe quoi !!! */
+#ifndef NOFLOAT
+			if (tp1->type!=bt_float)
+#endif
+#ifdef MC68000
+				tp1 = (TYP *)&tp_short;
+#endif
+#endif
+			break;
+		}
+		ep1->etype = tp1->type;
+		ep1->esize = tp1->size;
+	}
+	*node = ep1;
+	return tp1;
+}
+
+static TYP *addops(struct enode **node) {
+/*
+ * addops handles the addition and subtraction operators.
+ */
+	struct enode   *ep1, *ep2, *ep3;
+	TYP 		   *tp1, *tp2;
+	int 			oper;
+	tp1 = multops(&ep1);
+	if (tp1 == 0)
+		return 0;
+	while (lastst == plus || lastst == minus) {
+/*		if (asm_zflag)
+			printf("gfi");*/
+/*		if (lineid==852)
+			bkpt();*/
+		oper = (lastst - minus);
+		getsym();
+		tp2 = multops(&ep2);
+		if (tp2 == 0) {
+			error(ERR_IDEXPECT);
+			*node = ep1;
+			return tp1;
+		}
+		if (tp1->type == bt_pointer && tp2->type == bt_pointer
+			&& tp1->btp->size == tp2->btp->size && (!oper)) {
+			/* pointer subtraction */
+			ep1 = mk_node(en_sub, ep1, ep2);
+			ep1->etype = bt_long;
+			ep1->esize = 4;
+			/* divide the result by the size */
+			ep2 = mk_icon((long) tp1->btp->size);
+			ep2->etype = bt_long;
+			ep2->esize = 4;
+			ep1 = mk_node(en_div, ep1, ep2);
+			ep1->etype = bt_long;
+			ep1->esize = 4;
+//#ifdef POINTER_DIFF_IS_SHORT
+			/*
+			 * cast the result to ,,int''. K&R says that pointer subtraction
+			 * yields an int result so I do it although it is not sensible on
+			 * an 68000 with 32-bit pointers and 16-bit ints. In my opinion,
+			 * it should remain ,,long''.
+			 */
+//			if (short_option) do_warning("pointer difference casted to 16-bit 'int'\n");
+			if (tp1->btp->size!=1)	/* if size is 1 maybe we want it bijective... */
+				tp1 = cast_op(&ep1, (TYP *)&tp_long, (TYP *)&tp_int);
+			else tp1 = (TYP *)&tp_long;
+//#endif
+			*node = ep1;
+			continue;
+		}
+		if (tp2->type == bt_pointer && oper) {
+			TYP *tpi;
+			/* integer + pointer */
+			tpi=tp1;
+			tp1=tp2;
+			tp2=tpi;
+			ep3=ep1;
+			ep1=ep2;
+			ep2=ep3;
+		}
+		if (tp1->type == bt_pointer) {
+			/* pointer +/- integer */
+			unsigned int s = tp1->btp->size;// int p;
+			if (!integral(tp2))
+				error(ERR_INTEGER);
+			/*if ((p=pwrof2(s))>=0) {
+				if (tp2->type == bt_char || tp2->type == bt_uchar)
+					tp2 = cast_op(&ep2, tp2, (TYP *)&tp_short);
+				if (p) {
+					ep3 = mk_icon((long)p);
+					ep3->etype = bt_short;
+					ep3->esize = 2;
+					ep2 = mk_node(en_lsh, ep3, ep2);
+					ep2->etype = bt_short;
+					ep2->esize = 2;
+				}
+				ep1 = mk_node(oper ? en_add : en_sub, ep1, ep2);
+				ep1->etype = bt_pointer;
+				ep1->esize = 4;
+				continue;
+			} else {*/
+				cast_op(&ep2, tp2, (TYP *)&tp_long);	// g_xmul will restore all this to short if
+				ep3 = mk_icon(s);				// necessary :)
+				ep3->etype = bt_long;
+				ep3->esize = 4;
+				ep2 = mk_node(en_mul, ep3, ep2);
+				ep2->etype = bt_long;
+				ep2->esize = 4;
+//				cast_op(&ep2, (TYP *)&tp_short, (TYP *)&tp_long);
+				ep1 = mk_node(oper ? en_add : en_sub, ep1, ep2);
+				ep1->etype = bt_pointer;
+				ep1->esize = 4;
+				continue;
+			/*}*/
+		}
+		tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+		ep1 = mk_node(oper ? en_add : en_sub, ep1, ep2);
+		ep1->etype = tp1->type;
+		ep1->esize = tp1->size;
+	}
+	*node = ep1;
+	return tp1;
+}
+
+TYP *shiftop(struct enode **node) {
+/*
+ * shiftop handles the shift operators << and >>.
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp1, *tp2;
+	int 			oper;
+	tp1 = addops(&ep1);
+	if (tp1 == 0)
+		return 0;
+	while (lastst == lshift || lastst == rshift) {
+		oper = (lastst == lshift);
+		getsym();
+		tp2 = addops(&ep2);
+		if (tp2 == 0)
+			error(ERR_IDEXPECT);
+		else {
+#ifndef MINIMAL_SIZES
+			tp1 = forcefit(&ep1, tp1, &ep2, tp2);
+#else
+			/*
+			tp1 = forcefit(&ep1, tp1, &ep2, tp2);	-> this is wrong: C89 specifies the type depends only on the left op.
+			cast_op(&ep2, tp2, (TYP *)&tp_char);
+			*/
+			if (tp1->type == bt_char || tp1->type == bt_uchar)
+				tp1 = cast_op(&ep1, tp1, (TYP *)&tp_short);
+			cast_op(&ep2, tp2, (TYP *)&tp_char);
+#endif
+			ep1 = mk_node(oper ? en_lsh : en_rsh, ep1, ep2);
+			ep1->etype = tp1->type;
+			ep1->esize = tp1->size;
+			if (!integral(tp1))
+				error(ERR_INTEGER);
+		}
+	}
+	*node = ep1;
+	return tp1;
+}
+
+TYP *relation(struct enode **node) {
+/*
+ * relation handles the relational operators < <= > and >=.
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp1, *tp2;
+	enum(e_node) 	nt;
+	tp1 = shiftop(&ep1);
+	if (tp1 == 0)
+		return 0;
+	for (;;) {
+		switch (lastst) {
+		  case lt:
+			nt = en_lt;
+			break;
+		  case gt:
+			nt = en_gt;
+			break;
+		  case leq:
+			nt = en_le;
+			break;
+		  case geq:
+			nt = en_ge;
+			break;
+		  default:
+			goto fini;
+		}
+		getsym();
+		tp2 = shiftop(&ep2);
+		if (tp2 == 0)
+			error(ERR_EXPREXPECT);
+		else {
+			tp1 = forceft2(&ep1, tp1, &ep2, tp2);
+			if (!iscomparable(tp1))
+				uerr(ERR_ILLTYPE);
+			ep1 = mk_node(nt, ep1, ep2);
+			tp1 = (TYP *)&tp_int;
+			ep1->etype = tp_int.type;
+			ep1->esize = tp_int.size;
+			if (lastst>=lt && lastst<=geq) {
+				if (flags & X_COMP_STRING) {
+					uwarn("not implemented\n");
+				} else uwarn("() suggested to clarify priority");
+			}
+		}
+	}
+fini:*node = ep1;
+	return tp1;
+}
+
+TYP *equalops(struct enode **node) {
+/*
+ * equalops handles the equality and inequality operators.
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp1, *tp2;
+	int 			oper;
+	tp1 = relation(&ep1);
+	if (tp1 == 0)
+		return 0;
+	while (lastst == eq || lastst == neq) {
+		oper = (lastst == eq);
+		getsym();
+		tp2 = relation(&ep2);
+		if (tp2 == 0)
+			error(ERR_IDEXPECT);
+		else {
+			tp1 = forceft2(&ep1, tp1, &ep2, tp2);
+			ep1 = mk_node(oper ? en_eq : en_ne, ep1, ep2);
+			tp1 = (TYP *)&tp_int;
+			ep1->etype = tp_int.type;
+			ep1->esize = tp_int.size;
+		}
+	}
+	*node = ep1;
+	return tp1;
+}
+
+TYP *binop(struct enode **node, TYP *(*xfunc)(), enum(e_node) nt, enum (e_sym) sy) {
+/*
+ * binop is a common routine to handle all of the legwork and error checking
+ * for bitand, bitor, bitxor
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp1, *tp2;
+	tp1 = (*xfunc) (&ep1);
+	if (tp1 == 0)
+		return 0;
+	while (lastst == sy) {
+		getsym();
+		tp2 = (*xfunc) (&ep2);
+		if (tp2 == 0)
+			error(ERR_IDEXPECT);
+		else {
+			tp1 = forceft2(&ep1, tp1, &ep2, tp2);
+			ep1 = mk_node(nt, ep1, ep2);
+			ep1->etype = tp1->type;
+			ep1->esize = tp1->size;
+			if (!integral(tp1))
+				error(ERR_INTEGER);
+		}
+	}
+	*node = ep1;
+	return tp1;
+}
+
+TYP *binlog(struct enode **node, TYP *(*xfunc)(), enum(e_node) nt, enum(e_sym) sy) {
+/*
+ * binlog is a common routine to handle all of the legwork and error checking
+ * for logical and, or
+ */
+	struct enode   *ep1, *ep2;
+	TYP 		   *tp1, *tp2;
+	tp1 = (*xfunc) (&ep1);
+	if (tp1 == 0)
+		return 0;
+	while (lastst == sy) {
+		getsym();
+		tp2 = (*xfunc) (&ep2);
+		if (tp2 == 0)
+			error(ERR_IDEXPECT);
+		else {
+			ep1 = mk_node(nt, ep1, ep2);
+			tp1 = (TYP *)&tp_int;
+			ep1->etype = tp_int.type;
+			ep1->esize = tp_int.size;
+		}
+	}
+	*node = ep1;
+	return tp1;
+}
+
+TYP *bitand(struct enode **node) {
+/*
+ * the bitwise and operator...
+ */
+	return binop(node, equalops, en_and, and);
+}
+
+TYP *bitxor(struct enode **node) {
+	return binop(node, bitand, en_xor, uparrow);
+}
+
+TYP *bitor(struct enode **node) {
+	return binop(node, bitxor, en_or, or);
+}
+
+TYP *andop(struct enode **node) {
+	return binlog(node, bitor, en_land, land);
+}
+
+TYP *orop(struct enode **node) {
+	return binlog(node, andop, en_lor, lor);
+}
+
+TYP *conditional(struct enode **node) {
+/*
+ * this routine processes the hook operator.
+ */
+	TYP 		   *tp1, *tp2, *tp3;
+	struct enode   *ep1, *ep2, *ep3;
+	tp1 = orop(&ep1);			/* get condition */
+	if (tp1 == 0)
+		return 0;
+	if (lastst == hook) {
+		getsym();
+		if (lastst==colon) {
+			ep2=NULL; tp2=tp1;
+		} else if ((tp2 = expression(&ep2)) == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+		needpunc(colon);
+		if ((tp3 = exprnc(&ep3)) == 0) {
+			error(ERR_IDEXPECT);
+			return 0;
+		}
+/*
+ * If either type is void and the other is not, cast the other one to void.
+ * I dare not doing this in forceft2
+ * Strict ANSI does not allow that only one part of the sentence is void,
+ * that is what gcc -pedantic tells me.
+ * But since such conditionals occur even in GNU Software (look at obstack.h),
+ * I allow such constructs here.
+ */
+		if (tp2->type == bt_void && tp3->type != bt_void)
+			tp3 = cast_op(&ep3, tp3, tp2);
+		else if (tp3->type == bt_void && tp2->type != bt_void && ep2!=NULL)
+			tp2 = cast_op(&ep2, tp2, tp3);
+
+		if (ep2==NULL)
+			tp1 = forceft2(&ep1, tp1, &ep3, tp3);
+		else tp1 = forceft2(&ep2, tp2, &ep3, tp3);
+		if (tp1 == 0)
+			return 0;
+		ep2 = mk_node(en_void, ep2, ep3);
+		ep1 = mk_node(en_cond, ep1, ep2);
+		ep1->etype = tp1->type;
+		ep1->esize = tp1->size;
+	}
+	*node = ep1;
+	return tp1;
+}
+
+TYP *asnop(struct enode **node) {
+/*
+ * asnop handles the assignment operators.
+ */
+	struct enode   *ep1, *ep2, *ep3;
+	TYP 		   *tp1, *tp2, *tp0;
+	enum(e_node) 	op;
+	tp0 = NULL;
+	tp1 = conditional(&ep1);
+	if (tp1 == 0)
+		return 0;
+	for (;;) {
+		switch (lastst) {
+		  case assign:
+			op = en_assign;
+	ascomm:	getsym();
+			tp2 = asnop(&ep2);
+	ascomm2:
+			if (tp2 == 0)
+				break;
+			if (ep1->nodetype != en_ref && ep1->nodetype != en_fieldref) {
+				if (ep1->nodetype==en_cast) {	/* CAUTION : works well only with en_assign */
+					enum(e_node) nt;
+					if ((nt=ep1->v.p[0]->nodetype) != en_ref && nt != en_fieldref)
+						error(ERR_LVALUE);
+					tp2 = cast_op(&ep2, tp2, tp1);
+					tp1 = (TYP *)ep1->v.p[1];
+/*				} else if (ep1->nodetype==en_cond) {
+					struct enode *epvoid=ep1->v.p[1];
+					
+					tp1 = cast_op(&epvoid->v.p[0], tp2, tp1);
+					tp1 = cast_op(&epvoid->v.p[1], tp2, tp1);*/
+				} else error(ERR_LVALUE);
+			}
+			if (tp1->const_flag)
+				uwarn("assignment of read-only lvalue");
+			if (tp0 != 0) tp1 = force_cast_op(&ep2, tp2, tp1);
+			else tp1 = cast_op(&ep2, tp2, tp1);
+			if (tp1 == 0)
+				break;
+			if (op!=en_assign && !iscomparable(tp1))
+				uerr(ERR_ILLTYPE);
+			ep1 = mk_node(op, ep1, ep2);
+			ep1->etype = tp1->type;
+			ep1->esize = tp1->size;
+			if (tp0 != 0) tp1 = cast_op(&ep1, tp1, tp0);
+#ifdef INTEL_386
+			/* trap struct assigns */
+			if (isaggregate(tp1))
+				uses_structassign=1;
+#endif
+			break;
+		  case asplus:
+			op = en_asadd;
+	ascomm3:
+			getsym();
+			tp2 = asnop(&ep2);
+			if (tp2 == 0)
+				break;
+			if (tp1->type == bt_pointer && integral(tp2)) {
+#ifdef NO_SECURE_POINTERS
+				if (tp1->btp->size!=1) {
+					cast_op(&ep2, tp2, (TYP *)&tp_short);
+					ep3 = mk_icon((long) tp1->btp->size);
+					ep3->etype = bt_short;
+					ep3->esize = 2;
+					ep2 = mk_node(en_mul, ep2, ep3);
+					ep2->etype = bt_short;
+					ep2->esize = 2;
+					tp2 = cast_op(&ep2, (TYP *)&tp_short, (TYP *)&tp_long);
+				} else
+					tp2 = cast_op(&ep2, tp2, (TYP *)&tp_long);
+				tp2 = cast_op(&ep2, (TYP *)&tp_long, tp1);
+#else
+				cast_op(&ep2, tp2, (TYP *)&tp_long);
+				ep3 = mk_icon((long) tp1->btp->size);
+				ep3->etype = bt_long;
+				ep3->esize = 4;
+				ep2 = mk_node(en_mul, ep2, ep3);
+				ep2->etype = bt_long;
+				ep2->esize = 4;
+				tp2 = cast_op(&ep2, (TYP *)&tp_long, tp1);
+#endif
+			}
+			goto ascomm2;
+		  case asminus:
+			op = en_assub;
+			goto ascomm3;
+		  case astimes:
+			op = en_asmul;
+			goto ascomm;
+		  case asdivide:
+			op = en_asdiv;
+			goto ascomm;
+		  case asmodop:
+			op = en_asmod;
+			goto ascomm;
+		  case aslshift:
+			op = en_aslsh;
+			goto ascomm;
+		  case asrshift:
+			op = en_asrsh;
+			goto ascomm;
+		  case asand:
+			op = en_asand;
+			goto ascomm;
+		  case asor:
+			op = en_asor;
+			goto ascomm;
+		  case asuparrow:
+			op = en_asxor;
+			goto ascomm;
+		  default:
+			goto asexit;
+		}
+	}
+asexit:
+   *node = ep1;
+	return tp1;
+}
+
+TYP *exprnc(struct enode **node) {
+/*
+ * evaluate an expression where the comma operator is not legal.
+ */
+	TYP *tp;
+	tp = asnop(node);
+	if (tp == 0)
+		*node = 0;
+	return tp;
+}
+
+TYP *commaop(struct enode **node) {
+/*
+ * evaluate the comma operator. comma operators are kept as void nodes.
+ */
+	TYP 		   *tp1;
+	struct enode   *ep1, *ep2;
+	tp1 = asnop(&ep1);
+	if (tp1 == 0)
+		return 0;
+	if (lastst == comma) {
+		getsym();
+		tp1 = commaop(&ep2);
+		if (tp1 == 0) {
+			error(ERR_IDEXPECT);
+			goto coexit;
+		}
+		ep1 = mk_node(en_void, ep1, ep2);
+		ep1->esize = ep2->esize;
+		ep1->etype = ep2->etype;
+	}
+coexit:*node = ep1;
+	return tp1;
+}
+
+TYP *expression(struct enode **node) {
+/*
+ * evaluate an expression where all operators are legal.
+ */
+	TYP 		   *tp;
+	tp = commaop(node);
+	if (tp == 0)
+		*node = 0;
+	return tp;
+}
+
+int cast_ok(TYP *tp1, TYP *tp2, int need_physically_compatible) {
+/*
+ * This is used to tell whether an implicit cast will generate a warning
+ *
+ * If need_physically_compatible is 0, then we do not make a difference between
+ * short[123], short[124], short[0] and short* (otherwise we do because they're
+ * not stored in memory the same way).
+ */
+	if (tp1 == 0 || tp2 == 0)
+		return 0;
+
+	if (tp1 == tp2 || tp2->type == bt_void)
+		return 1;
+	if (bt_integral(tp1->type))
+		return (tp1->type^tp2->type)<=1;
+
+	if (tp1->type != tp2->type)
+		return 0;
+
+	/* from now on, tp1->type==tp2->type */
+	if (tp1->type == bt_pointer) {
+		if (need_physically_compatible)
+			if (tp1->val_flag!=tp2->val_flag ||
+				(tp1->val_flag && tp1->size!=tp2->size))
+			return 0;
+		return tp1->btp->type == bt_void || cast_ok(tp1->btp, tp2->btp, 1);
+	}
+	if (tp1->type == bt_func) {
+		SYM *sp=tp1->lst.head,*sp2=tp2->lst.head;
+		if (!sp || !sp2)	// one is only a prototype : OK
+			return eq_type(tp1->btp, tp2->btp);
+		while (sp && sp2) {
+			if (!eq_type(sp->tp,sp2->tp)) return 0;
+			sp=sp->next; sp2=sp2->next;
+		}
+		if (sp || sp2) return 0;	// != # of args
+		return eq_type(tp1->btp, tp2->btp);
+	}
+	if (tp1->type == bt_struct || tp1->type == bt_union)
+		return (tp1->lst.head == tp2->lst.head);
+
+	return 1;
+}
+
+TYP *cast_op(struct enode **ep, TYP *tp1, TYP *tp2) {
+	struct enode   *ep2;
+
+	if (tp1 == 0 || tp2 == 0 || (tp1->type == bt_void && tp2->type != bt_void)) {
+		uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+		return 0;
+	}
+	if (tp1->type == tp2->type) {
+		if (!cast_ok(tp1, tp2, 0))
+			uwarn("conversion between incompatible %stypes",
+					(tp1->type == bt_pointer) ? "pointer " : "");
+		if (tp1->type == bt_struct || tp1->type == bt_union) {
+			if (tp1->size != tp2->size)
+				uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+		}
+#ifdef NO_VERYTRIVIAL_CASTS
+		return tp2;
+#endif
+	}
+	opt0(ep);					/* to make a constant really a constant */
+
+	if ((*ep)->nodetype == en_icon) {
+		if (integral(tp2) || tp2->type == bt_pointer || tp2->type == bt_void) {
+			long			j = (*ep)->v.i;
+			long d;
+			(*ep)->etype = tp2->type;
+			(*ep)->esize = tp2->size;
+			/*
+			 * The cast may affect the value of (*ep)->v.i
+			 */
+			(*ep)->v.i = strip_icon(j, tp2->type);
+			d = j ^ (*ep)->v.i;
+			if (d && d!=0xFFFF0000 && d!=0xFFFFFF00)
+				uwarn("cast changed integer constant 0x%08lx to 0x%08lx", j, (*ep)->v.i);
+			return tp2;
+#ifndef NOFLOAT
+		} else if (tp2->type == bt_float || tp2->type == bt_double) {
+#ifdef XCON_DOESNT_SUPPORT_FLOATS
+#error Fix me now :)
+#endif
+			(*ep)->nodetype = en_fcon;
+			(*ep)->etype = tp2->type;
+#ifdef PC
+			(*ep)->v.f = (double) (*ep)->v.i;
+#else
+#ifdef BCDFLT
+			(*ep)->v.f = ffpltof((*ep)->v.i);
+#else
+			(*ep)->v.f = (float) (*ep)->v.i;
+#endif
+#endif
+			(*ep)->esize =
+#if defined(DOUBLE) || defined(INTEL_386)
+				tp2->type == bt_float ? tp_float.size : tp_double.size;
+#else
+				float_size;
+#endif
+			return tp2;
+#endif
+		} else {
+ 			uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+			return 0;
+		}
+	}
+/*	if (tp2->type != bt_void && tp1->size > tp2->size)
+		uwarn("cast to a narrower type loses accuracy");*/
+	if (tp1->type == bt_pointer && tp2->type != bt_pointer)
+		uwarn("cast from pointer to integer is dangerous");
+	if (tp2->type == bt_pointer && tp1->size < 4)
+		uwarn("cast from short to pointer is dangerous");
+	if ((tp1->type == bt_func && tp2->type != bt_func)
+			|| (tp2->type == bt_func && tp1->type != bt_func))
+		uwarn("implicit cast from '%s' to '%s'",type_str(tp1),type_str(tp2));
+	if ((bt_uncastable(tp1->type) || bt_uncastable(tp2->type)) && tp1->type!=tp2->type)
+		uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+
+#ifdef NO_TRIVIAL_CASTS
+	if (tp2->size==tp1->size && (tp2->type==tp1->type
+			|| ((tp2->type^tp1->type)==1 && bt_integral(tp1->type))
+			|| (tp2->type==bt_pointer && (tp1->type==bt_long || tp1->type==bt_ulong))
+			|| (tp1->type==bt_pointer && (tp2->type==bt_long || tp2->type==bt_ulong)))) {
+		if (needs_trivial_casts((*ep)->nodetype))
+			goto trivial_cast_do;
+		(*ep)->etype = tp2->type;
+		return tp2;
+	}
+trivial_cast_do:
+#endif
+
+	ep2 = mk_node(en_cast, *ep, NIL_ENODE);
+	ep2->etype = tp2->type;
+	ep2->esize = tp2->size;
+
+	*ep = ep2;
+
+	return tp2;
+}
+
+TYP *force_cast_op(struct enode **ep, TYP *tp1, TYP *tp2) {
+	struct enode   *ep2;
+
+	if (tp1 == 0 || tp2 == 0 || (tp1->type == bt_void && tp2->type != bt_void)) {
+		uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+		return 0;
+	}
+	if (tp1->type == tp2->type) {
+		if (tp1->type == bt_struct || tp1->type == bt_union) {
+			if (tp1->size != tp2->size)
+				uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+		}
+//		return tp2;	so that an en_cast enode is generated & the old TYP is saved
+#ifdef NO_VERYTRIVIAL_CASTS
+		return tp2;
+#endif
+	}
+	opt0(ep);					/* to make a constant really a constant */
+
+	if ((*ep)->nodetype == en_icon) {
+		if (integral(tp2) || tp2->type == bt_pointer || tp2->type == bt_void) {
+			long			j = (*ep)->v.i;
+			(*ep)->etype = tp2->type;
+			(*ep)->esize = tp2->size;
+			/*
+			 * The cast may affect the value of (*ep)->v.i
+			 */
+			(*ep)->v.i = strip_icon(j, tp2->type);
+			return tp2;
+#ifndef NOFLOAT
+		} else if (tp2->type == bt_float || tp2->type == bt_double) {
+#ifdef XCON_DOESNT_SUPPORT_FLOATS
+#error Fix me now :)
+#endif
+			(*ep)->nodetype = en_fcon;
+			(*ep)->etype = tp2->type;
+#ifdef PC
+			(*ep)->v.f = (double) (*ep)->v.i;
+#else
+			(*ep)->v.f = ffpltof((*ep)->v.i);
+#endif
+			(*ep)->esize =
+#if defined(DOUBLE) || defined(INTEL_386)
+				tp2->type == bt_float ? tp_float.size : tp_double.size;
+#else
+				float_size;
+#endif
+			return tp2;
+#endif
+		} else {
+			uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+			return 0;
+		}
+	}
+	if ((bt_uncastable(tp1->type) || bt_uncastable(tp2->type)) && tp1->type!=tp2->type)
+		uerr(ERR_CAST,type_str(tp1),type_str(tp2));
+/*	if (tp2->type == bt_pointer && tp1->size < 4)
+		uwarn("cast from short to pointer is dangerous");*/
+
+#ifdef NO_TRIVIAL_CASTS
+	if (tp2->size==tp1->size && (tp2->type==tp1->type
+			|| ((tp2->type^tp1->type)==1 && bt_integral(tp1->type))
+			|| (tp2->type==bt_pointer && (tp1->type==bt_long || tp1->type==bt_ulong))
+			|| (tp1->type==bt_pointer && (tp2->type==bt_long || tp2->type==bt_ulong)))) {
+		if (needs_trivial_casts((*ep)->nodetype))
+			goto trivial_cast_do;
+		(*ep)->etype = tp2->type;
+		return tp2;
+	}
+trivial_cast_do:
+#endif
+
+	ep2 = mk_node(en_cast, *ep, (struct enode *)tp1);	// the latter is for (int)x=value;
+	ep2->etype = tp2->type;
+	ep2->esize = tp2->size;
+
+	*ep = ep2;
+
+	return tp2;
+}
+
+#ifndef isscalar
+int integral(TYP *tp) {
+/* returns true it tp is an integral type */
+	return bt_integral(tp->type);
+}
+#endif
+
+long strip_icon(long i, enum(e_bt) type) {
+/*
+ * This function handles the adjustment of integer constants upon
+ * casts. It forces the constant into the range acceptable for
+ * the given type.
+ * This code assumes somehow that longs are 32 bit on the
+ * machine that runs the compiler, but how do you get this
+ * machine independent?
+ */
+	switch (type) {
+	  case bt_uchar:			/* 0 .. 255 */
+#ifdef PC
+		i &= 0xff;
+#else
+		i = (long)((unsigned char)i);
+#endif
+		break;
+	  case bt_char: 			/* -128 .. 127 */
+#ifdef PC
+		i &= 0xff;
+		if (i >= 128)
+			i |= 0xffffff00;
+#else
+		i = (long)((char)i);
+#endif
+		break;
+	  case bt_ushort:			/* 0 .. 65535 */
+#ifdef PC
+		i &= 0xffff;
+#else
+		i = (long)((unsigned short)i);
+#endif
+		break;
+	  case bt_short:			/* -32768 .. 32767 */
+#ifdef PC
+		i &= 0xffff;
+		if (i >= 32768)
+			i |= 0xffff0000;
+#else
+		i = (long)((short)i);
+#endif
+		break;
+	}
+	return i;
+}
+// vim:ts=4:sw=4

+ 169 - 0
gtc/src/expr.h

@@ -0,0 +1,169 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * expressions
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+/* expression tree descriptions  */
+
+//enum e_node {
+//	en_void,
+//	en_icon/*1*/, en_fcon, en_labcon/*3*/, en_nacon/*4*/, en_autocon/*5*/,
+//	en_fcall, en_tempref, en_add, en_sub, en_mul, en_mod,
+//	en_div, en_lsh, en_rsh, en_cond, en_assign/*16*/, en_eq, en_ne,
+//	en_asadd, en_assub, en_asmul, en_asdiv, en_asmod, en_asrsh,
+//	en_asxor,
+//	en_aslsh, en_asand, en_asor, en_uminus, en_not, en_compl,
+//	en_lt/*32*/, en_le, en_gt, en_ge, en_and, en_or, en_land, en_lor,
+//	en_xor, en_ainc, en_adec,
+//	en_ref, en_cast, en_deref,
+//	en_fieldref,
+//};
+/* BEWARE!!! en_add must be even, and en_sub=en_add+1 (used in opt0) */
+enum e_node {
+	// 0x00
+	en_icon, en_fcon, en_labcon, en_nacon, en_autocon,
+	// 0x05
+	en_tempref, en_ref, en_fieldref,
+	// 0x08
+	en_void,
+	en_compound,
+	// 0x0A
+	en_fcall, en_cast, en_add, en_sub, en_mul, en_mod,
+	// 0x10
+	en_div, en_lsh, en_rsh, en_cond, en_assign, en_eq, en_ne,
+	// 0x17
+	en_asadd, en_assub, en_asmul, en_asdiv, en_asmod, en_asrsh,
+	en_asxor,
+	// 0x1E
+	en_aslsh, en_asand, en_asor, en_uminus, en_not, en_compl,
+	en_lt, en_le, en_gt, en_ge, en_and, en_or, en_land, en_lor,
+	en_xor, en_ainc, en_adec,
+	en_deref,
+// extensions
+	en_alloca,
+};
+/* below is the list of all nodes that need to have finer type considerations than below :
+  - char/uchar
+  - short/ushort
+  - long/ulong/pointer
+  - float
+  - struct
+  - union
+  - void
+  (these are considerations about the *parent* node, not about its children, whose type
+  may safely be accessed)
+ */
+#define needs_trivial_casts(x) ( \
+	/* pointer vs long/ulong */ \
+	(x)==en_fcall || \
+	/* signed vs unsigned */ \
+	(x)==en_div || (x)==en_mod || (x)==en_mul || (x)==en_rsh || \
+	(x)==en_asdiv || (x)==en_asmod || (x)==en_asmul || (x)==en_asrsh || \
+	0)
+
+/* statement node descriptions	 */
+
+enum e_stmt {
+	st_expr, st_while, st_for, st_do, st_if, st_switch,
+	st_case, st_goto, st_break, st_continue, st_label,
+	st_return, st_compound, st_default,
+	// GTC extensions
+	st_loop, st_asm,
+};
+
+struct xcon {
+	enum(e_node) 	nodetype;
+	enum(e_bt)		etype;
+	long			esize;
+	union {
+		long			i;
+#ifndef XCON_DOESNT_SUPPORT_FLOATS
+#ifndef NOFLOAT
+		double			f;
+#endif
+#endif
+	}				v;
+};
+
+struct enode {
+	enum(e_node) 	nodetype;
+	enum(e_bt)		etype;
+	long			esize;
+	union {
+		long			i;
+#ifndef NOFLOAT
+		double			f;
+#endif
+		int				enlab;
+		char		   *__sp[2];
+		struct enode   *p[2];
+		struct snode   *st;
+	}				v;
+	char			bit_width, bit_offset; /* possibly unsigned char */
+};
+
+#ifdef AS
+	#define ensp __sp[1]
+#else
+	#define ensp __sp[0]
+#endif
+int not_lvalue(struct enode *node);
+#define g_lvalue(node) (!not_lvalue(node))
+#define lvalue(node) (!not_lvalue(node))
+#define NIL_ENODE ( (struct enode *) 0)
+
+struct snode {
+	enum(e_stmt) 	stype;
+	struct snode   *next;		/* next statement */
+	struct enode   *exp;		/* condition or expression */
+	struct snode   *s1; 		/* internal statement */
+	union {
+		struct enode   *e;		/* condition or expression */
+		struct snode   *s;		/* internal statement (else) */
+		long			i;		/* (case)label or flag */
+	}				v1, v2;
+	unsigned int	count;		/* execution count */
+#ifdef DB_POSSIBLE
+	int				line;
+#endif
+};
+
+#define NIL_SNODE ( (struct snode *) 0)
+
+
+struct cse {
+	struct cse	   *next;
+	struct enode   *exp;		/* optimizable expression */
+	unsigned long	uses;		/* number of uses */
+	unsigned long	duses;		/* number of dereferenced uses */
+	short			voidf;		/* cannot optimize flag */
+#ifdef INFINITE_REGISTERS
+	int 			reg;		/* allocated register */
+#else
+	short			reg;		/* allocated register */
+#endif
+};
+
+struct enode   *mk_node(enum(e_node) nt, struct enode *v1, struct enode *v2);
+struct enode   *mk_icon(long v);
+struct enode   *parmlist();
+struct enode   *copynode();
+struct snode   *statement();
+struct snode   *compound();
+
+void opt4(struct enode **);
+#endif
+// vim:ts=4:sw=4

+ 74 - 0
gtc/src/ffplib.h

@@ -0,0 +1,74 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * Fast Floating Point routines
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef FFPLIB_H
+#define FFPLIB_H
+#ifndef str
+#define STR(__x) #__x
+#define str(__y) STR(__y)
+#endif
+
+#define ffpver ffplib__0000
+#define ffpadd ffplib__0001
+#define ffpsub ffplib__0002
+#define ffpcmp ffplib__0003
+#define ffpcmp_c ffplib__0004
+#define ffpipart ffplib__0005
+#define ffputof ffplib__0006
+#define ffpltof ffplib__0007
+#define ffpftou ffplib__0008
+#define ffpftol ffplib__0009
+#define ffpmul ffplib__000A
+#define ffpmulxp ffplib__000B
+#define ffpsqr ffplib__000C
+#define ffpdiv ffplib__000D
+#define ffpftoa ffplib__000E
+#define ffpftobcd ffplib__000F
+#define ffplog ffplib__0010
+#define ffplog2 ffplib__0011
+#define ffpexp ffplib__0012
+#define ffpexp2 ffplib__0013
+#define ffppwr ffplib__0014
+#define ffpsincos ffplib__0015
+#define ffpsin ffplib__0016
+#define ffpcos ffplib__0017
+#define ffptan ffplib__0018
+#define sqrt ffplib__0019
+
+double ffpadd(double a,double b);
+double ffpsub(double a,double b);
+void ffpcmp(double a,double b);
+long ffpcmp_c(double a,double b);
+double ffpipart(double a);
+double ffputof(unsigned long x);
+double ffpltof(long x);
+unsigned long ffpftou(double a);		// + round
+long ffpftol(double a);					// + round / floor
+double ffpmul(double a,double b);
+double ffpdiv(double a,double b);
+void ffpftoa(double a,char *s);
+void ffpftobcd(double a,void *d);
+double ffplog(double a);
+double ffplog2(double a);
+double ffpexp(double a);
+double ffpexp2(double a);
+double ffppwr(double a,double b);
+// {d0:double, d1:double} ffpsincos(double a);
+double ffpsin(double a);
+double ffpcos(double a);
+double ffptan(double a);
+int sqrt(long x);
+#endif
+// vim:ts=4:sw=4

+ 24 - 0
gtc/src/flashend.c

@@ -0,0 +1,24 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) end of flashapp marker
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+asm(
+"	.text\n"
+"	.align 4\n"
+"	.fdat\n"
+"	.align 4\n"
+"	.bss\n"
+"	.align 4\n"
+"	.fdat\n");
+// vim:ts=4:sw=4

+ 210 - 0
gtc/src/flashhdr.c

@@ -0,0 +1,210 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) flashapp header
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+//#define TEXT_SEG_SUPPORTED
+#ifdef GTDEV
+extern const SecureTab SecTab;
+const SecureTab *SecTabPtr=&SecTab;
+#endif
+
+#ifdef TEXT_SEG_SUPPORTED
+/* note that this is only useful to generate the ASM code below */ #ifdef VERYBASIC_OO
+/* note that this is only useful to generate the ASM code below */ static void AP_app(pFrame self, EVENT *ev);
+/* note that this is only useful to generate the ASM code below */ FRAME(appObj, OO_SYSTEM_FRAME, 0, OO_APP_FLAGS, 3)
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_FLAGS, APP_INTERACTIVE)
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_NAME, "GTC")
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_PROCESS_EVENT, &AP_app)
+/* note that this is only useful to generate the ASM code below */ //   ATTR(OO_APP_DEFAULT_MENU, &AppMenu )
+/* note that this is only useful to generate the ASM code below */ ENDFRAME
+/* note that this is only useful to generate the ASM code below */ #else
+/* note that this is only useful to generate the ASM code below */ #define H_Compile 0
+/* note that this is only useful to generate the ASM code below */ #define H_HELP 100
+/* note that this is only useful to generate the ASM code below */ APP_EXTENSION const extensions[] = {
+/* note that this is only useful to generate the ASM code below */ 	/* function name #, help string #, function index */
+/* note that this is only useful to generate the ASM code below */ #ifdef HAS_CMDLINE_EXTENSION
+/* note that this is only useful to generate the ASM code below */ 	{OO_APPSTRING+H_Compile, OO_APPSTRING+H_HELP+H_Compile, H_Compile },
+/* note that this is only useful to generate the ASM code below */ #endif
+/* note that this is only useful to generate the ASM code below */ };
+/* note that this is only useful to generate the ASM code below */ void _scr_main();
+/* note that this is only useful to generate the ASM code below */ APP_EXT_ENTRY const extEntries[] = {
+/* note that this is only useful to generate the ASM code below */ 	{_scr_main, APP_EXT_PROGRAM},
+/* note that this is only useful to generate the ASM code below */ };
+/* note that this is only useful to generate the ASM code below */ void AP_app(pFrame self, EVENT *ev);
+/* note that this is only useful to generate the ASM code below */ const char *AP_about(AppID self);
+/* note that this is only useful to generate the ASM code below */ FRAME(appObj, OO_SYSTEM_FRAME, 0, OO_APP_FLAGS, 10)
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_FLAGS, APP_INTERACTIVE)
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_NAME, "GTC")
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APP_TOK_NAME, "gtc")
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_PROCESS_EVENT, &AP_app)
+/* note that this is only useful to generate the ASM code below */ #ifdef HAS_CMDLINE_EXTENSION
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APP_EXT_COUNT, 1)
+/* note that this is only useful to generate the ASM code below */ #else
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APP_EXT_COUNT, 0)
+/* note that this is only useful to generate the ASM code below */ #endif
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APP_EXTENSIONS, extensions)
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APP_EXT_ENTRIES, extEntries)
+/* note that this is only useful to generate the ASM code below */    ATTR(OO_APP_ABOUT, &AP_about)
+/* note that this is only useful to generate the ASM code below */ #ifdef HAS_CMDLINE_EXTENSION
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APPSTRING+H_Compile, "compile")
+/* note that this is only useful to generate the ASM code below */ 	ATTR(OO_APPSTRING+H_HELP+H_Compile, "COMPILE A C PROGRAM")
+/* note that this is only useful to generate the ASM code below */ #endif
+/* note that this is only useful to generate the ASM code below */ ENDFRAME
+/* note that this is only useful to generate the ASM code below */ #endif
+/* note that this is only useful to generate the ASM code below */ 
+/* note that this is only useful to generate the ASM code below */ pFrame pAppObj = (pFrame)&appObj;  /* Must be 1st! */
+#else
+#define CODESEG ".text"
+#define DATASEG ".fdat"
+#ifdef VERYBASIC_OO
+asm(
+"	.globl	appObj\n"
+"	" CODESEG "\n"
+"	.align 4\n"
+"appObj:\n"
+"	.long	-16777216\n"
+"	.long	0\n"
+"	.word	3\n"
+"	.long	1\n"
+"	.long	3\n"
+"appObjAttr:\n"
+"	.long	1\n"
+"	.long	1\n"
+"	.long	2\n"
+"	.long	__GTC_str\n"
+"	.long	4\n"
+"	.long	AP_app\n"
+"__GTC_str:\n"
+"	.ascii \"GTC\\0\"\n"
+"	.align 4\n"
+"	.globl	pAppObj\n"
+"	" DATASEG "\n"
+"	.even\n"
+"pAppObj:\n"
+"	.long	appObj\n"
+"	" CODESEG "\n");
+#else
+asm(
+"	" CODESEG "\n"
+"	.even\n"
+#ifdef HAS_CMDLINE_EXTENSION
+"	.globl	extensions\n"
+"extensions:"
+"	.long	4096\n"
+"	.long	4196\n"
+"	.word	0\n"
+"	.globl	extEntries\n"
+"	.even\n"
+"extEntries:"
+"	.long	_scr_main\n"
+"	.word	0\n"
+#endif
+"	.globl	appObj\n"
+"	.even\n"
+"appObj:"
+"	.long	-16777216\n"
+"	.long	0\n"
+"	.word	3\n"
+"	.long	1\n"
+"	.long	10\n"
+"	.even\n"
+"appObjAttr:"
+"	.long	1\n"
+"	.long	1\n"
+"	.long	2\n"
+"	.long	MC0\n"
+"	.long	3\n"
+"	.long	MC1\n"
+"	.long	4\n"
+"	.long	AP_app\n"
+"	.long	7\n"
+#ifdef HAS_CMDLINE_EXTENSION
+"	.long	1\n"
+"	.long	8\n"
+"	.long	extensions\n"
+"	.long	9\n"
+"	.long	extEntries\n"
+#else
+"	.long	0\n"
+#endif
+"	.long	18\n"
+"	.long	AP_about\n"
+#ifdef HAS_CMDLINE_EXTENSION
+"	.long	4096\n"
+"	.long	MC2\n"
+"	.long	4196\n"
+"	.long	MC3\n"
+#endif
+"MC0:"
+"	.ascii \"GTC\\0\"\n"
+"MC1:"
+"	.ascii \"gtc\\0\"\n"
+#ifdef HAS_CMDLINE_EXTENSION
+"MC2:"
+"	.ascii \"compile\\0\"\n"
+"MC3:"
+"	.ascii \"COMPILE A C PROGRAM\\0\"\n"
+#endif
+"	.globl	pAppObj\n"
+"	" DATASEG "\n"
+"	.even\n"
+"pAppObj:"
+"	.long	appObj\n"
+"	" CODESEG "\n");
+#endif
+#endif
+
+void _main();
+void _scr_main();
+#define EV_quit() asm(".word $F800+1166")
+void AP_app(pFrame self, EVENT *ev) {
+   switch (ev->Type) {
+      case CM_STARTTASK:
+		_scr_main();
+		EV_quit();
+		break;
+	}
+}
+
+const char *AP_about(AppID self) {
+	return "GTC compiler\n\n(c) 2001-2003 by Paul Froissart\n\nInternal beta i1";
+}
+
+void _scr_main() {
+	_main();
+	// now redraw the screen... (thanks to PpHd for this code)
+	// 1) the current application
+	{ WINDOW w;
+	WinOpen(&w,&(WIN_RECT){0,0,239,127},WF_NOBOLD|WF_NOBORDER);
+	WinActivate(&w);
+	WinClose(&w); }
+	// 2) the status bar
+	ST_showHelp("");
+	ST_eraseHelp();
+	// 3) the black line
+#if !defined(_92) && !defined(_V200)
+	memset(LCD_MEM+30*(100-7),-1,30);
+#else
+	memset(LCD_MEM+30*(128-7),-1,30);
+#endif
+}
+
+#ifdef GTDEV
+#include "gtdevcomm.c"
+const SecureTab SecTab = {
+	0,
+	Compile
+};
+#endif
+// vim:ts=4:sw=4

+ 301 - 0
gtc/src/flashhdr.h

@@ -0,0 +1,301 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) flashapp header define's
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define OO_HANDLE (0xFF000000u)
+#define OO_SYSTEM_FRAME OO_HANDLE
+typedef ULONG pFrame;
+typedef HANDLE AppID;
+
+typedef void (* APP_EXT_FUNC)(void);
+typedef struct SAppExtension
+{
+   unsigned long name;
+   unsigned long help;
+   unsigned short index;
+} APP_EXTENSION;
+typedef struct SAppExtEntry
+{
+   APP_EXT_FUNC extension;
+   unsigned short flags;
+} APP_EXT_ENTRY;
+enum {APP_EXT_PROGRAM=0x0000, APP_EXT_FUNCTION=0x0001};
+typedef enum
+{
+   ACB_BUILTIN   =0x0001,
+   ACB_INSTALLED =0x0002,
+   ACB_LOCALIZER =0x0004,
+   ACB_LOCK      =0x0008,
+   ACB_JT_VERSION=0x0010,
+   ACB_SELECTED  =0x0020,
+   ACB_COLLAPSE  =0x0800,
+   ACB_BG        =0x1000,
+   ACB_COMPRESS  =0x4000,
+   ACB_DELETE    =0x8000
+} ACB_Flags;
+
+#define MAKE_OO_HANDLE(h) ((h) | OO_HANDLE)
+#define OO_GET_HANDLE(h) ((h) & ~OO_HANDLE)
+#define IS_OO_HANDLE(h) ((h) > OO_HANDLE)
+typedef enum {OO_RW=0,  OO_RO=1,
+              OO_SEQ=0, OO_KEYED=2} OO_Flags;
+typedef struct
+{
+   ULONG key;
+   void *value;
+} OO_Attr;
+typedef struct SFrameHdr
+{
+   pFrame parent;
+   pFrame prototype;
+   OO_Flags flags;
+   ULONG first;
+   ULONG count;
+} OO_Hdr;
+typedef struct SFrame
+{
+   OO_Hdr head;
+   union
+   {
+      void *value[65000];
+      OO_Attr pair[65000];
+   } attr;
+} Frame;
+typedef void (* const OO_MethodPtr)(void);
+#define STRING_FRAME(name, parent, proto, first, count) \
+const OO_Hdr name =   \
+{                     \
+   (pFrame)parent,    \
+   (pFrame)proto,     \
+   OO_RO | OO_SEQ,    \
+   first,             \
+   count              \
+};                    \
+static const char * const name##Attr[count] = \
+{
+#define FRAME(name, parent, proto, first, count) \
+const OO_Hdr name =   \
+{                     \
+   (pFrame)parent,    \
+   (pFrame)proto,     \
+   OO_RO | OO_KEYED,  \
+   first,             \
+   count              \
+};                    \
+static const OO_Attr name##Attr[count] = \
+{
+#define ATTR(selector, val) {selector, (void *)(val)},
+#define STRING_ATTR(sel, s) {OO_FIRST_STRING+(sel), s},
+#define ENDFRAME };
+#define MAX_APPLET_NAME_SIZE (8)
+
+#define OO_APP_FLAGS (1)
+#define GetAppFlags(obj) \
+  (APP_Flags)OO_GetAppAttr(obj,1)
+#define SetAppFlags(obj,value) \
+  OO_SetAppAttr(obj,1,(void *)value)
+#define OO_APP_NAME (2)
+#define GetAppName(obj) \
+  (UCHAR *)OO_GetAppAttr(obj,2)
+#define SetAppName(obj,value) \
+  OO_SetAppAttr(obj,2,(void *)value)
+#define OO_APP_TOK_NAME (3)
+#define GetAppTokName(obj) \
+  (UCHAR *)OO_GetAppAttr(obj,3)
+#define SetAppTokName(obj,value) \
+  OO_SetAppAttr(obj,3,(void *)value)
+#define OO_APP_PROCESS_EVENT (4)
+#define AppProcessEvent(obj,a) \
+  ((void (* const)(pFrame, PEvent))OO_GetAttr(obj,4))(obj,a)
+#define OO_APP_DEFAULT_MENU (5)
+#define GetAppDefaultMenu(obj) \
+  (MENU *)OO_GetAppAttr(obj,5)
+#define SetAppDefaultMenu(obj,value) \
+  OO_SetAppAttr(obj,5,(void *)value)
+#define OO_APP_DEFAULT_MENU_HANDLE (6)
+#define GetAppDefaultMenuHandle(obj) \
+  (HANDLE)OO_GetAppAttr(obj,6)
+#define SetAppDefaultMenuHandle(obj,value) \
+  OO_SetAppAttr(obj,6,(void *)value)
+#define OO_APP_EXT_COUNT (7)
+#define GetAppExtCount(obj) \
+  (long)OO_GetAppAttr(obj,7)
+#define SetAppExtCount(obj,value) \
+  OO_SetAppAttr(obj,7,(void *)value)
+#define OO_APP_EXTENSIONS (8)
+#define GetAppExtensions(obj) \
+  (APP_EXTENSION const *)OO_GetAppAttr(obj,8)
+#define SetAppExtensions(obj,value) \
+  OO_SetAppAttr(obj,8,(void *)value)
+#define OO_APP_EXT_ENTRIES (9)
+#define GetAppExtEntries(obj) \
+  (APP_EXT_ENTRY const *)OO_GetAppAttr(obj,9)
+#define SetAppExtEntries(obj,value) \
+  OO_SetAppAttr(obj,9,(void *)value)
+#define OO_APP_LOCALIZE (10)
+#define AppLocalize(obj,a) \
+  ((BOOL (* const)(AppID, UCHAR const *))OO_GetAppAttr(obj,10))(obj,a)
+#define OO_APP_UNLOCALIZE (11)
+#define AppUnlocalize(obj) \
+  ((void (* const)(AppID))OO_GetAppAttr(obj,11))(obj)
+#define OO_APP_CAN_DELETE (12)
+#define AppCanDelete(obj) \
+  ((BOOL (* const)(AppID))OO_GetAppAttr(obj,12))(obj)
+#define OO_APP_CAN_MOVE (13)
+#define AppCanMove(obj) \
+  ((BOOL (* const)(AppID))OO_GetAppAttr(obj,13))(obj)
+#define OO_APP_VIEWER (14)
+#define AppViewer(obj,a,b,c) \
+  ((BOOL (* const)(AppID, BYTE *, WINDOW *, HSYM))OO_GetAppAttr(obj,14))(obj,a,b,c)
+#define OO_APP_ICON (15)
+#define GetAppIcon(obj) \
+  (BITMAP *)OO_GetAppAttr(obj,15)
+#define SetAppIcon(obj,value) \
+  OO_SetAppAttr(obj,15,(void *)value)
+#define OO_APP_EXT_HELP (16)
+#define AppExtHelp(obj,a) \
+  ((void (* const)(AppID, USHORT))OO_GetAppAttr(obj,16))(obj,a)
+#define OO_APP_NOTICE_INSTALL (17)
+#define AppNoticeInstall(obj,a) \
+  ((void (* const)(AppID, ACB const *))OO_GetAppAttr(obj,17))(obj,a)
+#define OO_APP_ABOUT (18)
+#define AppAbout(obj) \
+  ((char const * (* const)(AppID))OO_GetAppAttr(obj,18))(obj)
+#define OO_SFONT (768)
+#define Getsfont(obj) \
+  (SF_CHAR *)OO_GetAttr(obj,768)
+#define Setsfont(obj,value) \
+  OO_SetAttr(obj,768,(void *)value)
+#define OO_LFONT (769)
+#define Getlfont(obj) \
+  (LF_CHAR *)OO_GetAttr(obj,769)
+#define Setlfont(obj,value) \
+  OO_SetAttr(obj,769,(void *)value)
+#define OO_HFONT (770)
+#define Gethfont(obj) \
+  (HF_CHAR *)OO_GetAttr(obj,770)
+#define Sethfont(obj,value) \
+  OO_SetAttr(obj,770,(void *)value)
+#define OO_APP_SFONT (768)
+#define GetAppSFont(obj) \
+  (SF_CHAR *)OO_GetAppAttr(obj,768)
+#define SetAppSFont(obj,value) \
+  OO_SetAppAttr(obj,768,(void *)value)
+#define OO_APP_LFONT (769)
+#define GetAppLFont(obj) \
+  (LF_CHAR *)OO_GetAppAttr(obj,769)
+#define SetAppLFont(obj,value) \
+  OO_SetAppAttr(obj,769,(void *)value)
+#define OO_APP_HFONT (770)
+#define GetAppHFont(obj) \
+  (HF_CHAR *)OO_GetAppAttr(obj,770)
+#define SetAppHFont(obj,value) \
+  OO_SetAppAttr(obj,770,(void *)value)
+#define OO_LANGUAGE (784)
+#define GetLanguage(obj) \
+  (WORD)OO_GetAttr(obj,784)
+#define SetLanguage(obj,value) \
+  OO_SetAttr(obj,784,(void *)value)
+#define OO_DATE_FORMAT (785)
+#define GetDateFormat(obj) \
+  (char const *)OO_GetAttr(obj,785)
+#define SetDateFormat(obj,value) \
+  OO_SetAttr(obj,785,(void *)value)
+#define OO_BUILTIN_HELP (786)
+#define BuiltinHelp(obj,a) \
+  ((void (* const)(pFrame, USHORT))OO_GetAttr(obj,786))(obj,a)
+#define OO_KTLIST (800)
+#define GetKTList(obj) \
+  (keytag const *)OO_GetAttr(obj,800)
+#define SetKTList(obj,value) \
+  OO_SetAttr(obj,800,(void *)value)
+#define OO_CAT_TABLE (801)
+#define GetCAT_table(obj) \
+  (CATALOG const *)OO_GetAttr(obj,801)
+#define SetCAT_table(obj,value) \
+  OO_SetAttr(obj,801,(void *)value)
+#define OO_CAT_INDEX (802)
+#define GetCAT_index(obj) \
+  (short const *)OO_GetAttr(obj,802)
+#define SetCAT_index(obj,value) \
+  OO_SetAttr(obj,802,(void *)value)
+#define OO_CAT_COUNT (803)
+#define GetCAT_count(obj) \
+  (short)OO_GetAttr(obj,803)
+#define SetCAT_count(obj,value) \
+  OO_SetAttr(obj,803,(void *)value)
+#define OO_CHAR_MENU (816)
+#define GetCharMenu(obj) \
+  (const MENU *)OO_GetAttr(obj,816)
+#define SetCharMenu(obj,value) \
+  OO_SetAttr(obj,816,(void *)value)
+#define OO_CHAR_HANDLER (817)
+#define CharHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,817))(obj)
+#define OO_APPS_HANDLER (818)
+#define AppsHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,818))(obj)
+#define OO_FLASH_APPS_HANDLER (819)
+#define FlashAppsHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,819))(obj)
+#define OO_MATH_HANDLER (820)
+#define MathHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,820))(obj)
+#define OO_MEM_HANDLER (821)
+#define MemHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,821))(obj)
+#define OO_STO_HANDLER (822)
+#define StoHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,822))(obj)
+#define OO_QUIT_HANDLER (823)
+#define QuitHandler(obj) \
+  ((void (* const)(pFrame))OO_GetAttr(obj,823))(obj)
+
+#define OO_FIRST_STRING             2048
+#define OO_FIRST_APP_STRING         2048
+#define OO_APPSTRING (OO_FIRST_STRING+OO_FIRST_APP_STRING)
+#define OO_FIRST_APP_ATTR        0x10000
+typedef enum {APP_NONE=0,
+              APP_INTERACTIVE=1,
+              APP_CON=2,
+              APP_ACCESS_SYSVARS=4,
+              APP_BACKGROUND=8}
+        APP_Flags;
+
+typedef struct SAppHdr
+{
+   ULONG magic;
+   UCHAR name[MAX_APPLET_NAME_SIZE];
+   BYTE  zeros[24];
+   USHORT flags;
+   ULONG dataLen;
+   ULONG codeOffset;
+   ULONG initDataOffset;
+   ULONG initDataLen;
+   ULONG optlen;
+} AppHdr;
+typedef struct SACB
+{
+   USHORT flags;
+   AppID myID;
+   AppID next;
+   AppID prev;
+   ULONG publicstorage;
+   AppHdr const *appHeader;
+   BYTE const *certhdr;
+   pFrame appData;
+} ACB;
+#define MY_ACB(p) ((ACB*)((BYTE*)&(p)-OFFSETOF(ACB,appData)))
+#define MY_APP_ID(p) (MY_ACB(p)->myID)
+// vim:ts=4:sw=4

+ 471 - 0
gtc/src/func.c

@@ -0,0 +1,471 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * function routines
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define DECLARE
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+int 			is_leaf_function CGLOB, uses_link CGLOB, pushed CGLOB;
+XLST_TYPE		reg_size CGLOB;
+
+
+void funcbottom(void);
+void block(struct sym *sp); /* CAUTION : always requires a compound_done() after call */
+
+/* function compilation routines */
+
+#ifdef REGPARM
+SYM *parmsp[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1+1];
+#endif
+void funcbody(SYM *sp, char *names[], int nparms) {
+/*
+ * funcbody starts with the current symbol being the begin for the local
+ * block or the first symbol of the parameter declaration
+ */
+	long			poffset;
+	int 			i, j;
+	struct sym	   *sp1, *mk_int();
+	int 			old_global;
+	long			old_spvalue;
+	XLST_TYPE	   *p;
+#ifdef REGPARM
+	int regs=sp->tp->rp_dn+sp->tp->rp_an;
+#endif
+
+#ifdef VERBOSE
+	time_t			ltime;
+#endif							/* VERBOSE */
+
+#ifdef VERBOSE
+	times(&tms_buf);
+	ltime = tms_buf.tms_utime;
+#endif							/* VERBOSE */
+/*	uses_structassign=0;*/
+	lc_auto = 0;
+	max_scratch = 0;
+	is_leaf_function = 1;
+	uses_link = 0;
+	pushed = 0;
+	init_node = 0;
+	old_global = global_flag;
+	global_flag = 0;
+	poffset = 8;				/* size of return block */
+#ifdef REGPARM
+	memset(parmsp,0,sizeof(parmsp));
+#endif
+	/*if (!strcmp(declid,"MnuSel"))
+		printf("sgio");*/
+	if (bt_aggregate(sp->tp->btp->type))
+		poffset = 12;
+	if (!start_block(0))
+		dodecl(sc_parms);		/* declare parameters */
+	/* undeclared parameters are int's */
+	if (!lc_auto)	/* otherwise there are declared vars that aren't parameters : error */
+		for (i = 0; i < nparms; ++i) {
+			if (!(sp1 = search(names[i], -1, &lsyms))) {
+				sp1 = mk_int(names[i]);
+	//			do_warning("argument '%s' implicitly declared 'int'",names[i]);
+			}
+			old_spvalue = sp1->value.i;
+			sp1->value.i = poffset;
+			sp1->storage_class = sc_auto;
+	#ifdef REGPARM
+			if (regs) {
+				int siz;
+				if (sp1->tp->type==bt_pointer || sp1->tp->type==bt_func) {
+					/*
+					 * arrays and functions are never passed. They are really
+					 * Pointers
+					 */
+					if (sp1->tp->val_flag != 0) {
+						TYP *tp1 = (TYP *) xalloc((int) sizeof(TYP), _TYP+FUNCBODY);
+						*tp1 = *(sp1->tp);
+						sp1->tp = tp1;
+						tp1->st_flag = 0;
+						sp1->tp->val_flag = 0;
+						sp1->tp->size = 4;
+					}
+				}
+				siz=sp1->tp->size;
+		#ifdef AS
+				sp1->value.i = -(lc_auto+siz+(siz&1)/* dirty hack, but it works */);
+		#else
+				sp1->value.i = -(lc_auto+siz+(siz&1)/* dirty hack, but it works */);
+//				if (siz&1) printf("[crp]"),getchar();
+		#endif
+				siz+=siz&1;
+				lc_auto+=siz;
+				parmsp[i]=sp1;
+				regs--;
+//				goto ok_param;
+				poffset -= siz;	/* to undo the effect of the following statements */
+			}
+	#endif
+			/*
+			 * char, unsigned char, short, unsigned short, enum have been widened
+			 * to int by the caller. This has to be un-done The same is true for
+			 * float/double but float==double actually convert x[] to *x by
+			 * clearing val_flag
+			 * 
+			 * It is shown here how to do this correctly, but if we know something
+			 * about the data representation, it can be done much more
+			 * effectively. Therefore, we define MC680X0 and do the cast
+			 * by hand. This means that we can retrieve a char, widened to short
+			 * and put at machine address n, at machine address n+1. This should
+			 * work on most machines. BIGendian machines can do it like it is
+			 * shown here, LOWendian machines must not adjust sp1->value.i The
+			 * function castback is still needed if someone decides to have a
+			 * double data type which is not equivalent to float.
+			 * This approach is, of course, ugly since some
+			 * assumptions on the target machine enter the front end here, but
+			 * they do anyway through the initial value of poffset which is the
+			 * number of bytes that separate the local block from the argument
+			 * block. On a 68000 this are eight bytes since we do a link a6,...
+			 * always.
+			 */
+			switch (sp1->tp->type) {
+			  case bt_char:
+			  case bt_uchar:
+	#ifdef MC680X0
+				if (short_option) {
+					sp1->value.i += 1;
+					poffset += 2;
+				} else {
+					sp1->value.i += 3;
+					poffset += 4;
+				}
+	#endif
+	#ifdef INTEL_386
+				/* note that we only support 32-bit integers */
+				poffset += 4; /* byte already right there */
+	#endif
+				break;
+			  case bt_short:
+			  case bt_ushort:
+	#ifdef MC680X0
+				if (short_option) {
+					poffset += 2;
+				} else {
+					sp1->value.i += 2;
+					poffset += 4;
+				}
+	#endif
+	#ifdef INTEL_386
+				poffset += 4; /* word already right there */
+	#endif
+				break;
+			  case bt_float:
+	#ifdef MC68000
+				/* float is the same as double in the 68000 implementation */
+				poffset += float_size;
+	#endif
+	#ifdef INTEL_386
+				castback(poffset, &tp_double, &tp_float);
+				poffset += 8;
+	#endif
+				break;
+			  case bt_pointer:
+			  case bt_func:
+				poffset += 4;
+				/*
+				 * arrays and functions are never passed. They are really
+				 * Pointers
+				 */
+				if (sp1->tp->val_flag != 0) {
+					TYP 		   *tp1 = (TYP *) xalloc((int) sizeof(TYP), _TYP+FUNCBODY);
+					*tp1 = *(sp1->tp);
+					sp1->tp = tp1;
+					tp1->st_flag = 0;
+					sp1->tp->val_flag = 0;
+					sp1->tp->size = 4;
+				}
+				break;
+			  default:
+				poffset += sp1->tp->size;
+				break;
+			}
+//		  ok_param:
+			/*
+			 * The following code updates the reglst and autolst arrays
+			 * old_spvalue is zero for undeclared parameters (see mk_int), so it
+			 * works. We do a linear search through the reglst and autolst array,
+			 * so this is inefficient. Howewer, these arrays are usually short
+			 * since they only contain the function arguments at moment. In
+			 * short, function argument processing need not be efficient.
+			 */
+			p=reglst; j=regptr; while (j--) {
+				if ((XLST_TYPE)*p++ == (XLST_TYPE)old_spvalue) {
+					p[-1] = sp1->value.i;
+					break;
+				}
+			}
+			p=autolst; j=autoptr; while (j--) {
+				if ((XLST_TYPE)*p++ == (XLST_TYPE)old_spvalue) {
+					p[-1] = sp1->value.i;
+					break;
+				}
+			}
+		}
+	else
+		/*
+		 * Check if there are declared parameters missing in the argument list.
+		 *  (this needs to be done iff lc_auto!=0, so with DETAILED_ERR not defined
+		 *   this is just OK)
+		 */
+#ifdef DETAILED_ERR
+		for (i=0;i<N_HASH;i++) {
+			sp1 = lsyms.h[i].tail;
+			while (sp1 != 0) {
+				/*
+				 * assume that value.i is negative for normal auto variables
+				 * and positive for parameters -- in fact this is correct either
+				 * with REGPARM not defined, or before the parameter scan whose code is
+				 * just above this
+				 */
+				if (sp1->value.i <= 0)
+#endif
+					error(ERR_ARG);
+#ifdef DETAILED_ERR
+				sp1 = sp1->prev;
+			}
+		}
+#endif
+#ifdef REGPARM
+	reg_size=lc_auto;
+#endif
+	if (!start_block(0))
+		error(ERR_BLOCK);
+	else {
+		block(sp);
+		funcbottom();
+	}
+	global_flag = old_global;
+	compound_done();					// due to block(sp)
+#ifdef VERBOSE
+	times(&tms_buf);
+	parse_time += tms_buf.tms_utime - ltime;
+#endif							/* VERBOSE */
+}
+
+struct sym *mk_int(char *name) {
+	struct sym	   *sp;
+	TYP 		   *tp;
+	sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM+MK_INT);
+	tp = (TYP *) xalloc((int) sizeof(TYP),_TYP+MK_INT);
+	if (short_option) {
+		tp->type = bt_short;
+		tp->size = 2;
+	} else {
+		tp->type = bt_long;
+		tp->size = 4;
+	}
+#ifdef NO_CALLOC
+	tp->btp = 0;
+	tp->lst.tail = tp->lst.head = 0; tp->lst.hash = 0;
+	tp->vol_flag = tp->val_flag = tp->const_flag = tp->st_flag = 0;
+#ifdef LISTING
+	tp->sname = 0;
+#endif
+#endif
+	sp->name = name;
+	sp->storage_class = sc_auto;
+	sp->tp = tp;
+#ifdef NO_CALLOC
+	sp->value.i = 0;			/* dummy -> means param is undeclared */
+#endif
+	append(&sp, &lsyms);
+	return sp;
+}
+
+void check_table(HTABLE *table) {
+	SYM *head;
+	struct htab *ptr; int i;
+	ptr=&table->h[0];
+	i=N_HASH;
+	while (i--) {
+		head=ptr->head;
+		while (head != 0) {
+			if (head->storage_class == sc_ulabel) {
+				uerrc2("undefined label '%s'",head->name);
+//				msg2("*** UNDEFINED LABEL - %s\n", head->name);
+#ifdef LISTING
+				if (list_option)
+					fprintf(list, "*** UNDEFINED LABEL - %s\n", head->name);
+#endif
+			}
+			head = head->next;
+		}
+		ptr++;
+	}
+}
+
+void funcbottom(void) {
+	nl();
+	check_table(&labsyms);
+#ifdef LISTING
+//	if (list_option && lsyms.head != 0) {
+		fprintf(list, "\n\n*** argument symbol table ***\n\n");
+		list_table(&lsyms, 0);
+		fprintf(list, "\n\n\n");
+//	}
+//	if (list_option && labsyms.head != 0) {
+		fprintf(list, "\n\n*** label symbol table ***\n\n");
+		list_table(&labsyms, 0);
+		fprintf(list, "\n\n\n");
+//	}
+#endif
+#ifdef AS
+	local_clean();
+#endif
+	rel_local();				/* release local symbols */
+	hashinit(&lsyms);
+	hashinit(&ltags);
+	hashinit(&labsyms);
+}
+
+extern char *curname;
+xstatic struct enode save_sp CGLOBL;
+struct snode *dump_stmt;
+SYM *func_sp CGLOB;
+void block(struct sym *sp) { /* CAUTION : always requires a compound_done() after call */
+	struct snode   *stmt;
+	int local_total_errors = total_errors;
+	int				line0;
+#ifdef VERBOSE
+	time_t			ltime;
+#endif							/* VERBOSE */
+
+//#ifdef VERBOSE
+#ifdef AS
+	scope_init();
+#endif
+	func_sp=sp;
+	/*infunc("fire")
+		bkpt();*/
+#ifndef GTDEV
+#ifdef PC
+	if (verbose)
+#endif
+		msg2("Compiling '%s'... ", sp->name);
+#endif
+//#endif							/* VERBOSE */
+
+#ifdef ICODE
+	if (icode_option)
+		if (sp->storage_class == sc_external || sp->storage_class == sc_global)
+			fprintf(icode, "%s:\n", sp->name);
+		else
+			fprintf(icode, "L%ld:\n", sp->value.i);
+#endif
+#ifdef SHOWSTEP
+	printf("\nparsing");
+#endif
+	start_block(1);
+	line0=prevlineid;
+	dump_stmt = stmt = compound(-1);
+#ifdef SHOWSTEP
+	printf(" ok ");
+#endif
+#ifdef VERBOSE
+	times(&tms_buf);
+	ltime = tms_buf.tms_utime;
+#endif							/* VERBOSE */
+/*
+ * If errors so far, do not try to generate code
+ */
+	if (total_errors > local_total_errors) {
+		cseg();
+		dumplits();
+		return;
+	}
+	lineid=line0;
+	genfunc(stmt);
+#ifdef VERBOSE
+	times(&tms_buf);
+	gen_time += tms_buf.tms_utime - ltime;
+	ltime = tms_buf.tms_utime;
+#endif							/* VERBOSE */
+	cseg();
+	dumplits();
+	put_align(AL_FUNC);
+#ifndef AS
+	if (sp->storage_class == sc_external || sp->storage_class == sc_global)
+		g_strlab(sp->name);
+	else
+		put_label((unsigned int) sp->value.i);
+#else
+	put_label(splbl(sp));
+#endif
+	if (!strcmp(sp->name,"__main") && !search("NO_EXIT_SUPPORT",-1,&defsyms)) {
+		save_sp.nodetype = en_nacon;
+		save_sp.etype = bt_pointer;
+		save_sp.esize = 4;
+		save_sp.v.ensp = "__save__sp__";
+#ifdef AS
+		save_sp.v.enlab = label("__save__sp__");
+#endif
+		g_coder(op_move,4,mk_reg(STACKPTR),mk_offset(&save_sp));
+	}
+	flush_peep();
+#ifdef AS
+	scope_flush();
+#endif
+	func_sp=NULL;
+#ifdef VERBOSE
+	times(&tms_buf);
+	flush_time += tms_buf.tms_utime - ltime;
+#endif							/* VERBOSE */
+}
+
+void castback(long offset, TYP *tp1, TYP *tp2) {
+/*
+ * cast an argument back which has been widened on the caller's side.
+ * append the resulting assignment expression to init_node
+ */
+	struct enode   *ep1, *ep2;
+
+	ep2 = mk_node(en_autocon, NIL_ENODE, NIL_ENODE);
+	ep2->v.i = offset;
+	ep2->etype = bt_pointer;
+	ep2->esize = 4;
+
+	ep1 = copynode(ep2);
+
+	ep2 = mk_node(en_ref, ep2, NIL_ENODE);
+	ep2->etype = tp1->type;
+	ep2->esize = tp1->size;
+
+	ep2 = mk_node(en_cast, ep2, NIL_ENODE);
+	ep2->etype = tp2->type;
+	ep2->esize = tp2->size;
+
+	ep1 = mk_node(en_ref, ep1, NIL_ENODE);
+	ep1->etype = tp2->type;
+	ep1->esize = tp2->size;
+
+	ep1 = mk_node(en_assign, ep1, ep2);
+	ep1->etype = tp2->type;
+	ep1->esize = tp2->size;
+
+	if (init_node == 0)
+		init_node = ep1;
+	else
+		init_node = mk_node(en_void, init_node, ep1);
+}
+// vim:ts=4:sw=4

+ 352 - 0
gtc/src/gen.h

@@ -0,0 +1,352 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * code generator
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef GEN_H
+#define GEN_H
+
+/* addressing modes */
+
+#ifdef MC680X0
+#define F_DREG	1				/* data register direct mode allowed */
+#define F_AREG	2				/* address register direct mode allowed */
+#define F_MEM	4				/* memory alterable modes allowed */
+#define F_IMMED 8				/* immediate mode allowed */
+#define F_ALT	7				/* alterable modes */
+#define F_DALT	5				/* data-alterable modes */
+#define F_ALL	15				/* all modes allowed */
+#define F_VOL	16				/* need volatile operand */
+#define F_NOVALUE 32			/* dont need result value */
+#define F_USES	  64			/* need result value more than once */
+								/* (this forbids autoincrement modes) */
+#define F_DEREF 128				/* for derefenced use only (eg allow #L1) */
+#define F_SRCOP 256				/* for source operand only (eg allow L1(pc)) */
+#endif /* MC680X0 */
+
+#ifdef INTEL_386
+#define F_REG		1			/* a register, like %eax, %edi etc. */
+#define F_MEM		2			/* direct, indirect, indexed */
+#define F_IMMED 	4			/* immedate */
+#define F_FPSTACK	8			/* top of floating-point stack */
+#define F_NOVALUE  16			/* dont need result value */
+#define F_VOL	   32			/* need scratch register */
+#define F_ALL	   15			/* any mode */
+#define F_NOEDI    64			/* do not use %edi and %esi */
+#endif /* INTEL_386 */
+
+/* The instructions */
+
+#ifdef MC680X0
+/*
+ * The order of the branch instructions must not be changed
+ * since array revcond[] in the peephole optimizer and 
+ * truejp/falsejp in the code generator rely on them.
+ * Beware of OUT_AS too.
+ * In addition, peep::SPEED_OPT assumes that (op_jmp,op_rts)<op_bra<_op_cond
+ */
+enum e_op {
+	// 0x00
+	op_move, op_moveq, op_clr, op_lea,	/* destructive instructions */
+	op_add, op_addi, op_addq, op_sub, op_subi,
+	op_subq, op_muls, op_mulu, op_divs, op_divu, op_and, op_andi,
+	// 0x10
+	op_or, op_ori, op_eor, op_eori, op_lsl, op_lsr, op_jmp, op_jsr, op_movem,
+	op_rts, op_bra, op_bsr, op_beq, op_bne,
+	// 0x1E
+	op_bhs, op_bge, op_bhi, op_bgt, op_bls, op_ble, op_blo, op_blt,	/* unsigned, signed */
+	op_tst, op_ext, op_swap,
+	// 0x29
+	op_neg, op_not, op_cmp, op_link, op_unlk, op_label,
+	op_pea, op_cmpi, op_dbra, op_asr, op_bset, op_bclr, op_bchg, _op_asm, _op_adj,
+#ifdef INFINITE_REGISTERS
+	_op_cleanup_for_external_call,
+#endif
+	// 0x38
+#ifdef ASM
+	/* ASM-only */
+	op_asl, op_rol, op_ror, op_roxl, op_roxr, op_btst, op_exg, op_dc, op_ds, op_dcb,
+	// 0x42
+	op_bvs, op_bvc, op_bpl, op_bmi, op_trap, op_negx, op_addx, op_subx,
+	// 0x4A
+	op_chk, op_even,
+	/*op_dbt,*/ /*op_dbf,*/ op_dbeq, op_dbne,
+#ifndef LIGHT_DBXX_AND_SXX
+	op_dbhs, op_dbge, op_dbhi, op_dbgt, op_dbls, op_dble, op_dblo, op_dblt,/* unsigned, signed */
+	op_dbvs, op_dbvc, op_dbpl, op_dbmi,
+	op_st,  op_sf,  op_seq, op_sne,
+	op_shs, op_sge, op_shi, op_sgt, op_sls, op_sle, op_slo, op_slt,	/* unsigned, signed */
+	op_svs, op_svc, op_spl, op_smi,
+	op_tas,
+#endif
+#endif
+};
+#define op_destroy(__op) (__op<=op_lea)
+#define _op_bxx_min op_bra
+#define _op_bcond_min op_beq
+#define _op_bxx_max op_blt
+#ifdef ASM
+#define op_bxx op_bra: case op_bsr: case op_beq: case op_bne: case op_bhs: case op_bge: case op_bhi: case op_bgt: case op_bls: case op_ble: case op_blo: case op_blt: case op_bpl: case op_bmi: case op_bvc: case op_bvs
+#else
+#define op_bxx op_bra: case op_bsr: case op_beq: case op_bne: case op_bhs: case op_bge: case op_bhi: case op_bgt: case op_bls: case op_ble: case op_blo: case op_blt
+#endif
+#define op_bcond op_beq: case op_bne: case op_bhs: case op_bge: case op_bhi: case op_bgt: case op_bls: case op_ble: case op_blo: case op_blt
+#define op_dbxx op_dbra: case op_dbeq: case op_dbne
+#ifdef ASM
+#ifndef LIGHT_DBXX_AND_SXX
+#define _op_max op_tas
+#else
+#define _op_max op_dbne
+#endif
+#else
+#define _op_max _op_adj
+#endif
+#endif
+
+#ifdef INTEL_386
+enum e_op {
+	op_movsbl, op_movzbl, op_movswl, op_movzwl,
+	op_movsbw, op_movzbw,
+	op_cltd,
+	op_mov, op_lea,
+	op_not, op_neg,
+	op_add, op_sub, op_imul, op_idiv,
+	op_and, op_or, op_xor,
+	op_inc, op_dec,
+	op_cmp,
+	op_push, op_pop,
+	op_jmp, op_bra, op_call, op_leave, op_ret,
+	op_test,
+	op_je, op_jne,
+	op_jl, op_jle, op_jg, op_jge,
+	op_ja, op_jae, op_jb, op_jbe,
+	op_rep, op_smov,
+	op_shl, op_shr, op_asr,
+	op_fadd, op_fsub, op_fdiv, op_fmul,
+	op_fsubr, op_fdivr,
+	op_fld, op_fst, op_fstp, op_fpop,
+	op_fild, op_ftst,
+	op_fchs, op_fcompp, op_fnstsw, op_sahf,
+	op_label
+};
+#endif
+
+#ifdef MC680X0
+/* CAUTION : changing this order requires changing sz_table, */
+/*  modifying out68k_as::Pass1()                             */
+/*  and requires am_immed to be right before am_direct and   */
+/*  am_areg right before am_ind                              */
+/*  - in addition, changing am_dreg is not recommended... -  */
+enum e_am {
+	am_dreg, am_areg, am_ind, am_ainc, am_adec, am_indx, am_indx2,
+	am_indx3, am_immed, am_direct, am_mask1, am_mask2,
+	/* AS-only (subcases of am_direct) : */
+	am_pcrel, am_dirw, am_dirl,
+	/* ASM-only */
+	am_sr, am_ccr, am_usp,
+};
+#define am_deref(x) ((x)+1)
+#define am_doderef(x) (++(x))
+#define am_is_increment(x) ((x)==am_ainc || (x)==am_adec)
+#endif
+
+#ifdef INTEL_386
+enum e_am {
+	am_reg, am_indx, am_indx2, am_direct, am_immed, am_star, am_fpstack
+};
+#endif
+
+#ifdef INFINITE_REGISTERS
+#if 0
+typedef struct {
+	int n;
+} reg_t;
+#define init_reg_t(x) {x}
+#define nil_reg_t {-1}
+#else
+typedef int reg_t;
+#define init_reg_t(x) (x)
+#define nil_reg_t (-1)
+#endif
+#define FIRSTREG    1000
+#define MAX_ADDR  100000
+#define MAX_DATA  100000
+#define AREGBASE  400000
+#define TDREGBASE 300000
+#define TAREGBASE 700000
+#define reg_t_to_regexp(x) ((x)>=AREGBASE?2*((x)-AREGBASE-MAX_ADDR)+1:2*((x)-MAX_DATA))
+#define REGEXP_SIZE 20000
+#else
+#define reg_t char
+#define init_reg_t(x) (x)
+#define nil_reg_t 0
+#define AREGBASE 8
+#define FIRSTREG 0
+#define reg_t_to_regexp(x) (x)
+#define REGEXP_SIZE 16
+#define TDREGBASE 0
+#endif
+#define CONVENTION_MAX_DATA 2
+#define CONVENTION_MAX_ADDR 1
+
+/* addressing mode structure */
+
+struct amode {
+	enum(e_am)		mode;
+	struct enode   *offset;
+/*
+ * these chars may be unsigned...
+ */
+	reg_t			preg, sreg;
+	char			deep, slen;
+};
+
+#define NIL_AMODE ( (struct amode *) 0)
+
+/* output code structure */
+
+struct ocode {
+	enum(e_op)		opcode;
+	struct ocode   *fwd, *back;
+	struct amode   *oper1, *oper2;
+	int 			length;
+#ifdef DB_POSSIBLE
+	int				line;
+#endif
+#ifdef AS
+	char			sz,opt;
+#endif
+};
+struct lbls {
+	enum(e_op)		opcode;
+	struct ocode   *fwd, *back;
+	int 			lab;
+};
+
+/* register naming, special registers */
+
+#ifdef MC680X0
+#ifdef INFINITE_REGISTERS
+#define RESULT	  (TDREGBASE+0) 			/* register returning function results */
+#define PRESULT   (TAREGBASE+0) 			/* register returning pointer function results */
+#ifdef USE_LINK
+#define FRAMEPTR  (TAREGBASE+6)			/* frame pointer register */
+#else
+#define TRUE_FRAMEPTR (TAREGBASE+6)
+#define FRAMEPTR  (TAREGBASE+8)			/* frame pointer pseudo-register */
+#endif
+#define STACKPTR  (TAREGBASE+7)			/* system stack pointer register */
+#else
+#define RESULT	  0 			/* register returning function results */
+#define PRESULT   8 			/* register returning pointer function results */
+#ifdef USE_LINK
+#define FRAMEPTR  14			/* frame pointer register */
+#else
+#define TRUE_FRAMEPTR 14
+#define FRAMEPTR  16			/* frame pointer pseudo-register */
+#endif
+#define STACKPTR  15			/* system stack pointer register */
+#endif
+#endif /* MC680X0 */
+
+#ifdef INTEL_386
+#define RESULT			0		/* reg ret. integer-type function results */
+#define EAX 			0
+#define EDX 			1
+#define EBX 			2
+#define ECX 			3
+#define ESI 			4
+#define EDI 			5
+#define ESP 			6
+#define STACKPTR		6		/* system stack pointer */
+#define EBP 			7		/* frame pointer */
+#define FRAMEPTR		7
+/* attention: same order as above */
+#define AX				8
+#define DX				9
+#define BX				10
+#define CX				11
+#define SI				12
+#define DI				13
+/* attention: same order as above */
+#define AL				14
+#define DL				15
+#define BL				16
+#define CL				17
+
+#define NUMREG			REG8(EBP)
+
+/*
+ * The code generator does not distinguish between %eax, %ax, %al
+ * because some assemblers want it strict, the real register names
+ * are determined when the assembly instruction is PRINTED, e.g.
+ * code generator produces movb junk,%eax,
+ * assembly code printer prints movb junk,%al
+ * The conversion is done by the following macros
+ */
+#define REG16(X) ((X)-EAX+AX)
+#define REG8(X)  ((X)-EAX+AL)
+#endif
+
+#ifdef MC680X0
+#ifndef INFINITE_REGISTERS
+#define 		MAX_REG_STACK	30
+
+#define MAX_ADDR 1				/* max. scratch address register (A1) */
+#define MAX_DATA 2				/* max. scratch data	register (D2) */
+#endif
+#endif
+#ifdef INTEL_386
+#define MAX_REG  1				/* scratch registers: %eax..%edx */
+#endif
+
+struct reg_struct {
+	enum(e_am)		mode;
+	int 			reg;
+	int 			flag;		/* flags if pushed or corresponding reg_alloc
+								 * number */
+};
+
+struct amode   *g_expr();
+struct amode   *mk_reg();
+#ifdef MC680X0
+struct amode   *temp_data();
+struct amode   *temp_addr();
+#endif
+#ifdef INTEL_386
+struct amode   *get_register();
+#endif
+struct amode   *mk_offset();
+struct amode   *g_cast();
+struct amode   *g_fcall();
+struct amode   *func_result();
+struct amode   *as_fcall();
+#ifdef MC68000
+struct amode   *mk_rmask();
+struct amode   *mk_smask();
+#endif
+struct amode   *mk_label();
+struct amode   *mk_strlab();
+struct amode   *mk_immed(long i);
+struct amode   *g_offset();
+struct amode   *mk_legal();
+struct amode   *copy_addr();
+#endif
+void truejp();
+void falsejp();
+
+void g_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2);
+
+void initstack();
+void freeop(struct amode *ap);
+// vim:ts=4:sw=4

+ 3536 - 0
gtc/src/gen68k.c

@@ -0,0 +1,3536 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * code generator for the 68000
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifndef NOFLOAT
+#include	"ffplib.h"
+#endif
+
+#ifdef VCG
+extern int vcg_lvl;
+#endif
+
+#ifdef MC680X0
+readonly struct amode	push = {am_adec, 0, init_reg_t(STACKPTR - AREGBASE), nil_reg_t, 0},
+				pop =  {am_ainc, 0, init_reg_t(STACKPTR - AREGBASE), nil_reg_t, 0};
+#endif
+XLST_TYPE		act_scratch CGLOB;
+
+#ifdef FLINE_RC
+int				fline_rc CGLOB;
+#endif
+
+/*
+ * this module contains all of the code generation routines for evaluating
+ * expressions and conditions.
+ */
+
+#ifdef MC680X0
+
+void swap_nodes(struct enode *node);
+void opt_compare(struct enode *node);
+
+struct amode *mk_scratch(long size) {
+/*
+ * returns addressing mode of form offset(FRAMEPTR)
+ * size is rounded up to AL_DEFAULT
+ */
+				struct amode			 *ap;
+
+				/* round up the request */
+				if (size % AL_DEFAULT)
+								size += AL_DEFAULT - (size % AL_DEFAULT);
+
+				/* allocate the storage */
+				act_scratch += size;
+
+/*
+ * The next statement could be deferred and put into the
+ * routine checkstack(), but this is just safer.
+ */
+				if (act_scratch > max_scratch)
+								max_scratch = act_scratch;
+
+				ap = (struct amode *) xalloc((int) sizeof(struct amode),AMODE+MK_SCRATCH);
+				ap->mode = am_indx;
+				ap->preg = FRAMEPTR - AREGBASE;
+				ap->offset = mk_icon((long) -(lc_auto+act_scratch));
+				return ap;
+}
+
+
+struct amode *mk_label(unsigned int lab) {
+/*
+ * construct a reference node for an internal label number.
+ */
+				struct enode			 *lnode;
+				struct amode			 *ap;
+				lnode = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+				lnode->v.enlab = lab;
+				ap = (struct amode *) xalloc((int) sizeof(struct amode),AMODE+MK_LABEL);
+				ap->mode = am_direct;
+				ap->offset = lnode;
+				return ap;
+}
+
+struct amode *mk_immed(long i) {
+/*
+ * make a node to reference an immediate value i.
+ */
+				struct amode			 *ap;
+				struct enode			 *ep;
+				ep = mk_icon(i);
+/*				ep = mk_icon(0l);
+				ep->v.i = i;*/
+				ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_IMMED);
+				ap->mode = am_immed;
+				ap->offset = ep;
+				return ap;
+}
+
+struct amode *mk_offset(struct enode *node) {
+/*
+ * make a direct reference to a node.
+ */
+				struct amode			 *ap;
+				ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_OFFSET);
+				ap->mode = am_direct;
+				ap->offset = node;
+				return ap;
+}
+
+struct amode *mk_legal(struct amode *ap, int flags, long size) {
+/*
+ * mk_legal will coerce the addressing mode in ap1 into a mode that is
+ * satisfactory for the flag word.
+ */
+				struct amode			 *ap2;
+
+	if (flags & F_NOVALUE) {
+		freeop(ap);
+		return 0;
+	}
+
+	if (size==1)
+		flags &= ~F_AREG;
+
+	switch (ap->mode) {
+		case am_immed:
+			if (!(flags & F_DEREF) && ap->offset
+#ifdef EXE_OUT
+				//&& !exestub_mode		-> because it remains profitable to do this
+				//						even with very efficient relocations...
+#endif
+				&& (ap->offset->nodetype == en_nacon
+				 || ap->offset->nodetype == en_labcon)
+#ifdef AS
+				&& !external(ap->offset->v.enlab)
+#else
+#if defined(PC) && !defined(DISABLE_OPTS)
+				&& ((long)ap->offset->v.ensp>0x1000 ? internal(ap->offset->v.ensp) : 1)
+#endif
+#endif
+					) {
+					ap->mode = am_direct;
+					ap2 = temp_addr();		/* allocate to areg */
+					g_code(op_lea, 0, ap, ap2);
+					if (flags & F_AREG)
+							return ap2;
+					freeop(ap2);
+					ap = temp_data();
+					g_code(op_move, (int) (size+(size&1)), ap2, ap); /* if we want a byte, do a move.w, not a move.b */
+					if (flags & F_DREG)
+							return ap;
+					ierr(MK_LEGAL,1);
+			}
+			if (flags & F_IMMED) {
+				return ap;		/* mode ok */
+			}
+			break;
+		case am_areg:
+			if (flags & F_AREG && (!(flags & F_VOL) || ap->preg <= MAX_ADDR))
+				return ap;
+			break;
+		case am_dreg:
+			if (flags & F_DREG && (!(flags & F_VOL) || ap->preg <= MAX_DATA))
+				return ap;
+			break;
+		case am_direct:
+/*				infunc("DrawColorLine")
+					bkpt();*/
+			if (!(flags & F_SRCOP) && !(flags & F_DEREF) && ap->offset
+#ifdef EXE_OUT
+				//&& !exestub_mode		-> because it remains rentable to do this
+				//						even with very efficient relocations...
+#endif
+				&& (ap->offset->nodetype == en_nacon
+				 || ap->offset->nodetype == en_labcon)
+#ifdef AS
+				&& !external(ap->offset->v.enlab)
+#else
+#if defined(PC) && !defined(DISABLE_OPTS)
+				&& ((long)ap->offset->v.ensp>0x1000 ? internal(ap->offset->v.ensp) : 1)
+#endif
+#endif
+				&& (flags & F_MEM)
+					 ) {
+					ap2 = temp_addr();		// allocate to areg
+					g_code(op_lea, 0, ap, ap2);
+					ap2 = copy_addr(ap2);
+					ap2->mode = am_ind;
+//					if (flags & F_MEM)
+							return ap2;
+/*					freeop(ap2);
+					if ((flags&(F_AREG|F_DEREF))==(F_AREG|F_DEREF) || !(flags&F_DREG))
+						ap=temp_addr();
+					else ap=temp_data();
+//					ap = temp_data();
+					g_code(op_move, (int) size, ap2, ap);
+//					if (flags & F_DREG)
+							return ap;
+					ierr(MK_LEGAL,2);*/
+			}
+			/* FALL THROUGH */
+		case am_ind:
+		case am_indx:
+		case am_indx2:
+		case am_indx3:
+		case am_ainc:
+			if (flags & F_MEM)
+				return ap;
+			break;
+	}
+	if ((flags & F_DREG) && (flags & F_AREG)) {
+		/* decide which mode is better */
+		if (ap->mode == am_immed) {
+						if (isbyte(ap->offset))
+						flags &= F_DREG;
+						else if (isshort(ap->offset) && size == 4)
+						flags &= F_AREG;
+		}
+	}
+	if (flags & F_DREG) {
+		freeop(ap); 			/* maybe we can use it... */
+		ap2 = temp_data();		/* allocate to dreg */
+		g_code(op_move, (int) size, ap, ap2);
+		return ap2;
+	}
+	if (!(flags & F_AREG))
+		ierr(MK_LEGAL,3);
+	if (size < 2)
+		ierr(MK_LEGAL,4);
+	freeop(ap);
+	ap2 = temp_addr();
+	g_code(op_move, (int) size, ap, ap2);
+	return ap2;
+}
+
+int isshort(struct enode *node) {
+/*
+ * return true if the node passed can be generated as a short offset.
+ */
+				return node->nodetype == en_icon &&
+				(node->v.i >= -32768 && node->v.i <= 32767);
+}
+
+int isbyte(struct enode *node) {
+				return node->nodetype == en_icon &&
+				(node->v.i >= -128 && node->v.i <= 127);
+}
+
+
+struct amode *copy_addr(struct amode *ap) {
+/*
+ * copy an address mode structure.
+ */
+	struct amode			 *newap;
+	if (ap == 0)
+		ierr(COPY_ADDR,1);
+	newap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+COPY_ADDR);
+	*newap = *ap;
+	return newap;
+}
+
+
+struct amode *g_index(struct enode *node) {
+/*
+ * generate code to evaluate an index node and return the addressing
+ * mode of the result.
+ */
+	struct amode			 *ap1, *ap2;
+	char size=4;
+#ifndef FORBID_TABLES
+	if (node->v.p[0]->nodetype == en_tempref &&
+		node->v.p[1]->nodetype == en_tempref &&
+			(node->v.p[0]->v.i >= AREGBASE || node->v.p[1]->v.i >= AREGBASE)) {
+		/* both nodes are registers, one is address */
+		if (node->v.p[0]->v.i < AREGBASE) {	/* first node is data register */
+			ap1 = g_expr(node->v.p[1], F_AREG);
+			ap1 = copy_addr(ap1);
+			ap1->sreg = (reg_t)node->v.p[0]->v.i;
+			ap1->mode = am_indx2; /* 0(Ax,Dx) */
+			ap1->slen = 4;
+			ap1->offset = mk_icon(0l);
+			return ap1;
+		} else {						/* first node is address register */
+			ap1 = g_expr(node->v.p[0], F_AREG);
+			ap2 = g_expr(node->v.p[1], F_AREG | F_DREG);
+			validate(ap1);
+			ap1 = copy_addr(ap1);
+			if (ap2->mode == am_dreg) {
+				/* 0(Ax,Dx) */
+				ap1->mode = am_indx2;
+				ap1->sreg = ap2->preg;
+				ap1->slen = 4;
+			} else {
+				/* 0(Ax,Ay) */
+				ap1->mode = am_indx3;
+				ap1->sreg = ap2->preg;
+				ap1->slen = 4;
+			}
+			ap1->offset = mk_icon(0l);
+			return ap1;
+		}
+	}
+#endif
+	/* The general case (no tempref) */
+	/* put address temprefs first place, data temprefs second place */
+	if (node->v.p[1]->nodetype == en_tempref && node->v.p[1]->v.i >= AREGBASE)
+		swap_nodes(node);
+	else if (node->v.p[0]->nodetype == en_tempref && node->v.p[0]->v.i < AREGBASE)
+		swap_nodes(node);
+	else if (node->v.p[1]->etype==bt_pointer && node->v.p[0]->etype!=bt_pointer)
+		swap_nodes(node);
+
+	ap1 = g_expr(node->v.p[0], F_AREG | F_IMMED);
+	if (ap1->mode == am_areg) {
+		struct enode *ep=node->v.p[1],*tempep=ep;
+		while (tempep->nodetype==en_cast)	/* avoid useless op_ext's */
+			if ((tempep=tempep->v.p[0])->esize==2)
+				size=2, ep=tempep;
+		ap2 = g_expr(ep, F_AREG | F_DREG | F_IMMED);
+		validate(ap1);
+	} else {
+		ap2 = ap1;
+		ap1 = g_expr(node->v.p[1], F_AREG/* | F_IMMED*/);
+		validate(ap2);
+	}
+	/*
+	 * possible combinations:
+	 * 
+	 * F_AREG + F_IMMED, F_AREG + F_DREG and F_AREG + F_AREG
+	 * (F_IMMED + F_IMMED is now impossible, since it would mean a bug
+	 *  in the optimizer, and it does no harm except for optimization
+	 *  if such a bug does exist)
+	 */
+
+
+	/* watch out for: tempref(addr) + temp_addr, tempref(addr) + temp_data */
+
+	if (/*ap1->mode == am_areg && */ap1->preg > MAX_ADDR) {
+		/* ap1 = tempref address register */
+		ap1 = copy_addr(ap1);
+#ifndef FORBID_TABLES
+		if (ap2->mode == am_dreg) {
+						/* 0(Ax,Dy) */
+						ap1->mode = am_indx2;
+						ap1->sreg = ap2->preg;
+						ap1->slen = size;
+						ap1->deep = ap2->deep;
+						ap1->offset = mk_icon(0l);
+						return ap1;
+		}
+		if (ap2->mode == am_areg) {
+						/* 0(Ax,Ay) */
+						ap1->mode = am_indx3;
+						ap1->sreg = ap2->preg;
+						ap1->slen = size;
+						ap1->deep = ap2->deep;
+						ap1->offset = mk_icon(0l);
+						return ap1;
+		}
+#endif
+#ifndef FORBID_TABLES
+		if (ap2->mode == am_immed &&			/* if FORBID_TABLES, then we */
+				(!isshort(ap2->offset)))		/* always want ap1 to be F_VOL */
+#endif
+						/* we want to add to ap1 later... */
+						ap1 = mk_legal(ap1, F_AREG | F_VOL, 4l);
+	}
+	/* watch out for: temp_addr + tempref(data) */
+
+#ifndef FORBID_TABLES
+	if (/*ap1->mode == am_areg && */ap2->mode == am_dreg && ap2->preg > MAX_DATA) {
+		ap1 = copy_addr(ap1);
+		ap1->mode = am_indx2;
+		ap1->sreg = ap2->preg;
+		ap1->slen = size;
+		ap1->offset = mk_icon(0l);
+		return ap1;
+	}
+#endif
+/*	if (ap1->mode == am_immed && ap2->mode == am_immed) {
+	ap1 = copy_addr(ap1);
+	ap1->offset = mk_node(en_add, ap1->offset, ap2->offset);
+	ap1->mode = am_direct;
+	return ap1;
+	}*/
+	if (ap2->mode == am_immed && isshort(ap2->offset)) {
+		ap1 = mk_legal(ap1, F_AREG, 4l);
+		ap1 = copy_addr(ap1);
+		ap1->mode = am_indx;
+		ap1->offset = ap2->offset;
+		return ap1;
+	}
+	/* ap1 is volatile ... */
+	g_code(op_add, size, ap2, ap1);/* add left to address reg */
+	ap1 = copy_addr(ap1);
+	ap1->mode = am_ind; 			/* mk_ indirect */
+	freeop(ap2);							/* release any temps in ap2 */
+	return ap1; 							/* return indirect */
+}
+
+struct amode *g_deref(struct enode *node, enum(e_bt) type, int flags, long size) {
+/*
+ * return the addressing mode of a dereferenced node.
+ */
+	struct amode			 *ap1;
+/*
+ * If a reference to an aggregate is required, return a pointer to the
+ * struct instead
+ */
+	if (bt_aggregate(type)) {
+		return g_expr(node, /*F_ALL*/flags); // possibly BUGGY
+	}
+#ifdef PREFER_POS_VALUES
+	if (node->nodetype == en_sub && node->v.p[1]->nodetype==en_icon)
+		node->nodetype = en_add, node->v.p[1]->v.i=-node->v.p[1]->v.i;
+#endif
+	if (node->nodetype == en_add) {
+		return g_index(node);
+	}
+	if (node->nodetype == en_autocon) {
+#ifdef BIGSTACK
+		if (node->v.i >= -32768 && node->v.i <= 32767) {
+#endif
+			ap1 = (struct amode *) xalloc((int) sizeof(struct amode),
+					AMODE+G_DEREF);
+			ap1->mode = am_indx;
+			ap1->preg = FRAMEPTR-AREGBASE;
+			ap1->offset = mk_icon((long) node->v.i);
+#ifdef BIGSTACK
+		} else {
+			ap1 = temp_addr();
+			g_code(op_move, 4, mk_immed((long) node->v.i), ap1);
+			g_code(op_add, 4, mk_reg(FRAMEPTR), ap1);
+			ap1 = copy_addr(ap1);
+			ap1->mode = am_ind;
+		}
+#endif
+		return ap1;
+	}
+	/*				if (lineid==309)
+					bkpt();*/
+	/* special 68000 instructions */
+	if (node->nodetype == en_ainc
+			&& (size ==1 || size ==2 || size ==4)
+			&& node->v.p[1]->v.i == size
+			&& node->v.p[0]->nodetype == en_tempref
+			&& node->v.p[0]->v.i >= AREGBASE
+			&& !(flags & F_USES)) {
+		/* (An)+ */
+		ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_DEREF);
+		ap1->mode = am_ainc;
+		ap1->preg = (reg_t)(node->v.p[0]->v.i - AREGBASE);
+		return ap1;
+	}
+	if (node->nodetype == en_assub
+			&& (size ==1 || size ==2 || size ==4)
+			&& node->v.p[1]->v.i == -size
+			&& node->v.p[0]->nodetype == en_tempref
+			&& node->v.p[0]->v.i >= AREGBASE
+			&& !(flags & F_USES)) {
+		/* -(An) */
+		ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_DEREF);
+		ap1->mode = am_adec;
+		ap1->preg = (reg_t)(node->v.p[0]->v.i - AREGBASE);
+		return ap1;
+	}
+	ap1 = g_expr(node, F_AREG | F_IMMED | F_DEREF); /* generate address */
+	ap1 = copy_addr(ap1);
+#ifdef PC
+	if (ap1->mode != am_areg && ap1->mode != am_immed)
+		ierr(G_DEREF,1);
+#endif
+	am_doderef(ap1->mode);
+	return mk_legal(ap1,flags,size); // mk_legal was missing here : F_VOL wasn't
+	// taken into a count...
+}
+
+struct amode *g_fderef(struct enode *node, struct amode *ap0, int flags) {
+/*
+ * get a bitfield value
+ */
+	struct amode *ap, *ap1;
+	long mask;
+	int width = node->bit_width;
+	int offs = (node->esize<<3)-node->bit_offset-width;
+
+	if (!ap0)
+		ap = g_deref(node->v.p[0], node->etype, flags, node->esize);
+	else ap = ap0;
+	ap = mk_legal(ap, F_DREG|F_VOL, node->esize);
+	if (offs > 0) {
+		if (offs <= 8) {
+			/* can shift with quick constant */
+			g_code(op_lsr, (int) node->esize,
+				mk_immed((long) offs), ap);
+		} else {
+			/* must load constant first */
+			ap1 = temp_data();
+			g_code(op_moveq, 0, mk_immed((long) offs), ap1);
+			g_code(op_lsr, (int) node->esize, ap1, ap);
+			freeop(ap1);
+		}
+	}
+	/*mask = 0;
+	while (width--)
+		mask = mask + mask + 1;*/
+	mask = (1<<width)-1;
+	g_code(op_and, (int) node->esize, mk_immed(mask), ap);
+
+	return mk_legal(ap, flags, node->esize);
+}
+
+
+struct amode *g_unary(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate code to evaluate a unary minus or complement. float: unary minus
+ * calls a library function
+ */
+	struct amode			 *ap;
+#ifdef DOUBLE
+	long		i;
+#endif
+	if (flags & F_NOVALUE) {
+		return g_expr(node->v.p[0], flags);
+	}
+	switch (node->etype) {
+		case bt_uchar:
+		case bt_char:
+		case bt_short:
+		case bt_ushort:
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			ap = g_expr(node->v.p[0], F_DREG | F_VOL);
+			g_code(op, (int) node->esize, ap, NIL_AMODE);
+			return mk_legal(ap, flags, node->esize);
+#ifndef NOFLOAT
+		case bt_float:
+#ifdef DOUBLE
+		case bt_double:
+#endif
+			if (op == op_neg) {
+#ifdef DOUBLE
+				temp_inv();
+				i = push_param(node->v.p[0]);
+				call_library(str(ffpneg));
+				return func_result(flags, i);
+#else
+				int null_lab = nxtlabel();
+				struct amode *ap = g_expr(node->v.p[0], F_DREG | F_VOL);
+				g_code(op_tst, 4, ap, NIL_AMODE);
+				g_code(op_beq, 0, mk_label(null_lab), NIL_AMODE);
+				g_code(op_neg, 4, ap, NIL_AMODE);
+				g_label(null_lab);
+				return mk_legal(ap, flags, node->esize);
+#endif
+			}
+#endif
+	}
+	ierr(G_UNARY,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_addsub(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate code to evaluate a binary node and return the addressing mode of
+ * the result.
+ */
+	struct amode			 *ap1, *ap2;
+	long											i;
+	if (flags & F_NOVALUE) {
+		g_expr(node->v.p[0], flags);
+		return g_expr(node->v.p[1], flags);
+	}
+	switch (node->etype) {
+		case bt_uchar:
+		case bt_char:
+		case bt_short:
+		case bt_ushort:
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			flags &= (F_DREG | F_AREG);
+#ifdef LONG_ADDS_IN_AREG
+			if (node->v.p[1]->nodetype==en_icon && node->esize==4
+#if 1
+					&& !((unsigned long)(i=node->v.p[1]->v.i)+8<=16)
+					&& (long)(short)i==i
+#else
+					&& (i=node->v.p[1]->v.i,(long)(short)i==i)
+#endif
+					&& (flags&F_AREG))
+				flags = F_AREG;
+#endif
+#ifdef TWOBYTE_ARRAY_EXTRA_OPT
+			if (node->v.p[1]->nodetype==en_lsh && node->v.p[1]->v.p[1]->nodetype==en_icon
+					&& node->v.p[1]->v.p[1]->v.i==1) {
+				ap1 = g_expr(node->v.p[0], F_VOL | flags);
+				ap2 = g_expr(node->v.p[1]->v.p[0], F_ALL | F_SRCOP | F_USES);
+				validate(ap1);					/* in case push occurred */
+				g_code(op, (int) node->esize, ap2, ap1);
+				g_code(op, (int) node->esize, ap2, ap1);
+			} else {
+#endif
+				ap1 = g_expr(node->v.p[0], F_VOL | flags);
+				ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+				validate(ap1);					/* in case push occurred */
+				g_code(op, (int) node->esize, ap2, ap1);
+#ifdef TWOBYTE_ARRAY_EXTRA_OPT
+			}
+#endif
+			freeop(ap2);
+			return mk_legal(ap1, flags, node->esize);
+#ifndef NOFLOAT
+		case bt_double:
+			temp_inv();
+			i = push_param(node->v.p[1]);
+			i += push_param(node->v.p[0]);
+			switch (op) {
+				case op_add:
+					call_library(str(ffpadd));
+					break;
+				case op_sub:
+					call_library(str(ffpsub));
+					break;
+			}
+			return func_result(flags, i);
+#endif
+	}
+
+	ierr(G_ADDSUB,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_xbin(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate code to evaluate a restricted binary node and return the
+ * addressing mode of the result.
+ * these are bitwise operators so don't care about the type.
+ * This needs to be revised with scalar types longer than 32 bit
+ */
+				struct amode			 *ap1, *ap2;
+				ap1 = g_expr(node->v.p[0], F_VOL | F_DREG);
+				ap2 = g_expr(node->v.p[1], F_DREG);
+				validate(ap1);					/* in case push occurred */
+				g_code(op, (int) node->esize, ap2, ap1);
+				freeop(ap2);
+				return mk_legal(ap1, flags, node->esize);
+}
+
+struct amode *g_shift(struct enode *node, int flags, enum(e_op) op);
+int equalnode(struct enode *node1, struct enode *node2);
+struct amode *g_ybin(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate code to evaluate a restricted binary node and return the
+ * addressing mode of the result.
+ */
+				struct amode			 *ap1, *ap2;
+#ifdef GENERATE_ROL_ROR
+	if (
+			(op==op_or || op==op_eor) &&
+			node->v.p[0]->nodetype==en_lsh && node->v.p[1]->nodetype==en_rsh && bt_uns(node->v.p[1]->etype) &&
+			node->v.p[0]->v.p[1]->nodetype==en_icon && node->v.p[1]->v.p[1]->nodetype==en_icon &&
+			equalnode(node->v.p[0]->v.p[0],node->v.p[1]->v.p[0])
+			) {
+		long lsh = node->v.p[0]->v.p[1]->v.i;
+		long rsh = node->v.p[1]->v.p[1]->v.i;
+		long sz = lsh+rsh;
+		if (lsh>=0 && rsh>=0 && sz==8*node->esize) {
+			int need_swap = 0;
+			if (lsh>8 && rsh>8) {
+				need_swap = 1;
+				if (lsh>=16)
+					lsh-=16,rsh+=16;
+				else
+					rsh-=16,lsh+=16;
+			}
+			if (!lsh || !rsh) {
+				ap1 = g_expr(node->v.p[0]->v.p[0], F_DREG | F_VOL);
+			} else {
+				int shift_left = lsh<=8;
+				struct enode *ep1,*ep2;
+				ep1 = mk_icon(shift_left?lsh:rsh);
+				ep1->etype = bt_uchar;
+				ep1->esize = 1;
+				ep2 = mk_node(en_lsh, node->v.p[0]->v.p[0], ep1);
+				ep2->etype = node->etype;
+				ep2->esize = node->esize;
+				ap1 = g_shift(ep2, F_DREG|F_VOL, shift_left?op_rol:op_ror);
+			}
+			if (need_swap)
+				g_code(op_swap, (int)node->esize, ap1, NIL_AMODE);
+			return mk_legal(ap1, flags, node->esize);
+		} else {
+			// we could do better, but hey, we're lazy, aren't we?
+		}
+	}
+#endif
+				ap1 = g_expr(node->v.p[0], F_VOL | F_DREG);
+				ap2 = g_expr(node->v.p[1], (F_ALL & ~F_AREG) | F_SRCOP);
+				validate(ap1);					/* in case push occurred */
+				g_code(op, (int) node->esize, ap2, ap1);
+				freeop(ap2);
+				return mk_legal(ap1, flags, node->esize);
+}
+#ifdef VCG
+typedef struct amode *(*COMMUTATIVE_G)(struct enode *node,int flags,enum(e_op) op);
+typedef struct amode *(*REVERSAL_G)(struct amode *ap, struct enode *ep,int flags);
+//struct amode *symmetric(struct amode *ap, struct enode *ep,int flags) {
+//	if (ap==NULL) return (struct amode *)(void *)flags;
+//	return ap;
+//}
+//struct amode *antisymmetric(struct amode *ap, struct enode *ep,int flags) {
+//	if (ap==NULL) return (struct amode *)(void *)(F_DREG|F_VOL);
+//	g_code(op_neg, ep->esize, ap, NIL_AMODE);
+//	return mk_legal(ap,flags,ep->esize);
+//}
+enum { symmetric = 0 }; // antisymmetric is not supported
+struct amode *g_commute(void *func,struct enode *node,int flags,enum(e_op) op,int dummy/*void *reversal*/) {
+	if (vcg_init()) {
+		struct amode *ap = NULL;
+		struct enode *n0=node->v.p[0],*n1=node->v.p[1];
+		int o1,o2;
+		//struct amode *ap;
+		((COMMUTATIVE_G)func)(node,flags,op);
+		o1=vcg_done();
+		node->v.p[0]=n1,node->v.p[1]=n0;
+		vcg_init();
+		((COMMUTATIVE_G)func)(node,flags,op);
+		//((REVERSAL_G)reversal)(((COMMUTATIVE_G)func)
+		//		(node,(int)((REVERSAL_G)reversal)(NULL,node,flags),op),node,flags);
+		o2=vcg_done();
+		if (o2<=o1)
+			ap = ((COMMUTATIVE_G)func)(node,flags,op);
+			//ap = ((REVERSAL_G)reversal)(((COMMUTATIVE_G)func)
+			//	(node,(int)((REVERSAL_G)reversal)(NULL,node,flags),op),node,flags);
+		node->v.p[0]=n0,node->v.p[1]=n1; /* always restore the original node, even when reverse is better! */
+		if (ap)
+			return ap;
+	}
+	return ((COMMUTATIVE_G)func)(node,flags,op);
+}
+#endif
+
+struct amode *g_shift(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate code to evaluate a shift node and return the address mode of the
+ * result.
+ */
+	struct amode *ap1,*ap2;
+
+	if (op == op_lsl && node->v.p[1]->nodetype == en_icon
+		&& (node->v.p[1]->v.i == 1
+#ifndef HARDCORE_FOR_UNPACKED_SIZE
+#ifdef SPEED_OPT
+		|| ((speed_opt_value>=0
+#ifdef EXE_OUT
+				|| exestub_mode
+#endif
+			) && node->v.p[1]->v.i == 2)
+#else
+		|| node->v.p[1]->v.i == 2
+#endif
+#endif
+		)) {
+		int i;
+		ap1 = g_expr(node->v.p[0], F_VOL | (flags & (F_DREG | F_AREG)));
+		i = node->v.p[1]->v.i-1;
+		do
+			g_code(op_add, (int) node->esize, ap1, ap1);
+		while (i--);
+	} else {
+		ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
+		ap2 = g_expr(node->v.p[1], F_DREG | F_IMMED);
+		validate(ap1);
+
+		/* quick constant only legal if 1<=const<=8 */
+		if (ap2->mode == am_immed && ap2->offset->nodetype == en_icon
+			&& (ap2->offset->v.i > 8 || ap2->offset->v.i < 1)) {
+			if (ap2->offset->v.i <= 0 || ap2->offset->v.i > 32)
+				uwarn("shift constant out of range");
+#ifdef USE_SWAP_FOR_SHIFT16
+			if ((unsigned int)ap2->offset->v.i <= 16 && node->esize==4) {
+				/* validate(ap1); -> useless since ap2 is am_immed :) */
+				g_code(op_swap, 0, ap1, NIL_AMODE);
+				if ((ap2->offset->v.i -= 16)) {
+					ap2 = mk_immed(-ap2->offset->v.i);
+					op = (op==op_lsl?op_ror:op_rol); /* since op might be op_asr too */
+					g_code(op, (int) node->esize, ap2, ap1);
+				}
+				#error The following bugs... ((long)x)<<16 => ext/swap/ext #roll#
+				/* to be improved since it normally results from 'long' shifts and surrounding
+					g_cast does not recurse down to the shift node...
+					The current optimization is nevertheless useful with respect to speed. */
+				if (node->esize==4) g_code(op_ext, (int) node->esize, ap1, NIL_AMODE);
+				goto ok_shift;
+			} else
+#endif
+				ap2 = mk_legal(ap2, F_DREG, 1l);
+		}
+		g_code(op, (int) node->esize, ap2, ap1);
+#ifdef USE_SWAP_FOR_SHIFT16
+	ok_shift:
+#endif
+		freeop(ap2);
+	}
+	return mk_legal(ap1, flags, node->esize);
+}
+
+struct amode *g_div(struct enode *node, int flags) {
+/*
+ * generate code to evaluate a divide operator
+ */
+	struct amode			 *ap1, *ap2;
+	long											i;
+	switch (node->etype) {
+		case bt_short:
+		case bt_ushort:
+			ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
+			ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+			validate(ap1);
+			if (node->etype == bt_short) {
+				g_code(op_ext, 4, ap1, NIL_AMODE);
+				g_code(op_divs, 0, ap2, ap1);
+			} else {
+				g_code(op_and, 4, mk_immed(65535l), ap1);
+				g_code(op_divu, 0, ap2, ap1);
+			}
+			freeop(ap2);
+			return mk_legal(ap1, flags, 2l);
+		case bt_long:
+		case bt_ulong:
+		case bt_double:
+			temp_inv();
+			i = push_param(node->v.p[1]);
+			i += push_param(node->v.p[0]);
+			switch (node->etype) {
+				case bt_long:
+					call_library("__divsi3");
+					break;
+				case bt_ulong:
+				case bt_pointer:
+					call_library("__udivsi3");
+					break;
+#ifndef NOFLOAT
+				case bt_double:
+					call_library(str(ffpdiv));
+					break;
+#endif
+			}
+			return func_result(flags, i);
+	}
+	ierr(G_DIV,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_mod(struct enode *node, int flags) {
+/*
+ * generate code to evaluate a mod operator
+ */
+	struct amode			 *ap1, *ap2;
+	long											i;
+	switch (node->etype) {
+		case bt_short:
+		case bt_ushort:
+			ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
+			ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+			validate(ap1);
+			if (node->etype == bt_short) {
+				g_code(op_ext, 4, ap1, NIL_AMODE);
+				g_code(op_divs, 0, ap2, ap1);
+			} else {
+				g_code(op_and, 4, mk_immed(65535l), ap1);
+				g_code(op_divu, 0, ap2, ap1);
+			}
+			g_code(op_swap, 0, ap1, NIL_AMODE);
+			freeop(ap2);
+			return mk_legal(ap1, flags, 2l);
+		case bt_long:
+		case bt_ulong:
+			temp_inv();
+			i = push_param(node->v.p[1]);
+			i += push_param(node->v.p[0]);
+			if (node->etype == bt_long)
+				call_library("__modsi3");
+			else
+				call_library("__umodsi3");
+			return func_result(flags, i);
+	}
+	ierr(G_MOD,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+void swap_nodes(struct enode *node) {
+/*
+ * exchange the two operands in a node.
+ */
+	struct enode			 *temp;
+	temp = node->v.p[0];
+	node->v.p[0] = node->v.p[1];
+	node->v.p[1] = temp;
+}
+
+struct amode *g_mul(struct enode *node, int flags) {
+	struct amode			 *ap1, *ap2;
+#ifdef OLD_GCCLIKE_MULSI3
+	long											i;
+#endif
+/*				switch (node->etype) {
+								case bt_long:
+								case bt_ulong:
+				if (node->v.p[0]->nodetype == en_icon)
+								swap_nodes(node);
+				ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
+				ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+				validate(ap1);
+				if (node->etype == bt_long)
+								g_code(op_muls, 0, ap2, ap1);
+				else
+								g_code(op_mulu, 0, ap2, ap1);
+				freeop(ap2);
+				return mk_legal(ap1, flags, 2l);
+								case bt_pointer:
+								case bt_double:
+				temp_inv();
+				i = push_param(node->v.p[1]);
+				i += push_param(node->v.p[0]);
+				if (node->etype == bt_ulong)
+								call_library(".ulmul");	// obsolete
+				else if (node->etype == bt_double)
+								call_library(".fpmult");	// obsolete
+				else
+								call_library(".lmul");	// obsolete
+				return func_result(flags, i);
+				}*/
+	switch (node->etype) {
+		case bt_short:
+		case bt_ushort:
+			if (node->v.p[0]->nodetype == en_icon)
+				swap_nodes(node);
+			ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
+			ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+			validate(ap1);
+			if (node->v.p[0]->etype == bt_short)
+				g_code(op_muls, 0, ap2, ap1);
+			else
+				g_code(op_mulu, 0, ap2, ap1);
+			freeop(ap2);
+			return mk_legal(ap1, flags, 2l);
+		case bt_ulong:
+		case bt_long:
+		case bt_pointer:
+		case bt_double:
+			temp_inv();
+#ifdef OLD_GCCLIKE_MULSI3
+			i = push_param(node->v.p[1]);
+			i += push_param(node->v.p[0]);
+#ifndef NOFLOAT
+			if (node->etype == bt_double)
+				call_library(str(ffpmul));
+			else
+#endif
+				call_library("__mulsi3");	/* it's the same function for ulong & long :) */
+			return func_result(flags, i);
+#else
+			{ char *libfunc="__mulsi3_rp";
+				if (tst_ushort(node->v.p[0]))
+					swap_nodes(node);
+				if (tst_ushort(node->v.p[1])) {	/* favour ushort rather than short! */
+					node->v.p[1]->etype=bt_ushort;
+					node->v.p[1]->esize=2;
+					libfunc="__mulsi3ui2_rp";
+				} else {
+					if (tst_short(node->v.p[0]))
+						swap_nodes(node);
+					if (tst_short(node->v.p[1])) {
+						node->v.p[1]->etype=bt_short;
+						node->v.p[1]->esize=2;
+						libfunc="__mulsi3si2_rp";
+					}
+				}
+				ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);	/* put it in D0 */
+				ap2 = g_expr(node->v.p[1], F_DREG | F_VOL);	/* put it in D1 */
+				validate(ap1);
+				call_library(libfunc);
+				freeop(ap2);
+				return mk_legal(ap1, flags, 4l);
+			}
+#endif
+	}
+	ierr(G_MUL,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+/*
+ * Returns a complexity measure (in terms of time) of the given node, if it's constant.
+ * If it's not, returns -128.
+ */
+int complexity(struct enode *ep) {
+	int comp=1;
+	if (!ep) return 0;
+restart:
+	switch (ep->nodetype) {
+		case en_icon:
+			if (ep->v.i) comp++;
+		case en_tempref:
+			comp--;
+		case en_fcon:
+		case en_nacon:
+		case en_labcon:
+		case en_autocon:
+			return comp;
+		case en_fcall:
+		case en_assign:
+		case en_asadd: case en_assub:
+		case en_asmul: case en_asmod: case en_asdiv:
+		case en_aslsh: case en_asrsh:
+		case en_asand: case en_asor: case en_asxor:
+		case en_ainc: case en_adec:
+		case en_alloca:
+			return -128;
+		case en_cond:
+//			msg("DEBUG: complexity\n");
+			return -128;
+		case en_compound:
+//			msg("DEBUG: complexity\n");
+			return -128;
+		case en_mod: case en_div:
+			comp+=2;
+		case en_mul:
+			comp+=2;
+		case en_void:
+		case en_add: case en_sub:
+		case en_lsh: case en_rsh:
+		case en_and: case en_or: case en_xor:
+		case en_eq: case en_ne:
+		case en_lt: case en_le: case en_gt: case en_ge:
+		case en_land: case en_lor:
+			comp+=complexity(ep->v.p[0]);
+			if (comp<0) return -128;
+			{
+				int comp2=complexity(ep->v.p[1]);
+				if (comp2<0) return -128;
+				return comp+comp2;
+			}
+		case en_ref:
+		case en_fieldref:
+		case en_deref:
+		case en_uminus: case en_not:
+		case en_compl:
+		case en_cast:
+			comp++;
+			ep=ep->v.p[0];
+			goto restart;
+		default:
+			fatal("COMPLEXITY");
+			return 0; // make the compiler happy
+	}
+}
+
+struct amode *g_hook(struct enode *node, int flags) {
+/*
+ * generate code to evaluate a condition operator node (?:)
+ */
+			struct amode			 *ap1, *ap2;
+			unsigned int			false_label, end_label;
+			int 							flagx;
+			int 							result_is_void;
+			long size=node->esize;
+			struct enode *vnode=node->v.p[1];
+#ifdef VCG
+			int alternatives = complexity(node->v.p[0]);
+			int best_flagx;
+			unsigned int cost1=-1,cost2=-1;
+#endif
+			end_label = nxtlabel();
+
+			result_is_void = (node->etype == bt_void);
+			if (bt_aggregate(node->etype)) {
+							size = 4;
+			}
+
+			if (!result_is_void) {
+							flagx = (flags & (F_DREG | F_AREG)) == F_AREG ?
+											F_AREG | F_VOL : F_DREG | F_VOL;
+#ifdef VCG
+							best_flagx = vcg_lvl?-1:flagx;
+#endif
+			} else {
+#ifdef VCG
+					best_flagx =
+#endif
+							flagx = F_ALL | F_SRCOP | F_NOVALUE;
+			}
+
+//			temp_inv(); /* I do not think I can avoid that */
+
+#ifdef VCG
+			best_flagx=flagx;
+			while (1) {
+				if (best_flagx<0)
+					vcg_init();	// always succeeds, otherwise best_flagx would be flagx
+#endif
+			if (vnode->v.p[0]) {
+				/* all scratch registers are void */
+#ifdef OPTIMIZED_HOOK
+				struct ocode *old_peep_tail=peep_tail;
+				int old_max_reg=max_reg;
+				max_reg=0;
+#endif
+#ifdef VCG
+				if (vcg_lvl && alternatives IS_VALID) {
+					int alt1,alt2,norm;
+				  if (complexity(vnode->v.p[1])>=0) {
+				   vcg_init();
+					ap1 = g_expr(vnode->v.p[1], flagx);
+					falsejp(node->v.p[0], end_label);
+					if (ap_hasbeenpushed(ap1)) {
+						validate(ap1);
+						freeop(ap1);
+						vcg_done();
+						best_flagx=0;
+						goto classic_fashion;
+					}
+					freeop(ap1);
+					alt1=vcg_cost()>>3;
+					ap2 = g_expr(vnode->v.p[0], flagx);
+					alt1+=vcg_done();
+				  } else alt1=32767;
+					swap_nodes(vnode);
+				  if (complexity(vnode->v.p[1])>=0) {
+				   vcg_init();
+					ap1 = g_expr(vnode->v.p[1], flagx);
+					truejp(node->v.p[0], end_label);
+					if (ap_hasbeenpushed(ap1))
+						ierr(G_HOOK,3);
+					freeop(ap1);
+					alt2=vcg_cost()>>3;
+					ap2 = g_expr(vnode->v.p[0], flagx);
+					alt2+=vcg_done();
+				  } else alt2=32767;
+					swap_nodes(vnode);
+				   vcg_init();
+					false_label = nxtlabel();
+					falsejp(node->v.p[0], false_label);
+					norm=vcg_cost()>>3;
+					ap1 = g_expr(vnode->v.p[0], flagx);
+					freeop(ap1);
+					g_code(op_bra, 0, mk_label(end_label), NIL_AMODE);
+					g_label(false_label);
+					ap2 = g_expr(vnode->v.p[1], flagx);
+					norm+=vcg_done();
+
+					if (norm>alt1 && norm>alt2) {
+						if (alt2<alt1) swap_nodes(vnode);
+						ap1 = g_expr(vnode->v.p[1], flagx);
+						(alt2>=alt1?falsejp:truejp)
+							(node->v.p[0], end_label);
+						freeop(ap1);
+						ap2 = g_expr(vnode->v.p[0], flagx);
+						if (alt2<alt1) swap_nodes(vnode);	// we absolutely need this!!!
+						goto done;							// (hardcore TI-Chess+VTILog debug)
+					}
+				}
+#endif
+#if defined(ALTERNATE_HOOK) || defined(OPTIMIZED_HOOK)
+				int c1=complexity(vnode->v.p[0]),c2=complexity(vnode->v.p[1]);
+				if (c1>=0 || c2>=0) {
+					if ((unsigned)c1<(unsigned)c2)
+						swap_nodes(vnode);
+					ap1 = g_expr(vnode->v.p[1], flagx);
+					((unsigned)c1<(unsigned)c2?truejp:falsejp)
+						(node->v.p[0], end_label);
+					freeop(ap1);
+					ap2 = g_expr(vnode->v.p[0], flagx);
+					if ((unsigned)c1<(unsigned)c2)
+						swap_nodes(vnode);
+				} else {
+#endif
+				classic_fashion:
+					false_label = nxtlabel();
+					falsejp(node->v.p[0], false_label);
+
+					/* all scratch registers are void */
+					ap1 = g_expr(vnode->v.p[0], flagx);
+					freeop(ap1);
+
+					/* all scratch registers are void */
+					g_code(op_bra, 0, mk_label(end_label), NIL_AMODE);
+
+					g_label(false_label);
+
+					ap2 = g_expr(vnode->v.p[1], flagx);
+#if defined(ALTERNATE_HOOK) || defined(OPTIMIZED_HOOK)
+				}
+#endif
+			done:
+				if (!result_is_void && !equal_address(ap1,ap2))
+					ierr(G_HOOK,1);
+
+			} else {
+				ap1 = g_expr(node->v.p[0], flagx);
+				/* all scratch registers are void */
+				g_code(op_tst, (int)node->v.p[0]->esize, ap1, NIL_AMODE);
+				freeop(ap1);
+				g_code(op_bne, 0, mk_label(end_label), NIL_AMODE);
+				ap2 = g_expr(vnode->v.p[1], flagx);
+				if (!result_is_void && !equal_address(ap1,ap2))
+					ierr(G_HOOK,2);
+			}
+				g_label(end_label);
+
+#ifdef VCG
+			if (best_flagx>=0)
+#endif
+				return mk_legal(ap2, flags, size);
+#ifdef VCG
+			if (best_flagx<0) {
+				cost1=cost2;
+				cost2=vcg_done();
+				if (!(flags&F_AREG) || size==1 || flagx==(F_AREG|F_VOL))
+					best_flagx = cost1<cost2?(F_DREG|F_VOL):flagx;
+				else flagx=F_AREG|F_VOL;
+			}
+		}
+#endif
+}
+
+struct amode *g_asadd(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate a plus equal or a minus equal node.
+ */
+	int 											f;
+	struct amode			 *ap1, *ap2;
+	switch (node->etype) {
+		case bt_char:
+		case bt_uchar:
+		case bt_short:
+		case bt_ushort:
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			if (flags & F_NOVALUE)
+				f = F_ALL;
+			else
+				f = F_ALL | F_USES;
+			ap1 = g_expr(node->v.p[0], f);
+			if (ap1->mode==am_dreg || ap1->mode==am_areg)
+				f = F_ALL | F_SRCOP;
+			else f = F_DREG | F_IMMED;
+			ap2 = g_expr(node->v.p[1], f);
+			validate(ap1);
+			g_code(op, (int) node->esize, ap2, ap1);
+			freeop(ap2);
+			return mk_legal(ap1, flags, node->esize);
+#ifndef NOFLOAT
+		case bt_float:
+#ifdef DOUBLE
+		case bt_double:
+#endif
+			if (op == op_add)
+				return as_fcall(node, flags, str(ffpadd));
+			else
+				return as_fcall(node, flags, str(ffpsub));
+#endif
+	}
+	ierr(G_ASADD,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+readonly xstatic int bits_for_size[4]={7,15,0,31};
+void g_bitmancode(enum(e_op) op,int size,struct amode *ap1,struct amode *ap2) {
+	struct amode *ap3=0;
+	if (ap2->mode!=am_dreg && size && size!=1) {
+		int bits_to_skip;
+		if (ap1->mode!=am_immed || ap1->offset->nodetype!=en_icon)
+			uerrc("illegal address mode");
+		bits_to_skip=bits_for_size[size-1]-ap1->offset->v.i;
+		while (bits_to_skip>=8) {
+			if (!ap3) ap3=copy_addr(ap2),ap3->offset=copynode(ap3->offset);
+			if (ap3->mode==am_ind)
+				ap3->mode=am_indx,ap3->offset=mk_icon(0);
+			if (ap3->offset->nodetype==en_icon)
+				ap3->offset->v.i++;
+			else ap3->offset=mk_node(en_add,ap3->offset,mk_icon(1)),opt4(&ap3->offset);
+			bits_to_skip-=8;
+		}
+		ap1=mk_immed(7-bits_to_skip);
+	}
+	if (!ap3) ap3=ap2;
+	g_code(op,ap2->mode==am_dreg?4:1,ap1,ap3);
+}
+#ifdef BITWISE_REDUCE
+/* the latter relies on the big-endianness of the 68k */
+int bitwise_reduction(unsigned long x,int *size) {
+	if (!x) return;	// anyway the constant folder will already have taken care :)
+	int offs=0,end_offs=0;
+	unsigned long v=0xFF<<((*size-1)*8);
+	while (!(x&v)) offs++,x<<=8;
+	if (!(x&(v>>8))) {
+		if (!(x&(v>>16)) && !(x&(v>>24)))
+			*size=4;
+		else *size=2;
+	} else *size=1;
+	if (*size==1) {
+		if (offs==1 && v!=0xFF) /* avoid such a case... (unless *size _was_ already 1) */
+			offs=0,*size=2;
+	} else if (offs&1)	/* too bad... we can do nothing */
+		offs=0,*size=4;
+	return offs;
+}
+readonly int deflt_types[5]={0,bt_uchar,bt_ushort,0,bt_ulong};
+void bitwise_optimize(struct enode *ep,long mode) {
+	long *ref=0;
+	/* we may not call swap_nodes here! VCG needs to preserve the order */
+	if (ep->v.p[0]->nodetype==en_icon && ep->v.p[1]->nodetype==en_ref)
+		ref=&ep->v.p[0]->v.i;
+	else if (ep->v.p[1]->nodetype==en_icon && ep->v.p[0]->nodetype==en_ref)
+		ref=&ep->v.p[1]->v.i;
+	if (ref) {
+		int offs=bitwise_reduction((*ref)^mode,&ep->esize);
+		ep->etype=deflt_types[ep->esize];
+		ep->v.p[0]->etype=
+#endif
+
+struct amode *g_asxor(struct enode *node, int flags) {
+/*
+ * generate an ^= node
+ */
+	int 											f;
+	struct amode			 *ap1, *ap2;
+	switch (node->etype) {
+		case bt_char:
+		case bt_uchar:
+		case bt_short:
+		case bt_ushort:
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			if (flags & F_NOVALUE)
+				f = F_ALL;
+			else
+				f = F_ALL | F_USES;
+			ap1 = g_expr(node->v.p[0], f);
+			if (ap1->mode==am_dreg || ap1->mode==am_areg)
+				f = F_ALL | F_SRCOP;
+			else f = F_DREG | F_IMMED;
+			ap2 = g_expr(node->v.p[1], f);
+			validate(ap1);
+			if (ap2->mode==am_immed && ap1->mode!=am_dreg && ap1->mode!=am_areg) {
+				int i,n=0,j=0; long z=ap2->offset->v.i;
+				for (i=0;i<8*node->esize;i++)
+					if (z&(1<<i)) { n++; j=i; }
+				if (n==1) {
+					g_bitmancode(op_bchg, (int) node->esize, mk_immed(j), ap1);
+				} else g_code(op_eor, (int) node->esize, ap2, ap1);
+			} else g_code(op_eor, (int) node->esize, ap2, ap1);
+			freeop(ap2);
+			return mk_legal(ap1, flags, node->esize);
+	}
+	ierr(G_ASXOR,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_aslogic(struct enode *node, int flags, enum(e_op) op) {
+	/*
+	 * generate a&= or a|=
+	 */
+	int 											f;
+	struct amode			 *ap1, *ap2, *ap3;
+	if (flags & F_NOVALUE)
+		f = F_ALL;
+	else
+		f = F_ALL | F_USES;
+	ap1 = g_expr(node->v.p[0], f);
+	if (ap1->mode==am_dreg || ap1->mode==am_areg)
+		f = (F_ALL & ~F_AREG) | F_SRCOP;
+	else f = F_DREG | F_IMMED;
+	ap2 = g_expr(node->v.p[1], f);
+	validate(ap1);
+	if (ap1->mode != am_areg) {
+		if (/*(op==op_and || op==op_or || op==op_eor) && */ap2->mode==am_immed
+				&& ap1->mode!=am_dreg && ap1->mode!=am_areg
+				&& (node->esize==1/* || (ap1->mode!=am_ainc && ap1->mode!=am_adec)*/)) {
+			int i,n=-1,j=0,and=(op==op_and); long z=ap2->offset->v.i;
+			for (i=0;i<8*node->esize;i++)
+				if ((!!(z&(1<<i)))^and) { n++; j=i; }
+			if (!n) {
+				ap3 = ap1;
+				/*								if (node->esize!=1) {
+												ap3 = copy_addr(ap1);
+												switch (ap1->mode) {
+												case am_ind:
+												ap3->mode=am_indx;
+												ap3->offset=mk_immed(
+												}*/
+				g_bitmancode(and?op_bclr:(op==op_or?op_bset:op_bchg),
+						0/* ALWAYS .B !!! */, mk_immed(j), ap3);
+				goto asdone;
+			}
+		}
+		g_code(op, (int) node->esize, ap2, ap1);
+	} else {
+		ap3 = temp_data();
+		g_code(op_move, 4, ap1, ap3);
+		g_code(op, (int) node->esize, ap2, ap3);
+		g_code(op_move, (int) node->esize, ap3, ap1);
+		freeop(ap3);
+	}
+asdone:
+	freeop(ap2);
+	return mk_legal(ap1, flags, node->esize);
+}
+
+struct amode *g_asshift(struct enode *node, int flags, enum(e_op) op) {
+	/*
+	 * generate shift equals operators.
+	 */
+	int f;
+	struct amode *ap1, *ap2, *ap3;
+	switch (node->etype) {
+		case bt_uchar:
+		case bt_char:
+		case bt_ushort:
+		case bt_short:
+		case bt_ulong:
+		case bt_long:
+		case bt_pointer:
+			if (flags & F_NOVALUE)
+				f = F_ALL;
+			else
+				f = F_ALL | F_USES;
+			ap1 = g_expr(node->v.p[0], f);
+			if (ap1->mode != am_dreg) {
+				ap3 = temp_data();
+				g_code(op_move, (int) node->esize, ap1, ap3);
+			} else
+				ap3 = ap1;
+			ap2 = g_expr(node->v.p[1], F_DREG | F_IMMED);
+
+			/* add if const=1 and op is << */
+			if (op==op_lsl && ap2->mode == am_immed && ap2->offset->nodetype == en_icon
+					&& ap2->offset->v.i == 1) {
+				op=op_add; ap2=ap3;
+			}
+			/* quick constant if 2<=const<=8 */
+			if (ap2->mode == am_immed && ap2->offset->nodetype == en_icon
+					&& (ap2->offset->v.i > 8 || ap2->offset->v.i < 1)) {
+				/*if (ap2->offset->v.i <= 0)
+				  uwarn("negative shift constant");*/
+				ap2 = mk_legal(ap2, F_DREG, 1l);
+			}
+			validate(ap3);
+			g_code(op, (int) node->esize, ap2, ap3);
+			if (ap2 != ap3)
+				freeop(ap2);
+			if (ap3 != ap1) {
+				g_code(op_move, (int) node->esize, ap3, ap1);
+				freeop(ap3);
+			}
+			return mk_legal(ap1, flags, node->esize);
+	}
+	ierr(G_ASSHIFT,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_asmul(struct enode *node, int flags) {
+	/*
+	 * generate a *= node.
+	 */
+	struct amode			 *ap1, *ap2, *ap3;
+	enum(e_op)		op = op_mulu;
+	switch (node->etype) {
+		case bt_char:
+			ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
+			if (ap1->mode != am_dreg) {
+				ap2 = temp_data();
+				g_code(op_move, 1, ap1, ap2);
+			} else
+				ap2 = ap1;
+			g_code(op_ext, 2, ap2, NIL_AMODE);
+			ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
+			if (ap3->mode == am_dreg)
+				g_code(op_ext, 2, ap3, NIL_AMODE);
+			validate(ap2);
+			g_code(op_muls, 0, ap3, ap2);
+			freeop(ap3);
+			if (ap2 != ap1) {
+				validate(ap1);
+				g_code(op_move, 1, ap2, ap1);
+				freeop(ap2);
+			}
+			return mk_legal(ap1, flags, node->esize);
+		case bt_uchar:
+			ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
+			if (ap1->mode != am_dreg) {
+				ap2 = temp_data();
+				g_code(op_move, 1, ap1, ap2);
+			} else
+				ap2 = ap1;
+			g_code(op_and, 2, mk_immed(255l), ap2);
+			ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
+			if (ap3->mode == am_dreg)
+				g_code(op_and, 2, mk_immed(255l), ap3);
+			validate(ap2);
+			g_code(op_mulu, 0, ap3, ap2);
+			freeop(ap3);
+			if (ap2 != ap1) {
+				validate(ap1);
+				g_code(op_move, 1, ap2, ap1);
+				freeop(ap2);
+			}
+			return mk_legal(ap1, flags, node->esize);
+		case bt_short:
+			op = op_muls;
+		case bt_ushort:
+			ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
+			ap2 = g_expr(node->v.p[1], F_ALL);
+			validate(ap1);
+			if (ap1->mode != am_dreg) {
+				ap3 = temp_data();
+				g_code(op_move, 2, ap1, ap3);
+				g_code(op, 0, ap2, ap3);
+				freeop(ap2);
+				freeop(ap3);
+				g_code(op_move, 2, ap3, ap1);
+			} else {
+				g_code(op_muls, 0, ap2, ap1);
+				freeop(ap2);
+			}
+			return mk_legal(ap1, flags, node->esize);
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			return as_fcall(node, flags, "__mulsi3");
+#ifndef NOFLOAT
+		case bt_float:
+#ifdef DOUBLE
+		case bt_double:
+#endif
+			return as_fcall(node, flags, str(ffpmul));
+#endif
+	}
+	ierr(G_ASMUL,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_asdiv(struct enode *node, int flags) {
+/*
+ * generate /= and %= nodes.
+ */
+	struct amode	 *ap1, *ap2, *ap3;
+	switch (node->etype) {
+		case bt_char:
+			ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
+			if (ap1->mode != am_dreg) {
+				ap2 = temp_data();
+				g_code(op_move, 1, ap1, ap2);
+			} else
+				ap2 = ap1;
+			g_code(op_ext, 2, ap2, NIL_AMODE);
+			g_code(op_ext, 4, ap2, NIL_AMODE);
+			ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
+			if (ap3->mode == am_dreg)
+				g_code(op_ext, 2, ap3, NIL_AMODE);
+			validate(ap2);
+			g_code(op_divs, 0, ap3, ap2);
+			freeop(ap3);
+			if (ap2 != ap1) {
+				validate(ap1);
+				g_code(op_move, 1, ap2, ap1);
+				freeop(ap2);
+			}
+			return mk_legal(ap1, flags, node->esize);
+		case bt_uchar:
+			ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
+			if (ap1->mode != am_dreg) {
+				ap2 = temp_data();
+				g_code(op_move, 1, ap1, ap2);
+			} else
+				ap2 = ap1;
+			g_code(op_and, 4, mk_immed(255l), ap2);
+			ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
+			if (ap3->mode == am_dreg)
+				g_code(op_and, 2, mk_immed(255l), ap3);
+			validate(ap2);
+			g_code(op_divu, 0, ap3, ap2);
+			freeop(ap3);
+			if (ap2 != ap1) {
+				validate(ap1);
+				g_code(op_move, 1, ap2, ap1);
+				freeop(ap2);
+			}
+			return mk_legal(ap1, flags, node->esize);
+		case bt_short:
+		case bt_ushort:
+			ap1 = temp_data();
+			ap2 = g_expr(node->v.p[0], F_ALL | F_USES);
+			validate(ap1);
+			g_code(op_move, 2, ap2, ap1);
+			ap3 = g_expr(node->v.p[1], F_ALL & ~F_AREG);
+			validate(ap2);
+			validate(ap1);
+			if (node->etype == bt_short) {
+				g_code(op_ext, 4, ap1, NIL_AMODE);
+				g_code(op_divs, 0, ap3, ap1);
+			} else {
+				g_code(op_and, 4, mk_immed(65535l), ap1);
+				g_code(op_divu, 0, ap3, ap1);
+			}
+			freeop(ap3);
+			g_code(op_move, 2, ap1, ap2);
+			freeop(ap2);
+			return mk_legal(ap1, flags, 2l);
+		case bt_long:
+			return as_fcall(node, flags, "__divsi3");
+		case bt_ulong:
+		case bt_pointer:
+			return as_fcall(node, flags, "__udivsi3");
+#ifndef NOFLOAT
+#ifdef DOUBLE
+		case bt_double:
+#endif
+		case bt_float:
+			return as_fcall(node, flags, str(ffpdiv));
+#endif
+	}
+	ierr(G_ASDIV,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+struct amode *g_asmod(struct enode *node, int flags) {
+/*
+ * generate /= and %= nodes.
+ */
+	struct amode	 *ap1, *ap2, *ap3;
+	switch (node->etype) {
+		case bt_short:
+		case bt_ushort:
+			ap1 = temp_data();
+			ap2 = g_expr(node->v.p[0], F_ALL | F_USES);
+			validate(ap1);
+			g_code(op_move, 2, ap2, ap1);
+			ap3 = g_expr(node->v.p[1], F_ALL & ~F_AREG);
+			validate(ap2);
+			validate(ap1);
+			if (node->etype == bt_short) {
+				g_code(op_ext, 4, ap1, NIL_AMODE);
+				g_code(op_divs, 0, ap3, ap1);
+			} else {
+				g_code(op_and, 4, mk_immed(65535l), ap1);
+				g_code(op_divu, 0, ap3, ap1);
+			}
+			g_code(op_swap, 0, ap1, NIL_AMODE);
+			freeop(ap3);
+			g_code(op_move, 2, ap1, ap2);
+			freeop(ap2);
+			return mk_legal(ap1, flags, 2l);
+		case bt_long:
+			return as_fcall(node, flags, ".lrem");
+		case bt_ulong:
+		case bt_pointer:
+			return as_fcall(node, flags, ".ulrem");
+	}
+	ierr(G_ASMOD,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+void structassign(struct amode *ap1, struct amode *ap2, long size, int mode) {
+/*
+ * assign structure from ap1 to ap2
+ * ap1, ap2 are scratch address registers
+ */
+#ifdef BIGMEM
+				long	loop_c;
+#else
+				int		loop_c;
+#endif
+				int 	rest;
+				struct amode	 *ap3;
+				unsigned int			label;
+
+				ap1 = copy_addr(ap1);
+				ap2 = copy_addr(ap2);
+				ap1->mode = mode;
+				ap2->mode = mode;
+				loop_c = size >> 2;
+				rest = (int) (size & 3);
+				if (loop_c <= 5) 				/* loop-unrolling */
+					while (loop_c--)
+								g_code(op_move, 4, ap1, ap2);
+				else {
+				loop_c--; 								/* for dbra */
+				ap3 = temp_data();
+				freeop(ap3);
+				label = nxtlabel();
+#ifdef BIGMEM
+				if (loop_c <= 65535) {			// single loop
+#endif
+								g_code(op_move, 2, mk_immed(loop_c), ap3);
+								g_label(label);
+								g_code(op_move, 4, ap1, ap2);
+								g_code(op_dbra, 0, ap3, mk_label(label));
+#ifdef BIGMEM
+				} else {								// extended loop
+								g_code(op_move, 4, mk_immed(loop), ap3);
+								g_label(label);
+								g_code(op_move, 4, ap1, ap2);
+								g_code(op_dbra, 0, ap3, mk_label(label));
+								g_code(op_sub, 4, mk_immed(65536l), ap3);
+								g_code(op_bhs, 0, mk_label(label), NIL_AMODE);
+				}
+#endif
+				}
+#if AL_DEFAULT!=2
+				if (rest >= 2) {
+					rest -= 2;
+					g_code(op_move, 2, ap1, ap2);
+				}
+
+				/* This cannot happen if the size of structures is always even */
+				if (rest)
+					g_code(op_move, 1, ap1, ap2);
+#ifdef SHORT_STRUCT_PASSING
+#error "Much of the short struct stuff assumes that structs whose size is under 4 \
+	really are short structs (while they aren't, since to do an assignment of a  \
+	3-byte struct, you have to do 2 moves, if not 3...)"
+#error "So let AL_DEFAULT be 2."
+#endif
+#else
+				if (rest)
+					g_code(op_move, 2, ap1, ap2);
+#endif
+}
+
+struct amode *g_assign(struct enode *node, int flags) {
+/*
+ * generate code for an assignment node.
+ */
+	int 			f;
+	struct amode   *ap1, *ap2, *ap3;
+	struct enode   *ep;
+	long			size = node->esize;
+	if (flags & F_NOVALUE)
+		f = F_ALL;
+	else
+		f = F_ALL | F_USES;
+	if (bt_aggregate(node->etype)) {
+#ifdef SHORT_STRUCT_PASSING
+		if (node->esize<=4) {
+			ap1 = g_expr(node->v.p[1], F_AREG);
+			ap2 = g_expr(node->v.p[0], F_AREG);
+			validate(ap1);
+			structassign(ap1, ap2, (long)node->esize, am_ind);
+			freeop(ap2);
+			return mk_legal(ap1, flags, 4l);
+		}
+#endif
+		/*
+		* Other parts of this module return a pointer to a struct in a register,
+		* not the struct itself
+		*/
+		ap1 = g_expr(node->v.p[1], F_AREG | F_VOL);
+		ap2 = g_expr(node->v.p[0], F_AREG | F_VOL);
+		validate(ap1);
+
+		/* hacky: save ap1 if needed later, structassign destroys it */
+		if (!(flags & F_NOVALUE)) {
+			ap3 = temp_addr();
+			/* BTW, this code gets eliminated with MAX_ADDR = 1 */
+			g_code(op_move, 4, ap1, ap3);
+			structassign(ap3, ap2, (long)size, am_ainc);
+			freeop(ap3);
+			freeop(ap2);
+			validate(ap1);
+			return mk_legal(ap1, flags, 4l);
+		} else {					/* no need to save any registers */
+			structassign(ap1, ap2, (long)node->esize, am_ainc);
+			freeop(ap2);
+			/* mk_legal is a no-op here */
+			return mk_legal(ap1, flags, 4l);
+		}
+	}
+	if (node->v.p[0]->nodetype == en_fieldref) {
+		long mask;
+		int i;
+		/*
+		 * Field assignment
+		 */
+
+#ifdef OLD_FIELD_ASSIGN
+		/* get the value */
+		ap1 = g_expr(node->v.p[1], F_DREG | F_VOL);
+		i = node->v.p[0]->bit_width;
+		mask = 0;
+		while (i--)
+			mask = mask + mask + 1;
+		g_code(op_and, (int) size, mk_immed(mask), ap1);
+		i = (node->v.p[0]->esize<<3)-node->v.p[0]->bit_offset-node->v.p[0]->bit_width;
+		mask <<= i;
+		if (!(flags & F_NOVALUE)) {
+			/*
+			 * result value needed
+			 */
+			ap3 = temp_data();
+			g_code(op_move, 4, ap1, ap3);
+		} else
+			ap3 = ap1;
+		if (i > 0) {
+			if (i == 1) {
+				/* add dn,dn */
+				g_code(op_add, (int) node->esize, ap3, ap3);
+			} else if (i <= 8) {
+				g_code(op_lsl, (int) size,
+					mk_immed(i), ap3);
+			} else {
+				ap2 = temp_data();
+				g_code(op_moveq, 0,
+					mk_immed(i), ap2);
+				g_code(op_lsl, (int) size, ap2, ap3);
+				freeop(ap2);
+			}
+		}
+		ep = mk_node(en_ref, node->v.p[0]->v.p[0], NIL_ENODE);
+		ep->esize = 1;
+		ap2 = g_expr(ep, F_MEM);
+		validate(ap3);
+		g_code(op_and, (int) size, mk_immed(~mask), ap2);
+		g_code(op_or, (int) size, ap3, ap2);
+		freeop(ap2);
+		if (!(flags & F_NOVALUE)) {
+			freeop(ap3);
+			validate(ap1);
+		}
+#else
+		{
+			ep = mk_node(en_ref, node->v.p[0]->v.p[0], NIL_ENODE);
+			ep->esize = node->v.p[1]->esize;
+			ep->etype = node->v.p[1]->etype;
+			ap2 = g_expr(ep, F_MEM);
+
+			ep=node->v.p[1];
+			/* get the value */
+			i = node->v.p[0]->bit_width;
+			mask = 0;
+			while (i--)
+				mask = mask + mask + 1;
+			ep = mk_node(en_and, ep, mk_icon(mask));
+			ep->esize=ep->v.p[0]->esize;
+			ep->etype=ep->v.p[0]->etype;
+			ep->v.p[1]->esize=ep->esize;
+			ep->v.p[1]->etype=ep->etype;
+			i = (node->v.p[0]->esize<<3)-node->v.p[0]->bit_offset-node->v.p[0]->bit_width;
+			mask <<= i;
+			ep = mk_node(en_lsh, ep, mk_icon(i));
+			ep->esize=ep->v.p[0]->esize;
+			ep->etype=ep->v.p[0]->etype;
+			ep->v.p[1]->esize=1;
+			ep->v.p[1]->etype=bt_char;
+			opt0(&ep);
+			ap1 = g_expr(ep, F_DREG | F_IMMED);
+			validate(ap2);
+			if (ap1->mode==am_immed && node->v.p[0]->bit_width==1) {
+				// note that thus, we need not free/validate anything...
+				if (!((~ap1->offset->v.i)&mask)) {
+					ap1->offset->v.i = i;
+					g_bitmancode(op_bset, (int)size, ap1, ap2);
+					freeop(ap2);
+					if (!(flags & F_NOVALUE))
+						return mk_legal(mk_immed(1L),flags,node->esize);
+					return NIL_AMODE;
+				} else if (!(ap1->offset->v.i&mask)) {
+					ap1->offset->v.i = i;
+					g_bitmancode(op_bclr, (int)size, ap1, ap2);
+					freeop(ap2);
+					if (!(flags & F_NOVALUE))
+						return mk_legal(mk_immed(0L),flags,node->esize);
+					return NIL_AMODE;
+				}
+			} else {
+				g_code(op_and, (int) size, mk_immed(~mask), ap2);
+				g_code(op_or, (int) size, ap1, ap2);
+				freeop(ap1);
+				if (!(flags & F_NOVALUE))
+					return g_fderef(node->v.p[0], ap2, flags);
+				freeop(ap2);
+				return NIL_AMODE;
+			}
+		}
+#endif
+		return mk_legal(ap1, flags, size);
+	}
+	/*
+	 * (uns.) char, (uns.) short, (uns.) long, float
+	 * 
+	 * we want to pass the right hand side as the expression value. This can't
+	 * be done if the left side is a register variable on which the right
+	 * hand side addressing mode depends. But if the left side IS a register
+	 * variable, it is desirable to pass the left side, so no problem.
+	 */
+	if (node->v.p[0]->nodetype == en_tempref) {
+		/* pass the left side as expr. value */
+		ap1 = g_expr(node->v.p[0], f);
+		ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+		validate(ap1);
+		g_code(op_move, (int) size, ap2, ap1);
+		freeop(ap2);
+		return mk_legal(ap1, flags, size);
+	} else {
+		/* pass the right side as expr. value */
+		/* normally, this is more efficient */
+		ap1 = g_expr(node->v.p[1], f | F_SRCOP);
+		ap2 = g_expr(node->v.p[0], F_ALL);
+		validate(ap1);
+		g_code(op_move, (int) size, ap1, ap2);
+		freeop(ap2);
+		return mk_legal(ap1, flags, size);
+	}
+}
+
+struct amode *g_aincdec(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * generate an auto increment or decrement node. op should be either op_add
+ * (for increment) or op_sub (for decrement).
+ */
+	struct amode	 *ap1, *ap2;
+	switch (node->etype) {
+		case bt_uchar:
+		case bt_char:
+		case bt_short:
+		case bt_ushort:
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			if (flags & F_NOVALUE) {/* dont need result */
+				ap1 = g_expr(node->v.p[0], F_ALL);
+				g_code(op, (int) node->esize, mk_immed((long) node->v.p[1]->v.i),
+						ap1);
+				return mk_legal(ap1, flags, node->esize);
+			}
+			if (flags & F_DREG)
+				ap1 = temp_data();
+			else
+				ap1 = temp_addr();
+			ap2 = g_expr(node->v.p[0], F_ALL | F_USES);
+			validate(ap1);
+			g_code(op_move, (int) node->esize, ap2, ap1);
+			g_code(op, (int) node->esize, mk_immed((long) node->v.p[1]->v.i), ap2);
+			freeop(ap2);
+			return mk_legal(ap1, flags, node->esize);
+	}
+	ierr(G_AINCDEC,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+long push_param(struct enode *ep) {
+/*
+ * push the operand expression onto the stack. return the number of bytes
+ * pushed
+ */
+	struct amode	 *ap;
+#ifdef OLD_STRUCT_PUSH
+	struct amode	 *ap1;
+#endif
+	long											size = ep->esize;
+	int old_pushed;
+
+	/* pushing of aggregates: (short) structures and unions, as well as BCD floats */
+	if (bt_aggregate(ep->etype)) {
+		if (ep->nodetype==en_ref)
+			ep = ep->v.p[0];
+			/* all other cases return a pointer to the struct anyway */
+#ifdef OLD_STRUCT_PUSH
+		/* allocate stack space */
+		g_code(op_sub, 4, mk_immed(size), mk_reg(STACKPTR));
+		/*
+		 * F_VOL was missing in the following line --
+		 * it took a hard-core debugging session to find this error
+		 */
+		ap = g_expr(ep, F_AREG | F_VOL);
+		ap1 = temp_addr();
+		validate(ap);
+		g_code(op_move, 4, mk_reg(STACKPTR), ap1);
+		/* now, copy it on stack - the same as structassign */
+		structassign(ap, ap1, size, am_ainc);
+		freeop(ap1);
+		freeop(ap);
+#else
+		if ((size&1)) size++;	/* otherwise there will be a bunch of problems */
+
+		{
+		struct enode *ep2=mk_icon(size);
+		ep2->etype=bt_long; ep2->esize=4;
+		ep = mk_node(en_add,ep,ep2);
+		ep->etype=bt_pointer; ep->esize=4;
+		opt0(&ep);
+		ap = g_expr(ep, F_AREG | F_VOL);
+		/* now, copy it on stack - the same as structassign */
+		structassign(ap, mk_reg(STACKPTR), size, am_adec);
+		freeop(ap);
+		}
+#endif
+		return size;
+	}
+	old_pushed = pushed;
+	pushed = 0;
+	ap = g_expr(ep, F_ALL | F_DEREF);
+
+	/*
+	 * This is a hook for the peephole optimizer, which will convert lea
+	 * <ea>,An + pea (An) ==> pea <ea>
+	 */
+
+#ifdef POP_OPT
+	if (old_pushed && pushed)
+		g_code(_op_adj, 0, NIL_AMODE, NIL_AMODE);
+#endif
+	pushed = 1;
+	if ((ap->mode == am_areg || ap->mode == am_immed)
+		&& size == 4 && ap->preg <= MAX_ADDR) {
+		ap = copy_addr(ap);
+		am_doderef(ap->mode);
+		g_code(op_pea, 0, ap, NIL_AMODE);
+	} else
+		g_code(op_move, (int) size, ap, push_am);
+	freeop(ap);
+	return size+(size&1);
+}
+
+int req_all_aregs(struct enode *plist,int rp_dn,int rp_an) {
+	/* requires all regs if and only if (num_params>=regs_num || num_pointers>=aregs_num) */
+	rp_dn+=rp_an;
+	while (plist) {
+		if (!--rp_dn) return 1;
+		if (plist->v.p[0]->etype==bt_pointer && !--rp_an) return 1;
+		plist=plist->v.p[1];
+	}
+	return 0;
+}
+
+long g_parms(struct enode *plist
+#ifdef REGPARM
+	, int rp_dn, int rp_an, struct amode **a1ap
+#endif
+		) {
+/*
+ * push a list of parameters onto the stack and return the number of
+ * parameters pushed.
+ */
+#ifdef BIGSTACK
+	long i=0;
+#else
+	int i=0;
+#endif
+	pushed = 0;
+#ifdef REGPARM
+#ifdef PC
+	if (rp_dn IS_INVALID || rp_an IS_INVALID)
+		ierr(G_PARMS,1);
+#endif
+	if (rp_dn || rp_an) {
+		int nr=rp_dn+rp_an,np=0,n;
+		struct enode *ep=plist,**p,**dp,**ap,*allocbase[16],*list[16];
+		struct amode deep[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1],*deepp;
+		while (ep) np++, ep=ep->v.p[1];
+		/* first, push stack params while all the temp registers are free */
+		while (np>nr) {
+			i += push_param(plist->v.p[0]);
+			plist = plist->v.p[1];
+			np--;
+		}
+		/* store the last params so we can examinate them in the correct order */
+		n=np; while (n--) list[n]=plist->v.p[0], plist=plist->v.p[1];
+		/* now, fill in 'allocbase' */
+		p=list; dp=&allocbase[0]; ap=&allocbase[8];
+		n=np; while (n--) {
+			ep=*p++;
+			if ((ep->etype==bt_pointer && rp_an) || !rp_dn)
+				*ap++=ep, rp_an--;
+			else *dp++=ep, rp_dn--;
+		}
+		*ap=NULL; *dp=NULL;
+		/* finally, load all the parameters into the correct registers */
+		dp=&allocbase[0]; ap=&allocbase[8];
+		deepp=deep;
+		n=8; while (n--) {	/* push d0/a0/d1/a1/... */
+			if (*dp) {
+//#ifdef PC
+				struct amode *amp=
+//#endif
+					g_expr(*dp++,F_DREG|F_VOL);
+#ifdef INFINITE_REGISTERS
+				struct amode *ap2 = (struct amode *) xalloc((int) sizeof(struct amode), 0);
+				ap2->mode = am_dreg;
+				ap2->preg = TDREGBASE+dp-allocbase-1;
+				g_code(op_move, dp[-1]->esize, amp, ap2);
+				freeop(amp);
+				amp=ap2;
+#endif
+#ifdef PC
+				if (amp->mode!=am_dreg || amp->preg!=TDREGBASE+dp-allocbase-1)
+					ierr(REGPARM,1);
+#endif
+				*deepp++=*amp;
+			}
+			if (*ap) {
+//#ifdef PC
+				struct amode *amp=
+//#endif
+					*a1ap = g_expr(*ap++,F_AREG|F_VOL);
+#ifdef INFINITE_REGISTERS
+				struct amode *ap2 = (struct amode *) xalloc((int) sizeof(struct amode), 0);
+				ap2->mode = am_areg;
+				ap2->preg = TDREGBASE+ap-allocbase-1-8;
+				g_code(op_move, ap[-1]->esize, amp, ap2);
+				freeop(amp);
+				amp=ap2;
+#endif
+#ifdef PC
+				if (amp->mode!=am_areg || amp->preg!=TDREGBASE+ap-allocbase-1-8)
+					ierr(REGPARM,2);
+#endif
+				*deepp++=*amp;
+			}
+		}
+		while (deepp>deep)
+			validate(--deepp);
+	} else {
+#endif
+		while (plist != 0) {
+			i += push_param(plist->v.p[0]);
+			plist = plist->v.p[1];
+		}
+#ifdef REGPARM
+	}
+#endif
+	return i;
+}
+
+struct amode *func_result(int flags, long bytes) {
+	/*
+	 * saves a function call result in D0 it is assumed that flags contain
+	 * either F_DREG or F_AREG return value is the addressing mode of the
+	 * result bytes is the number of bytes to pop off the stack
+	 *
+	 * This routine does not use mk_legal and takes care of the stuff itself.
+	 */
+	struct amode *ap;
+	if (bytes != 0)
+		/* adjust stack pointer */
+		g_code(op_add, 4, mk_immed(bytes), mk_reg(STACKPTR));
+	if (flags & F_NOVALUE)
+		return 0;
+	if (flags & F_DREG) {
+		ap = temp_data();
+		g_code(op_move, 4, mk_reg(RESULT), ap);
+	} else if (flags & F_AREG) {
+		ap = temp_addr();
+		g_code(op_move, 4, mk_reg(RESULT), ap);
+#ifdef PC
+	} else {
+		ierr(FUNC_RESULT,1);
+		return 0; // make the compiler happy
+#endif
+	}
+	return ap; 
+}
+
+struct amode *func_result2(int flags, long bytes, int reg) {
+	/*
+	 * Saves a function call result in REG. It is assumed that flags contain
+	 * either F_DREG or F_AREG. Return value is the addressing mode of the
+	 * result; bytes is the number of bytes to pop off the stack
+	 *
+	 * This routine does not use mk_legal and takes care of the stuff itself.
+	 */
+	struct amode	 *ap;
+	if (bytes != 0) /* adjust stack pointer */
+		g_code(op_add, 4, mk_immed(bytes), mk_reg(STACKPTR));
+	if (flags & F_NOVALUE)
+		return 0;
+	if ((flags & F_DREG) && reg==RESULT) {		// permet d'éviter move.l a0,d0 /
+		ap = temp_data();						//  move.l d0,rn #roll#
+		g_code(op_move, 4, mk_reg(reg), ap);
+	} else if (flags & F_AREG) {
+		ap = temp_addr();
+		g_code(op_move, 4, mk_reg(reg), ap);
+	} else {
+#ifdef PC
+		if (flags & F_DREG) {
+#endif
+		ap = temp_data();
+		g_code(op_move, 4, mk_reg(reg), ap);
+#ifdef PC
+	} else {
+		ierr(FUNC_RESULT,2);
+		return 0; // make the compiler happy
+	}
+#endif
+	}
+	return ap;
+}
+
+struct amode *as_fcall(struct enode *node, int flags, char *libname) {
+/* assignment operations with library calls */
+	long											i;
+	struct amode	 *ap1;
+	long											size;
+	size = node->esize;
+	temp_inv();
+	i = push_param(node->v.p[1]);
+	if (node->v.p[0]->nodetype == en_tempref) {
+		/* ap1 cannot be destroyed, no problem */
+		ap1 = g_expr(node->v.p[0], F_DREG | F_AREG);
+		g_code(op_move, (int) size, ap1, push_am);
+		i += size;
+		call_library(libname);
+		/* ap1 is always valid and not equal to RESULT */
+		g_code(op_move, (int) size, mk_reg(RESULT), ap1);
+	} else {
+		uwarn("possible flaw in lib call");
+		ap1 = g_expr(node->v.p[0], F_DREG | F_AREG);
+		g_code(op_move, (int) size, ap1, push_am);
+		i += size;
+		call_library(libname);
+		/* ap1 is always valid and not equal to RESULT */
+		g_code(op_move, (int) size, mk_reg(RESULT), ap1);
+	}
+	g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
+	if (!(flags & F_NOVALUE)) {
+		if (flags & F_AREG)
+			ap1 = temp_addr();
+		else
+			ap1 = temp_data();
+		g_code(op_move, 4, mk_reg(RESULT), ap1);
+		return mk_legal(ap1, flags, size);
+	} else
+		return 0;
+}
+
+#ifndef __HAVE_REGS_IMAGE
+#define __HAVE_REGS_IMAGE
+typedef struct _regsimg {
+#ifndef INFINITE_REGISTERS
+	int reg_alloc_ptr,reg_stack_ptr;
+	int next_data,next_addr;
+#endif
+} REGS_IMAGE;
+#endif
+
+readonly struct amode am_a1={am_areg,0,1,0,0,0};
+readonly struct amode am_a2={am_areg,0,2,0,0,0};
+readonly struct amode am_a2ind={am_ind,0,2,0,0,0};
+
+extern int hexatoi(char *s);
+
+struct amode *g_fcall(struct enode *node, int flags) {
+/*
+ * generate a function call node and return the address mode of the result.
+ */
+		struct amode	 *ap; enum(e_node) nt;
+		long											i;
+#ifdef SHORT_STRUCT_PASSING
+		int short_struct_return=0;
+#endif
+#ifdef PC
+		// avoid a compiler warning...
+		struct amode *struct_ap = 0;
+#else
+		struct amode *struct_ap = struct_ap;
+#endif
+	#ifdef REGPARM
+//		struct amode	 *regap[(MAX_DATA+1+MAX_ADDR+1)+1],**rapp;
+		struct amode *a1ap; struct enode *dep;
+		REGS_IMAGE regs_img;
+		int allaregs_patch=0;
+	#endif
+		/* push any used addr&data temps */
+		dep = node->v.p[0];
+		while (dep->nodetype==en_cast && dep->esize==4) dep=dep->v.p[0];
+		nt = dep->nodetype;
+//		nt = node->v.p[0]->nodetype;
+/*		if (nt==en_nacon && !strcmp(node->v.p[0]->v.ensp,"rand"))
+			printf("jdfio");*/
+		temp_inv();
+	#ifdef REGPARM
+		useregs(&regs_img);
+#ifndef INFINITE_REGISTERS
+		if (node->rp_an>MAX_ADDR && !(nt==en_nacon || nt==en_labcon
+				|| (nt==en_tempref && node->v.p[0]->v.i>=AREGBASE))
+			&& req_all_aregs(node->v.p[1],node->rp_dn,node->rp_an))
+				allaregs_patch=1;
+#endif
+		i = g_parms(node->v.p[1],node->rp_dn,
+			node->rp_an/*-allaregs_patch*/,&a1ap); /* generate parameters */
+		if (allaregs_patch) freeop(a1ap);
+	#else
+		i = g_parms(node->v.p[1]);		/* generate parameters */
+	#endif
+		/*
+		 * for functions returning a structure or a union, push a pointer to the
+		 * return value as additional argument The scratch space will be
+		 * allocated in the stack frame of the calling function.
+		 */
+		if (bt_aggregate(node->etype)) {
+			struct_ap = mk_scratch(node->esize);
+#ifdef SHORT_STRUCT_PASSING
+			if (node->esize>4)
+#endif
+				g_code(op_pea, 0, struct_ap, NIL_AMODE), i += 4l;
+#ifdef SHORT_STRUCT_PASSING
+			else short_struct_return=1;
+#endif
+			// freeop(ap); it is useless, as scratch amode's need not be freed
+		}
+		/* call the function */
+		if (nt == en_nacon || nt == en_labcon) {
+			/*if (!strcmp(node->v.p[0]->v.ensp,"rand"))
+				printf("jdfio");*/
+#ifdef FLINE_RC
+			if (fline_rc && nt==en_nacon && dep->v.ensp && !strncmp(dep->v.ensp,"_ROM_CALL_",10))
+				g_code(op_dc, 2, mk_offset(mk_icon(0xF800+hexatoi(dep->v.ensp+10))), NIL_AMODE);
+			else
+#endif
+			g_code(op_jsr, 0, mk_offset(dep), NIL_AMODE);
+//			g_code(op_jsr, 0, mk_offset(node->v.p[0]), NIL_AMODE);
+		} else {
+#ifdef REGPARM
+			if (allaregs_patch) {
+				g_code(op_move, 4, (struct amode *)&am_a2, push_am);
+				g_code(op_move, 4, (struct amode *)&am_a1, (struct amode *)&am_a2);
+			}
+#endif
+			ap = g_expr(node->v.p[0], F_AREG);
+			ap = copy_addr(ap);
+			ap->mode = am_ind;
+			freeop(ap);
+#ifdef REGPARM
+			if (allaregs_patch) {
+#ifdef PC
+				if (ap->preg!=1)
+					ierr(REGPARM,3);
+#endif
+/*				struct amode *ap2 =
+					(struct amode *) xalloc((int) sizeof(struct amode), AMODE);*/
+				g_code(op_exg, 4, (struct amode *)&am_a1, (struct amode *)&am_a2);
+				ap=(struct amode *)&am_a2ind;
+/*				ap2->mode = am_areg;
+				ap2->preg = node->rp_an-1;
+				g_code(op_move, 4, pop_am, ap2);	// always long since it's 'bt_pointer'
+				i-=4;*/
+			}
+#endif
+			g_code(op_jsr, 0, ap, NIL_AMODE);
+#ifdef REGPARM
+			if (allaregs_patch)
+				g_code(op_move, 4, pop_am, (struct amode *)&am_a2);
+#endif
+		}
+	#ifdef REGPARM
+		/* free register params */
+/*		rapp=regap;
+		while (*rapp)
+			freeop(*rapp++);*/
+		freeregs(&regs_img);
+	#endif
+#ifdef SHORT_STRUCT_PASSING
+	if (short_struct_return) {
+		if (flags & F_NOVALUE)
+			return func_result2(F_NOVALUE,i,0);
+		g_code(op_lea,0,struct_ap,mk_reg(PRESULT));	/* note : this *is* commutative with
+													 * popping args off as we use a virtual
+													 * a6-like register for struct_ap...
+													 *   But we had better postpone this lea
+													 * as late as possible to take advantage
+													 * of peephole optimizations.
+													 */
+		ap = mk_reg(PRESULT); ap->mode=am_ind;
+		g_code(op_move,node->esize,mk_reg(RESULT),ap);
+	}
+#endif
+	return func_result2(flags, i,
+		(node->etype>=bt_pointer&&node->etype<=bt_union)?PRESULT:RESULT);
+}
+
+struct amode *g_alloca(struct enode *node) {
+	struct enode *ep=mk_node(en_add,node->v.p[0],mk_icon(1));
+	struct amode *ap1, *ap2;
+	ep->etype=node->v.p[0]->etype;
+	ep->esize=node->v.p[0]->esize;
+	ep->v.p[1]->etype=ep->etype;
+	ep->v.p[1]->esize=ep->esize;
+	ep=mk_node(en_and,mk_icon(-2),ep);
+	ep->etype=ep->v.p[1]->etype;
+	ep->esize=ep->v.p[1]->esize;
+	ep->v.p[0]->etype=ep->etype;
+	ep->v.p[0]->esize=ep->esize;
+	ap1 = mk_reg(STACKPTR);
+	opt0(&ep);
+	ap2 = g_expr(ep, F_DREG | F_IMMED);
+	g_code(op_sub, 2, ap2, ap1);
+	freeop(ap2);
+	return ap1;
+}
+
+#define F_GCAST 0
+//#define F_GCAST F_USES => seems completely useless...
+
+#ifdef G_CAST2
+struct amode *g_cast2(struct enode *ep, enum(e_bt) typ2, int flags) {
+/*
+ * generates code for a en_cast node
+ *
+ */
+	struct amode	*ap;
+	enum(e_bt) typ1=ep->etype;
+	if (typ1==bt_long && typ2==bt_short) {	/* useful when using short mul's */
+		if (ep->nodetype==en_cast && ep->v.p[0]->etype==bt_short)
+			return g_expr(ep->v.p[0], flags);
+	}
+	ap=g_expr(ep, F_ALL | F_SRCOP | F_GCAST);
+	return g_cast(ap, typ1, typ2, flags);
+}
+#endif
+
+struct amode *g_cast(struct amode *ap, enum(e_bt) typ1, enum(e_bt) typ2, int flags) {
+/*
+ * generates code for an en_cast node
+ *
+ */
+	struct amode	 *ap1;
+	int 									 f;
+
+	if (flags & F_NOVALUE) {
+		freeop(ap);
+		return 0;
+	}
+
+	/* the following code from now on is meaningless :
+	 *  'useless' casts are sometimes generated to keep track of
+	 *  the previous TYP structure */
+#if 0
+	if (typ1 == typ2)
+		/*
+		 * this can happen in with the g_xmul stuff, where a cast from
+		 * (u)short to long now casts from (u)short to (u)short for an 68000
+		 * mulu or muls instruction.
+		 * It is safe to cut things short then.
+		 * It should not happen with types other than (u)short, but
+		 * it does not harm either.
+		 */
+		if (typ1 == bt_short || typ1 == bt_ushort)
+			return mk_legal(ap, flags, 2l);
+		//else
+		//	msg("DEBUG: g_cast: typ1 == typ2\n");
+#endif
+
+	switch (typ2) {
+		/* switch: type to cast to */
+		case bt_char:
+		case bt_uchar:
+			switch (typ1) {
+				case bt_uchar:
+				case bt_char:
+					return mk_legal(ap, flags, 1l);
+				case bt_ushort:
+				case bt_short:
+					if ((ap1 = g_offset(ap, 1)) == 0)
+						ap1 = mk_legal(ap, F_DREG, 2l);
+					return mk_legal(ap1, flags, 1l);
+				case bt_ulong:
+				case bt_long:
+				case bt_pointer:
+					if ((ap1 = g_offset(ap, 3)) == 0)
+						ap1 = mk_legal(ap, F_DREG, 4l);
+					return mk_legal(ap1, flags, 1l);
+				case bt_float:
+#ifdef DOUBLE
+				case bt_double:
+#endif
+					return g_cast(g_cast(ap, bt_double, bt_long, F_DREG),
+							bt_long, typ2, F_DREG);
+			}
+			break;
+		case bt_ushort:
+		case bt_short:
+			switch (typ1) {
+				case bt_uchar:
+					ap = mk_legal(ap, F_DREG | F_VOL, 1l);
+					g_code(op_and, 2, mk_immed(255l), ap);
+					return mk_legal(ap, flags, 2l);
+				case bt_char:
+					ap = mk_legal(ap, F_DREG | F_VOL, 1l);	// F_VOL is important here!
+					g_code(op_ext, 2, ap, NIL_AMODE);		// (otherwise (short)(char)my_short fails...)
+					return mk_legal(ap, flags, 2l);
+				case bt_short:
+				case bt_ushort:
+					return mk_legal(ap, flags, 2l);
+				case bt_long:
+				case bt_ulong:
+				case bt_pointer:
+					if ((ap1 = g_offset(ap, 2)) == 0)
+						ap1 = mk_legal(ap, F_DREG, 4l);
+					return mk_legal(ap1, flags, 2l);
+				case bt_float:
+#ifdef DOUBLE
+				case bt_double:
+#endif
+					return g_cast(g_cast(ap, bt_double, bt_long, F_DREG),
+							bt_long, typ2, F_DREG);
+			}
+			break;
+		case bt_long:
+		case bt_ulong:
+		case bt_pointer:
+			switch (typ1) {
+				case bt_uchar:
+					ap = mk_legal(ap, F_DREG | F_VOL, 1l);
+					g_code(op_and, 4, mk_immed(255l), ap);
+					return mk_legal(ap, flags, 4l);
+				case bt_char:
+					ap = mk_legal(ap, F_DREG | F_VOL, 1l);	// F_VOL is important here!
+					g_code(op_ext, 2, ap, NIL_AMODE);		// (otherwise (short)(char)my_short fails...)
+					g_code(op_ext, 4, ap, NIL_AMODE);
+					return mk_legal(ap, flags, 4l);
+				case bt_ushort:
+					ap = mk_legal(ap, F_DREG | F_VOL, 2l);
+					g_code(op_and, 4, mk_immed(65535l), ap);
+					return mk_legal(ap, flags, 4l);
+				case bt_short:
+					f = flags & (F_DREG | F_AREG);
+					if (f == 0) f = F_DREG | F_AREG;
+					ap = mk_legal(ap, f | F_VOL, 2l);	// F_VOL is important here!
+					if (ap->mode == am_dreg)			// (otherwise (short)(char)my_short fails...)
+						g_code(op_ext, 4, ap, NIL_AMODE);
+					return mk_legal(ap, flags, 4l);
+				case bt_long:
+				case bt_ulong:
+				case bt_pointer:
+					return mk_legal(ap, flags, 4l);
+#ifndef NOFLOAT
+				case bt_float:
+#ifdef DOUBLE
+				case bt_double:
+#endif
+					/* library call */
+#ifndef BCDFLT
+					freeop(ap);
+					temp_inv();
+					g_code(op_move, 4, ap, push_am);
+					if (typ2 == bt_long)
+						call_library(str(ffpftol));
+					else
+						call_library(str(ffpftou));
+					return func_result(flags, 4l);
+#else
+					fatal(
+							"__floatsibf");	// !!!STUDY ME!!!
+#endif
+#endif
+			}
+			break;
+#ifndef NOFLOAT
+		case bt_float:
+#ifdef DOUBLE
+		case bt_double:
+#endif
+			switch (typ1) {
+				case bt_char:
+				case bt_uchar:
+				case bt_short:
+				case bt_ushort:
+					ap = g_cast(ap, typ1, bt_long, F_ALL);
+				case bt_long:
+				case bt_ulong:
+				case bt_pointer:
+					/* library call */
+#ifndef BCDFLT
+					freeop(ap);
+					temp_inv();
+					g_code(op_move, 4, ap, push_am);
+					if (typ1 == bt_ulong || typ1 == bt_pointer)
+						call_library(str(ffputof));
+					else
+						call_library(str(ffpltof));
+					return func_result(flags, 4l);
+#else
+					fatal(
+							"__fixbfsi");	// !!!STUDY ME!!!
+#endif
+				case bt_float:
+#ifdef DOUBLE
+				case bt_double:
+#endif
+					return mk_legal(ap, flags, (long)float_size);
+			}
+#endif
+			break;
+	}
+	ierr(G_CAST,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+
+struct amode *g_offset(struct amode *ap, int off) {
+/*
+ * return true, if ap can be switched to address a location with a short
+ * offset. typical application: cast long -> short: 8(a6) --> 10(a6) offset
+ * is a small number (1,2 or 3)
+ */
+				switch (ap->mode) {
+						case am_ind:
+				ap = copy_addr(ap);
+				ap->mode = am_indx;
+				ap->offset = mk_icon((long) off);
+				return ap;
+						case am_indx:
+				if (ap->offset->nodetype == en_icon &&
+								off + ap->offset->v.i <= 32767) {
+								ap = copy_addr(ap);
+								ap->offset->v.i += off;
+								return ap;
+				}
+				break;
+						case am_indx2:
+						case am_indx3:
+				if (ap->offset->nodetype == en_icon &&
+								off + ap->offset->v.i <= 127) {
+								ap = copy_addr(ap);
+								ap->offset->v.i += off;
+								return ap;
+				}
+				break;
+						case am_direct:
+				ap = copy_addr(ap);
+				ap->offset = mk_node(en_add, ap->offset,
+																 mk_icon((long) off));
+				return ap;
+				}
+				/* special value indicating that it must be done by hand */
+				return 0;
+}
+
+struct amode *g_xmul(struct enode *node, int flags, enum(e_op) op) {
+/*
+ * performs a mixed-mode multiplication
+ */
+				struct amode	 *ap1, *ap2;
+
+/*				if (lineid==139)
+					bkpt();*/
+				ap1 = g_expr(node->v.p[1], F_DREG | F_VOL);
+				ap2 = g_expr(node->v.p[0], F_ALL & ~F_AREG);
+				validate(ap1);
+
+				g_code(op, 0, ap2, ap1);
+				freeop(ap2);
+				return mk_legal(ap1, flags, node->esize);
+}
+
+#ifndef __HAVE_STACK_IMAGE
+#define __HAVE_STACK_IMAGE
+typedef struct _stackimg {
+	int next_data,next_addr;
+#ifndef INFINITE_REGISTERS
+	int reg_alloc_ptr,reg_stack_ptr;
+	char dreg_in_use[MAX_DATA+1];
+	char areg_in_use[MAX_ADDR+1];
+	struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1];
+	int act_scratch;
+#endif
+} STACK_IMAGE;
+#endif
+
+struct amode *g_compound(struct snode *st, int flags) {
+	STACK_IMAGE img;
+	struct amode *ap1,*ap2;
+	int old=need_res;
+	need_res=(~flags)&F_NOVALUE;
+	temp_inv();		/* we are forced to do so :'( */
+	usestack(&img);
+	genstmt(st);
+	need_res=old;
+	if (!(ap1=lastexpr_am)) {
+		if (!(flags&F_NOVALUE))
+			err_force_line=st->line, uerrc("no value returned in compound expression");
+	}
+	if (flags&F_NOVALUE) {
+		freeop(lastexpr_am);
+		return NIL_AMODE;
+	}
+	freestack(&img);
+	/* always one of F_DREG or F_AREG is set */
+	if ((flags&(F_AREG|F_DEREF))==(F_AREG|F_DEREF) || !(flags&F_DREG))
+		ap2=temp_addr();
+	else ap2=temp_data();
+	g_code(op_move, 4, ap1, ap2);
+	return ap2;	/* we needn't call mk_legal :) */
+}
+
+struct amode *g_expr(struct enode *node, int flags) {
+/*
+ * general expression evaluation. returns the addressing mode of the result.
+ *
+ * notice how most of the code actually lies in other functions: this is to
+ * reduce the stack footprint, which is necessary because calls to g_expr may
+ * be deeply nested
+ */
+	struct amode	 *ap1, *ap2;
+	unsigned int			lab0
+#ifndef ALTERNATE_HOOK
+		, lab1
+#endif
+		;
+	long size;
+	enum(e_bt)						type;
+	if (node == 0)
+		ierr(G_EXPR,1);
+/*	if (node==0x7e1b50)
+		bkpt();*/
+	if (tst_const(node)) {
+#ifndef NOBCDFLT
+		if (node->nodetype==en_fcon) {
+			extern int glblabel;
+			int lab = nxtglabel();
+			int i;
+			dseg();
+			put_align(2);
+			put_label(lab);
+			genfloat(node->v.f);
+			//char s[2+BCDLEN];
+			//int i;
+			//s[0] = (node->v.f.exponent>>8)&255;
+			//s[1] = (node->v.f.exponent>>0)&255;
+			//for (i=0;i<BCDLEN;i++)
+			//	s[i+2] = node->v.f.mantissa[i];
+			//lab = stringlit(s,sizeof(s)-1);
+
+			node = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+			node->v.enlab = lab;
+			node->etype = bt_pointer;
+			node->esize = 4;
+		}
+#endif
+		ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_EXPR);
+		ap1->mode = am_immed;
+		ap1->offset = node;
+		return mk_legal(ap1, flags, node->esize);
+	}
+	type = node->etype;
+	size = node->esize;
+	switch (node->nodetype) {
+		case en_autocon:
+			ap1 = temp_addr();
+#ifdef BIGSTACK
+			if (node->v.i >= -32768 && node->v.i <= 32767) {
+#endif
+				ap2 = (struct amode *) xalloc((int) sizeof(struct amode),
+						AMODE+G_EXPR);
+				ap2->mode = am_indx;
+				ap2->preg = FRAMEPTR - AREGBASE;		/* frame pointer */
+				ap2->offset = node; /* use as constant node */
+				g_code(op_lea, 0, ap2, ap1);
+#ifdef BIGSTACK
+			} else {
+				g_code(op_move, 4, mk_immed((long) node->v.p[0]->v.i), ap1);
+				g_code(op_add, 4, mk_reg(FRAMEPTR), ap1);
+				ap1 = copy_addr(ap1);
+				ap1->mode = am_ind;
+			}
+#endif
+			return mk_legal(ap1, flags, size);
+		case en_ref:
+			/*
+			 * g_deref uses flags and size only to test F_USES
+			 */
+			ap1 = g_deref(node->v.p[0], type, flags, node->esize);
+			if (bt_aggregate(type))
+				return mk_legal(ap1, flags, 4l);
+			else
+				return mk_legal(ap1, flags, size);
+		case en_fieldref:
+			return g_fderef(node, NULL, flags);
+		case en_tempref:
+			ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_EXPR);
+			if (node->v.i < AREGBASE) {
+				ap1->mode = am_dreg;
+				ap1->preg = (reg_t)node->v.i;
+			} else {
+				ap1->mode = am_areg;
+				ap1->preg = (reg_t)(node->v.i - AREGBASE);
+			}
+			return mk_legal(ap1, flags, size);
+		case en_uminus:
+			return g_unary(node, flags, op_neg);
+		case en_compl:
+			return g_unary(node, flags, op_not);
+		case en_add:
+#ifdef VCG
+			return g_commute(g_addsub, node, flags, op_add, symmetric);
+#else
+			return g_addsub(node, flags, op_add);
+#endif
+		case en_sub:
+			//#ifdef VCG
+			//	return g_commute(g_addsub, node, flags, op_sub, antisymmetric);
+			//#else
+				return g_addsub(node, flags, op_sub);
+			//#endif
+		case en_and:
+#ifdef BITWISE_REDUCE
+			bitwise_optimize(node, -1L);
+#endif
+#ifdef VCG
+			return g_commute(g_ybin, node, flags, op_and, symmetric);
+#else
+			return g_ybin(node, flags, op_and);
+#endif
+		case en_or:
+#ifdef BITWISE_REDUCE
+			bitwise_optimize(node, 0L);
+#endif
+#ifdef VCG
+			return g_commute(g_ybin, node, flags, op_or, symmetric);
+#else
+			return g_ybin(node, flags, op_or);
+#endif
+		case en_xor:
+#ifdef BITWISE_REDUCE
+			bitwise_optimize(node, 0L);
+#endif
+#ifdef VCG
+			return g_commute(g_xbin, node, flags, op_eor, symmetric);
+#else
+			return g_xbin(node, flags, op_eor);
+#endif
+		case en_mul:
+			/*
+			 * special optimization possible if there are patterns matching the
+			 * 68000 mulu, muls instructions. ugly, but it gives a big
+			 * performance increase
+			 */
+
+			if (type == bt_long || type == bt_ulong || type == bt_pointer) {
+				/* TODO : (char/uchar) * (icon both short & ushort) would be more
+				 * efficient with muls instead of mulu (ext.w instead of and.w
+				 * #255)
+				 */
+				if (tst_ushort(node->v.p[0]) && tst_ushort(node->v.p[1])) {
+					/*if (node->v.p[0]->esize>2) {*/
+					node->v.p[0]->etype = bt_ushort;
+					node->v.p[0]->esize = 2;
+					/*}
+					  if (node->v.p[1]->esize>2) {*/
+					node->v.p[1]->etype = bt_ushort;
+					node->v.p[1]->esize = 2;
+					/*}*/
+					return g_xmul(node, flags, op_mulu);
+				} else if (tst_short(node->v.p[0]) && tst_short(node->v.p[1])) {
+					/*if (node->v.p[0]->esize>2) {*/
+					node->v.p[0]->etype = bt_short;
+					node->v.p[0]->esize = 2;
+					/*}
+					  if (node->v.p[1]->esize>2) {*/
+					node->v.p[1]->etype = bt_short;
+					node->v.p[1]->esize = 2;
+					/*}*/
+					return g_xmul(node, flags, op_muls);
+				}
+			}
+			return g_mul(node, flags);
+		case en_div:
+			return g_div(node, flags);
+		case en_mod:
+			return g_mod(node, flags);
+		case en_lsh:
+			return g_shift(node, flags, op_lsl);
+		case en_rsh:
+			if (type==bt_ulong || type==bt_ushort || type==bt_uchar)
+				return g_shift(node, flags, op_lsr);
+			else
+				return g_shift(node, flags, op_asr);
+		case en_asadd:
+			return g_asadd(node, flags, op_add);
+		case en_assub:
+			return g_asadd(node, flags, op_sub);
+		case en_asand:
+			return g_aslogic(node, flags, op_and);
+		case en_asor:
+			return g_aslogic(node, flags, op_or);
+		case en_aslsh:
+			return g_asshift(node, flags, op_lsl);
+		case en_asrsh:
+			if (type==bt_ulong || type==bt_ushort || type==bt_uchar)
+				return g_asshift(node, flags, op_lsr);
+			else
+				return g_asshift(node, flags, op_asr);
+		case en_asmul:
+			return g_asmul(node, flags);
+		case en_asdiv:
+			return g_asdiv(node, flags);
+		case en_asmod:
+			return g_asmod(node, flags);
+		case en_asxor:
+			return g_asxor(node, flags);
+		case en_assign:
+			return g_assign(node, flags);
+		case en_ainc:
+			return g_aincdec(node, flags, op_add);
+		case en_adec:
+			return g_aincdec(node, flags, op_sub);
+		case en_land:
+		case en_lor:
+		case en_eq:
+		case en_ne:
+		case en_lt:
+		case en_le:
+		case en_gt:
+		case en_ge:
+		case en_not:
+#ifndef ALTERNATE_HOOK
+			lab0 = nxtlabel();
+			lab1 = nxtlabel();
+			falsejp(node, lab0);
+			ap1 = temp_data();
+			g_code(op_moveq, 0, mk_immed(1l), ap1);
+			g_code(op_bra, 0, mk_label(lab1), NIL_AMODE);
+			g_label(lab0);
+			g_code(op_moveq, 0, mk_immed(0l), ap1);
+			g_label(lab1);
+#else
+			lab0 = nxtlabel();
+			ap1 = temp_data();
+			g_code(op_moveq, 0, mk_immed(0l), ap1);
+			falsejp(node, lab0);
+			g_code(op_moveq, 0, mk_immed(1l), ap1);
+			g_label(lab0);
+#endif
+			return mk_legal(ap1, flags, size);
+		case en_cond:
+			return g_hook(node, flags);
+		case en_void:
+			freeop(g_expr(node->v.p[0], F_ALL | F_SRCOP | F_NOVALUE));
+			return g_expr(node->v.p[1], flags);
+		case en_fcall:
+			return g_fcall(node, flags);
+		case en_alloca:
+			return mk_legal(g_alloca(node), flags, 4);
+		case en_cast:
+			/*
+			 * On the 68000, suppress all casts between any of
+			 * long, unsigned long, pointer
+			 */
+			if (type == bt_pointer || type == bt_long || type == bt_ulong) {
+				type = node->v.p[0]->etype;
+				if (type == bt_pointer || type == bt_long || type == bt_ulong)
+					return g_expr(node->v.p[0], flags);
+			}
+			/*
+			 * The cast really results in some work
+			 */
+#ifdef G_CAST2
+			return g_cast2(node->v.p[0], node->etype, flags);
+#else
+			return g_cast(g_expr(node->v.p[0], F_ALL | F_SRCOP | F_GCAST),
+					node->v.p[0]->etype,
+					node->etype, flags);
+#endif
+		case en_deref:
+			/*
+			 * The cases where this node occurs are handled automatically:
+			 * g_assign and g_fcall return a pointer to a structure rather than a
+			 * structure.
+			 */
+			return g_expr(node->v.p[0], flags);
+		case en_compound:
+			return g_compound(node->v.st, flags);
+		default:
+			uerr(ERR_OTH,"debug: node=$%lx, nodetype=%d, etype=%d, esize=%d",node,node->nodetype,node->etype,node->esize);
+			ierr(G_EXPR,2);
+			/* NOTREACHED */
+			return 0; // make the compiler happy
+	}
+}
+
+extern struct enode   *regexp[REGEXP_SIZE];
+int tst_ushort(struct enode *node) {
+/*
+ * tests if node is a integer constant falling in the range of uns. short or
+ * if node is cast from uns. short, uns. char or char.
+ */
+				enum(e_bt)						type;
+
+				if (node->nodetype == en_icon && 0 <= node->v.i && node->v.i <= 65535)
+				return 1;
+
+				if (node->nodetype == en_tempref)	/* because it could be something
+														like a constant in a register */
+					return tst_ushort(regexp[reg_t_to_regexp(node->v.i)]);
+				if (node->nodetype == en_cast) {
+				type = node->v.p[0]->etype;
+				if (type == bt_ushort || type == bt_uchar || type == bt_char)
+								return 1;
+				}
+				return 0;
+}
+
+int tst_short(struct enode *node) {
+/*
+ * tests if node is a integer constant falling in the range of short or if
+ * node is cast from signed or unsigned short.
+ */
+				enum(e_bt)						type;
+
+				if (node->nodetype == en_icon && -32768 <= node->v.i && node->v.i <= 32767)
+				return 1;
+
+				if (node->nodetype == en_tempref)	/* because it could be something
+														like a constant in a register */
+					return tst_short(regexp[reg_t_to_regexp(node->v.i)]);
+				if (node->nodetype == en_cast) {
+				type = node->v.p[0]->etype;
+				if (type == bt_short || type == bt_ushort
+					|| type == bt_char || type == bt_uchar)
+								return 1;
+				}
+				return 0;
+}
+
+int tst_const(struct enode *node) {
+/*
+ * tests if it is a constant node, that means either en_icon, en_nacon or
+ * en_labcon, or sums or differences of such nodes
+ */
+				enum(e_node) 			typ1 = node->nodetype;
+				enum(e_node) 			typ2;
+				if (typ1 == en_icon || typ1 == en_nacon || typ1 == en_labcon
+				|| typ1 == en_fcon)
+				return 1;
+
+				if (typ1 == en_add || typ1 == en_sub) {
+				typ1 = node->v.p[0]->nodetype;
+				typ2 = node->v.p[1]->nodetype;
+				if (((typ1 == en_nacon || typ1 == en_labcon) && typ2 == en_icon) ||
+								((typ2 == en_nacon || typ2 == en_labcon) && typ1 == en_icon))
+								return 1;
+				}
+				return 0;
+}
+
+
+static int g_compare(struct enode *node) {
+/*
+ * generate code to do a comparison of the two operands of node. returns 1 if
+ * it was an unsigned comparison
+ */
+	struct amode	 *ap1, *ap2, *ap3;
+#ifndef NOFLOAT
+	long											i;
+#endif
+	switch (node->v.p[0]->etype) {
+		case bt_uchar:
+		case bt_char:
+		case bt_ushort:
+		case bt_short:
+		case bt_pointer:
+		case bt_long:
+		case bt_ulong:
+			ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
+			/* We want to handle the special case 'tst.w pcrel_variable' smoothly,
+			 * which is why we set F_SRCOP in the latter
+			 * We will unset it later on. */
+			if (ap2->mode == am_immed)
+				ap1 = g_expr(node->v.p[0], (F_ALL & ~F_IMMED) | F_SRCOP);
+			else
+				ap1 = g_expr(node->v.p[0], F_AREG | F_DREG);
+			validate(ap2);
+			/*if (ap1->mode == am_direct
+			  && (ap->offset->nodetype == en_nacon
+			  || ap->offset->nodetype == en_labcon)
+#ifdef AS
+&& !external(ap->offset->v.enlab)
+#else
+#ifdef PC
+&& ((long)ap->offset->v.ensp>0x1000 ? internal(ap->offset->v.ensp) : 1)
+#endif
+#endif
+)
+t*/
+			/*
+			 * sorry, no tst.l An on the 68000, but we can move to a data
+			 * register if one is free
+			 * As there is no tst.l myval(pc), we can do it this way for am_direct's too.
+			 */
+			if ((ap1->mode == am_areg || ap1->mode==am_direct)
+					&& node->v.p[1]->nodetype == en_icon
+					&& node->v.p[1]->v.i == 0 && free_data()) {
+				ap3 = temp_data();
+				g_code(op_move, node->v.p[0]->esize, ap1, ap3);
+				/* tst.l ap3 not needed */
+				freeop(ap3);
+			} else {
+				/* the only case where the following != nop is when ap2->mode==am_immed and ap1->mode==am_direct */
+				ap1=mk_legal(ap1, F_ALL, node->v.p[0]->esize);
+				g_code(op_cmp, (int) node->v.p[0]->esize, ap2, ap1);
+			}
+			freeop(ap1);
+			freeop(ap2);
+			if (node->v.p[0]->etype == bt_char ||
+					node->v.p[0]->etype == bt_short ||
+					node->v.p[0]->etype == bt_long)
+				return 0;
+			return 1;
+		case bt_struct:
+			ap1 = g_expr(node->v.p[1], F_AREG | F_VOL);
+			ap2 = g_expr(node->v.p[0], F_AREG | F_VOL);
+			validate(ap1); {
+				int lab=nxtlabel();
+				ap1 = copy_addr(ap1);
+				ap2 = copy_addr(ap2);
+				ap2->mode=ap1->mode=am_ainc;
+				ap3 = temp_data();
+				freeop(ap3);
+				g_code(op_move,2,mk_immed((node->esize-1)>>1),ap3);
+				g_label(lab);
+				g_code(op_cmp,2,ap1,ap2);
+				g_code(op_dbne,0,ap3,mk_label(lab));
+			}
+			freeop(ap2);
+			freeop(ap1);
+			return 1;
+#ifndef NOFLOAT
+		case bt_float:
+#ifdef DOUBLE
+		case bt_double:
+#endif
+#ifndef BCDFLT
+			if (node->v.p[1]->nodetype == en_fcon && node->v.p[1]->v.f==0) {
+				node->etype = bt_long;	/* no conversion func call (raw cast) */
+				node=mk_node(en_cast,node,NIL_ENODE);
+				node->etype = bt_char;
+				node->esize = 1;
+				ap1 = g_expr(node, F_DALT);
+				g_code(op_tst, (int) node->esize, ap1, NIL_AMODE);
+				freeop(ap1);
+			} else {
+#endif
+				temp_inv();
+				i = push_param(node->v.p[1]);
+				i += push_param(node->v.p[0]);
+#ifndef BCDFLT
+				call_library(str(ffpcmp));
+#else
+				call_library("__cmpbf2");
+#endif
+				g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
+				return 0;
+#ifndef BCDFLT
+			}
+#endif
+#endif
+	}
+	ierr(G_COMPARE,1);
+	/* NOTREACHED */
+	return 0; // make the compiler happy
+}
+
+#ifndef NOBCDFLT
+readonly struct enode __bcd_zero__value={
+	en_labcon,
+#ifdef DOUBLE
+	bt_double,
+#else
+	bt_float,
+#endif
+	10
+};
+#ifdef AS
+#define bcd_zero (pchsearch("__bcd_zero",PCHS_ADD), \
+	__bcd_zero__value.v.enlab=label("__bcd_zero"), \
+	&__bcd_zero__value)
+#else
+#define bcd_zero (__bcd_zero__value.v.ensp="__bcd_zero", &__bcd_zero__value)
+#endif
+#endif
+void truejp(struct enode *node, unsigned int lab) {
+/*
+ * generate a jump to lab if the node passed evaluates to a true condition.
+ */
+	struct amode	 *ap;
+	unsigned int			lab0;
+	if (node == 0)
+		ierr(TRUEJP,1);
+	if (node->nodetype == en_icon) {
+		if (node->v.i)
+			g_code(op_bra, 0, mk_label(lab), NIL_AMODE);
+		return;
+	}
+	opt_compare(node);
+	switch (node->nodetype) {
+		case en_eq:
+			(void) g_compare(node);
+			g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
+			break;
+		case en_ne:
+			(void) g_compare(node);
+			g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
+			break;
+		case en_lt:
+		case en_le:
+		case en_gt:
+		case en_ge:
+			{
+				int n=(en_ge-node->nodetype)*2+op_bhs;
+				g_code(g_compare(node)?n:++n, 0, mk_label(lab), NIL_AMODE);
+				break;
+			}
+		case en_fieldref:
+			{
+				struct enode *ep,*ep2;
+				ep=mk_node(en_ref, node->v.p[0], (struct enode *) NIL_AMODE);
+				ep->esize=node->esize;
+				ep->etype=node->etype;
+				ep2=mk_icon(((1<<node->bit_width)-1) <<
+						((node->esize<<3)-node->bit_offset-node->bit_width));
+				ep2->esize=node->esize;
+				ep2->etype=node->etype;
+				ep=mk_node(en_and,ep,ep2);
+				ep->esize=node->esize;
+				ep->etype=node->etype;
+				truejp(ep, lab);
+				break;
+			}
+
+			/*						case en_lt:
+									g_compare(node) ?
+									g_code(op_blo, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_blt, 0, mk_label(lab), NIL_AMODE);
+									break;
+									case en_le:
+									g_compare(node) ?
+									g_code(op_bls, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_ble, 0, mk_label(lab), NIL_AMODE);
+									break;
+									case en_gt:
+									g_compare(node) ?
+									g_code(op_bhi, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_bgt, 0, mk_label(lab), NIL_AMODE);
+									break;
+									case en_ge:
+									g_compare(node) ?
+									g_code(op_bhs, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_bge, 0, mk_label(lab), NIL_AMODE);
+									break;*/
+		case en_land:
+			lab0 = nxtlabel();
+			falsejp(node->v.p[0], lab0);
+			truejp(node->v.p[1], lab);
+			g_label(lab0);
+			break;
+		case en_lor:
+			truejp(node->v.p[0], lab);
+			truejp(node->v.p[1], lab);
+			break;
+		case en_not:
+			falsejp(node->v.p[0], lab);
+			break;
+#ifdef OPTIMIZED_AINCDEC_TEST
+		case en_adec:
+			//				struct amode *lblap = mk_label(lab);
+			ap = g_expr(node->v.p[0], F_ALL);
+			/*				if (ap->mode==am_dreg)
+							freeop(ap),
+							g_code(op_dbra, 0, ap, lblap);
+							else {*/
+			g_code(op_sub, (int) node->esize, mk_immed(1), ap);
+			freeop(ap);
+			g_code(op_bhs, 0, /*lblap*/mk_label(lab), NIL_AMODE);
+			/*				}*/
+			break;
+#endif
+		case en_and:
+			/*#ifdef PC*/
+#define is_powerof2(x) (((x)<<1)==((x)^((x)-1))+1)
+			/*#else
+#define is_powerof2(x) ({int __x=x;((__x)<<1)==((__x)^((__x)-1))+1;})
+#endif*/
+			if (node->v.p[1]->nodetype==en_icon) {
+				unsigned long v=node->v.p[1]->v.i;
+				if (v>=128/*otherwise moveq is cool enough and faster for dregs*/
+						&& is_powerof2(v)) {
+					ap=g_expr(node->v.p[0],F_DREG|F_MEM);
+					g_bitmancode(op_btst,node->v.p[0]->esize,mk_immed(pwrof2(v)),ap);
+					freeop(ap);
+					g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
+					break;
+				}
+			}
+			/* FALL THROUGH */
+		default:
+#ifndef NOFLOAT
+			if (node->etype == bt_float || node->etype == bt_double) {
+#ifdef DOUBLE
+				long i;
+				temp_inv();
+				i = push_param(node);
+				call_library(".fptst");	// obsolete
+				/* The pop-off does not change the condition codes */
+				g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
+			} else {
+#else
+#ifndef BCDFLT
+				node->etype = bt_long;	/* no conversion func call (raw cast) */
+				node=mk_node(en_cast,node,NIL_ENODE);
+				node->etype = bt_char;
+				node->esize = 1;
+			}
+			{
+#else
+				g_compare(mk_node(en_void,node,bcd_zero));
+			} else {
+#endif
+#endif
+#else
+			{
+#endif
+				ap = g_expr(node, F_DALT|F_SRCOP);
+				if (ap->mode==am_direct && free_data()) {
+					struct amode *ap2 = temp_data();
+					g_code(op_move, (int) node->esize, ap, ap2);
+					g_code(op_tst, (int) node->esize, ap2, NIL_AMODE);
+					freeop(ap2);
+				} else
+					g_code(op_tst, (int) node->esize, ap, NIL_AMODE);
+				freeop(ap);
+			}
+			g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
+			break;
+	}
+}
+
+void falsejp(struct enode *node, unsigned int lab) {
+/*
+ * generate code to execute a jump to lab if the expression passed is
+ * false.
+ */
+	struct amode	 *ap;
+	unsigned int			lab0;
+	if (node == 0)
+		ierr(FALSEJP,1);
+	if (node->nodetype == en_icon) {
+		if (!node->v.i)
+			g_code(op_bra, 0, mk_label(lab), NIL_AMODE);
+		return;
+	}
+	opt_compare(node);
+	switch (node->nodetype) {
+		case en_eq:
+			(void) g_compare(node);
+			g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
+			break;
+		case en_ne:
+			(void) g_compare(node);
+			g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
+			break;
+		case en_lt:
+		case en_le:
+		case en_gt:
+		case en_ge:
+			{
+				int n=(node->nodetype-en_lt)*2+op_bhs;
+				g_code(g_compare(node)?n:++n, 0, mk_label(lab), NIL_AMODE);
+				break;
+			}
+		case en_fieldref:
+			{
+				struct enode *ep,*ep2;
+				ep=mk_node(en_ref, node->v.p[0], (struct enode *) NIL_AMODE);
+				ep->esize=node->esize;
+				ep->etype=node->etype;
+				ep2=mk_icon(((1<<node->bit_width)-1) <<
+						((node->esize<<3)-node->bit_offset-node->bit_width));
+				ep2->esize=node->esize;
+				ep2->etype=node->etype;
+				ep=mk_node(en_and,ep,ep2);
+				ep->esize=node->esize;
+				ep->etype=node->etype;
+				falsejp(ep, lab);
+				break;
+			}
+			/*						case en_lt:
+									g_compare(node) ?
+									g_code(op_bhs, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_bge, 0, mk_label(lab), NIL_AMODE);
+									break;
+									case en_le:
+									g_compare(node) ?
+									g_code(op_bhi, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_bgt, 0, mk_label(lab), NIL_AMODE);
+									break;
+									case en_gt:
+									g_compare(node) ?
+									g_code(op_bls, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_ble, 0, mk_label(lab), NIL_AMODE);
+									break;
+									case en_ge:
+									g_compare(node) ?
+									g_code(op_blo, 0, mk_label(lab), NIL_AMODE) :
+									g_code(op_blt, 0, mk_label(lab), NIL_AMODE);
+									break;*/
+		case en_land:
+			falsejp(node->v.p[0], lab);
+			falsejp(node->v.p[1], lab);
+			break;
+		case en_lor:
+			lab0 = nxtlabel();
+			truejp(node->v.p[0], lab0);
+			falsejp(node->v.p[1], lab);
+			g_label(lab0);
+			break;
+		case en_not:
+			truejp(node->v.p[0], lab);
+			break;
+#ifdef OPTIMIZED_AINCDEC_TEST
+		case en_adec:
+			ap = g_expr(node->v.p[0], F_ALL);
+			g_code(op_sub, (int) node->esize, mk_immed(1), ap);
+			freeop(ap);
+			g_code(op_blo, 0, mk_label(lab), NIL_AMODE);
+			break;
+#endif
+		case en_and:
+			if (node->v.p[1]->nodetype==en_icon) {
+				unsigned long v=node->v.p[1]->v.i;
+				if (v>=128/*otherwise moveq is cool enough and faster for dregs*/
+						&& is_powerof2(v)) {
+					ap=g_expr(node->v.p[0],F_DREG|F_MEM);
+					g_bitmancode(op_btst,node->v.p[0]->esize,mk_immed(pwrof2(v)),ap);
+					freeop(ap);
+					g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
+					break;
+				}
+			}
+			/* FALL THROUGH */
+		default:
+#ifndef NOFLOAT
+			if (node->etype == bt_float || node->etype == bt_double) {
+#ifdef DOUBLE
+				long i;
+				temp_inv();
+				i = push_param(node);
+				call_library(".fptst");	// obsolete
+				/* The pop-off does not change the condition codes */
+				g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
+			} else {
+#else
+#ifndef BCDFLT
+				node->etype = bt_long;	/* no conversion func call (raw cast) */
+				node=mk_node(en_cast,node,NIL_ENODE);
+				node->etype = bt_char;
+				node->esize = 1;
+			}
+			{
+#else
+				g_compare(mk_node(en_void,node,bcd_zero));
+			} else {
+#endif
+#endif
+#else
+			{
+#endif
+				ap = g_expr(node, F_DALT|F_SRCOP);
+				if (ap->mode==am_direct && free_data()) {
+					struct amode *ap2 = temp_data();
+					g_code(op_move, (int) node->esize, ap, ap2);
+					g_code(op_tst, (int) node->esize, ap2, NIL_AMODE);
+					freeop(ap2);
+				} else
+					g_code(op_tst, (int) node->esize, ap, NIL_AMODE);
+				freeop(ap);
+			}
+			g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
+			break;
+	}
+}
+
+void opt_compare(struct enode *node) {
+	/* temprefs should be the second operand to a cmp instruction */
+	enum(e_node) 			t = node->nodetype;
+	if ((t == en_eq || t == en_ne || t == en_le || t == en_ge
+				|| t == en_lt || t == en_gt)
+			&& (node->v.p[1]->nodetype == en_tempref ||
+				node->v.p[0]->nodetype == en_icon)) {
+
+		swap_nodes(node);
+		/* if you change the operands, change the comparison operator */
+		switch (t) {
+			case en_le:
+				node->nodetype = en_ge;
+				break;
+			case en_ge:
+				node->nodetype = en_le;
+				break;
+			case en_lt:
+				node->nodetype = en_gt;
+				break;
+			case en_gt:
+				node->nodetype = en_lt;
+				break;
+		}
+	}
+}
+#endif /* MC680X0 */
+// vim:ts=4:sw=4

+ 174 - 0
gtc/src/genffp.c

@@ -0,0 +1,174 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * Fast Floating-Point generator
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+/*
+ * The following floating-point operations are needed in this module:
+ *
+ * - comparision with 0.0, 0.5 and 1.0 - division by 2.0 - multiplication with
+ * 2.0 (performed as addition here) - subtraction of 1.0
+ */
+
+#ifndef NOFLOAT
+#ifdef PC
+#include	"define.h"
+_FILE(__FILE__)
+#ifndef BCDFLT
+unsigned long double2ffp(double d) {
+	unsigned long	mantissa;
+	int 			sign = 0, exponent = 64, i;
+
+	if (d < 0.0) {
+		sign = 128;
+		d = -d;
+	}
+	while (d < 0.5) {
+		d += d;
+		--exponent;
+		if (exponent == 0)
+			return sign;		/* zero fp number */
+	}
+
+	while (d >= 1.0) {
+		d /= 2.0;
+		++exponent;
+		if (exponent >= 127)
+			return 127 + sign;	/* +/- infinity */
+	}
+
+	/* 0.5 <=d <1.0 now: construct the mantissa */
+
+	mantissa = 0;
+	for (i = 0; i < 24; i++) {
+		/* 24 mantissa bits */
+		d += d;
+		mantissa = mantissa + mantissa;
+		if (d >= 1.0) {
+			++mantissa;
+			d -= 1.0;
+		}
+	}
+
+	/* round up, if the next bit would be 1 */
+	if (d >= 0.5)
+		++mantissa;
+	/* check on mantissa overflow */
+	if (mantissa > 0xFFFFFF) {
+		++exponent;
+		/* exponent overflow? */
+		if (exponent >= 127)
+			return (127 + sign);
+		mantissa >>= 1;
+	}
+	/* put the parts together and return the value */
+
+	return (mantissa << 8) + sign + exponent;
+}
+#else
+void double2bcd(double d,struct bcd *bcd) {
+	unsigned char *mantptr=bcd->mantissa;
+	int bias = 16384, exponent = 0, i;
+
+	if (d < 0.0) {
+		bias += 32768;
+		d = -d;
+	}
+	if (d != 0.0) {
+		while (d < 1.0) {
+			d *= 10.0;
+			--exponent;
+			if (exponent < -999) {
+				d = 0.0;
+				break;
+			}
+		}
+	}
+
+	while (d >= 10.0) {
+		d /= 10.0;
+		++exponent;
+	}
+
+	if (d==0.0) {
+		bcd->exponent=16384;
+		memset(bcd->mantissa,0,BCDLEN);
+		return;
+	}
+
+	/* 1.0 <= d < 10.0 now: construct the mantissa */
+
+	d += 5e-16;	/* round up now */
+	for (i = 0; i < BCDLEN; i++) {
+		unsigned char digit,buffer;
+		/* 8 mantissa groups of 2 digits */
+		if (d>=5.0) {
+			if (d>=7.0) {
+				if (d>=8.0) {
+					if (d>=9.0)
+						digit=9;
+					else digit=8;
+				} else digit=7;
+			} else if (d>=6.0)
+				digit=6;
+			else digit=5;
+		} else {
+			if (d>=2.0) {
+				if (d>=3.0) {
+					if (d>=4.0)
+						digit=4;
+					else digit=3;
+				} else digit=2;
+			} else if (d>=1.0)
+				digit=1;
+			else digit=0;
+		}
+		d -= digit;
+		d *= 10.0;
+		buffer = digit<<4;
+		if (d>=5.0) {
+			if (d>=7.0) {
+				if (d>=8.0) {
+					if (d>=9.0)
+						digit=9;
+					else digit=8;
+				} else digit=7;
+			} else if (d>=6.0)
+				digit=6;
+			else digit=5;
+		} else {
+			if (d>=2.0) {
+				if (d>=3.0) {
+					if (d>=4.0)
+						digit=4;
+					else digit=3;
+				} else digit=2;
+			} else if (d>=1.0)
+				digit=1;
+			else digit=0;
+		}
+		d -= digit;
+		d *= 10.0;
+		*mantptr++ = buffer | digit;
+	}
+
+	/* put the parts together and return the value */
+	bcd->exponent = exponent+bias;
+
+	return;
+}
+
+#endif /* !defined(BCDFLT) */
+#endif /* defined(PC) */
+#endif /* !defined(NOFLOAT) */
+// vim:ts=4:sw=4

+ 1248 - 0
gtc/src/genstmt.c

@@ -0,0 +1,1248 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * statement generator
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+#ifndef PC
+#define checkstack() while (0)
+#endif
+
+int				nextlabel CGLOB;
+/*int 			uses_structassign CGLOB;*/
+TYP 		   *ret_type CGLOB;
+XLST_TYPE		lc_auto CGLOB;
+XLST_TYPE		max_scratch CGLOB;
+#ifdef MC680X0
+unsigned int	save_mask CGLOB;
+#endif
+xstatic unsigned int breaklab CGLOB;
+xstatic unsigned int contlab CGLOB;
+xstatic unsigned int retlab CGLOB;
+
+void genstmt(struct snode *stmt);
+
+struct amode *mk_reg(int r) {
+/*
+ * make an address reference to a register.
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_REG);
+#ifdef MC680X0
+	if (r < AREGBASE) {
+		ap->mode = am_dreg;
+		ap->preg = r;
+	} else {
+		ap->mode = am_areg;
+		ap->preg = r - AREGBASE;
+	}
+#endif
+#ifdef INTEL_386
+	ap->mode = am_reg;
+	ap->preg = r;
+#endif
+	return ap;
+}
+
+
+#ifdef MC680X0
+struct amode *mk_rmask(unsigned int mask) {
+/*
+ * generate the mask address structure.
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_MASK);
+	ap->mode = am_mask1;
+	ap->offset = mk_icon((long) mask);
+	return ap;
+}
+
+struct amode *mk_smask(unsigned int mask) {
+/*
+ * generate the mask address structure.
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_MASK);
+	ap->mode = am_mask2;
+	ap->offset = mk_icon((long) mask);
+	return ap;
+}
+#endif
+
+struct amode *mk_strlab(char *s) {
+/*
+ * generate a direct reference to a string label.
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_STRLAB);
+	ap->mode = am_direct;
+	ap->offset = mk_node(en_nacon, NIL_ENODE, NIL_ENODE);
+	ap->offset->v.ensp = s;
+#ifdef AS
+	ap->offset->v.enlab = label(s);
+#endif
+	return ap;
+}
+
+static void genwhile(struct snode *stmt) {
+/*
+ * generate code to evaluate a while statement.
+ */
+	unsigned int	lab1, lab2;
+	initstack();				/* initialize temp registers */
+	lab1 = contlab; 			/* save old continue label */
+	lab2 = breaklab;			/* save old break label */
+	contlab = nxtlabel();		/* new continue label */
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\tL%u:\n", contlab);
+#endif
+	g_label(contlab);
+	if (stmt->s1 != 0) {		/* has block */
+		breaklab = nxtlabel();
+		initstack();
+#ifdef ICODE
+		if (icode_option) {
+			fprintf(icode, "*falsejp L%u\n", breaklab);
+			g_icode(stmt->exp);
+		}
+#endif
+		falsejp(stmt->exp, breaklab);
+		checkstack();
+		genstmt(stmt->s1);
+		g_code(op_bra, 0, mk_label(contlab), NIL_AMODE);
+		g_label(breaklab);
+#ifdef ICODE
+		if (icode_option) {
+			fprintf(icode, "\tbranch_unconditional\tL%u\n", contlab);
+			fprintf(icode, "\tL%u:\n", breaklab);
+		}
+#endif
+		breaklab = lab2;		/* restore old break label */
+	} else {					/* no loop code */
+		initstack();
+#ifdef ICODE
+		if (icode_option) {
+			fprintf(icode, "*truejp L%u\n", contlab);
+			g_icode(stmt->exp);
+		}
+#endif
+		truejp(stmt->exp, contlab);
+		checkstack();
+	}
+	contlab = lab1; 			/* restore old continue label */
+}
+
+struct amode *g_deref();
+static void genloop(struct snode *stmt) {
+/*
+ * generate code to evaluate a loop statement.
+ */
+	unsigned int	lab1, lab2;
+	struct amode *counter,*ap2;
+	struct enode *node;
+	initstack();				/* initialize temp registers */
+	lab1 = contlab; 			/* save old continue label */
+	lab2 = breaklab;			/* save old break label */
+	node=stmt->exp->v.p[0];
+	counter = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+GENLOOP);
+	switch (node->nodetype) {
+		case en_autocon:
+			counter->mode = am_indx;
+			counter->preg = FRAMEPTR - AREGBASE;		/* frame pointer */
+			counter->offset = node; /* use as constant node */
+			break;
+		case en_tempref:
+			if (node->v.i < AREGBASE) {
+				counter->mode = am_dreg;
+				counter->preg = (reg_t)node->v.i;
+			} else {
+				fatal("LOOP can't use aregs");
+/*				counter->mode = am_areg;
+				counter->preg = (reg_t)(node->v.i - AREGBASE);*/
+			}
+			break;
+		case en_nacon:
+		case en_labcon:
+			counter->mode = am_direct;
+			counter->offset = node;
+			break;
+		case en_ref:
+			counter=g_deref(node->v.p[0],node->etype,F_MEM|F_USES,node->esize);
+			break;
+		default:
+			ierr(GENLOOP,1);
+	}
+//	ap2 = g_expr(stmt->exp, F_ALL);
+	ap2 = g_expr(stmt->exp->v.p[1], F_ALL | F_SRCOP);
+	g_code(op_move, 2, ap2, counter);
+	freeop(ap2);
+	if (counter->mode==am_dreg && counter->preg<=MAX_DATA)
+		ierr(GENLOOP,2);
+	contlab = nxtlabel();		/* new continue label */
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\tL%u:\n", contlab);
+#endif
+	g_label(contlab);
+	breaklab = nxtlabel();
+	if (stmt->s1 != 0)		/* has block */
+		genstmt(stmt->s1);
+	if (stmt->v2.e != 0) {		/* has 'until' condition */
+#ifdef ICODE
+	if (icode_option) {
+		fprintf(icode, "*truejp L%u\n", breaklab);
+		g_icode(stmt->v1.e);
+	}
+#endif
+		truejp(stmt->v2.e, breaklab);
+	}
+	if (counter->mode==am_dreg) g_code(op_dbra, 0, counter, mk_label(contlab));
+	else {
+		struct amode *ap1;
+		ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+GENLOOP);
+		ap1->mode = am_immed;
+		ap1->offset = mk_icon(1L);
+		g_code(op_subq, 2, ap1, counter);
+		g_code(op_bhs, 0, mk_label(contlab), NIL_AMODE);
+	}
+	g_label(breaklab);
+#ifdef ICODE
+	if (icode_option) {
+		fprintf(icode, "\tbranch_unconditional\tL%u\n", contlab);
+		fprintf(icode, "\tL%u:\n", breaklab);
+	}
+#endif
+	breaklab = lab2;		/* restore old break label */
+	contlab = lab1; 			/* restore old continue label */
+}
+
+#ifndef ASM
+static void genasm(struct snode *stmt) {
+	g_code(_op_asm, 0, (struct amode *)stmt->v1.i, NIL_AMODE);
+}
+#else
+#ifdef VCG
+extern int vcg_lvl;
+extern int vcg_aborted[];
+#endif
+static void genasm(struct snode *stmt) {
+	struct ocode *ip=(struct ocode *)stmt->v1.i;
+#ifdef VCG
+	if (vcg_lvl!=VCG_MAX)
+		vcg_aborted[vcg_lvl]++;
+	else
+#endif
+		while (ip) {
+			add_peep(ip);
+			ip=ip->fwd;
+		}
+}
+#endif
+
+static void g_for(struct snode *stmt) {
+/*
+ * generate code to evaluate a for loop
+ */
+	unsigned int	old_break, old_cont, exit_label, loop_label;
+	old_break = breaklab;
+	old_cont = contlab;
+	loop_label = nxtlabel();
+	exit_label = nxtlabel();
+	if (stmt->v2.e != 0)
+		contlab = nxtlabel();
+	else
+		contlab = loop_label;
+#ifdef ICODE
+	if (icode_option) {
+		if (stmt->exp != 0)
+			g_icode(stmt->exp);
+		fprintf(icode, "\tL%u:\n", loop_label);
+	}
+#endif
+	initstack();
+	if (stmt->exp != 0) {
+		(void) g_expr(stmt->exp, F_ALL | F_SRCOP | F_NOVALUE);
+		checkstack();
+	}
+	g_label(loop_label);
+	initstack();
+	if (stmt->v1.e != 0) {
+#ifdef ICODE
+		if (icode_option) {
+			fprintf(icode, "*falsejp L%u\n", exit_label);
+			g_icode(stmt->v1.e);
+		}
+#endif
+		falsejp(stmt->v1.e, exit_label);
+		checkstack();
+	}
+	if (stmt->s1 != 0) {
+		breaklab = exit_label;
+		genstmt(stmt->s1);
+	}
+#ifdef ICODE
+	if (icode_option) {
+		if (stmt->v2.e != 0) {
+			fprintf(icode, "\tL%u:\n", contlab);
+			g_icode(stmt->v2.e);
+		}
+		fprintf(icode, "\tbranch_unconditional\tL%u\n", loop_label);
+	}
+#endif
+	initstack();
+	if (stmt->v2.e != 0) {
+		g_label(contlab);
+		(void) g_expr(stmt->v2.e, F_ALL | F_SRCOP | F_NOVALUE);
+		checkstack();
+	}
+	g_code(op_bra, 0, mk_label(loop_label), NIL_AMODE);
+	breaklab = old_break;
+	contlab = old_cont;
+	g_label(exit_label);
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\tL%u:\n", exit_label);
+#endif
+}
+
+static void genif(struct snode *stmt) {
+/*
+ * generate code to evaluate an if statement.
+ */
+	unsigned int	lab1, lab2, oldbreak;
+	lab1 = nxtlabel(); 		/* else label */
+	lab2 = nxtlabel(); 		/* exit label */
+	oldbreak = breaklab;		/* save break label */
+#ifdef ICODE
+	if (icode_option) {
+		fprintf(icode, "*falsejp L%u\n", lab1);
+		g_icode(stmt->exp);
+	}
+#endif
+	initstack();				/* clear temps */
+	falsejp(stmt->exp, lab1);
+	checkstack();
+	if (stmt->s1 != 0 && stmt->s1->next != 0) {
+		if (stmt->v1.s != 0)
+			breaklab = lab2;
+		else
+			breaklab = lab1;
+	}
+	genstmt(stmt->s1);
+	if (stmt->v1.s != 0) {		/* else part exists */
+		g_code(op_bra, 0, mk_label(lab2), NIL_AMODE);
+		g_label(lab1);
+#ifdef ICODE
+		if (icode_option) {
+			fprintf(icode, "\tbranch_unconditional\tL%u\n", lab2);
+			fprintf(icode, "\tL%u:\n", lab1);
+		}
+#endif
+		if (stmt->v1.s == 0 || stmt->v1.s->next == 0)
+			breaklab = oldbreak;
+		else
+			breaklab = lab2;
+		genstmt(stmt->v1.s);
+		g_label(lab2);
+#ifdef ICODE
+		if (icode_option)
+			fprintf(icode, "\tL%u:\n", lab2);
+#endif
+	} else {					/* no else code */
+		g_label(lab1);
+#ifdef ICODE
+		if (icode_option)
+			fprintf(icode, "\tL%u:\n", lab1);
+#endif
+	}
+	breaklab = oldbreak;
+}
+
+static void gendo(struct snode *stmt) {
+/*
+ * generate code for a do - while loop.
+ */
+	unsigned int	oldcont, oldbreak, dolab;
+	oldcont = contlab;
+	oldbreak = breaklab;
+	dolab = nxtlabel();
+	contlab = nxtlabel();
+	breaklab = nxtlabel();
+	g_label(dolab);
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\tL%u:\n", dolab);
+#endif
+	genstmt(stmt->s1);			/* generate body */
+	g_label(contlab);
+#ifdef ICODE
+	if (icode_option) {
+		fprintf(icode, "\tL%u:\n", contlab);
+		fprintf(icode, "*truejp L%u\n", dolab);
+		g_icode(stmt->exp);
+		fprintf(icode, "\tL%u:\n", breaklab);
+	}
+#endif
+	initstack();
+	truejp(stmt->exp, dolab);
+	checkstack();
+	g_label(breaklab);
+	breaklab = oldbreak;
+	contlab = oldcont;
+}
+
+void call_library(char *lib_name) {
+/*
+ * generate a call to a library routine.
+ * it is assumed that lib_name won't be clobbered
+ */
+	struct sym	   *sp;
+	sp = gsearch(lib_name, -1);
+	if (sp == 0) {
+		pchsearch(lib_name,PCHS_ADD);
+		sp = gsearch(lib_name, -1);
+		if (sp == 0) {
+			++global_flag;
+			sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM);
+	#ifdef NO_CALLOC
+			sp->tp = 0;
+	#endif
+			sp->name = strsave(lib_name);
+			sp->storage_class = sc_external;
+			append(&sp, &gsyms);
+			--global_flag;
+		}
+	}
+	sp->used = 1;
+#ifdef MC680X0
+	g_code(op_jsr, 0, mk_strlab(sp->name), NIL_AMODE);
+#endif
+#ifdef INTEL_386
+	g_code(op_call, 0, mk_strlab(sp->name), NIL_AMODE);
+#endif
+}
+
+static void genswitch(struct snode *stmt) {
+/*
+ * generate a linear search switch statement.
+ */
+	unsigned int	curlab;
+	unsigned int	deflab;
+	unsigned int	tablab;
+	long			i;
+	struct snode   *defcase, *s;
+	struct amode   *ap, *ap1;
+#ifndef USE_WORDS_IN_SWITCH
+	struct amode   *ap2;
+#endif
+	struct enode   *ep;
+	long			size;
+	enum(e_bt)		type;
+	long			min_caselabel, max_caselabel, nxt_caselabel;
+	int 			number_of_cases;
+	defcase = 0;
+#ifdef ICODE
+	if (icode_option) {
+		fprintf(icode, "$switchexp\n");
+		g_icode(stmt->exp);
+	}
+#endif
+	initstack();
+#ifdef MC680X0
+	ap = g_expr(stmt->exp, F_DREG | F_VOL);
+#endif
+#ifdef INTEL_386
+	ap = g_expr(stmt->exp, F_REG);
+#endif
+	size = stmt->exp->esize;
+	type = stmt->exp->etype;
+	stmt = stmt->s1;
+	/*
+	 * analyze the switch statement
+	 */
+	s = stmt;
+	if (s != 0 && s->stype == st_default) {
+		defcase = s;
+		s = s->s1;
+	}
+	/* s points to the first case label */
+	number_of_cases = 1;
+	if (s != 0) {
+		max_caselabel = min_caselabel = s->v2.i;
+		s = s->s1;
+		while (s != 0) {
+			if (s->stype == st_default) {
+				defcase = s;
+			} else {
+				if (s->v2.i > max_caselabel)
+					max_caselabel = s->v2.i;
+				else if (s->v2.i < min_caselabel)
+					min_caselabel = s->v2.i;
+				number_of_cases++;
+			}
+			s = s->s1;
+		}
+	}
+	if (number_of_cases > 7 &&
+		(max_caselabel - min_caselabel) / number_of_cases <= 5) {
+		/*
+		 * we need the case label as a 32-bit item.
+		 */
+#ifdef MC680X0
+		switch (type) {
+		  case bt_char:
+			g_code(op_ext, 2, ap, NIL_AMODE);
+#ifndef USE_WORDS_IN_SWITCH
+			/*FALLTHROUGH*/
+		  case bt_short:
+			g_code(op_ext, 4, ap, NIL_AMODE);
+			break;
+		  case bt_uchar:
+			g_code(op_and, 4, mk_immed(255l), ap);
+			break;
+		  case bt_ushort:
+			g_code(op_and, 4, mk_immed(65535l), ap);
+#else
+			break;
+		  case bt_uchar:
+			g_code(op_and, 2, mk_immed(255l), ap);
+			break;
+#endif
+		}
+#endif
+#ifdef INTEL_386
+		switch (type) {
+		  case bt_char:
+			g_code(op_movsbl, 0, ap, ap);
+			break;
+		  case bt_short:
+			g_code(op_movswl, 0, ap, ap);
+			break;
+		  case bt_uchar:
+			g_code(op_movzbl, 0, ap, ap);
+			break;
+		  case bt_ushort:
+			g_code(op_movzwl, 0, ap, ap);
+		}
+#endif
+		/*
+		 * move the interval
+		 */
+#ifdef MC680X0
+#ifndef USE_WORDS_IN_SWITCH
+#define switch_size 4
+#else
+#define switch_size 2
+#endif
+		if (min_caselabel != 0) {
+			g_code(op_sub, switch_size, mk_immed(min_caselabel), ap);
+			g_code(op_cmp, switch_size, mk_immed(max_caselabel - min_caselabel), ap);
+		} else
+			g_code(op_cmp, (int) size,
+						   mk_immed(max_caselabel-min_caselabel), ap);
+#endif
+#ifdef INTEL_386
+		if (min_caselabel != 0) {
+			g_code (op_sub, 4, mk_immed(min_caselabel), ap);
+			g_code(op_cmp, 4, mk_immed(max_caselabel-min_caselabel), ap);
+		} else
+			g_code(op_cmp, (int) size,
+						   mk_immed(max_caselabel-min_caselabel), ap);
+#endif
+		if (defcase == 0)
+			deflab = breaklab;
+		else {
+			deflab = nxtlabel();
+			defcase->v2.i = deflab;
+		}
+#ifdef MC680X0
+		g_code(op_bhi, 0, mk_label(deflab), NIL_AMODE);
+#endif
+#ifdef INTEL_386
+		g_code(op_ja, 0, mk_label(deflab), NIL_AMODE);
+#endif
+		tablab = nxtlabel();
+#ifdef MC680X0
+#ifndef USE_WORDS_IN_SWITCH
+		g_code(op_add, 4, ap, ap);
+		g_code(op_add, 4, ap, ap);
+#else
+		g_code(op_add, 2, ap, ap);
+#endif
+		ap1 = temp_addr();
+		g_code(op_lea, 0, mk_label(tablab), ap1);
+#ifndef USE_WORDS_IN_SWITCH
+		g_code(op_add, 4, ap, ap1);
+#endif
+		freeop(ap1);
+		ap1 = copy_addr(ap1);
+#ifndef USE_WORDS_IN_SWITCH
+		ap1->mode = am_ind;
+		ap2 = temp_addr();
+		g_code(op_move, 4, ap1, ap2);
+		ap2 = copy_addr(ap2);
+		ap2->mode = am_ind;
+		g_code(op_jmp, 0, ap2, NIL_AMODE);
+		freeop(ap2);
+#else
+		ap1->mode=am_indx2;
+		ap1->sreg=ap->preg;
+		ap1->slen=2;
+		ap1->offset=mk_icon(0l);
+		g_code(op_move, 2, ap1, ap);
+		g_code(op_jmp, 0, ap1, NIL_AMODE);
+#endif
+		freeop(ap);
+#endif
+#ifdef INTEL_386
+		g_code(op_shl, 4, mk_immed(2l), ap);
+		ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+		ep->v.enlab = tablab;
+		ap1 = copy_addr(ap);
+		ap1->mode = am_indx;
+		ap1->offset = ep;
+		g_code(op_mov, 4, ap1, ap);
+		ap1=copy_addr(ap);
+		ap1->mode = am_star;
+/*
+ * DO NOT USE OP_BRA here....
+ * op_bra is reserved for jumps to internal labels.
+ * This keeps things easy in the peephole optimizer
+ * While producing assembler output, op_bra and op_jmp yield
+ * the same
+ */
+		g_code(op_jmp, 0, ap1, NIL_AMODE);
+		freeop(ap);
+#endif
+/*
+ * now, ship out the switch table
+ *	we have just generated the following code (MC68000 expample)
+ *
+ * sub.l		#min_caselabel,d0
+ * cmp.l		#max_caselabel-min_caselabel,d0
+ * bhi			deflab
+ * add.l		d0,d0
+ * add.l		d0,d0
+ * lea			table,a0
+ * add.l		d0,a0
+ * move.l		(a0),a0
+ * jmp			(a0)
+ */
+/*
+ * search the cases: look for min_caselabel. nxt_caselabel is set to
+ * the label looked for in the next pass
+ */
+#ifdef ICODE
+		if (icode_option)
+			fprintf(icode, "default             ==> L%u\n",
+					(unsigned int) deflab);
+#endif
+//#ifdef AS
+		g_label(tablab);
+//#else
+//		cseg();
+//		nl();
+//		put_align(AL_POINTER);
+//		put_label(tablab);
+//#endif
+		ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+		ep->v.enlab=deflab;
+		{
+#ifdef USE_WORDS_IN_SWITCH
+		struct enode *ep0 = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+		struct amode *ap0;
+		ep0->v.enlab=tablab;
+		ap0=mk_offset(mk_node(en_sub,ep,ep0));
+#endif
+		while (min_caselabel <= max_caselabel) {
+			nxt_caselabel = max_caselabel + 1;
+			s = stmt;
+			while (s != 0) {
+				if (s->stype != st_default) {
+					if (s->v2.i == min_caselabel) {
+						ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+						s->v2.i = ep->v.enlab = nxtlabel();
+						/* remove statment from the list */
+						s->stype = st_default;
+#ifndef USE_WORDS_IN_SWITCH
+//#ifdef AS
+						g_code(op_dc, 4, mk_offset(ep), NIL_AMODE);
+						// this is because AS can't handle local references in 'genptr'
+//#else
+//						genptr(ep);
+//#endif
+#else
+						ep=mk_node(en_sub,ep,ep0);
+						g_code(op_dc, 2, mk_offset(ep), NIL_AMODE);
+#endif
+#ifdef ICODE
+						if (icode_option)
+							fprintf(icode, "case-value %8ld ==> L%u\n",
+									min_caselabel, (unsigned int) (s->v2.i));
+#endif
+					} else if (nxt_caselabel > s->v2.i)
+						nxt_caselabel = s->v2.i;
+				}
+				s = s->s1;
+			}
+			/* fill the holes */
+			for (i = min_caselabel + 1; i < nxt_caselabel; i++) {
+
+#ifndef USE_WORDS_IN_SWITCH
+				ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
+				ep->v.enlab = deflab;
+//#ifdef AS
+				g_code(op_dc, 4, mk_offset(ep), NIL_AMODE);
+				// this is because AS can't handle local references in 'genptr'
+//#else
+//				genptr(ep);
+//#endif
+#else
+				g_code(op_dc, 2, ap0, NIL_AMODE);
+#endif
+#ifdef ICODE
+				if (icode_option)
+					fprintf(icode, "case-value %8ld ==> L%u\n",
+							i, (unsigned int) deflab);
+#endif
+			}
+			min_caselabel = nxt_caselabel;
+		}
+		}
+		nl();
+	} else {
+		/*
+		 * generate sequential compare instructions this is not very
+		 * intelligent, but quicker than a lookup in a (value,label) table
+		 * and has no startup time, this makes it fast if there are few
+		 * labels.
+		 */
+		while (stmt != 0) {
+			curlab = nxtlabel();
+			if (stmt->stype == st_default) {	/* default case ? */
+				defcase = stmt;
+			} else {
+#ifdef MC680X0
+				g_code(op_cmp, (int) size, mk_immed((long) stmt->v2.i), ap);
+				g_code(op_beq, 0, mk_label(curlab), NIL_AMODE);
+#endif
+#ifdef INTEL_386
+				g_code(op_cmp, (int) size, mk_immed((long) stmt->v2.i), ap);
+				g_code(op_je, 0, mk_label(curlab), NIL_AMODE);
+#endif
+#ifdef ICODE
+				if (icode_option)
+					fprintf(icode, "*ifeq\t%ld,L%u\n", stmt->v2.i, curlab);
+#endif
+			}
+			stmt->v2.i = curlab;
+			stmt = stmt->s1;
+		}
+		if (defcase == 0) {
+			g_code(op_bra, 0, mk_label(breaklab), NIL_AMODE);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tbranch_unconditional\tL%u\n", breaklab);
+#endif
+		} else {
+			g_code(op_bra, 0, mk_label((unsigned int) defcase->v2.i),
+				   NIL_AMODE);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tbranch_unconditional\tL%u\n",
+						(unsigned int) defcase->v2.i);
+#endif
+		}
+		freeop(ap);
+	}
+	checkstack();
+}
+
+static void gencase(struct snode *stmt) {
+/*
+ * generate the label for the case statement.
+ */
+	g_label((unsigned int) stmt->v2.i);
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\tL%u:\n", (unsigned int) stmt->v2.i);
+#endif
+}
+
+static void genxswitch(struct snode *stmt) {
+/*
+ * analyze and generate best switch statement.
+ */
+	int 			oldbreak;
+	oldbreak = breaklab;
+	breaklab = nxtlabel();
+	genswitch(stmt);
+	genstmt(stmt->v1.s);
+	g_label(breaklab);
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\tL%u:\n", breaklab);
+#endif
+	breaklab = oldbreak;
+}
+
+static void genreturn(struct snode *stmt) {
+/*
+ * generate a return statement.
+ */
+	struct amode   *ap;
+	struct enode   *ep,*ep1;
+//	long			stack_offset;
+	if (stmt != 0 && stmt->exp != 0) {
+#ifdef ICODE
+		if (icode_option) {
+			fprintf(icode, "$return_value\n");
+			g_icode(stmt->exp);
+		}
+#endif
+		initstack();
+		switch (ret_type->type) {
+		  case bt_struct:
+		  case bt_union:
+		  aggregate:
+/*			uses_structassign = 1;*/
+#ifdef SHORT_STRUCT_PASSING
+			if (ret_type->size<=4) {
+				if (stmt->exp->nodetype!=en_ref)
+					ierr(GENRETURN,1);
+				ap = g_expr(stmt->exp->v.p[0], F_AREG);
+				ap = copy_addr(ap);
+				ap->mode = am_ind;
+				g_code(op_move,ret_type->size,ap,mk_reg(RESULT));
+				freeop(ap);
+				break;
+			}
+#endif
+			/* assign structure */
+			ep = mk_node(en_autocon, NIL_ENODE, NIL_ENODE);
+			ep->v.i = 8;
+			ep->esize = 4;
+			ep->etype = bt_pointer;
+			ep = mk_node(en_ref, ep, NIL_ENODE);
+			ep->etype = bt_pointer;
+			ep->esize = 4;
+			ep1 = mk_node(en_ref, ep, NIL_ENODE);
+			ep1->etype = ret_type->type;
+			ep1->esize = ret_type->size;
+			ep1 = mk_node(en_assign, ep1, stmt->exp);
+			ep1->etype = ret_type->type;
+			ep1->esize = ret_type->size;
+			(void) g_expr(ep1, F_ALL | F_SRCOP | F_NOVALUE);
+#ifdef MC680X0
+			/* move pointer to A0 */
+			ap = g_expr(ep, F_ALL | F_SRCOP);
+			g_code(op_move, 4, ap, mk_reg(PRESULT));
+			freeop(ap);
+#endif
+#ifdef INTEL_386
+			/* move pointer to eax */
+			ap = g_expr(ep, F_ALL | F_SRCOP);
+			g_code(op_mov, 4, ap, mk_reg(RESULT));
+			freeop(ap);
+#endif
+			break;
+		  case bt_float:
+#ifdef DOUBLE
+		  case bt_double:
+#endif
+#ifdef INTEL_386
+			/* return floating point value on top of fpu stack */
+			(void) g_expr(stmt->exp, F_FPSTACK);
+#ifdef FUNCS_USE_387
+			if (!fpu_option)
+/*
+ *	.fpgetstack may pop off the top of the software stack into
+ *	the hardware stack. Thus this function can be linked with
+ *	code that expexts the result value in the hardware stack.
+ */
+			   call_library(".fpgetstack");	// obsolete
+#endif
+			/* DO NOT call freeop since this might pop the value off */
+			break;
+#endif
+#ifdef MC68000
+#ifndef BCDFLT
+			/* fallthrough, return value in RESULT register */
+#else
+			goto aggregate;
+#endif
+#endif
+		  case bt_char:
+		  case bt_uchar:
+		  case bt_short:
+		  case bt_ushort:
+		  case bt_long:
+		  case bt_ulong:
+#ifdef MC680X0
+			/* evaluate a parameter in D0 */
+			ap = g_expr(stmt->exp, (F_ALL | F_SRCOP)&~F_AREG);
+			g_code(op_move, (int) stmt->exp->esize, ap, mk_reg(RESULT));
+			freeop(ap);
+#endif
+#ifdef INTEL_386
+		  case bt_pointer:
+			/* evaluate a parameter in eax */
+			ap = g_expr(stmt->exp, F_ALL);
+			g_code(op_mov, (int) stmt->exp->esize, ap, mk_reg(RESULT));
+			freeop(ap);
+#endif
+			break;
+#ifdef MC680X0
+		  case bt_pointer:
+			/* evaluate a parameter in A0 */
+			ap = g_expr(stmt->exp, (F_ALL | F_SRCOP)&~F_DREG);
+			g_code(op_move, (int) stmt->exp->esize, ap, mk_reg(PRESULT));
+			freeop(ap);
+			break;
+#endif
+		  case bt_void:
+			uwarn("return <val> in function returning void");
+			break;
+		  default:
+			ierr(GENRETURN,1);
+		}
+		checkstack();
+	}
+
+/*
+ * The epilogue is now postponed till the end of the function body since
+ * we have to know the final value of max_scratch
+ * If stmt is zero, this is the implicit return statement at the end of
+ * the function
+ */
+	if (stmt != 0) {
+		if (retlab == 0)
+			retlab = nxtlabel();
+		g_code(op_bra, 0, mk_label(retlab), NIL_AMODE);
+#ifdef ICODE
+		if (icode_option)
+			fprintf(icode, "\tbranch_unconditional\tL%u\n", retlab);
+#endif
+	} else {
+		if (retlab != 0) {
+			g_label(retlab);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tL%u:\n", retlab);
+#endif
+		}
+/*
+ * Note that if the function has called other functions (imagine alloca!),
+ * the only safe reference to the saved registers is via the framepointer,
+ * not the stackpointer.
+ */
+#ifdef MC680X0
+		if (regs_used > 0) {
+#ifndef USE_LINK
+			if (!uses_link)
+#endif
+				g_code(op_movem, 4, pop_am, mk_smask(save_mask));
+#ifndef USE_LINK
+			else {
+				int stack_offset = lc_auto + max_scratch + 4*regs_used;
+#ifdef BIGSTACK
+				if (stack_offset <= 32768l) {
+#endif
+					ap=mk_reg(TRUE_FRAMEPTR);
+					ap->mode = am_indx;
+					ap->offset = mk_icon(-stack_offset);
+					g_code(op_movem, 4, ap, mk_smask(save_mask));
+#ifdef BIGSTACK
+				} else {
+					ap = mk_reg(STACKPTR);
+					g_code(op_move, 4, mk_reg(TRUE_FRAMEPTR), ap);
+					g_code(op_sub,	4, mk_immed(stack_offset), ap);
+					g_code(op_movem, 4, pop_am, mk_smask(save_mask));
+				}
+#endif
+			}
+#endif
+		}
+#ifdef USE_LINK
+		g_code(op_unlk, 0, mk_reg(FRAMEPTR), NIL_AMODE);
+#else
+		if (uses_link)
+			g_code(op_unlk, 0, mk_reg(TRUE_FRAMEPTR), NIL_AMODE);
+		else if (lc_auto || max_scratch)
+			g_code(op_add, 4, mk_immed(lc_auto + max_scratch), mk_reg(STACKPTR));
+#endif
+		g_code(op_rts, 0, NIL_AMODE, NIL_AMODE);
+#endif
+#ifdef INTEL_386
+		/*
+		 * Adjust stack pointer to initial value
+		 */
+		if (regs_used > 0 && !is_leaf_function) {
+			stack_offset = lc_auto + max_scratch + 4*regs_used;
+			ap = mk_reg(EBP);
+			ap->mode = am_indx;
+			ap->offset = mk_icon(-stack_offset);
+			g_code(op_lea, 4, ap, mk_reg(ESP));
+		}
+/*
+ * pop clobbered register variables
+ */
+		if (esi_used)
+			g_code(op_pop, 4, mk_reg(ESI), NIL_AMODE);
+		if (edi_used)
+			g_code(op_pop, 4, mk_reg(EDI), NIL_AMODE);
+		if (ebx_used)
+			g_code(op_pop, 4, mk_reg(EBX), NIL_AMODE);
+		g_code(op_leave, 0, NIL_AMODE, NIL_AMODE);
+		g_code(op_ret, 0, NIL_AMODE, NIL_AMODE);
+#endif
+#ifdef ICODE
+		if (icode_option)
+			fprintf(icode, "\t$leave\n");
+#endif
+	}
+}
+
+struct amode *lastexpr_am;
+int need_res;
+
+void genstmt(struct snode *stmt) {
+/*
+ * genstmt will generate a statement and follow the next pointer until the
+ * block is generated.
+ */
+	while (stmt != 0) {
+#ifdef DB_POSSIBLE
+		lineid=stmt->line;
+#endif
+		switch (stmt->stype) {
+		  case st_label:
+			g_label((unsigned int) stmt->v2.i);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tL%u:\n", (unsigned int) stmt->v2.i);
+#endif
+			genstmt(stmt->s1);
+			break;
+		  case st_goto:
+			g_code(op_bra, 0, mk_label((unsigned int) stmt->v2.i), NIL_AMODE);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tbranch_unconditional\tL%u\n",
+						(unsigned int) stmt->v2.i);
+#endif
+			break;
+		  case st_expr: {
+			int flgs;
+#ifdef ICODE
+			if (icode_option)
+				g_icode(stmt->exp);
+#endif
+			initstack();
+/*			if ((long)stmt->exp==0x7b82cc)
+				bkpt();*/
+			lastexpr_am=g_expr(stmt->exp, flgs = 
+				(!(stmt->next) && need_res ? F_ALL | F_SRCOP : F_ALL | F_SRCOP | F_NOVALUE));
+			if (flgs & F_NOVALUE) checkstack();
+			break;
+		  }
+		  case st_return:
+			genreturn(stmt);
+			break;
+		  case st_if:
+			genif(stmt);
+			break;
+		  case st_asm:
+			genasm(stmt);
+			break;
+		  case st_loop:
+			genloop(stmt);
+			break;
+		  case st_while:
+			genwhile(stmt);
+			break;
+		  case st_do:
+			gendo(stmt);
+			break;
+		  case st_for:
+			g_for(stmt);
+			break;
+		  case st_continue:
+			g_code(op_bra, 0, mk_label(contlab), NIL_AMODE);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tbranch_unconditional\tL%u\n", contlab);
+#endif
+			break;
+		  case st_break:
+			g_code(op_bra, 0, mk_label(breaklab), NIL_AMODE);
+#ifdef ICODE
+			if (icode_option)
+				fprintf(icode, "\tbranch_unconditional\tL%u\n", breaklab);
+#endif
+			break;
+		  case st_switch:
+			genxswitch(stmt);
+			break;
+		  case st_compound:
+			genstmt(stmt->s1);
+			break;
+		  case st_case:
+		  case st_default:
+			gencase(stmt);
+			genstmt(stmt->v1.s);
+			break;
+		  default:
+			ierr(GENSTMT,1);
+			break;
+		}
+		stmt = stmt->next;
+	}
+}
+
+extern SYM *func_sp;
+extern SYM *parmsp[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1+1];
+void genfuncbegin(void) {
+#ifdef REGPARM
+	int				dregs=func_sp->tp->rp_dn, aregs=func_sp->tp->rp_an;
+	int				dreg=RESULT, areg=PRESULT;
+#endif
+
+#ifdef BIGSTACK
+	if (lc_auto < 32768l) {
+#ifdef REGPARM
+#error This codes needs a little fix if REGPARM is defined...
+#endif
+#endif
+#ifdef USE_LINK
+		g_coder(op_link, 0, mk_reg(FRAMEPTR), mk_immed(-lc_auto));
+#else
+#ifndef REGPARM
+		if (uses_link)
+			g_coder(op_link, 0, mk_reg(TRUE_FRAMEPTR), mk_immed(-lc_auto));
+		else if (lc_auto) g_coder(op_sub, 4, mk_immed(lc_auto), mk_reg(STACKPTR));
+#else
+		if (!uses_link && lc_auto!=reg_size)
+			g_coder(op_sub, 4, mk_immed(lc_auto-reg_size), mk_reg(STACKPTR));
+#endif
+#endif
+#ifdef BIGSTACK
+	} else {
+		g_coder(op_sub, 4, mk_immed(lc_auto), mk_reg(STACKPTR));
+#ifdef USE_LINK
+		if (uses_link)
+			g_coder(op_link, 0, mk_reg(FRAMEPTR), mk_immed(0l));
+#endif
+	}
+#endif
+	/* now generate pushing code for reg params */
+#ifdef REGPARM
+  { struct amode *apl[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1];
+	int aps[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1],i=0;
+	SYM **spp=parmsp;
+	while (*spp) {
+		SYM *sp1 = *spp++;
+		if (dregs || aregs) {
+			apl[i]=mk_reg(((sp1->tp->type==bt_pointer && aregs) || !dregs)
+				?(aregs--, areg++):(dregs--, dreg++));
+			aps[i]=sp1->tp->size;
+			aps[i]+=aps[i]&1;
+			if (uses_link) {
+				struct amode *ap = (struct amode *) xalloc((int) sizeof(struct amode),
+					AMODE+G_DEREF);
+				ap->mode = am_indx;
+				ap->preg = FRAMEPTR-AREGBASE;
+				ap->offset = mk_icon(sp1->value.i);
+				g_coder(op_move, aps[i], apl[i], ap);
+			}
+			i++;
+		} else break;
+	}
+	if (!uses_link) {
+//		i=nparms; if (i>dregs+aregs) i=dregs+aregs;
+		while (i--) g_coder(op_move, aps[i], apl[i], push_am);
+	} else g_coder(op_link, 0, mk_reg(TRUE_FRAMEPTR), mk_immed(-lc_auto));
+  }
+#endif
+}
+
+void genfunc(struct snode *stmt) {
+/*
+ * generate a function body.
+ */
+#ifdef VERBOSE
+	time_t			ltime;
+#endif							/* VERBOSE */
+	int line0 = lineid;
+
+	retlab = contlab = breaklab = 0;
+	max_scratch = 0;
+	if (lc_auto % AL_DEFAULT != 0)
+		lc_auto += AL_DEFAULT - (lc_auto % AL_DEFAULT);
+#ifdef VERBOSE
+	times(&tms_buf);
+	ltime = tms_buf.tms_utime;
+#endif							/* VERBOSE */
+#ifdef SHOWSTEP
+	printf("\ncse");
+#endif
+	opt1(stmt);
+#ifdef SHOWSTEP
+	printf(" ok ");
+#endif
+#ifdef VERBOSE
+	times(&tms_buf);
+	opt_time += tms_buf.tms_utime - ltime;
+#endif							/* VERBOSE */
+	need_res=0;
+#ifdef SHOWSTEP
+	printf("\ngen");
+#endif
+	genstmt(stmt);
+	genreturn(NIL_SNODE);
+#ifdef SHOWSTEP
+	printf(" ok ");
+#endif
+/*
+ *	It is desirable to postpone the generation of the
+ *	stack fram until here since it it now possible for
+ *	the code generation routines to allocate stack space
+ *	as they want. A little hack (defining g_coder)
+ *	allows us to put the following code to the BEGINNING
+ *	of a function body. Note that this means that we have
+ *	to generate all code in REVERSE order
+ */
+	lineid = line0;
+	lc_auto += max_scratch;
+#ifdef MC680X0
+	genfuncbegin();
+#endif
+#ifdef INTEL_386
+	if (lc_auto != 0)
+		g_coder(op_sub, 4, mk_immed(lc_auto), mk_reg(STACKPTR));
+	g_coder(op_mov, 4, mk_reg(STACKPTR), mk_reg(FRAMEPTR));
+	g_coder(op_push, 4, mk_reg(FRAMEPTR), NIL_AMODE);
+#endif
+#ifdef ICODE
+	if (icode_option)
+		fprintf(icode, "\t$framesize was %ld\n", lc_auto);
+#endif
+}
+// vim:ts=4:sw=4

+ 718 - 0
gtc/src/getasm.c

@@ -0,0 +1,718 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * inline assembly extraction routines
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifdef ASM
+#define DECLARE
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifdef PC
+#ifdef SHORT_INT
+#undef int
+#endif
+#include	<ctype.h>
+#ifdef SHORT_INT
+#define int short
+#endif
+#endif
+
+#define newline semicolon
+
+#ifndef AS
+#define label(__l) 12345
+#endif
+
+xstatic char * readonly asmreservedlist[] = {
+	"a0",
+	"a1",
+	"a2",
+	"a3",
+	"a4",
+	"a5",
+	"a6",
+	"a7",
+	"b",
+	"ccr",
+	"d0",
+	"d1",
+	"d2",
+	"d3",
+	"d4",
+	"d5",
+	"d6",
+	"d7",
+	"l",
+	"s",
+	"sp",
+	"sr",
+	"usp",
+	"w",
+};
+
+xstatic readonly struct oplst_elem {
+	char		   *s;
+	enum(e_op)		ov;
+	short			val;
+}				oplist[] =
+
+{{
+	"add", op_add
+}, {
+	"adda", op_add
+}, {
+	"addi", op_addi
+}, {
+	"addq", op_addq
+}, {
+	"addx", op_addx
+}, {
+	"and", op_and
+}, {
+	"andi", op_andi
+}, {
+	"asl", op_asl
+}, {
+	"asr", op_asr
+}, {
+	"bcc", op_bhs
+}, {
+	"bchg", op_bchg
+}, {
+	"bclr", op_bclr
+}, {
+	"bcs", op_blo
+}, {
+	"beq", op_beq
+}, {
+	"bge", op_bge
+}, {
+	"bgt", op_bgt
+}, {
+	"bhi", op_bhi
+}, {
+	"bhs", op_bhs
+}, {
+	"ble", op_ble
+}, {
+	"blo", op_blo
+}, {
+	"bls", op_bls
+}, {
+	"blt", op_blt
+}, {
+	"bmi", op_bmi
+}, {
+	"bne", op_bne
+}, {
+	"bpl", op_bpl
+}, {
+	"bra", op_bra
+}, {
+	"bset", op_bset
+}, {
+	"bsr", op_bsr
+}, {
+	"btst", op_btst
+}, {
+	"bvs", op_bvs
+}, {
+	"bvc", op_bvc
+}, {
+	"chk", op_chk
+}, {
+	"clr", op_clr
+}, {
+	"cmp", op_cmp
+}, {
+	"cmpi", op_cmpi
+}, {
+#ifndef LIGHT_DBXX_AND_SXX
+	"dbcc", op_dbhs
+}, {
+	"dbcs", op_dblo
+}, {
+#endif
+	"dbeq", op_dbeq
+}, {
+	"dbf", op_dbra
+}, {
+#ifndef LIGHT_DBXX_AND_SXX
+	"dbge", op_dbge
+}, {
+	"dbgt", op_dbgt
+}, {
+	"dbhi", op_dbhi
+}, {
+	"dbhs", op_dbhs
+}, {
+	"dble", op_dble
+}, {
+	"dblo", op_dblo
+}, {
+	"dbls", op_dbls
+}, {
+	"dblt", op_dblt
+}, {
+	"dbmi", op_dbmi
+}, {
+#endif
+	"dbne", op_dbne
+}, {
+#ifndef LIGHT_DBXX_AND_SXX
+	"dbpl", op_dbpl
+}, {
+#endif
+	"dbra", op_dbra
+}, {
+#ifndef LIGHT_DBXX_AND_SXX
+	"dbvs", op_dbvs
+}, {
+	"dbvc", op_dbvc
+}, {
+#endif
+	"dc", op_dc
+}, {
+	"dcb", op_dcb
+}, {
+	"divs", op_divs
+}, {
+	"divu", op_divu
+}, {
+	"ds", op_ds
+}, {
+	"eor", op_eor
+}, {
+	"eori", op_eori
+}, {
+	"even", op_even
+}, {
+	"exg", op_exg
+}, {
+	"ext", op_ext
+}, {
+	"jmp", op_jmp
+}, {
+	"jsr", op_jsr
+}, {
+	"lea", op_lea
+}, {
+	"link", op_link
+}, {
+	"lsl", op_lsl
+}, {
+	"lsr", op_lsr
+}, {
+	"move", op_move
+}, {
+	"movea", op_move
+}, {
+	"movem", op_movem
+}, {
+	"moveq", op_moveq
+}, {
+	"muls", op_muls
+}, {
+	"mulu", op_mulu
+}, {
+	"neg", op_neg
+}, {
+	"negx", op_negx
+}, {
+	"nop", op_dc, 0x4e71
+}, {
+	"not", op_not
+}, {
+	"or", op_or
+}, {
+	"ori", op_ori
+}, {
+	"pea", op_pea
+}, {
+	"rol", op_rol
+}, {
+	"ror", op_ror
+}, {
+	"roxl", op_roxl
+}, {
+	"roxr", op_roxr
+}, {
+	"rte", op_dc, 0x4e73
+}, {
+	"rtr", op_dc, 0x4e77
+}, {
+	"rts", op_rts
+}, {
+#ifndef LIGHT_DBXX_AND_SXX
+	"scc", op_shs
+}, {
+	"scs", op_slo
+}, {
+	"seq", op_seq
+}, {
+	"sf", op_sf
+}, {
+	"sge", op_sge
+}, {
+	"sgt", op_sgt
+}, {
+	"shi", op_shi
+}, {
+	"shs", op_shs
+}, {
+	"sle", op_sle
+}, {
+	"slo", op_slo
+}, {
+	"sls", op_sls
+}, {
+	"slt", op_slt
+}, {
+	"smi", op_smi
+}, {
+	"sne", op_sne
+}, {
+	"spl", op_spl
+}, {
+	"st", op_st
+}, {
+#endif
+	"sub", op_sub
+}, {
+	"suba", op_sub
+}, {
+	"subi", op_subi
+}, {
+	"subq", op_subq
+}, {
+	"subx", op_subx
+}, {
+#ifndef LIGHT_DBXX_AND_SXX
+	"svs", op_svs
+}, {
+	"svc", op_svc
+}, {
+#endif
+	"swap", op_swap
+}, {
+	"tas", op_tas
+}, {
+	"trap", op_trap
+}, {
+	"trapv", op_dc, 0x4e76
+}, {
+	"tst", op_tst
+}, {
+	"unlk", op_unlk
+}};
+#ifndef LIGHT_DBXX_AND_SXX
+#define asm_N 118
+#else
+#define asm_N 85
+#endif
+
+int lastreg CGLOB;
+
+void asm_getsym() {
+	int l=lineid;
+	getsym();
+	if (lineid!=l)
+		cached_sym=lastst, cached_lineid = lineid, lastst=newline;
+}
+
+struct ocode *asm_head CGLOB;
+xstatic struct ocode *asm_tail CGLOB;
+struct ocode *new_code(int s) {
+	struct ocode   *new_ocode;
+	new_ocode = (struct ocode *) xalloc(s, OCODE);
+#ifdef NO_CALLOC
+	new_ocode->fwd = 0;
+#endif
+	if (!asm_head) {
+		asm_head = new_ocode;
+#ifdef NO_CALLOC
+		new_ocode->back = 0;
+#endif
+	} else {
+		new_ocode->back = asm_tail;
+		asm_tail->fwd = new_ocode;
+	}
+	return asm_tail = new_ocode;
+}
+
+void add_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2, int line) {
+/*
+ * generate a code sequence into the asm list.
+ */
+	struct ocode   *new_ocode = new_code(sizeof(struct ocode));
+	new_ocode->opcode = op;
+	new_ocode->length = len;
+	if ((unsigned int)len>4 || len==3)
+		ierr(ADD_CODE,1);
+	new_ocode->oper1 = ap1;
+	new_ocode->oper2 = ap2;
+#ifdef DB_POSSIBLE
+	new_ocode->line=line;
+#endif
+#ifdef AS
+	new_ocode->opt = 1;
+#endif
+}
+
+void add_label(int lab) {
+	struct lbls *new_ocode = (struct lbls *)new_code(sizeof(struct lbls));
+	new_ocode->opcode = op_label;
+	new_ocode->lab = lab;
+}
+
+int has_autocon(struct enode *ep) {
+	switch (ep->nodetype) {
+		case en_icon:
+#ifndef NOFLOAT
+		case en_fcon:
+#endif
+		case en_labcon:
+		case en_nacon:
+			return 0;
+		case en_autocon:
+			return 1;
+		case en_add:
+			return has_autocon(ep->v.p[0]) + has_autocon(ep->v.p[1]);
+		case en_sub:
+			return has_autocon(ep->v.p[0]) - has_autocon(ep->v.p[1]);
+		case en_uminus:
+			return - has_autocon(ep->v.p[0]);
+		default:
+			uerrc("invalid expression");
+			return 0; // avoid compiler warning
+	}
+}
+void get_offset(struct amode *ap) {
+	asm_xflag++;
+	asm_zflag++;
+/*	if (!strcmp(lastid,"__Int5_body__"))
+		printf("fgio");*/
+	if (!exprnc(&ap->offset))
+		error(ERR_INTEXPR);
+	else {
+		opt4(&ap->offset);
+		if (ap->offset->nodetype==en_deref)
+			ap->offset=ap->offset->v.p[0];
+#ifdef OLD_AMODE_INPUT
+		if (lastst==kw_offs_end) {
+#else
+		if (lastst==openpa) {
+#endif
+			asm_getsym();
+			if (lastst==kw_areg) {
+				ap->preg=lastreg;
+				asm_getsym();
+				if (lastst==comma) {
+					asm_getsym();
+					ap->sreg=lastreg;
+					if (lastst==kw_dreg)
+						ap->mode=am_indx2;
+					else if (lastst==kw_areg)
+						ap->mode=am_indx3;
+					else error(ERR_SYNTAX);
+					asm_getsym();
+					if (lastst==dot) {
+#ifdef EXT_AS_ID
+						asm_getsym();
+#else
+						char c=lastch;
+#endif
+						ap->slen=0;
+#ifdef EXT_AS_ID
+						if (lastst==id && lastid[1]==0) {
+							char c=lastid[0];
+#endif
+							if (c=='b' || c=='s') ap->slen=1;
+							else if (c=='w') ap->slen=2;
+							else if (c=='l') ap->slen=4;
+#ifdef EXT_AS_ID
+							asm_getsym();
+						}
+#else
+						getch();
+						asm_getsym();
+#endif
+						if (!ap->slen)
+							error(ERR_SYNTAX);
+					} else ap->slen=2;
+				} else ap->mode=am_indx;
+				needpunc(closepa);
+			} else if (lastst==id && !strcmp("pc",lastid))
+				ap->mode=am_pcrel, asm_getsym()/* 'pc' */, asm_getsym()/* ')' */;
+		} else
+			ap->mode=am_direct;
+		if (has_autocon(ap->offset)) {
+			if (ap->mode!=am_direct && (ap->mode!=am_indx || ap->preg<TRUE_FRAMEPTR-AREGBASE))
+				error(ERR_INTEXPR);
+			ap->mode=am_indx, ap->preg=FRAMEPTR-AREGBASE;
+		}
+	}
+	asm_zflag--;
+	asm_xflag--;
+}
+
+xstatic enum(e_op) lastop CGLOB;
+xstatic int lastval CGLOB,second_parm CGLOB;
+struct amode *get_asmparam() {
+	struct amode *ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE);
+	ap->preg=lastreg;
+/*	if ((long)&ap->offset==0x7D53CC)
+		printf("gio");*/
+	if (lastop==op_movem && (lastst==kw_dreg || lastst==kw_areg)) {
+		unsigned int mask=0; int n,d,x;
+		if (second_parm) ap->mode=am_mask2,x=0;
+		else ap->mode=am_mask1,x=15;
+		/* Format : d0=0x8000 in mask1, 0x0001 in mask2 */
+		while (lastst==kw_dreg || lastst==kw_areg) {
+			d=n=lastreg+((lastst-kw_dreg)<<3);
+			asm_getsym();
+			if (lastst==minus) {
+				asm_getsym();
+				if (lastst==kw_dreg || lastst==kw_areg)
+					d=lastreg+((lastst-kw_dreg)<<3);
+				else error(ERR_SYNTAX);
+				asm_getsym();
+			}
+			if (n>d)
+				error(ERR_SYNTAX);
+			while (n<=d) {
+				mask |= 1<<(n^x);
+				n++;
+			}
+			if (lastst==divide)
+				asm_getsym();
+		}
+		ap->offset=mk_icon(mask);
+	} else if (lastst==kw_dreg)
+		ap->mode=am_dreg, asm_getsym();
+	else if (lastst==kw_areg)
+		ap->mode=am_areg, asm_getsym();
+	else if (lastst==openpa) {
+		asm_getsym();
+		if (lastst==kw_areg) {
+			ap->preg=lastreg;
+			asm_getsym();
+			needpunc(closepa);
+			if (lastst==plus)
+				asm_getsym(), ap->mode=am_ainc;
+			else ap->mode=am_ind;
+		} else {
+			cached_sym=lastst;
+			cached_lineid=lineid;
+			lastst=openpa;
+			get_offset(ap);
+		}
+	} else if (lastst==minus) {
+		if (lastch=='(') {	// a bit dirty, but doesn't matter since you never type '- (an)'
+			asm_getsym();	// remove '-'
+			asm_getsym();	// remove '('
+			if (lastst==kw_areg) {
+				ap->preg=lastreg;
+				asm_getsym();
+				needpunc(closepa);
+				ap->mode=am_adec;
+			} else {
+				get_offset(ap);
+				needpunc(closepa);
+				ap->offset=mk_node(en_uminus,ap->offset,NIL_ENODE);
+				opt4(&ap->offset);
+			}
+		} else get_offset(ap);
+	} else if (lastst==sharp) {
+		asm_getsym();
+		get_offset(ap);
+		if (ap->mode!=am_direct)
+			error(ERR_SYNTAX);
+		else ap->mode=am_immed;
+	} else if (lastst==id && ((!lastid[2] && lastid[1]=='r' && lastid[0]=='s') ||
+			(!lastid[3] && ((lastid[2]=='r' && lastid[1]=='c' && lastid[0]=='c') ||
+							(lastid[2]=='p' && lastid[0]=='u' && lastid[1]=='s'))))) {
+		ap->mode=lastid[2]?(lastid[0]=='u'?am_usp:am_ccr):am_sr;
+		getsym();
+	} else get_offset(ap);
+	return ap;
+}
+
+/* dichotomic keyword search */
+void asm_searchkw() {
+	char *s1,*s2,c;
+	const struct oplst_elem *op_ptr;
+	int a=0,b=asm_N-1,m;
+#ifdef PC
+	if (sizeof(oplist)/sizeof(struct oplst_elem)!=asm_N)
+		fatal("BUILD ERROR, WRONG ASM KEYWORDS #");
+#endif
+/*	if (!strcmp("addq",lastid))
+		printf("");*/
+	while (a<=b) {
+		m=(a+b)>>1;
+		op_ptr=&oplist[m];
+		s1=lastid;
+		s2=op_ptr->s;
+		do {
+			if (!(c=*s2++)) {
+				if (!*s1) {
+					lastst=kw_instr;
+					lastop=op_ptr->ov;
+					lastval=op_ptr->val;
+					return;
+				}
+				/* otherwise continue ( < 'addi' doesn't match 'add' but yet exists) */
+			}
+		} while (*s1++==c);
+		if (s1[-1]<c)	// il faut aller plus haut
+			b=m-1;
+		else a=m+1;
+	}
+}
+int asm_isreserved() {
+	char *s1,*s2,c;
+	int a=0,b=sizeof(asmreservedlist)/sizeof(char*)-1,m;
+	while (a<=b) {
+		m=(a+b)>>1;
+		s1=lastid;
+		s2=asmreservedlist[m];
+		do {
+			if (!(c=*s2++)) {
+				if (!*s1)
+					return 1;
+				/* otherwise continue ( < 'addi' doesn't match 'add' but yet exists) */
+			}
+		} while (*s1++==c);
+		if (s1[-1]<c)	// il faut aller plus haut
+			b=m-1;
+		else a=m+1;
+	}
+	asm_searchkw();
+	return (lastst==kw_instr);
+}
+
+
+int getasm_main() {
+	int has_lab=0;
+  restart:
+	if (lastst==newline) {
+		has_lab=0;
+		asm_getsym();
+		goto restart;
+	} else if (lastst==kw_instr) {
+		int line=lineid,l=0,v=lastval; struct amode *ap1=0,*ap2=0;
+		enum(e_op) op=lastop;
+		int cont=1;
+		asm_getsym();
+		if (lastst!=newline) {
+			if (lastst==dot) {
+#ifndef EXT_AS_ID
+				char c=lastch;
+				if (c=='b' || c=='s') l=1;
+				else if (c=='w') l=2;
+				else if (c=='l') l=4;
+				getch();
+				asm_getsym();
+#else
+				asm_getsym();
+				if (lastst==id && lastid[1]==0) {
+					char c=lastid[0];
+					if (c=='b' || c=='s') l=1;
+					else if (c=='w') l=2;
+					else if (c=='l') l=4;
+					asm_getsym();
+				}
+#endif
+				if (!l) {
+					error(ERR_SYNTAX);
+					goto restart;
+				}
+			}
+			if (lastst!=newline && lastst!=end) {
+				second_parm=0;
+				ap1=get_asmparam();
+				if (lineid==line && lastst!=newline && lastst!=end) {
+													// since exprnc calls getsym, not asm_getsym
+					if (lastst!=comma)
+						cont=0;/*error(ERR_PUNCT);*/
+					else if (op!=op_dc) {
+						asm_getsym();
+						if (lastst!=newline)
+							second_parm=1,ap2=get_asmparam();
+					} else {
+						while (lineid==line && lastst==comma) {
+							asm_getsym();
+							add_code(op,l,ap1,0,line);
+							ap1=get_asmparam();
+						}
+					}
+				} else if ((int)cached_sym IS_INVALID)	// otherwise it's because last getsym was
+					cached_sym=lastst,			// an asm_getsym, and we already know the 'NL'
+						cached_lineid=lineid,
+						lastst=newline;
+			}
+		}
+		if (v) {
+			if (ap1)
+				uerrc("too many arguments");
+			ap1=mk_offset(mk_icon(v)), ap2=0;
+			l=2;	// always 16-bit declaration
+		}
+		add_code(op,l,ap1,ap2,line);
+		return cont;
+	} else if (lastst==id) {	/* it's a label */
+		if (has_lab)			// forbid multiple labels on one single line
+			error(ERR_SYNTAX);
+		has_lab=1;
+		add_label(label(lastid));
+		asm_getsym();
+		if (lastst==colon)
+			asm_getsym();
+		goto restart;
+	} else return 0;
+}
+
+struct snode *asmstmt(void) {
+/*
+ * asmstmt parses the gtc c asm statement.
+ */
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_asm;
+	snp->count = 1;
+	asm_flag++;
+	asm_head = 0;
+	getsym();
+	if (lastst == kw_volatile)
+		getsym();
+	if (lastst != begin)
+		error(ERR_EXPREXPECT);
+	asm_getsym();
+	while (getasm_main());
+	snp->v1.i=(long)asm_head;
+	asm_flag--;
+	needpunc(end);
+	needpunc(semicolon);
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	return snp;
+}
+#undef newline
+#endif
+// vim:ts=4:sw=4

+ 2293 - 0
gtc/src/getsym.c

@@ -0,0 +1,2293 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * symbol extraction routines
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define DECLARE
+#include	"define.h"
+_FILE(__FILE__)
+#include	"version.h"
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifdef PCH
+#include	"pch.h"
+#endif
+#ifndef NOFLOAT
+#include	"ffplib.h"
+#define FFP_TEN 0xA0000044
+#define FFP_TENINV 0xCCCCCD3D
+#endif
+#ifdef PC
+#ifdef SHORT_INT
+#undef int
+#endif
+#include	<ctype.h>
+#include	<stdarg.h>
+#ifdef SHORT_INT
+#define int short
+#endif
+#endif
+
+#ifdef PC
+unsigned long _w2ul(TI_LONG *x) {
+	return ((unsigned long)x->x0<<24)+((unsigned long)x->x1<<16)+
+		   ((unsigned long)x->x2<< 8)+((unsigned long)x->x3<< 0);
+}
+unsigned short _w2us(TI_SHORT *x) {
+	return ((unsigned short)x->hi<<8)+x->lo;
+}
+#endif
+
+FILE		   *input CGLOB;
+int 			total_errors CGLOB;
+int				err_force_line CGLOB,err_cur_line CGLOB,err_assembly CGLOB;
+int 			lastch CGLOB;
+enum(e_sym)		lastst CGLOB;
+int				lastst_flag CGLOB;
+char			lastid[MAX_ID_LEN+1];
+int 			got_sym CGLOB;
+#ifdef PCH
+char			curpch[MAX_ID_LEN+1];
+#endif
+int				lastcrc CGLOB;
+struct sym	   *lastsp CGLOB;
+char			laststr[MAX_STRLEN + 1];
+int 			lstrlen CGLOB;
+unsigned long	ival CGLOB;
+#ifndef NOFLOAT
+double			rval CGLOB;
+#endif
+
+//#define MAX_NUM_ERRS 80
+#define MAX_NUM_ERRS 2
+int 	 err_num[MAX_NUM_ERRS];
+int 	 numerrs;
+char	 linein[LINE_LENGTH];
+//#define linemax &linein[LINE_LENGTH]
+//xstatic int	  act_line;
+//xstatic char	  act_file[100] = "<unknown file>";
+//xstatic int	  lineno;
+
+#ifdef OLD_MACRO
+#define CHAR_POPMAC 1
+#define MAX_MAC_NUM 100
+TABLE *mac_stk[MAX_MAC_NUM];
+TABLE **mac_sp;
+#else
+#define MAX_MAC_ARGS 20
+#endif
+
+char *curname CGLOB;
+char			*lptr CGLOB;	/* shared with preproc */
+char			*inclname[10];	/* shared with preproc */
+FILE			*inclfile[10];	/* shared with preproc */
+int 			inclline[10];	/* shared with preproc */
+int 			inclifreldepth[10];	/* shared with preproc */
+#ifdef GTDEV
+int				inclread[10];	/* shared with preproc */
+int				inclcoeff[10];	/* shared with preproc */
+#endif
+int 			incldepth;		/* shared with preproc */
+char			*linstack[20];	/* stack for substitutions */
+char			chstack[20];	/* place to save lastch */
+int 			lstackptr CGLOB;/* substitution stack pointer */
+int				preproc_stmt CGLOB;
+#ifdef PC
+enum(e_sym)		cached_sym CGLOB;	/* cached symbol (for preproc-emulation prefetching) */
+#else
+enum(e_sym)		_cached_sym CGLOB;
+#endif
+int				cached_flag CGLOB;
+int				cached_lineid CGLOB;
+enum(e_sym)		forbid CGLOB;
+int				pch_init CGLOB;
+
+extern int getch_comment,getch_pp,getch_in_string,getch_noppdir;
+
+xstatic char *linemin CGLOB,*linemax CGLOB;
+
+int getline(int f);
+int getcache(enum(e_sym) f);
+
+#ifndef isalnum
+#define isalnum _isalnum
+static int isalnum(char c) {
+/*
+ * This function makes assumptions about the character codes.
+ */
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+		(c >= '0' && c <= '9');
+}
+#endif
+
+//#ifndef isidch
+#ifdef PC
+static int isidch(char c) {
+	return (c>='0'&&c<='9') || (c>='A'&&c<='Z') || (c>='a'&&c<='z')
+		|| c == '_' || c == '$';
+}
+static int isbegidch(char c) {
+	return (c>='A'&&c<='Z') || (c>='a'&&c<='z') || c == '_' || c == '$';
+}
+#else
+#define isidch(___c) ({register short __c=(___c); \
+(__c>='0'&&__c<='9') || (__c>='A'&&__c<='Z') || (__c>='a'&&__c<='z') || __c=='_' || __c=='$';})
+#define isbegidch(___c) ({register short __c=(___c); \
+(__c>='A'&&__c<='Z') || (__c>='a'&&__c<='z') || __c=='_' || __c=='$';})
+#endif
+//#endif
+
+#undef isspace
+#ifdef PC
+#define isspace _isspace
+int isspace(int c) {
+	return (c == ' ' || c == '\t' || c == '\n');
+}
+#else
+#define isspace(___c) ({register short __c=(___c); \
+__c==' ' || __c=='\t' || __c=='\n';})
+#endif
+
+#ifndef isdigit
+#define isdigit _isdigit
+static int isdigit(char c) {
+/*
+ * This function makes assumptions about the character codes.
+ */
+	return (c >= '0' && c <= '9');
+}
+#endif
+
+#ifdef GTDEV
+void progr_initforcurfile();
+int progr CGLOB,progr_readtonow CGLOB,progr_coeff CGLOB;
+#endif
+#define stringify_noexpand(s) #s
+#define stringify(s) stringify_noexpand(s)
+char * readonly stddefines="__GTC__\000"stringify(GTC_MAJOR)"\0" "__GTC_MINOR__\000"stringify(GTC_MINOR)"\0" "__VERSION__\000\""GTC_VERSION"\"\0"
+	"mc68000\000\0" "__embedded__\000\0"
+	"__DATE__\000\""__DATE__"\"\0" "__TIME__\000\""__TIME__"\"\0"
+	;
+void insert_macros(char *p) {
+	SYM *sp;
+	while (*p) {
+		sp=(SYM *)xalloc((int)sizeof(SYM), _SYM);
+		sp->name=p;
+		while (*p++);
+		sp->value.s=p;
+		while (*p++);
+		insert(sp,&defsyms);
+	}
+}
+#ifdef PC
+/* warning: duplicated in cmain.c! */
+enum OptionModes { optn_parse=0, optn_global_init, optn_global_init_post, optn_preproc_init };
+void option_parse_all(enum(OptionModes) ex_mode);
+#endif
+extern TI_SHORT func_attr;
+#ifdef PCH
+void initpch() {
+	pchnum = 0;
+}
+#endif
+void initsym() {
+#if defined(PC) || (defined(PCH) && defined(MULTIFILE))
+	int i;
+#endif
+#ifdef OLD_MACRO
+	lptr = &linein[MAX_MAC_LEN+1];
+#else
+	lptr = linein+1;
+#endif
+	*lptr = 0;
+	numerrs = 0;
+	total_errors = 0;
+	err_force_line = -1;
+	err_assembly = 0;
+	lineno = lineid = 0;
+	ifsd = ifskip = ifdepth = ifreldepth = 0;
+	ifcount[0] = 0;
+	ifval[0] = 0;
+#ifdef PCH
+#ifdef MULTIFILE
+	for (i=pchnum;i--;)
+		memset(pchtab[i],0,(short)w2us(pchhead[i]->nID));
+#endif
+	pch_init = 0;
+#endif
+#ifdef MID_DECL
+	middle_decl = 0;
+#endif
+#ifdef NEW_ATTR
+#ifdef PC
+	func_attr.lo = -1;
+	func_attr.hi = -1;
+#else
+	func_attr = -1;
+#endif
+#endif
+#ifdef OLD_MACRO
+	mac_sp = &mac_stk[MAX_MAC_NUM];
+#endif
+#ifdef FLINE_RC
+	fline_rc=0;
+#endif
+#ifdef GTDEV
+	progr_initforcurfile();
+#endif
+	getch_comment=0;
+	getch_pp=0;
+	getch_in_string=0;
+	getch_noppdir=0;
+	preproc_stmt=0;
+	/*cached_sym2=*/cached_sym=-1;
+	forbid=-1;
+#ifdef MIN_TEMP_MEM
+	min_temp_mem=0;
+#endif
+	linemin=linein+1;
+	linemax=linein+LINE_LENGTH;
+	global_strings = 0;
+	hashinit(&defsyms);	// this is because the file could *begin* with #define's and/or #if's
+	global_flag = 1;	//  (idem)
+	temp_local = 0;
+	/* pre-defined preprocessor macros */
+	insert_macros(stddefines);
+#ifdef PC
+	option_parse_all(optn_preproc_init);
+#endif
+}
+
+#if defined(PC) || defined(FLASH_VERSION)
+xstatic readonly char    * readonly __err[] = {
+	"syntax error",
+	"illegal character",
+	"illegal floating-point constant",
+	"illegal type",
+	"undefined identifier '%s'",
+	"no field allowed here",
+	"'%c' expected",
+	"identifier expected",
+	"initialization invalid here",
+	"incomplete struct/union/enum declaration",
+	"illegal initialization",
+	"too many initializers",
+	"illegal storage class",
+	"function body expected",
+	"pointer type expected",
+	"function type expected",
+	"'%s' is not a member of structure",
+	"l-value required",
+	"error dereferencing a pointer",
+	"mismatch between types '%s' and '%s'",
+	"expression expected",
+	"'while' expected in do-loop",
+	"enum value out of range",
+	"duplicate case label",
+	"undefined label",
+	NULL/*"preprocessing error"*/,
+	"declared argument missing",
+	"illegal field width",
+	"illegal constant integer expression",
+	"cannot cast from '%s' to '%s'",
+	"integer-valued type expected",
+	"error casting a constant",
+	"illegal redeclaration of '%s'",
+	NULL/*"error while scanning parameter list"*/,
+	"bad field type, must be unsigned or int",
+	"invalid #include statement",
+	"cannot open file \"%s\"",
+	"wrong #define",
+	"#error: %s",
+	"duplicate symbol '%s'",
+	"constant expression expected",
+	"value out of range",
+	"too many parameters to function",
+	"too few parameters to function",
+	"invalid case range",
+	"unexpected end of file",
+	"%s",
+	"internal limit exceeded: %s",
+	"invalid relocation in expression",
+};
+#endif
+
+int _getline(int listflag,char *base) {
+	//int rv; //char *p;
+#ifdef LISTING
+	int i;
+#endif
+	char *lptr=base;
+#ifdef LISTING
+	if (lineno > 0 && list_option && !ifskip) {
+		fprintf(list, "%s:%6d", lptr, lineno);
+		for (i = 0; i < numerrs; i++)
+			fprintf(list, " error: %s\n", __err[err_num[i]]);
+		numerrs = 0;
+	}
+#endif
+#ifdef GTDEV
+	{
+	int new_progr=((long)/*progr_readtonow*/(((void *)input->fpos-input->base)-7)*progr_coeff)>>16;
+	if (new_progr!=progr)
+		progr=new_progr,progr_process(func_sp?func_sp->name:0,curname,new_progr);
+	}
+#endif
+	do {
+		++lineno;
+	//	  ++act_line;
+		if ((int)(&linein[LINE_LENGTH-1]-lptr)<100)
+			uerrsys("line is too long");
+		if (!fgets(lptr,(int)(&linein[LINE_LENGTH-1]-lptr),input)) {
+			if (incldepth > 0) {
+				if (ifreldepth) uerrc("unterminated '#if' statement");
+				fclose(input);
+				input = inclfile[--incldepth];
+				curname = inclname[incldepth];
+#ifdef GTDEV
+				progr_readtonow = inclread[incldepth];
+				progr_coeff = inclcoeff[incldepth];
+#endif
+				lineno = inclline[incldepth];
+				ifreldepth = inclifreldepth[incldepth];
+	#ifdef OLD_MACRO
+				lptr=&linein[MAX_MAC_LEN+1];
+	#else
+				lptr=linein+1;
+	#endif
+				*lptr='\n'; lptr[1]=0;
+				return 0;
+	//			return getline(0);
+			} else
+				return 1;
+		}
+#ifdef PC
+		if (strlen(lptr)>=2 && lptr[strlen(lptr)-2]=='\r')	// workaround so that Unix version accepts DOS files
+			strcpy(&lptr[strlen(lptr)-2],"\n");
+#endif
+	} while (*(lptr+=strlen(lptr)-2)=='\\' && !ifskip);
+#ifdef GTDEV
+	progr_readtonow+=strlen(lptr);	// this isn't byte-precise, but OK for a percentage :)
+#endif
+	/* the following instruction is used so that when reading the character after '#endif'
+	 * at the end of a header file (in order to tell 'endif' from 'endif_foo'), the
+	 * preprocessor still operates in the current header file, preventing it from
+	 * generating an error since a '#if' statement isn't complete */
+	/*if (lineno==0x1DC)
+		bkpt();*/
+	if (lptr[1]!='\n')		/* lptr[2] is '\0' at this point */
+		lptr++,lptr[1]='\n',lptr[2]=0;
+	preproc_stmt=0;
+	return 0;
+}
+
+int getline(int listflag) {
+	return _getline(listflag,
+	#ifdef OLD_MACRO
+		lptr=&linein[MAX_MAC_LEN+1]
+	#else
+		lptr=linein+1
+	#endif
+		);
+/*	p=lptr;
+	while (*p && isspace(*p)) p++;
+	if (*p == '#') {
+		lptr=p;*/
+					/*	++lptr;
+						lastch = ' ';
+						getsym();
+						if (lastst == id && !strcmp(lastid, "line"))
+								getsym();
+						if (lastst != iconst)
+								error(ERR_PREPROC);
+						act_line = ival-1;
+						// scan file name
+						i = 0;
+						while (isspace(*lptr))
+								lptr++;
+						if (*lptr == '"')
+								lptr++;
+						// assume that a filename does not end with double-quotes
+						while (*lptr != '\0' && *lptr != '"' && !isspace(*lptr))
+								act_file[i++] = *lptr++;
+								// DECUS cpp suppresses the name if it has not changed
+								// in this case, i is simply zero, and then we keep the 
+								// old name
+						if (i > 0)
+								act_file[i] = '\0';
+						return getline();*/
+/*		preproc_stmt=1;
+		return preprocess();
+	}*/
+/*	while ((c=*lptr++))
+		if (c=='#' && *lptr=='#') {
+			char *p=lptr-1;
+			char id[MAX_ID_LEN+1],c=*lptr++;
+			int i = 0; SYM *sp;
+			while (isidch(c=*lptr++)) {
+				if (i < MAX_ID_LEN)
+					id[i++] = c;
+			}
+			id[i] = '\0';
+			if (mac_sp!=&mac_stk[MAX_MAC_NUM] && (sp = search(lastid, lastcrc, *mac_sp))) {
+				char *q=sp->value.s,*e=p+strlen(q);
+				//memmove(p,lptr,&linein[MAX_MAC_LEN+1000]-lptr);
+				//memmove(e,p,&linein[MAX_MAC_LEN+1000]-e);
+				memmove(e,lptr,&linein[MAX_MAC_LEN+1000]-(lptr>e?lptr:e));
+				memcpy(p,q,e-p);
+				lptr=e;
+			}
+		}
+	lptr=&linein[MAX_MAC_LEN+1];*/
+//	return 0;
+}
+
+/*
+ * getch - basic get character routine.
+ */
+xstatic int getch_comment CGLOB,getch_pp CGLOB,getch_in_string CGLOB;
+int getch_noppdir CGLOB;
+xstatic char *getch_p CGLOB;
+int getch() {
+	if (getch_pp) goto ppdo;
+	do {
+#ifdef MACRO_PPDIR
+		if (lptr!=linein+1 &&  lptr[-1]=='\n' && *lptr) {
+			lastch=*lptr;
+			goto pptest_continue;	/* we needn't bother about comments since all are removed
+									 *  because dodefine() calls getch() to read the macro   */
+		}
+#endif
+		while ((lastch = *(unsigned char *)lptr++) == '\0') {
+			if( lstackptr > 0 ) {
+				lptr = linstack[--lstackptr];
+				lastch = chstack[lstackptr];
+				return lastch;
+			}
+			if (getline(incldepth == 0))
+				return lastch = -1;
+		pptest_continue:
+			if (!getch_comment) {
+				getch_p=lptr;
+				while (*getch_p && isspace(*getch_p)) getch_p++;
+				if (*getch_p == '#' && !getch_noppdir) {
+					getch_pp=1;
+					lastch = ' ';
+					return 0;
+				ppdo:
+					getch_pp=0;
+					lptr=getch_p;
+					preproc_stmt=1;
+					if (preprocess()) return lastch = -1;
+					preproc_stmt=0;
+					goto pptest_continue;
+				}
+			}
+		}
+		if (lastch=='/' && !getch_in_string) {
+			if (*(unsigned char *)lptr=='/' && !getch_comment) {
+				while (*(unsigned char *)lptr++)
+					if (*(char *)lptr=='\n' && lptr[1])
+						uwarn("multi-line comment");
+				lptr--;
+				return getch();
+			} else if (*(unsigned char *)lptr=='*') {
+				char last;
+				if (getch_comment) {
+					uwarn("/" "* in comment block");
+					return 0;
+				}
+				getch_comment=1;
+				do {
+					last=(char)lastch;
+					if (getch()<0) uerrc("unended comment block");
+				} while (last!='*' || lastch!='/');
+				getch_comment=0;
+				return getch();
+			}
+		}
+/*#ifdef ASM
+		else if (asm_flag && lastch==';' && !comment) {
+			while (*(unsigned char *)lptr++);
+			lptr--; return getch();
+		}
+#endif*/
+#ifdef OLD_MACRO
+		if (lastch==CHAR_POPMAC) {
+			mac_sp++; return getch();
+		}
+#endif
+	} while (ifskip && !getch_comment/* since otherwise we would 'eat' the callers' chars */
+		&& !preproc_stmt);
+	//if (lastch=='\r') lastch='\n';
+#ifdef OLD_MACRO
+	if (isspace(lastch) || lastch=='#') {
+		char c,*z=lptr-1;
+		while (isspace(c=*z++));	// skip spaces
+		if (c=='#' && *z=='#') {	// ## ?
+			char *p=z-1;
+			char id[MAX_ID_LEN+1],c=*z++;
+			int i = 0; SYM *sp;
+			while (isidch(c=*z++)) {
+				if (i < MAX_ID_LEN)
+					id[i++] = c;
+			}
+			id[i] = '\0';
+			if (mac_sp!=&mac_stk[MAX_MAC_NUM] && (sp = search(id, -1, (HTABLE *)*mac_sp))) {
+				char *q=sp->value.s,*e=p+strlen(q);
+				//memmove(p,z,&linein[MAX_MAC_LEN+999]-z);
+				//memmove(e,p,&linein[MAX_MAC_LEN+999]-e);
+				memmove(e,z,&linein[MAX_MAC_LEN+999]-(z>e?z:e));
+				memcpy(p,q,e-p);
+				lptr=p;
+			} else lptr=p+2;	// ignore ##
+			return getch();
+		}
+	}
+#endif
+	/*if (lastch=='@')
+		bkpt();*/
+	return 0;
+}
+
+#ifndef GTDEV
+void locate(void) {
+	if (err_force_line IS_INVALID) {
+#ifdef PC
+		msg3("%s:%d: ", curname, lineno);
+#else
+		char lcl[6+1],*p=lcl,*l=lptr-1; int n=6;
+		while (n-- && *l!='\n') *p++=*l++;
+		*p=0;
+		msg4("%s:%d (%s): ", curname, lineno, lcl);
+#endif
+	} else
+		msg3("%s:%d: ", curname, err_force_line);
+}
+#endif
+
+#if 0
+/*
+ * error - print error information
+ */
+void error(int n) {
+	debug('e');
+	if (numerrs < MAX_NUM_ERRS)
+		err_num[numerrs++] = n;
+	++total_errors;
+	locate();
+#ifdef PC
+	msg3("error %d: %s\n", n, __err[n]);
+#else
+	msg2("error %d\n", n);
+#endif
+/*
+ * Do not proceed if more than MAX_ERROR_COUNT errors were detected.
+ * MAX_ERROR_COUNT should be high since each error might be reported
+ * more than once
+ */
+	if (total_errors > MAX_ERROR_COUNT) {
+		msg("Too many errors\n");
+		_exit(1);
+	}
+}
+#endif
+
+#if 0
+void do_warning(char *s, ...) {
+#ifndef __GTC__
+	va_list args;
+	va_start(args,s);
+	locate();
+	msg("warning: ");
+	vmsg(s,args);
+	va_end(args);
+/*	if (total_errors > MAX_ERROR_COUNT) {
+		msg("Too many errors\n");
+		_exit(1);
+	}*/
+#else
+	
+#endif
+}
+#endif
+
+#include "error.c"
+
+/*
+ * getidstr - get an identifier string, that is either a macro name or an include file.
+ *
+ * Note that there are no escape characters
+ */
+void getidstr() {
+	register int	i;
+	i = 0;
+	while (isidch(lastch) || lastch=='\\' || lastch=='/'
+#ifdef PC
+		|| lastch=='.'
+		|| lastch==':'
+		|| lastch=='-'
+#endif
+		) {
+		if (lastch=='/') lastch='\\';
+//		if (lastch=='\\') getch();
+		if (i < MAX_ID_LEN)
+			lastid[i++] = lastch;
+		getch();
+	}
+	lastid[i] = '\0';
+	lastcrc=crcN(lastid);
+}
+
+void getrawid() {
+	register int i = 0;
+	while (isidch(lastch)) {
+		if (i < MAX_ID_LEN)
+			lastid[i++] = lastch;
+		getch();
+	}
+	lastid[i] = '\0';
+#ifdef PCH
+	if (!lastid[1] && lastid[0]=='_')
+		memcpy(lastid,curpch,MAX_ID_LEN+1);
+#endif
+	lastcrc=crcN(lastid);
+}
+
+void skipspace() {
+	while (isspace(lastch)) getch();
+}
+
+extern HTABLE defsyms;
+// including #define's
+#ifdef OLD_MACRO
+int getid(int c) {
+	register int	i;
+	SYM *sp;
+	if (c>=0) {
+		lastid[0] = c;
+		i = 1;
+		while (isidch(lastch)) {
+			if (i < MAX_ID_LEN)
+				lastid[i++] = lastch;
+			getch();
+		}
+		lastid[i] = '\0';
+	}
+#ifdef PCH
+	if (!lastid[1] && lastid[0]=='_')
+		memcpy(lastid,curpch,MAX_ID_LEN+1);
+#endif
+//search_id:
+	lastcrc=crcN(lastid);
+#ifdef OLD_MACRO
+	if (mac_sp==&mac_stk[MAX_MAC_NUM] || !(sp = search(lastid, lastcrc, (HTABLE *)*mac_sp)))
+#endif
+		sp = search(lastid, lastcrc, &defsyms);
+	if (sp
+#ifdef OLD_MACRO
+		&& strcmp(sp->value.s,sp->name)
+#endif
+			) {
+		char *p,*q,c; TABLE *tp;
+		if ((tp=(TABLE *)sp->tp)!=NULL) {
+#ifdef OLD_MACRO
+			int d=0,nmac=sp->used,nargs=0;
+			char buf[150],*bp=buf;
+			SYM *s=tp->head;
+			*--mac_sp=tp;
+			if (mac_sp<=mac_stk) fatal("GETMAC/stk_overflow");
+			skipspace();
+			if (lastch!='(') fatal("GETMAC");
+			while (1) {
+				getch();
+				if (lastch=='(') d++;
+				else if (lastch==')') { if (--d<0) break; }
+				else if (lastch==',' && !d && (sp->storage_class!=sc_vamac || nargs!=nmac-1)) {
+					if (nargs<nmac) {
+						*bp=0; s->value.s=strsave(bp=buf); nargs++;
+						s=s->next; continue;
+					} else fatal("GETMAC");
+				}
+				*bp++=lastch;
+				if (bp>=&buf[150]) fatal("GETMAC/too_long");
+			}
+			if (tp->head) {
+				*bp=0; s->value.s=strsave(buf);
+				if (++nargs!=nmac) fatal("GETMAC");
+			}
+#else
+			int d=0,nmac=sp->used,nargs=0,concat_mode;
+			char ps[500],args[300];
+			char *argb=args,*argp=args;
+			char c,lastsym[MAX_ID_LEN+1],*psptr,*lptrsav; int lastchsav=lastch;
+			SYM *s=tp->head;
+			skipspace();
+			if (lastch!='(') return 0;
+			while (1) {
+				getch();
+				if (lastch=='(') d++;
+				else if (lastch==')') { if (--d<0) break; }
+				else if (lastch==',' && !d && (sp->storage_class!=sc_vamac || nargs<nmac-1)) {
+					if (nargs<nmac) {
+						while (isspace(argp[-1]))	/* remove trailing whitespace */
+							argp--;
+						*argp++=0; s->value.s=argb; nargs++; argb=argp;
+						s=s->next; continue;
+					} else fatal("Too many args to macro");
+				}
+				if (argb!=argp || !isspace(lastch))	/* remove leading whitespace */
+					*argp++=lastch;
+				if (argp>=&args[350]) fatal("GETMAC/too_long");
+			}
+			if (tp->head) {	/* i.e. sc_vamac */
+				while (isspace(argp[-1]))	/* remove trailing whitespace */
+					argp--;
+				*argp=0; s->value.s=argb;
+				nargs++;				/* this var argument might appear to be "" */
+			}
+			if (nargs<nmac) fatal("Too few args to macro");
+			lptrsav=lptr; lastchsav=lastch;
+			if (lptr
+			argp=sp->value.s;
+			psptr=ps; concat_mode=0;
+			while ((c=*argp++)) {
+				if (isbegidch(c)) {
+					int i=0; SYM *asp; char *str=lastsym;
+					while (isidch(c)) {
+						if (i<MAX_ID_LEN)
+							lastsym[i]=c, i++;
+						c=*argp++;
+					}
+					lastsym[i]=0;
+					argp--;
+					if ((asp = search(lastsym, -1, (HTABLE *)tp))) {
+						str=asp->value.s;
+						if (concat_mode && asp==s && sp->storage_class==sc_vamac && !*str
+							&& psptr[-1]==',')
+								psptr--;
+					} else memexg(lastsym,lastid,MAX_ID_LEN+1);
+					i=strlen(str);
+					memcpy(psptr,str,i); psptr+=i;
+					concat_mode=0;
+				} else if (c=='#') {
+					if (*argp!='#') {	/* single # */
+						int i=0; SYM *asp; char *str=lastsym;
+						if (!isbegidch(c=*argp++))
+							fatal("# id : Syntax");
+						while (isidch(c)) {
+							if (i<MAX_ID_LEN)
+								*str++=c, i++;
+							c=*argp++;
+						}
+						*str=0;
+						argp--;
+						if (!(asp = search(lastsym, -1, (HTABLE *)tp)))
+							fatal("# : arg not found");
+						str=asp->value.s;
+						*psptr++='"';
+						while ((c=*str++)) {
+							if (/*c=='\\' ||*/ c=='"') *psptr++='\\';	// ANSI specifies #x with x=\x7F should be "\x7F"...
+							*psptr++=c;
+						}
+						*psptr++='"';
+						concat_mode=0;
+					} else {			/*  ##  */
+						argp++;
+						concat_mode=1;
+					}
+				} else if (!concat_mode || !isspace(c))
+					concat_mode=0, *psptr++=c;
+			}
+			*psptr=0;
+			q=ps;
+			lptr-=strlen(q);	// se positionner avant le define
+								//	(pas très catholique mais rapide)
+			if ((p=lptr)<linein) fatal("EXPANDED LINE TOO LONG");
+			while ((c=*q++)) *p++=c;
+			goto quit;
+#endif
+		}
+		q=sp->value.s;
+		lptr-=strlen(q)+1;	// se positionner avant le define
+							//	(pas très catholique mais rapide)
+#ifdef OLD_MACRO
+		if (tp) lptr--;
+#endif
+		if ((p=lptr)<linein) fatal("EXPANDED LINE TOO LONG");
+		while ((c=*q++)) *p++=c;
+#ifdef OLD_MACRO
+		if (tp) *p++=' ',*p++=CHAR_POPMAC;
+#endif
+quit:
+		getch();
+		return 1;
+	} else {
+		lastst=id;
+		/*if (preproc_stmt)*/ return 0;
+/*		getcache(id);
+		if (cached_sym==glue) {
+			char b[MAX_ID_LEN]; int n;
+			strcpy(b,lastid);
+			n=strlen(b);
+			getsym();	// flush cache
+			getsym();	// get id
+			if (lastst!=id) error(ERR_SYNTAX);
+			else {
+				memmove(lastid+n,lastid,MAX_ID_LEN-n);
+				memcpy(lastid,b,n);
+			}
+			goto search_id;
+		}*/
+		return 0;
+	}
+}
+
+#else
+
+/*
+ * expand_do(): replace the first 'len' characters of 'in' with the string 'q'.
+ *
+ * The resulting line's terminating zero will not exceed 'inbound' (an error is
+ * raised otherwise), and the dualstack pointer will be updated if
+ * 'need_ds_update' is non-zero.
+ *
+ * The tricky bit is that when DUAL_STACK is defined, [q,q+strlen(q)] can
+ * overlap with [in,inbound[ (although it does not overlap with
+ * [in,in+strlen(in)]).
+ */
+void expand_do(char *q,int len,char *in,char *inbound,int need_ds_update) {
+	int newlen=strlen(q),n=newlen-len,r=inbound-in;
+	unsigned int oldbytes=strlen(in)+1;
+#ifdef DUAL_STACK
+	// we don't care about the terminating zero
+	char *q_overlapfree = alloca(newlen);
+	memcpy(q_overlapfree,q,newlen);
+	//printf("expand('%.*s'->'%s', '%s', %d)\n", len,in, q, in, need_ds_update);
+#else
+	char *q_overlapfree = q;
+#endif
+	if ((unsigned int)(oldbytes+n)>(unsigned int)r)
+		uerrsys("line too long");
+	if (n>0)
+		memmove(in+n,in,oldbytes);
+	else if (n<0)
+		memmove(in,in-n,oldbytes+n);
+	memcpy(in,q_overlapfree,newlen);
+#ifdef DUAL_STACK
+	//printf("  -> '%s'\n", in);
+	if (need_ds_update)
+		ds_update(in+(oldbytes+n));
+#endif
+}
+
+void macro_expansion(char *in,char *inbound,int need_ds_update);
+
+/*
+ * macro_expand(): expand identifier 'id', and depending on the status of 'id':
+ * - if 'id' is not a macro, do nothing and return 0
+ * - if 'id' is an identifier to be protected from expansion, modify 'oldin'
+ *   in-place to prepend an '@@' and return 0
+ * - otherwise, concatenate the expansion of 'id' with the contents of 'in',
+ *   place the result in 'oldin', and return 1
+ *
+ * The resulting line's terminating zero will not exceed 'inbound' (an error is
+ * raised otherwise), and the dualstack pointer will be updated if
+ * 'need_ds_update' is non-zero.
+ *
+ * The relation between 'in' and 'oldin' should fit one of these scenarios:
+ * - in == oldin+strlen(id)  &&  !strncmp(id,oldin,strlen(id))
+ * - in == oldin, and 'id' must not be protected from expansion
+ */
+int macro_expand(char *id,int crc/* may equal -1 */,char *in,char *oldin,char *inbound,int need_ds_update) {
+  restart: {
+	SYM *sp = search(id, crc, &defsyms);
+/*	if ((long)sp==0x7c2040 && asm_flag)
+		bkpt();*/
+	if (!sp) {
+#ifdef MEXP_SUPPORTS_PCH
+		int n=pchsearch(id,PCHS_ADD);
+		if (n>0)
+			goto restart;
+#endif
+		return 0;
+#ifdef PC
+	} else if ((sp->used&PPSYM_UNDER_EXPANSION)) {
+#else
+	} else if ((short)sp->used<0) {
+#endif
+		expand_do("@@",0,oldin,inbound,need_ds_update);
+		return 0;
+	} else if (asm_flag && (sp->used&PPSYM_ASM_KEYWORD) && !(asm_xflag&&!asm_zflag)) {
+		// for the few ASM keywords (e.g. move, b, l, d7) we don't want to perform expansion, unless:
+		// - we are currently parsing an asm operand (asm_xflag!=0)
+		// - *and* we are in __c__ mode (asm_zflag==0)
+		return 0;
+	} else {
+		TABLE *tp;
+		if ((tp=(TABLE *)sp->tp)!=NULL) {
+			int d=0,nmac=(int)(char)sp->used,nargs=0,concat_mode;
+			int string=0,number=0,asm_st=0;
+#ifdef DUAL_STACK
+			void *pop = ds_ensure(800+350);
+			char *args = ds_var(char *);
+			char *ps;
+#else
+			char ps[800],args[350];
+#endif
+			char *argb=args,*argp=args;
+			char c,lastsym[MAX_ID_LEN+1],*psptr;
+			SYM *s=tp->head;
+			while (isspace((c=*in++)));
+			if (c!='(') return 0;
+			sp->used|=PPSYM_UNDER_EXPANSION;
+			while (1) {
+				c=*in++;
+				if (c=='(') d++;
+				else if (c==')') { if (--d<0) break; }
+				else if (c=='"') {
+					*argp++=c;
+					while ((c=*in++) && c!='"') {
+						if (argp>=&args[350-3]) uerrsys("macro arguments too long");
+						*argp++=c;
+						if (c=='\\')	// normally never followed by a 0, since otherwise would be a line continuation
+							*argp++=*in++;
+					}
+					// c is now '"' or 0
+				} else if (c==',' && !d && (sp->storage_class!=sc_vamac || nargs<nmac-1)) {
+					if (nargs<nmac) {
+						while (isspace(argp[-1]))	/* remove trailing whitespace */
+							argp--;
+						*argp++=0; s->value.s=argb; nargs++; argb=argp;
+						s=s->next; continue;
+					} else
+						uerrc("too many args to macro");
+				}
+				if (argb!=argp || !isspace(c))	/* remove leading whitespace */
+					*argp++=c;
+				if (argp>=&args[350]) uerrsys("macro arguments too long");
+			}
+			if (tp->head) {
+				while (isspace(argp[-1]))	/* remove trailing whitespace */
+					argp--;
+				*argp=0;
+				if (!s) uerrc("too many args to macro");
+				s->value.s=argb;
+				nargs++;				/* if var, this argument might appear to be "" */
+			}
+			if (nargs<nmac) uerrc("too few args to macro");
+#ifdef DUAL_STACK
+			ds_update(argp+1);
+			ps = ds_var(char *);
+#endif
+			argp=sp->value.s;
+			psptr=ps; concat_mode=0;
+#ifdef ASM
+			if (asm_flag && !(sp->used&PPSYM_DEFINED_IN_ASM) && !(asm_xflag&&!asm_zflag)) {
+				// unless we're already in __c__ mode, transform C defines to
+				// '(unsigned long)__c__(normal_value)'
+				// (note: we assimilate !asm_xflag to non-__c__ mode, because
+				// otherwise getsym caching causes problems)
+				//
+				// IMPORTANT: this code has a counterpart a few lines below,
+				// don't forget to keep it in sync
+				strcpy(psptr,"(unsigned long)__c__(");
+				psptr+=strlen(psptr);
+			}
+#endif
+			while ((c=*argp++)) {
+				if (!isidch(c)) number=0;
+				if (c=='\\') { *psptr++=c; c=*argp++; if (!c) break; goto write; }
+				else if (c=='"') { string=~string; goto write; }
+				else if (c=='{') { if (asm_st<0) asm_st=100,asm_flag++; goto write; }
+				else if (c=='}') { if (asm_st>0) asm_st=0,asm_flag--; goto write; }
+				else if (c>='0' && c<='9' && !string) { number=1; goto write; }
+				else if (isbegidch(c) && !string && !number) {
+					int i=0; SYM *asp; char *str=lastsym;
+					while (isidch(c)) {
+						if (i<MAX_ID_LEN)
+							lastsym[i]=c, i++;
+						c=*argp++;
+					}
+					lastsym[i]=0;
+					argp--;
+					if (lastsym[0]=='a' && lastsym[2]=='m' && !lastsym[3] && lastsym[1]=='s')
+						asm_st--;
+					if ((asp = search(lastsym, -1, (HTABLE *)tp)))
+						str=asp->value.s;
+					strcpy(psptr,str);
+#ifdef NONSTD_MACRO_CONCAT
+					#ifdef DUAL_STACK
+					#error fixme
+					#endif
+					if (asp) macro_expansion(psptr,&ps[800],1);
+#endif
+#ifdef STD_MACRO_CONCAT
+					if (!concat_mode) {
+						char *p=argp;
+						while (isspace(*p)) p++;
+						if (!(*p=='#' && p[1]=='#')) {
+					#ifdef DUAL_STACK
+							ds_update(psptr+strlen(psptr)+1);
+					#endif
+							macro_expansion(psptr,&ps[800],1);
+						}
+					}
+#endif
+					psptr+=strlen(psptr);
+					concat_mode=0;
+				} else if (c=='#' && !string) {
+					if (*argp!='#') {	/* single # */
+						int i=0; SYM *asp; char *str=lastsym;
+						char *argpsave=argp;
+						while (isspace(*argp)) argp++;
+						if (!isbegidch(c=*argp++))
+//							uerrc("# : syntax");
+							{ c='#'; argp=argpsave; goto write; }
+								/* (because of immediate data in ASM macros) */
+						while (isidch(c)) {
+							if (i<MAX_ID_LEN)
+								*str++=c, i++;
+							c=*argp++;
+						}
+						*str=0;
+						argp--;
+						if (!(asp = search(lastsym, -1, (HTABLE *)tp)))
+//							uerrc("# : arg not found");
+							{ c='#'; argp=argpsave; goto write; }
+								/* (because of immediate data in ASM macros) */
+						str=asp->value.s;
+						*psptr++='"';
+						while ((c=*str++)) {
+							if (/*c=='\\' ||*/ c=='"') *psptr++='\\';	// ANSI specifies #x with x=\x7F should be "\x7F"...
+							*psptr++=c;
+						}
+						*psptr++='"';
+						concat_mode=0;
+					} else {			/*  ##  */
+						argp++;
+						concat_mode=1;
+						while (isspace(psptr[-1])) psptr--;
+					}
+				} else if (!concat_mode || !isspace(c)) {
+				  write:
+					concat_mode=0, *psptr++=c;
+				}
+			}
+			if (asm_st>0) asm_flag--;
+			if (string) uerrc("unbalanced quote");
+#ifdef ASM
+			if (asm_flag && !(sp->used&PPSYM_DEFINED_IN_ASM) && !(asm_xflag&&!asm_zflag)) {
+				*psptr++=')';
+			}
+#endif
+			*psptr=0;
+#ifdef DUAL_STACK
+			ds_update(psptr+1);
+#endif
+#if defined(NONSTD_MACRO_CONCAT_V2) || defined(STD_MACRO_CONCAT)
+			macro_expansion(ps,&ps[800],1);
+#endif
+			expand_do(ps,in-oldin,oldin,inbound,need_ds_update);
+#ifdef DUAL_STACK
+			/*
+			 * Note: this is slightly tricky, as expand_do() may overwrite part
+			 * of 'ps', 'args', and stuff like that. But it will not do
+			 * anything wrong, because [in,inbound[ was reserved by the caller,
+			 * and we are not writing outside of it.
+			 *
+			 * In fact, the key to this working is that we can postpone any
+			 * ds_pop()ing operation, as long as we do not ds_ensure() or
+			 * ds_pop() anything else during that time interval, and as long as
+			 * we back up the correct dualstack after the ds_pop(). This
+			 * wouldn't be true if for example ds_pop() relied on reading some
+			 * backup data from the dualstack and this backup data could happen
+			 * to be in a previously ds_ensure()d zone.
+			 */
+			{
+				// in fact, this is the caller dualstack only if
+				// 'need_ds_update' made 'expand_do' update dualstack,
+				// so we recall it only in this case.
+				void *caller_dualstack = dualstack;
+				ds_pop(pop);
+				if (need_ds_update)
+					ds_update(caller_dualstack);
+			}
+#endif
+		} else
+			sp->used|=PPSYM_UNDER_EXPANSION, expand_do(sp->value.s,in-oldin,oldin,inbound,need_ds_update);
+		sp->used&=~PPSYM_UNDER_EXPANSION;
+		return 1;
+	}
+  }
+}
+/*
+ * macro_expansion(): scan the string starting from 'in', expanding any
+ * identifiers.
+ * Modifies 'in' in-place, but only by calling macro_expand(), which in turn
+ * will only modify it through expand_do(). The dualstack size will be updated
+ * when 'need_ds_update' is non-zero.
+ */
+void macro_expansion(char *in,char *inbound,int need_ds_update) {
+	char c,*p=in; char newid[MAX_ID_LEN+1]; int string=0,number=0;
+	int asm_st=0;
+	while ((c=*p++)) {
+		if (((c>='0' && c<='9') || c=='@') && !string) number=1;/* so that @@id isn't expanded */
+		else if (!string && isbegidch(c)) {
+			if (!number) {
+				int i=0; char *begin=p-1;
+				while (isidch(c)) {
+					if (i<MAX_ID_LEN)
+						newid[i]=c, i++;
+					c=*p++;
+				}
+				newid[i]=0;
+				p--;
+				if (newid[0]=='a' && newid[2]=='m' && !newid[3] && newid[1]=='s')
+					asm_st--;
+				if (macro_expand(newid,-1,p,begin,inbound,need_ds_update)) p=begin;
+			}	/* otherwise don't do anything! (0xa with #define xa foo shouldn't do 0foo) */
+		} else if (c=='\\') p++;
+		else {
+			number=0;
+			if (c=='"') string=~string;
+			else if (c=='{' && asm_st<0) asm_st=100,asm_flag++;
+			else if (c=='}' && asm_st>0) asm_st=0,asm_flag--;
+		}
+	}
+	if (asm_st>0) asm_flag--;
+	if (string) uerrc("unmatched quote in macro");
+}
+int getid(int c) {
+	register int	i;
+	int res;
+	if (c>=0) {
+		lastid[0] = c;
+		i = 1;
+		while (isidch(lastch)) {
+			if (i < MAX_ID_LEN)
+				lastid[i++] = lastch;
+			getch();
+		}
+		lastid[i] = '\0';
+	}
+#ifdef PCH
+	if (!lastid[1] && lastid[0]=='_')
+		memcpy(lastid,curpch,MAX_ID_LEN+1);
+#endif
+	lastcrc=crcN(lastid);
+	/*if (!strcmp(lastid,"OSContrastUp"))
+		bkpt();*/
+	*--lptr=lastch;
+//	balance_parenthesis(lptr);
+	/*if (!strcmp(lastid,"put_sprite_24"))
+		printf("gjioh");*/
+	if (!(res=macro_expand(lastid,lastcrc,lptr,lptr,linemax,0)))
+		lastst=id;
+	getch();
+	return res;
+}
+#endif
+
+/*
+ * getsch - get a character in a quoted string.
+ *
+ * this routine handles all of the escape mechanisms for characters in strings
+ * and character constants.
+ * flag is 0, if a character constant is being scanned,
+ * flag is 1, if a string constant is being scanned
+ */
+int getsch(int flag) {
+	/* flag = "return an in-quote character?" */
+	register int	i, j;
+/*
+ * if we scan a string constant, stop if '"' is seen
+ */
+	if (flag && lastch == '"') {
+		getch();
+		if (!preproc_stmt) {
+			if (getcache(sconst)) {
+				getch();
+				return getsch(1);
+			}
+		}
+		return -1;
+	}
+	if (lastch != '\\') {
+		i = lastch;
+		getch();
+		return i;
+	}
+	getch();					/* get an escaped character */
+	if (isdigit(lastch)) {
+		i = 0;
+		for (j = 0; j < 3; ++j) {
+			if (isdigit(lastch) && lastch <= '7')
+				i = 8*i + radix36(lastch);
+			else
+				break;
+			getch();
+		}
+//		/* signed characters lie in the range -128..127 => shit so disabled */
+//		if ((i &= 0377) >= 128) i -= 256;
+		return i;
+	}
+	i = lastch;
+	getch();
+	switch (i) {
+	  case '\n':
+		return getsch(flag);
+	  case 'b':
+		return '\b';
+	  case 'f':
+		return '\f';
+	  case 'n':
+		return '\n';
+	  case 'r':
+		return '\r';
+	  case 't':
+		return '\t';
+	  case 'a':
+		return '\a';
+	  case 'v':
+		return '\v';
+	  case 'e':
+		return '\x1B';
+	  case 'x':
+		if ((i=radix36(lastch))<0 || i>=16)
+			error(ERR_SYNTAX);
+		getch();
+		if ((j=radix36(lastch))>=0 && j<16) {
+			i = 16*i + j;
+			getch();
+		}
+//		/* signed characters lie in the range -128..127 => shit so disabled */
+//		if (i >= 128) i -= 256;
+		return i;
+	  default:
+		uwarn("'%c' isn't an escaped character",i);
+		/* FALL THROUGH */
+	  case '\\': case '"': case '\'':
+		return i;
+	}
+}
+
+int radix36(char c) {
+/*
+ * This function makes assumptions about the character codes.
+ */
+	if (isdigit(c))
+		return c - '0';
+	if (c >= 'a' && c <= 'z')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'Z')
+		return c - 'A' + 10;
+	return -1;
+}
+#ifndef AS	/* otherwise in out68k_as.c */
+int hexatoi(char *s) {
+	int x=0;
+	if (strlen(s)>3) return -1;
+	while (*s) {
+		int y=radix36(*s++);
+		if (y<0) return -1;
+		x<<=4; x+=y;
+	}
+	return x;
+}
+#endif
+
+static void test_int(int hex_or_octal) {
+/* test on long or unsigned constants */
+	if (lastch == 'l' || lastch == 'L') {
+		getch();
+		lastst = lconst;
+		return;
+	}
+	if (lastch == 'u' || lastch == 'U') {
+		/*if (!hex_or_octal)  -> why was it so??? */
+			getch();
+		lastst = uconst;
+		if (lastch=='l' || lastch=='L')
+			getch(), lastst = ulconst;
+		if (short_option && ival > 65535)
+			lastst = ulconst;
+		return;
+	}
+	if ((long)ival<0) {			/* since '-' is treated as unary minus, this only */
+		lastst = ulconst;		/*  happens for values that are >0x7FFFFFFF       */
+		return;
+	}
+
+	/* -32768 thus is stored as (unary minus)(32768l) */
+/*
+ * Although I think it is not correct, octal or hexadecimal
+ * constants in the range 0x8000 ... 0xffff are unsigned in 16-bit mode
+ */
+	if (short_option) {
+		if (hex_or_octal && ival > 32767 && ival < 65536) {
+			lastst = uconst;
+			return;
+		}
+		if (ival > 32767) {
+			/* -32768 thus is stored as (unary minus)(32768l) */
+			lastst = lconst;
+			return;
+		}
+	}
+}
+
+/*
+ * getbase - get an integer in any base.
+ *  b==0 : base 10
+ *  b!=0 : base 1<<b (1,3,4)
+ */
+static void getbase(int b) {
+	/*
+	 * rval is computed simultaneously - this handles floating point
+	 * constants whose integer part is greater than INT_MAX correctly, e. g.
+	 * 10000000000000000000000.0
+	 */
+	register unsigned long i=0;
+	register int	j;
+#ifndef NOFLOAT
+	register double r = 0;
+#endif
+
+	if (!b) {
+		while (isdigit(lastch)) {
+			j = radix36(lastch);
+			i = 8 * i + 2 * i + j;
+#ifndef NOFLOAT
+#ifdef PC
+			r = 10.0 * r + (double) j;
+#else
+			r = ffpadd(ffpmul(FFP_TEN, r), ffputof(j));
+#endif
+#endif
+			getch();
+		}
+	} else {
+		while (isalnum(lastch)) {
+			if (!((j = radix36(lastch)) >> b)) {
+				i = (i << b) + j;
+				getch();
+			} else
+				break;
+		}
+	}
+	ival = i;
+#ifndef NOFLOAT
+	rval = r;
+#endif
+	lastst = iconst;
+}
+
+#ifndef NOFLOAT
+/*
+ * getfrac - get fraction part of a floating number.
+ */
+static void getfrac() {
+	double frmul;
+#ifdef PC
+	frmul = 0.1;
+#else
+	frmul = FFP_TENINV;
+#endif
+	while (isdigit(lastch)) {
+#ifdef PC
+		rval += frmul * radix36(lastch);
+#else
+		rval = ffpadd(rval, ffpmul(frmul, ffputof(radix36(lastch))));
+#endif
+		getch();
+#ifdef PC
+		frmul *= 0.1;
+#else
+		frmul = ffpmul(frmul, FFP_TENINV);
+#endif
+	}
+}
+
+/*
+ * getexp - get exponent part of floating number.
+ *
+ * this algorithm is primative but usefull.  Floating exponents are limited to
+ * +/-255 but most hardware won't support more anyway.
+ */
+static void getexp() {
+	double			expo, exmul;
+	expo = rval;
+	if (lastch == '-') {
+#ifdef PC
+		exmul = 0.1;
+#else
+		exmul = FFP_TENINV;
+#endif
+		getch();
+	} else
+#ifdef PC
+		exmul = 10.0;
+#else
+		exmul = FFP_TEN;
+#endif
+	getbase(0);
+	lastst = rconst;
+	while (ival--)
+#ifdef PC
+		expo *= exmul;
+#else
+		expo = ffpmul(expo, exmul);
+#endif
+	rval = expo;
+}
+#endif
+
+/*
+ * getnum - get a number from input.
+ *
+ * getnum handles all of the numeric input. it accepts decimal, octal,
+ * binary, hexadecimal, and floating point numbers.
+ */
+static void getnum() {
+		if (lastch == '0') {
+				getch();
+				if (lastch == 'x' || lastch == 'X') {
+						getch();
+						getbase(4);
+						test_int(1);
+						return;
+				}
+				if (lastch == 'b' || lastch == 'B') {
+						getch();
+						getbase(1);
+						test_int(1);
+						return;
+				}
+				if (lastch != '.' && lastst != 'e' && lastst != 'E') {
+						getbase(3);
+						test_int(1);
+						return;
+				}
+		}
+		getbase(0);
+#ifndef NOFLOAT
+		if (lastch == '.') {
+				/* rval already set */
+				getch();
+				getfrac();				/* add the fractional part */
+				lastst = rconst;
+		}
+		if (lastch == 'e' || lastch == 'E') {
+				getch();
+				getexp();				/* get the exponent */
+		}
+#endif
+		/*
+		* look for l and u qualifiers
+		*/
+		if (lastst == iconst)
+				test_int(0);
+	/*
+				* look for (but ignore) f and l qualifiers
+		*/
+		if (lastst == rconst)
+				if (lastch == 'f' || lastch == 'F' || lastch == 'l' ||
+						lastch == 'L')
+						getch();
+}
+
+#ifdef PCH
+#ifndef PC
+#include "sUnpack.c"
+#endif
+char sUnpackBuf[500];
+int pchload(char *name,char *data,unsigned int flags,unsigned char *tabp, unsigned char *p0,TI_SHORT *extTab) {
+	struct sym *sp = 0;
+	int r=0;
+	char na[MAX_ID_LEN+1];
+	char oldpch[MAX_ID_LEN+1];
+#ifdef MIN_TEMP_MEM
+	int old_min_temp_mem=min_temp_mem;
+	min_temp_mem=temp_mem;
+#endif
+	(*tabp)++;
+/*	if (!strcmp(name,"compare_t"))
+		bkpt();*/
+	if (*data || (flags&PCHID_MACRO)) {		// is there a #define ?
+		int n=0;
+#ifndef LOWMEM
+		global_flag++;
+#endif
+		sp = (SYM *)xalloc((int)sizeof(SYM), _SYM+DODEFINE);
+/*		if ((long)sp==0x789388)
+			bkpt();*/
+		sp->name = strsave(name);
+		sp->storage_class = sc_define;
+#ifdef NO_CALLOC
+		sp->tp=NULL;
+#endif
+		if (flags&PCHID_MACRO) {
+			TABLE *tp;
+			sp->tp=(TYP *)(tp=(TABLE *)xalloc((int)sizeof(TABLE), _TABLE+DODEFINE));
+	#ifdef NO_CALLOC
+			tp->hash=0;
+			tp->head=tp->tail=NULL;
+	#endif
+			if (*data) {
+				while (*data) {
+					SYM *arg;
+					n++;
+					arg=(SYM *)xalloc((int)sizeof(SYM), _SYM+DODEFINE);
+					arg->name=data;
+	#ifdef NO_CALLOC
+					arg->tp=NULL;
+	#endif
+					insert(arg,(HTABLE *)tp);
+					while (*data++);
+				}
+				if (flags&PCHID_VAMAC) sp->storage_class = sc_vamac;
+			}
+			data++;
+		}
+		if (flags&PCHID_PACKED)
+			sp->value.s = strsave(sUnpack(data,sUnpackBuf,p0+w2us(((PCH_HEAD *)p0)->dic_off)));
+		else sp->value.s = data;
+		insert(sp,&defsyms);
+		sp->used=n;
+#ifndef LOWMEM
+		global_flag--;
+#endif
+		r=1;
+	}
+	while (*data++);
+	if (*data) {
+		TYP *head0=head,*tail0=tail;
+		char *declid0=declid;
+		int nparms0=nparms;
+		char *names0[MAX_PARAMS];
+		int bit_offset0=bit_offset, bit_width0=bit_width, bit_next0=bit_next;
+		int decl1_level0=decl1_level,pch_init0=pch_init;
+		char lptr_save[LINE_LENGTH]; int l=strlen(data); // TODO: use DUAL_STACK for saving lptr
+		struct enode *old_init_node=init_node;
+		int old_middle_decl=middle_decl;
+		int lcrc=lastcrc;
+#ifdef MEXP_SUPPORTS_PCH
+		char *old_lptr=lptr;
+		char *old_linemin=linemin,*old_linemax=linemax;
+#endif
+		memcpy(names0,names,MAX_PARAMS*sizeof(char *));
+		memcpy(na,lastid,MAX_ID_LEN+1);
+		memcpy(oldpch,curpch,MAX_ID_LEN+1);
+		memcpy(curpch,name,MAX_ID_LEN+1);
+#ifdef MEXP_SUPPORTS_PCH
+		lptr=lptr_save+1;
+		linemin=lptr_save,linemax=lptr_save+LINE_LENGTH;
+#else
+		memcpy(lptr_save,lptr-1,LINE_LENGTH);
+#endif
+		pch_init=1;
+		lastch=' ';
+		head=tail=0;
+		init_node=0;
+		middle_decl=0;
+		decl1_level=0;
+#ifndef MEXP_SUPPORTS_PCH
+#ifdef OLD_MACRO
+		lptr=linein+MAX_MAC_LEN+1;
+#else
+		lptr=linein+1;
+#endif
+#endif
+		sUnpack(data,lptr,p0+w2us(((PCH_HEAD *)p0)->dic_off));
+		l=strlen(lptr);
+/*		memcpy(lptr,data,l);*/
+		memcpy(lptr+l," alloca  ",10);	/* the spaces are the end are there because we don't */
+		global_flag++;					/*  want to read a new line (otherwise bugs)         */
+		getsym();
+		while (lastst != kw_alloca) {
+			dodecl(sc_global);
+			if (lastst != kw_alloca)
+				getsym();
+		}
+		global_flag--;
+#ifdef MEXP_SUPPORTS_PCH
+		lptr=old_lptr-1;	/* so that it re-reads the last char */
+		linemin=old_linemin,linemax=old_linemax;
+#else
+#ifdef OLD_MACRO
+		lptr=linein+MAX_MAC_LEN+1;
+#else
+		lptr=linein+1;
+#endif
+		memcpy(lptr,lptr_save,LINE_LENGTH);	/* so that it re-reads the last char */
+#endif
+		getch();
+		lastst = id;
+		memcpy(lastid,na,MAX_ID_LEN+1);
+		memcpy(curpch,oldpch,MAX_ID_LEN+1);
+		init_node=old_init_node;
+		middle_decl=old_middle_decl;
+		head=head0; tail=tail0;
+		pch_init=pch_init0;
+		declid=declid0;
+		nparms=nparms0;
+		bit_offset=bit_offset0; bit_width=bit_width0; bit_next=bit_next0;
+		decl1_level=decl1_level0;
+		lastcrc=lcrc;
+		memcpy(names,names0,MAX_PARAMS*sizeof(char *));
+	}
+#ifdef AS							/* .ext management is enabled only in AS mode */
+	while (*data++);
+	if (*data) {
+		unsigned char *ext=p0+w2us(extTab[*data-1]);
+		extscan(ext);				/* load .ext files used by current ext */
+		extload(ext);				/* now write it :) */
+	}
+#endif
+#ifndef MEXP_SUPPORTS_PCH
+	if (r) getid(-1);
+#endif
+#ifndef MEXP_SUPPORTS_PCH
+	(*tabp)--;
+#endif
+#ifdef MIN_TEMP_MEM
+	min_temp_mem=old_min_temp_mem;
+#endif
+	return r;
+}
+
+int pchsearch(char *id,int mode) {	/* returns 0 if not PCH, 1 if PCH/def, -1 if PCH/init */
+	int n=pchnum;
+	/*if (!strcmp(id,"LINK_ME"))
+		bkpt();*/
+/*	if (!strcmp(id,"unpack"))
+		bkpt();*/
+	while (n--) {
+		unsigned char *p0=pchdata[n],*tab=pchtab[n],*tabp,*p,c,*q;
+		TI_SHORT *extTab=(TI_SHORT *)(p0+w2us(pchhead[n]->ext_off));
+		int z=PCH_HEAD_SIZE;
+		do {
+			p=p0+z; q=id;
+			while ((c=*p++) && c==*q++);
+			if (!c && !*q) {
+				int idnum=(p[4]<<8)+p[5];
+				tabp=&tab[idnum&PCHID_MASK];
+				if (*tabp)			/* really quit, because it would be a mess   */
+					return 0;		/*  if we scanned other files for this ID ;) */
+				if (mode>0) {		/* mode==PCHS_ADD */
+#ifdef REQ_MGT
+					pchrequired[n]=1;
+#endif
+					return pchload(id,p+6,idnum,tabp,p0,extTab)?1:-1;
+				} else			/* mode==PCHS_UNLOAD */
+					(*tabp)++;		/* forbid the loading of this symbol */
+			}
+			if (c) while (*p++);
+			if (c<q[-1]) p+=2;
+			z=(*p++)<<8; z+=*p;
+		} while (z);
+	}
+	return 0;
+}
+#endif
+
+/*
+ * getsym - get next symbol from input stream.
+ *
+ * getsym is the basic lexical analyzer.
+ * It builds basic tokens out of the characters on the input stream
+ * and sets the following global variables:
+ *
+ * lastch:		A look behind buffer.
+ * lastst:		type of last symbol read.
+ * laststr: 	last string constant read.
+ * lastid:		last identifier read.
+ * ival:		last integer constant read.
+ * rval:		last real constant read.
+ *
+ * getsym should be called for all your input needs...
+ */
+
+void getsym() {
+		register int	i, j;
+		got_sym = 1;
+		prevlineid = lineid;
+		if ((int)cached_sym IS_VALID) {
+			lastst=cached_sym; lineid=cached_lineid; cached_sym=-1;
+			return;
+		}
+restart:						/* we come back here after comments */
+		skipspace();
+		lineid = lineno;
+		if (lastch IS_INVALID)
+				lastst = eof;
+		else if (isdigit(lastch))
+				getnum();
+		else if (isidch(lastch)) {
+				if (forbid==(lastst=id)) return;
+				i=lastch; getch();
+				if (getid(i)) goto restart;
+		} else
+				switch (lastch) {
+				case '+':
+						getch();
+						if (lastch == '+') {
+								getch();
+								lastst = autoinc;
+						} else if (lastch == '=') {
+								getch();
+								lastst = asplus;
+						} else
+								lastst = plus;
+						break;
+				case '-':
+						getch();
+						if (lastch == '-') {
+								getch();
+								lastst = autodec;
+						} else if (lastch == '=') {
+								getch();
+								lastst = asminus;
+						} else if (lastch == '>') {
+								getch();
+								lastst = pointsto;
+						} else
+								lastst = minus;
+						break;
+				case '*':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = astimes;
+						} else
+								lastst = star;
+						break;
+				case '/':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = asdivide;
+						/*} else if (lastch == '*') {
+								getch();
+								for (;;) {
+										if (lastch == '*') {
+												getch();
+												if (lastch == '/') {
+														getch();
+														goto restart;
+												}
+										} else getch();
+								}
+						} else if (lastch == '/') {
+								getch();
+								for (;;) {
+										if (lastch == '\n') {
+												getch();
+												goto restart;
+										} else getch();
+								}*/
+						} else
+								lastst = divide;
+						break;
+				case '^':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = asuparrow;
+						} else
+								lastst = uparrow;
+						break;
+				case ';':
+						getch();
+						lastst = semicolon;
+						break;
+				case ':':
+						getch();
+						lastst = colon;
+						break;
+				case '=':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = eq;
+						} else
+								lastst = assign;
+						break;
+				case '>':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = geq;
+						} else if (lastch == '>') {
+								getch();
+								if (lastch == '=') {
+										getch();
+										lastst = asrshift;
+								} else
+										lastst = rshift;
+						} else
+								lastst = gt;
+						break;
+				case '<':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = leq;
+						} else if (lastch == '<') {
+								getch();
+								if (lastch == '=') {
+										getch();
+										lastst = aslshift;
+								} else
+										lastst = lshift;
+						} else
+								lastst = lt;
+						break;
+				case '\'':
+						getch();
+						ival = getsch(0);		/* get a string char */
+						if (lastch != '\'')
+								error(ERR_SYNTAX);
+						else
+								getch();
+						lastst = iconst;
+						break;
+				case '\"':
+					if (forbid!=sconst) {
+						getch_in_string=1;
+						getch();
+						for (i = 0; ; ++i) {
+								if ((j = getsch(1)) IS_INVALID)
+										break;
+								if (i < MAX_STRLEN)
+										laststr[i] = j;
+						}
+						getch_in_string=0;
+						/*
+			 * Attention: laststr may contain zeroes!
+			 */
+						if (i > MAX_STRLEN) {
+								i = MAX_STRLEN;
+								uwarn("string constant too long");
+						}
+						lstrlen = i;
+						laststr[i] = 0;
+					}
+					lastst = sconst;
+					break;
+				case '!':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = neq;
+						} else
+								lastst = not;
+						break;
+				case '%':
+						getch();
+						if (lastch == '=') {
+								getch();
+								lastst = asmodop;
+						} else
+								lastst = modop;
+						break;
+				case '~':
+						getch();
+						lastst = compl;
+						break;
+				case '.':
+						getch();
+						if (isdigit(lastch)) {
+#ifndef NOFLOAT
+							rval = 0;
+							getfrac();
+#endif
+							lastst = rconst;
+							if (lastch=='e' || lastch=='E') {
+								getch();
+#ifndef NOFLOAT
+								getexp();
+#endif
+							}
+						} else if (lastch=='.') {
+							getch();
+							if (lastch!='.') error(ERR_SYNTAX);
+							getch();
+							lastst = dots;
+						} else
+							lastst = dot;
+						break;
+				case ',':
+						getch();
+						lastst = comma;
+						break;
+				case '&':
+						getch();
+						if (lastch == '&') {
+								lastst = land;
+								getch();
+						} else if (lastch == '=') {
+								lastst = asand;
+								getch();
+						} else
+								lastst = and;
+						break;
+				case '|':
+						getch();
+						if (lastch == '|') {
+								lastst = lor;
+								getch();
+						} else if (lastch == '=') {
+								lastst = asor;
+								getch();
+						} else
+								lastst = or;
+						break;
+				case '(':
+						getch();
+#ifdef ASM
+#ifdef OLD_AMODE_INPUT
+						if (asm_xflag
+							&& ((lastch=='p' && *lptr=='c')
+								|| (lastch=='s' && *lptr=='p')
+								|| (lastch=='a' && *lptr>='0' && *lptr<='7'))
+							&& (lptr[1]==')' || lptr[1]==','))
+								lastst = kw_offs_end;
+						else
+#else
+						if (asm_xflag
+							&& ((lastch=='p' && *lptr=='c')
+								|| (lastch=='s' && *lptr=='p')
+								|| (lastch=='a' && *lptr>='0' && *lptr<='7'))
+							&& (lptr[1]==')' || lptr[1]==','))
+								lastst_flag=1;
+						else	lastst_flag=0;
+#endif
+#endif
+							lastst = openpa;
+						break;
+				case ')':
+						getch();
+						lastst = closepa;
+						break;
+				case '[':
+						getch();
+						lastst = openbr;
+						break;
+				case ']':
+						getch();
+						lastst = closebr;
+						break;
+				case '{':
+						getch();
+						lastst = begin;
+						break;
+				case '}':
+						getch();
+						lastst = end;
+						break;
+				case '?':
+						getch();
+						lastst = hook;
+						break;
+				case '#':
+						getch();
+						// TODO: rewrite the following (disabled because not ANSI-compliant)
+						/*getsym();
+						if (lastst==id) {
+							SYM *sp;
+							if (mac_sp!=&mac_stk[MAX_MAC_NUM] &&
+								(sp = search(lastid, lastcrc, (HTABLE *)*mac_sp))) {
+								char c,*q=sp->value.s; char buf[MAX_STRLEN],*bp; int i;
+								lastst=sconst;
+								bp=buf;
+								*bp++='"';
+								i=MAX_STRLEN-1-2;
+								do {
+									if (!(c=*q++)) break;
+									if (c=='"') { *bp++='\\'; *bp++='"'; }
+									else *bp++=c;
+								} while (i--);
+								*bp++='"';
+								lptr-=bp-buf+1;
+								memcpy(lptr,buf,bp-buf);
+								getch();
+							} else error(ERR_UNDEFINED);
+						} else if (lastst==lconst||lastst==iconst||lastst==uconst) {
+								char buf[MAX_STRLEN],*bp;
+								lastst=sconst;
+								bp=buf;
+								*bp++='"';
+								sprintf(bp,"%ld",ival);
+								bp+=strlen(bp);
+								*bp++='"';
+								lptr-=bp-buf+1;
+								memcpy(lptr,buf,bp-buf);
+								getch();
+						} else error(ERR_IDEXPECT);
+						getsym();*/
+#ifdef ASM
+						if (asm_flag) {
+							lastst = sharp;
+							break;
+						} else {
+#endif
+							error(ERR_ILLCHAR);
+							goto restart;	/* get a real token */
+#ifdef ASM
+						}
+#endif
+/*						if (lastst==iconst || lastst==lconst || lastst==uconst) {
+							lastst=sconst;
+							if (forbid!=lastst) sprintf(laststr,"%ld",ival);
+							else {
+								char b[20]; int n;
+								sprintf(b,"%ld",ival);
+								lptr-=1+(n=strlen(b));
+								strncpy(lptr,b,n);
+								lptr[n]='"';
+							}
+						} else error(ERR_INTEGER);*/
+						break;
+#ifdef ASM
+				case '\\':
+						if (asm_flag) {
+							if (forbid==(lastst=id)) return;
+							getch();
+							if (getid((int)'\\')) goto restart;
+						} else {
+							getch();
+							error(ERR_ILLCHAR);
+							goto restart;	/* get a real token */
+						}
+						break;
+#endif
+				case '@':
+						getch();
+						if (lastch=='@') {
+							getch();
+							if (isbegidch(lastch)) {
+								if (forbid==(lastst=id)) return;
+								getrawid();
+								break;
+							}
+						}
+						/* otherwise fall through */
+				default:
+						getch();
+						error(ERR_ILLCHAR);
+						goto restart;	/* get a real token */
+		}
+		if (lastst == id) {
+			searchkw();
+//#ifdef OLD_MACRO
+			if (lastst == kw_eval) {
+				struct enode *ep;
+				getsym();
+				needpunc(openpa);
+				if (!expression(&ep)) error(ERR_EXPREXPECT);
+				if (lastst!=closepa) needpunc(closepa);
+				opt0(&ep);
+				if (ep->nodetype==en_icon) {
+					lastst=lconst;
+					ival=ep->v.i;
+#ifndef NOFLOAT
+				} else if (ep->nodetype==en_fcon) {
+					lastst=rconst;
+					rval=ep->v.f;
+#endif
+				} else error(ERR_CONSTEXPECT);
+			}
+#ifdef ASM
+			else if (asm_flag && lastst == id) {
+				if (!lastid[2]) {
+					if (lastid[1]>='0' && lastid[1]<='7') {
+						lastreg=lastid[1]-'0';	// we don't care if we set lastreg even if
+						if (lastid[0]=='d')		//  lastst is an id
+							lastst=kw_dreg;		// (for example 'z6' will set lastreg to 6)
+						else if (lastid[0]=='a')
+							lastst=kw_areg;
+					} else if (lastid[1]=='p' && lastid[0]=='s')
+						lastst=kw_areg,lastreg=7;
+				}
+				asm_searchkw();
+			}
+#endif
+#if defined(PCH) && !defined(MEXP_SUPPORTS_PCH)
+			if (lastst==id && !(lastsp = search(lastid, lastcrc, &lsyms))
+				 && !(lastsp = search(lastid, lastcrc, &gsyms))) {
+#if 0
+				int n=pchnum;
+				while (n--) {
+					unsigned char *p0=pchdata[n],*tab=pchtab[n],*tabp,*p,c,*q;
+					TI_SHORT *extTab=(TI_SHORT *)(p0+w2s(pchhead[n]->ext_off));
+					int z=PCH_HEAD_SIZE;
+					do {
+						p=p0+z; q=lastid;
+						while ((c=*p++) && c==*q++);
+						if (!c && !*q) {
+							tabp=&tab[(p[4]<<8)+p[5]];
+							if (*tabp)			/* really quit, because it would be a mess   */
+								goto pch_done;	/*  if we scanned other files for this ID ;) */
+							if (pchload(p+6,tabp,p0,extTab)) goto restart;
+							else {
+								lastsp = gsearch(lastid, lastcrc);
+								goto pch_done;
+							}
+						}
+						if (c) while (*p++);
+						if (c<q[-1]) p+=2;
+						z=(*p++)<<8; z+=*p;
+					} while (z);
+				}
+			  pch_done:
+				(void)0;
+#else
+				int n=pchsearch(lastid,PCHS_ADD);
+				if (n>0) goto restart;
+				else if (n<0) lastsp = gsearch(lastid, lastcrc);
+#endif
+			}
+#else
+			if (lastst==id && !(lastsp = search(lastid, lastcrc, &lsyms)))
+				 lastsp = search(lastid, lastcrc, &gsyms);
+#endif
+		}
+/*		if (global_flag)
+		if (lastst==id && !strcmp(lastid,"pos"))
+			bkpt();*/
+/*	if (lineid==0x51)
+		bkpt();*/
+}
+
+int getcache(enum(e_sym) f) {
+	enum(e_sym) my_st=lastst;
+	int my_flag=lastst_flag;
+	int my_line=lineid,my_prev=prevlineid;
+	if (cached_sym!=-1) return (cached_sym==f);
+	cached_sym=-2;	// tell getcache not to put anything into cache
+	forbid=f;
+	getsym();
+	cached_sym=lastst;
+	cached_flag=lastst_flag;
+	cached_lineid=my_line;
+	lastst=my_st;
+	lastst_flag=my_flag;
+	lineid=my_line;
+	prevlineid=my_prev;
+	forbid=-1;
+	if (cached_sym==f) cached_sym=-1;
+	return (cached_sym==-1);
+/*	enum(e_sym) my_st=lastst,cached=cached_sym;
+	if ((int)cached_sym2 IS_VALID) return (cached_sym2==f);
+	cached_sym=-1;	// prevent getsym from caching :)
+	forbid=f;
+	getsym();
+	forbid=-1;
+	if ((int)cached IS_VALID) {
+		if ((int)cached_sym2 IS_VALID) fatal("CACHE");
+		cached_sym2=lastst;
+		cached_sym=cached;
+		lastst=my_st;
+		if (cached_sym2==f) cached_sym2=-1;
+		return (cached_sym2==f);
+	} else {
+		cached_sym=lastst;
+		lastst=my_st;
+		if (cached_sym==f) cached_sym=-1;
+		return (cached_sym==f);
+	}*/
+}
+
+void needpunc(enum(e_sym) p) {
+	if (lastst == p)
+		getsym();
+	else
+		uerr(ERR_PUNCT,
+			p==semicolon?';':
+			 (p==begin?'{':
+			  (p==end?'}':
+			   (p==openpa?'(':
+			    (p==closepa?')':
+			     (p==hook?'?':
+			      (p==comma?',':
+					  (p==closebr?']':' '))))))));
+}
+
+extern unsigned char sizeof_flag;
+extern unsigned char id_are_zero;
+void do_compile() {
+	/* parser initialization */
+	sizeof_flag=0; id_are_zero=0;
+	flags=flags_basegtc;
+#ifdef SPEED_OPT
+	speed_opt_value = default_speed_opt_value;
+#endif
+	/* lexical analyzer / preprocessor initialization */
+	initsym();
+	/* compilation itself */
+	compile();
+}
+#ifdef PCH
+void closepch() {
+#ifdef REQ_MGT
+	{
+		FILE *req_file=NULL;
+		int i,needs_req=0;
+		for (i=pchnum;i--;)
+			if (pchrequired[i] && strcmp(pchname[i],"stdhead"))
+				needs_req++;
+		if (needs_req) {
+			char buf[sizeof("[Req_v1]\n")+1];
+			char temp[5000];
+			*temp=0;
+			req_file=fopen(proj_file,"r");
+			if (req_file) {
+				while (!feof(req_file)) {
+					fgets(buf,sizeof("[Req_v1]\n"),req_file);
+					strcat(temp,buf);
+					if (!strcmp(buf,"[Req_v1]\n")) {
+						needs_req=0;
+						break;
+					}
+				}
+				fclose(req_file);
+			}
+			req_file=fopen(proj_file,"w");
+			if (!req_file) fatal("Could not open project file.");
+			fputs(temp,req_file);
+			if (needs_req)
+				fputs("[Req_v1]\n",req_file);
+			needs_req=1;
+		}
+#endif
+	/* close PCH files */
+	while (pchnum) {
+		pchnum--;
+#ifdef REQ_MGT
+		if (pchrequired[pchnum] && needs_req)
+			fprintf(req_file,"%s\n",pchname[pchnum]);
+#endif
+		fclose(pchfile[pchnum]);
+	}
+#ifdef REQ_MGT
+		if (needs_req)
+			fclose(req_file);
+	}
+#endif
+}
+#endif
+// vim:ts=4:sw=4

+ 43 - 0
gtc/src/gtdevcomm.c

@@ -0,0 +1,43 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) communication with the GT-Dev IDE
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include "GtDevComm.h"
+
+extern int has_error;
+
+char *in_file CGLOB,*out_file CGLOB;
+Msg_Callback_t msg_process CGLOB;
+Progr_Callback_t progr_process CGLOB;
+#include "identity.h"
+void _gtdevmain(void);
+int Compile(char *in,char *out,Msg_Callback_t _msg_process,Progr_Callback_t _progr_process) {
+	void *old_a5=bssdata;
+	int res;
+	bssdata=malloc(BSS_SIZE);
+	if (!bssdata) return;
+	memset(bssdata,0,BSS_SIZE);
+	in_file=in; out_file=out;
+	msg_process=_msg_process;
+	progr_process=_progr_process;
+	_gtdevmain();
+	bssdata=identity(bssdata);
+	if (!bssdata)
+		return 2;
+	res=has_error;
+	free(bssdata);
+	bssdata=old_a5;
+	return res;
+}
+// vim:ts=4:sw=4

+ 44 - 0
gtc/src/gtdevcomm.h

@@ -0,0 +1,44 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) communication with the GT-Dev IDE
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef __GTDEVCOMM_H
+#define __GTDEVCOMM_H
+
+//#include "E:\Paul\89\Ti-GCC\Projects\GT-Dev\SecureCommDef.h"
+#include "securecommdef.h"
+
+#define ET_FATAL -2
+#define ET_WARNING -1
+#define ET_ERROR 0
+#define ET_INTERNAL_WARNING 1
+#define ET_INTERNAL_FAILURE 2
+#define et_isinternal(x) ((x)>0)
+#define et_iserror(x) !((x)&1)
+#if __TIGCC_BETA__*100+__TIGCC_MINOR__>=94
+#define CALLBACK __ATTR_TIOS_CALLBACK__
+#else
+#define CALLBACK
+#endif
+typedef void (CALLBACK*Msg_Callback_t)(char *message,int err_type,char *func,char *file,int line,int chr);
+//typedef _Msg_Callback_t *Msg_Callback_t;
+#define MAX_PROGRESS 65535
+typedef void (CALLBACK*Progr_Callback_t)(char *func,char *file,unsigned int fprogress);
+//typedef _Progr_Callback_t *Progr_Callback_t;
+
+extern char *in_file,*out_file;
+extern Msg_Callback_t msg_process;
+extern Progr_Callback_t progr_process;
+#endif
+// vim:ts=4:sw=4

+ 2259 - 0
gtc/src/gtpack/gtpack.c

@@ -0,0 +1,2259 @@
+/******************************************************************************
+*
+* A variant of ttpack designed to output XPak compressed data.
+*
+* -----------------------------------------------------------------------------
+*
+* original project name:    TIGCC Tools Suite 
+* file name:		    ttpack.c
+* initial date:		    14/08/2000
+* authors:		    albert@cs.tut.fi
+*			    thomas.nussbaumer@gmx.net 
+*			    Paul Froissart
+* description:		    packing program
+*
+* -----------------------------------------------------------------------------
+*
+* based on code from Pasi 'Albert' Ojala, albert@cs.tut.fi                       
+*                                                                           
+* heavily reduced to fit to the needs by thomas.nussbaumer@gmx.net          
+*
+* modified to fit XPak's compression format
+*
+******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+
+//#define ONCALC_PACKER_EMU
+//#define EVEN_LZ	// allow only LZ sequences with the same parity
+//#define NEW_RANGE	// LZhuf-like range coding
+//#define X_STATS
+#define NO_XVERBOSE
+//#define ZRANGE
+//#define ZRANGE_FAST
+
+#include "tt.h"          // generic defines 
+#include "ttversion.h"   // tigcc tools suite version info
+#include "revtools.h"    // used for id displaying
+#include "ttunpack.h"    // errorcodes definition
+#include "packhead.h"    // compressed header definition
+
+#define CVS_FILE_REVISION "$Revision: 1.4 $"
+
+#define FIXF_MACHMASK	0xff	
+#define FIXF_WRAP	     256	
+#define FIXF_DLZ	     512
+
+
+#define F_VERBOSE    (1<<0)
+#define F_STATS      (1<<1)
+#define F_AUTO       (1<<2)
+#define F_NOOPT      (1<<3)
+#define F_AUTOEX     (1<<4)
+#define F_TEXTINPUT  (1<<5)
+#define F_TEXTOUTPUT (1<<6)
+#define F_NORLE      (1<<9)
+#define F_ERROR      (1<<15)
+
+#ifndef min
+#define min(a,b) ((a<b)?(a):(b))
+#endif
+
+#ifndef ONCALC_PACKER_EMU
+#define LRANGE          (((2<<maxGamma)-3)*256) /* 0..125, 126 -> 1..127 */
+#else
+#define LRANGE			6144 /* packer() emulation */
+#endif
+#ifdef NEW_RANGE
+#undef LRANGE
+#define LRANGE			4096
+#endif
+#ifdef ZRANGE
+#undef LRANGE
+#define LRANGE			6144
+#endif
+#define MAXLZLEN        (2<<maxGamma)
+#define MAXRLELEN       (((2<<maxGamma)-2)*256) /* 0..126 -> 1..127 */
+#define DEFAULT_LZLEN   LRANGE
+
+
+
+unsigned short *rle, *elr, *lzlen, *lzpos;
+unsigned short *lzlen2, *lzpos2;
+int *length, inlen;
+unsigned char *indata, *mode, *newesc;
+unsigned short *backSkip;
+
+
+enum MODE {
+    LITERAL = 0,
+    LZ77    = 1,
+    RLE     = 2,
+    DLZ     = 3,
+    MMARK   = 4
+};
+
+int lzopt = 0;
+
+
+int maxGamma       = 7; 
+int reservedBytes  = 2;
+int escBits        = 2;
+int escMask        = 0xc0;
+int extraLZPosBits = 0;
+int rleUsed        = 31;
+
+
+/*
+//=============================================================================
+// outputs usage information of this tool
+//=============================================================================
+void PrintUsage() {    
+    fprintf(stderr, "Usage: ttpack [-<flags>] <infile> <outfile>\n"             \
+                    "       -hti      treat input as hex textinput\n"           \
+                    "       -hto      generate hex textoutput\n"                \
+                    "       -fdelta   use delta-lz77 -- shortens some files\n"  \
+                    "       e<val>    force escape bits\n"                      \
+                    "       r<val>    restrict lz search range\n"               \
+                    "       n         no RLE/LZ length optimization\n"          \
+                    "       s         full statistics\n"                        \
+                    "       v         verbose\n"                                \
+                    "       p<val>    force extralzposbits\n"                   \
+                    "       m<val>    max len 5..7 (2*2^5..2*2^7)\n");
+}
+*/
+
+/*
+//=============================================================================
+// the packing code
+//=============================================================================
+int SavePack(int flags,int type, unsigned char *data, int size, char *target,
+             int start, int escape, unsigned char *rleValues,
+             int endAddr, int extraLZPosBits,int memStart, int memEnd) 
+{
+    FILE *fp = NULL;
+
+    int  i;
+
+    if (!data)   return 10;
+    if (!target) fp = stdout;
+
+    if ((type & FIXF_MACHMASK) == 0) {
+        // Save without decompressor
+
+        if (fp || (fp = fopen(target, "wb"))) {
+            PackedHeader   cth;
+            RLEEntries     re;
+               
+            cth.origsize_lo  = inlen & 0xff;
+            cth.origsize_hi  = (inlen >> 8);
+          #ifndef COMPACT
+			cth.magic1       = MAGIC_CHAR1;
+            cth.magic2       = MAGIC_CHAR2;
+            cth.compsize_lo  = (size + rleUsed + sizeof(PackedHeader)) & 0xff;
+            cth.compsize_hi  = (size + rleUsed + sizeof(PackedHeader)) >> 8;
+		  #else
+          #ifndef OLD_HDR
+			memcpy(cth.magic,"GTPk",4);
+            cth.compsize_lo  = (size + rleUsed + sizeof(PackedHeader)) & 0xff;
+            cth.compsize_hi  = (size + rleUsed + sizeof(PackedHeader)) >> 8;
+		  #endif
+		  #endif
+            cth.esc1         = (escape >> (8-escBits));
+            //cth.notused3   
+            //cth.notused4
+            cth.esc2         = escBits;
+		  #if !defined(COMPACT) || defined(OLD_HDR)
+            cth.gamma1       = maxGamma + 1;
+            cth.gamma2       = (1 << maxGamma);
+		  #endif
+            cth.extralz      = extraLZPosBits;
+            //cth.notused1     = 0xff;
+            //cth.notused2     = 0xff;
+            cth.rleentries   = rleUsed;
+
+            for(i=0; i<rleUsed; i++) re.value[i] = rleValues[i+1];
+
+            if (flags & F_TEXTOUTPUT) {
+                unsigned int loop;
+                unsigned int written=0;
+                for (i=0;i<sizeof(PackedHeader);i++,written++) {
+                    fprintf(fp,"0x%02x,",*(((unsigned char*)&cth)+i));
+                    if ((!(written % DEFAULT_ITEMS_PER_LINE)) && written) fputc('\n',fp);
+                }
+                for (i=0;i<cth.rleentries;i++,written++) {
+                    fprintf(fp,"0x%02x,",re.value[i]);
+                    if (!(written % DEFAULT_ITEMS_PER_LINE)) fputc('\n',fp);
+                }
+                for (loop=0;loop < size;loop++,written++) {
+                    if (loop < size - 1)  fprintf(fp,"0x%02x,",data[loop]);
+                    else                  fprintf(fp,"0x%02x",data[loop]);
+                    if (!(written % DEFAULT_ITEMS_PER_LINE)) fputc('\n',fp);
+                }
+            }
+            else {
+                fwrite(&cth, 1, sizeof(PackedHeader), fp); // write header
+                fwrite(&re,  1, cth.rleentries, fp);       // write rle values
+                fwrite(data, size, 1, fp);                 // write compressed data
+                if(fp != stdout) fclose(fp);
+            }
+            return 0;
+        }
+        fprintf(stderr, "Could not open %s for writing\n", target);
+        return 10;
+    }
+
+    fprintf(stderr, "FATAL: invalid type!!\n");
+    return 10;        
+}    */
+
+
+int lrange, maxlzlen, maxrlelen;
+
+
+#ifdef X_STATS
+#define OUT_SIZE (65536*10)
+#else
+#define OUT_SIZE 65536
+#endif
+unsigned char outBuffer[OUT_SIZE];
+int outPointer = 0;
+int bitMask = 0x80;
+
+
+//=============================================================================
+// 
+//=============================================================================
+void FlushBits(void) {
+    if (bitMask != 0x80) outPointer++;
+}
+
+
+//=============================================================================
+// 
+//=============================================================================
+void PutBit(int bit) {
+    if (bit && outPointer < OUT_SIZE) outBuffer[outPointer] |= bitMask;
+    bitMask >>= 1;
+
+    if (!bitMask) {
+#ifndef NO_XVERBOSE
+		printf("[%02x]\n",(int)(unsigned char)outBuffer[outPointer]);
+#endif
+        bitMask = 0x80;
+        outPointer++;
+    }
+}
+
+
+
+int lenValue[256];
+
+//--------------------------------------------
+// why not initializing value lenValue[0] ????
+//--------------------------------------------
+//=============================================================================
+//
+//=============================================================================
+#if K_GAMMA-1
+void InitValueLen() {
+    int i,h;
+
+    for (i=1; i<256; i++) {
+        int count = 0;
+
+        if (i<2)        count = 0;  /* 1       */
+        else if (i<4)   count = 1;  /* 2-3     */
+        else if (i<8)   count = 2;  /* 4-7     */
+        else if (i<16)  count = 3;  /* 8-15    */
+        else if (i<32)  count = 4;  /* 16-31   */
+        else if (i<64)  count = 5;  /* 32-63   */
+        else if (i<128) count = 6;  /* 64-127  */
+        else if (i<256) count = 7;  /* 128-255 */
+        
+//        lenValue[i] = (count>>1)+count+2;
+				switch (count) {
+				case 0: h=1; break;
+				case 1: if (i==2) h=1; else h=2; break;
+				case 2: h=4; break;
+				case 3: h=5; break;
+				case 4: h=6; break;
+				case 5: h=7; break;
+				case 6: h=8; break;
+				case 7: h=9; break;
+				}
+				lenValue[i]=h+count;
+    }        
+}
+#else
+void InitValueLen() {
+    int i;
+
+    // could be heavily optimized, but isn't necessary
+    for (i=1; i<256; i++) {
+        int count = 0;
+
+        if (i<2)        count = 0;  /* 1       */
+        else if (i<4)   count = 1;  /* 2-3     */
+        else if (i<8)   count = 2;  /* 4-7     */
+        else if (i<16)  count = 3;  /* 8-15    */
+        else if (i<32)  count = 4;  /* 16-31   */
+        else if (i<64)  count = 5;  /* 32-63   */
+        else if (i<128) count = 6;  /* 64-127  */
+        else if (i<256) count = 7;  /* 128-255 */
+        
+        lenValue[i] = 2*count;        
+        /*if (count<maxGamma)*/ lenValue[i]++;
+    }        
+}
+#endif
+
+#define LenValue(a) (lenValue[a])
+
+
+//=============================================================================
+//
+//=============================================================================
+void PutNBits(int byte, int bits) {
+    while (bits--)
+        PutBit((byte & (1<<bits)));
+}
+
+#if K_GAMMA-1
+static int stats[256];
+#endif
+//=============================================================================
+// 
+//=============================================================================
+void PutValue(int value) {
+    int bits = 0, count = 0;
+
+#if K_GAMMA-1
+		stats[value]++;
+		for (count=0;count<LenValue(value);count++) PutBit(0);
+#else
+    while (value>1) {
+        bits = (bits<<1) | (value & 1); /* is reversed compared to value */
+        value >>= 1;
+        count++;
+        PutBit(1);
+    }
+    /*if (count<maxGamma)*/ PutBit(0);
+    while (count--) {
+        PutBit((bits & 1));     /* output is reversed again -> same as value */
+        bits >>= 1;
+    }
+#endif
+}
+
+#ifdef NEW_RANGE
+unsigned char p_len[64] = {
+	0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+	0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+unsigned char p_code[64] = {
+	0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
+	0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
+	0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
+	0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
+	0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
+	0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
+	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+	0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+//=============================================================================
+// 
+//=============================================================================
+void PutRange(int c) {
+	int i;
+
+	/* output upper 6 bits with encoding */
+	i = c >> 6;
+	PutNBits((unsigned)p_code[i] >> (8-p_len[i]), p_len[i]);
+
+	/* output lower 6 bits directly */
+	PutNBits((c & 0x3f), 6);
+}
+#endif
+
+int gainedEscaped = 0;
+int gainedRle = 0, gainedSRle = 0, gainedLRle = 0;
+int gainedLz = 0, gainedRlecode = 0;
+int gainedDLz = 0, timesDLz = 0;
+
+int timesEscaped = 0, timesNormal = 0;
+int timesRle = 0, timesSRle = 0, timesLRle = 0;
+int timesLz = 0;
+
+int lenStat[8][4];
+	//0: 
+	//1: 
+	//2: SRLE
+	//3: RLE byte
+	//4: 
+
+//=============================================================================
+//
+//=============================================================================
+int OutputNormal(int *esc, unsigned char *data, int newesc) {
+    timesNormal++;
+    if ((data[0] & escMask) == *esc) {
+        PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */
+        PutBit(0);
+        PutBit(1);
+        PutBit(0);
+
+        *esc = newesc;
+        PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */
+        PutNBits(data[0], 8-escBits);
+
+        gainedEscaped += escBits + 3;
+        timesEscaped++;
+        return 1;
+    }
+    PutNBits(data[0], 8);
+    return 0;
+}
+
+
+//=============================================================================
+// 
+//=============================================================================
+void OutputEof(int *esc) {
+    /* EOF marker */
+    PutNBits((*esc>>(8-escBits)), escBits);     /* escBits>=0 */
+    PutValue(3);        /* >2 */
+    PutValue((2<<maxGamma)-1);  /* Maximum value */
+    FlushBits();
+}
+
+
+unsigned char rleValues[32] = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+int rleHist[256];
+
+
+//=============================================================================
+// 
+//=============================================================================
+int IsShortRleByte(int data) {
+    int index;
+
+    for (index = 1; index <= rleUsed; index++)
+        if (data == rleValues[index])
+	    return 1;
+    return 0;
+}
+void PutRleByte(int data) {
+    int index;
+
+    for (index = 1; index <= rleUsed; index++) {
+        if (data == rleValues[index]) {
+            if (index==1)       lenStat[0][3]++;
+            else if (index<=3)  lenStat[1][3]++;
+            else if (index<=7)  lenStat[2][3]++;
+            else if (index<=15) lenStat[3][3]++;
+            else if (index<=31) lenStat[4][3]++;
+
+            gainedRlecode += 8 - LenValue(index);
+
+            PutValue(index);
+            return;
+        }
+    }
+    PutValue(32 + (data>>3));
+
+    gainedRlecode -= LenValue(32+(data>>3)) + 3;
+
+    PutNBits(data, 3);
+
+    lenStat[5][3]++;
+}
+
+
+unsigned char rleLen[256];
+
+
+//=============================================================================
+//
+//=============================================================================
+void InitRleLen() {
+    int i;
+
+    for (i=0; i<256; i++) rleLen[i] = LenValue(32 + 0) + 3;
+    for (i=1; i<32; i++) rleLen[rleValues[i]] = LenValue(i);
+}
+
+#define LenRleByte(d) (rleLen[d])
+
+
+//=============================================================================
+//
+//=============================================================================
+int LenRle(int len, int data) {
+    int out = 0;
+
+    do {
+        if (len == 1) {
+            out += escBits + 3 + 8;
+            len = 0;
+        } 
+        else if (len <= (1<<maxGamma)) {
+            out += escBits + 3 + LenValue(len-1) + LenRleByte(data);
+            len = 0;
+        } 
+        else {
+            int tmp = min(len, maxrlelen);
+            out += escBits + 3 + maxGamma + 8 +
+                        LenValue(((tmp-1)>>8)+1) + LenRleByte(data);
+            len -= tmp;
+        }
+    } while (len);
+    return out;
+}
+
+
+//=============================================================================
+//
+//=============================================================================
+int OutputRle(int *esc, unsigned char *data, int rlelen) {
+    int len = rlelen, tmp;
+
+    while (len) {
+        if (len >= 2 && len <= (1<<maxGamma) && (len >= 3 || IsShortRleByte(*data))) {
+            /* Short RLE */
+            if (len==2)        lenStat[0][2]++;
+            else if (len<=4)   lenStat[1][2]++;
+            else if (len<=8)   lenStat[2][2]++;
+            else if (len<=16)  lenStat[3][2]++;
+            else if (len<=32)  lenStat[4][2]++;
+            else if (len<=64)  lenStat[5][2]++;
+            else if (len<=128) lenStat[6][2]++;
+            else if (len<=256) lenStat[6][2]++;
+
+            PutNBits((*esc>>(8-escBits)), escBits);     /* escBits>=0 */
+            PutBit(0);
+            PutBit(1);
+            PutBit(1);
+            PutValue(len-1);
+            PutRleByte(*data);
+
+            tmp = 8*len -escBits -3 -LenValue(len-1) -LenRleByte(*data);
+            gainedRle += tmp;
+            gainedSRle += tmp;
+
+            timesRle++;
+            timesSRle++;
+            return 0;
+        }
+        if (len<3) {
+            while (len--)
+                OutputNormal(esc, data, *esc);
+            return 0;
+        }
+
+        if (len <= maxrlelen) {
+            /* Run-length encoding */
+            PutNBits((*esc>>(8-escBits)), escBits);     /* escBits>=0 */
+
+            PutBit(0);
+            PutBit(1);
+            PutBit(1);
+
+            PutValue((1<<maxGamma) + (((len-1)&0xff)>>(8-maxGamma)));
+
+            PutNBits((len-1), 8-maxGamma);
+            PutValue(((len-1)>>8) + 1);
+            PutRleByte(*data);
+
+            tmp = 8*len -escBits -3 -maxGamma -8 -LenValue(((len-1)>>8)+1)
+                -LenRleByte(*data);
+            gainedRle += tmp;
+            gainedLRle += tmp;
+
+            timesRle++;
+            timesLRle++;
+            return 0;
+        }
+
+        /* Run-length encoding */
+        PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */
+
+        PutBit(0);
+        PutBit(1);
+        PutBit(1);
+
+        PutValue((1<<maxGamma) + (((maxrlelen-1)&0xff)>>(8-maxGamma)));
+
+        PutNBits((maxrlelen-1) & 0xff, 8-maxGamma);
+        PutValue(((maxrlelen-1)>>8)+1);
+        PutRleByte(*data);
+
+        tmp = 8*maxrlelen -escBits -3 -maxGamma -8
+            -LenValue(((maxrlelen-1)>>8)+1) -LenRleByte(*data);
+        gainedRle += tmp;
+        gainedLRle += tmp;
+        timesRle++;
+        timesLRle++;
+        len -= maxrlelen;
+        data += maxrlelen;
+    }
+    return 0;
+}
+
+
+#ifdef ZRANGE
+char zrlen[96]={
+	0,
+	2,2,2,2,
+	3,3,3,3,
+	4,4,4,4,4,4,4,4,
+	5,5,5,5,5,5,5,5,
+	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+#define ZrLen(p) (zrlen[((p)-1)>>6])
+#endif
+
+
+//=============================================================================
+//
+//=============================================================================
+int LenLz(int lzlen, int lzpos) {
+#ifdef EVEN_LZ
+	if (lzpos&1) return 100000;
+#endif
+    if (lzlen==2) {
+#if !defined(ZRANGE) || defined(ZRANGE_FAST)
+#ifdef EVEN_LZ
+        if (lzpos <= 256) return escBits + 2 + 7;
+#else
+        if (lzpos <= 256) return escBits + 2 + 8;
+#endif
+        else              return 100000;
+#else
+		if (lzpos <= 64) return escBits + 2 + 7;
+		else if (lzpos <= 128) return escBits + 2 + 8;
+		else if (lzpos <= 256) return escBits + 2 + 9;
+		else return 100000;
+#endif
+    }
+
+#ifdef ZRANGE
+    return escBits + 8 + ZrLen(lzpos) + LenValue(lzlen-1);
+#else
+#ifdef EVEN_LZ
+    return escBits + 7 + extraLZPosBits +
+#else
+    return escBits + 8 + extraLZPosBits +
+#endif
+           LenValue(((lzpos-1)>>(8+extraLZPosBits))+1) +
+           LenValue(lzlen-1);
+#endif
+}
+
+#ifdef X_STATS
+#define XS_NUM (LRANGE/64+1)
+int lzstats[16][XS_NUM];
+int lzstatlong[XS_NUM];
+#endif
+
+//=============================================================================
+//
+//=============================================================================
+int OutputLz(int *esc, int lzlen, int lzpos, char *data, int curpos) {
+#ifdef X_STATS
+	if (lzlen<=16)
+		lzstats[lzlen-1][(lzpos-1)>>6]++;
+	else
+		lzstatlong[(lzpos-1)>>6]++;
+#endif
+    if (lzlen==2)        lenStat[0][1]++;
+    else if (lzlen<=4)   lenStat[1][1]++;
+    else if (lzlen<=8)   lenStat[2][1]++;
+    else if (lzlen<=16)  lenStat[3][1]++;
+    else if (lzlen<=32)  lenStat[4][1]++;
+    else if (lzlen<=64)  lenStat[5][1]++;
+    else if (lzlen<=128) lenStat[6][1]++;
+    else if (lzlen<=256) lenStat[7][1]++;
+
+    if (lzlen >= 2 && lzlen <= maxlzlen) {
+        int tmp;
+
+        PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */
+
+        tmp = ((lzpos-1)>>(8+extraLZPosBits))+2;
+        if (tmp==2)         lenStat[0][0]++;
+        else if (tmp<=4)    lenStat[1][0]++;
+        else if (tmp<=8)    lenStat[2][0]++;
+        else if (tmp<=16)   lenStat[3][0]++;
+        else if (tmp<=32)   lenStat[4][0]++;
+        else if (tmp<=64)   lenStat[5][0]++;
+        else if (tmp<=128)  lenStat[6][0]++;
+        else if (tmp<=256)  lenStat[6][0]++;
+
+        if (lzlen==2) {
+            PutValue(lzlen-1);
+            PutBit(0);
+            if (lzpos > 256) fprintf(stderr,"Error at %d: lzpos too long (%d) for lzlen==2\n",curpos, lzpos);
+#ifdef ZRANGE
+#ifdef ZRANGE_FAST
+	        PutNBits(((lzpos-1) & 0xff) ^ 0xff, 8);
+#else
+			{
+				int x=lzpos-1;
+				switch (x>>6) {
+					case 0: PutNBits(x,7); break;		// x=0b00******	=> 0******
+					case 1: PutNBits(x+64,8); break;	// x=0b01******	=> 10******
+					case 2: PutNBits(x+256,9); break;	// x=0b10******	=> 110******
+					case 3: PutNBits(x+256,9); break;	// x=0b11******	=> 111******
+				}
+			}
+#endif
+#endif
+        } 
+        else {
+#ifdef ZRANGE
+            PutValue(lzlen-1);
+/*			PutNBits(0,ZrLen(lzpos));
+			PutNBits(0,8);*/
+			{
+				int x=~(lzpos-1),u=(x+64)>>8;
+			switch (ZrLen(lzpos)) {
+/*u=0*/			case 0:	PutNBits(x,8); break;
+/*u=-1*/		case 2: PutNBits(0x1,2); PutNBits(x,8); break;
+/*u=-2*/		case 3: PutNBits(0x0,2); PutNBits(x,8); PutNBits(0x0,1); break;
+/*u=-4..-3*/	case 4: PutNBits(0x0,2); PutNBits(x,8); PutNBits(0x2+(u&1),2); break;
+/*u=-6..-5*/	case 5: PutNBits(0x2,2); PutNBits(x,8); PutNBits(0x0+(u&1),3); break;
+/*u=-12..-7*/	case 6: PutNBits(0x2,2); PutNBits(x,8); PutNBits(0x4+((u+(12&7))&7),4); break;
+/*u=-24..-13*/	case 7: PutNBits(0x2,2); PutNBits(x,8); PutNBits(0x14+((u+(24&15))&15),5); break;
+			}
+			}
+#else
+#ifdef X_STATS
+            PutValue(lzlen-1);
+//			PutNBits(0,1+3);
+			PutNBits(0,3);
+#else
+            PutValue(lzlen-1);
+#ifndef NEW_RANGE
+            PutValue( ((lzpos-1) >> (8+extraLZPosBits)) +1);
+            PutNBits( ((lzpos-1) >> 8), extraLZPosBits);
+#endif
+#endif
+#endif
+        }
+//		PutNBits(0xFF, 8);
+#ifndef ZRANGE
+#ifndef NEW_RANGE
+#ifdef EVEN_LZ
+        PutNBits((((lzpos-1) & 0xff) ^ 0xff) >> 1, 7);
+	    if (lzpos&1) fprintf(stderr, "Error: odd lzpos\n");
+#else
+        PutNBits(((lzpos-1) & 0xff) ^ 0xff, 8);
+#endif
+#else
+		PutRange(lzpos-1);
+#endif
+#endif
+
+        gainedLz += 8*lzlen -LenLz(lzlen, lzpos);
+        timesLz++;
+        return 3;
+    }
+    fprintf(stderr, "Error: lzlen too short/long (%d)\n", lzlen);
+    return lzlen;
+}
+
+
+
+/* Non-recursive version */
+/* NOTE! IMPORTANT! the "length" array length must be inlen+1 */
+
+//=============================================================================
+//
+//=============================================================================
+int OptimizeLength(int optimize) {
+    int i;
+
+    length[inlen] = 0;          /* one off the end, our 'target' */
+    for (i=inlen-1; i>=0; i--) {
+        int r1 = 8 + length[i+1], r2, r3;
+
+/*		if (i<=0x40b1 && !(i&((1<<0)-1)))
+			printf("");*/
+        if (!lzlen[i] && !rle[i] && (!lzlen2 || !lzlen2[i])) {
+            length[i] = r1;
+            mode[i] = LITERAL;
+            continue;
+        }
+
+        /* If rle>maxlzlen, skip to the start of the rle-maxlzlen.. */
+        if (rle[i] > maxlzlen && elr[i] > 1) {
+            int z = elr[i];
+
+            i -= elr[i];
+
+            r2 = LenRle(rle[i], indata[i]) + length[i+ rle[i]];
+            if (optimize) {
+                int ii, mini = rle[i], minv = r2;
+
+                int bot = rle[i] - (1<<maxGamma);
+                if (bot < 2)
+                    bot = 2;
+
+                for (ii=mini-1; ii>=bot; ii--) {
+                    int v = LenRle(ii, indata[i]) + length[i + ii];
+                    if (v < minv) {
+                        minv = v;
+                        mini = ii;
+                    }
+                }
+                if (minv != r2) {
+                    lzopt += r2 - minv;
+                    rle[i] = mini;
+                    r2 = minv;
+                }
+            }
+            length[i] = r2;
+            mode[i] = RLE;
+
+            for (; z>=0; z--) {
+                length[i+z] = r2;
+                mode[i+z] = RLE;
+            }
+            continue;
+        }
+        r3 = r2 = r1 + 1000; /* r3 >= r2 > r1 */
+
+        if (rle[i]) {
+            r2 = LenRle(rle[i], indata[i]) + length[i+ rle[i]];
+
+            if (optimize) {
+                int ii, mini = rle[i], minv = r2;
+
+                /* Check only the original length and all shorter
+                   lengths that are power of two.
+
+                   Does not really miss many 'minimums' this way,
+                   at least not globally..
+
+                   Makes the assumption that the Elias Gamma Code is
+                   used, i.e. values of the form 2^n are 'optimal' */
+                ii = 2;
+                while (rle[i] > ii) {
+                    int v = LenRle(ii, indata[i]) + length[i + ii];
+                    if (v < minv) {
+                        minv = v;
+                        mini = ii;
+                    }
+                    ii <<= 1;
+                }
+                if (minv != r2) {
+                    lzopt += r2 - minv;
+                    rle[i] = mini;
+                    r2 = minv;
+                }
+            }
+        }
+        if (lzlen[i]) {
+            r3 = LenLz(lzlen[i], lzpos[i]) + length[i + lzlen[i]];
+
+            if (optimize && lzlen[i]>2) {
+                int ii, mini = lzlen[i], minv = r3;
+                int topLen = LenLz(lzlen[i], lzpos[i])
+                    - LenValue(lzlen[i]-1);
+
+                /* Check only the original length and all shorter
+                   lengths that are power of two.
+
+                   Does not really miss many 'minimums' this way,
+                   at least not globally..
+
+                   Makes the assumption that the Elias Gamma Code is
+                   used, i.e. values of the form 2^n are 'optimal' */
+                ii = 4;
+                while (lzlen[i] > ii) {
+                    int v = topLen + LenValue(ii-1) + length[i + ii];
+                    if (v < minv) {
+                        minv = v;
+                        mini = ii;
+                    }
+                    ii <<= 1;
+                }
+                /*
+                  Note:
+                  2-byte optimization checks are no longer done
+                  with the rest, because the equation gives too long
+                  code lengths for 2-byte matches if extraLzPosBits>0.
+                  */
+                /* Two-byte rescan/check */
+                if (backSkip[i] && backSkip[i] <= 256) {
+#ifdef EVEN_LZ
+					if (backSkip[i]&1) {
+						int j=backSkip[i];
+						while (j && (j&1))
+							j=backSkip[j];
+						if (j && j<=256) {
+							int v = LenLz(2, j) + length[i + 2];
+
+							if (v < minv) {
+								minv = v;
+								mini = 2;
+								lzlen[i] = mini;
+								r3 = minv;
+								lzpos[i] = j;
+							}
+						}
+					} else {
+#endif
+                    /* There are previous occurrances (near enough) */
+                    int v = LenLz(2, (int)backSkip[i]) + length[i + 2];
+
+                    if (v < minv) {
+                        minv = v;
+                        mini = 2;
+                        lzlen[i] = mini;
+                        r3 = minv;
+                        lzpos[i] = (int)backSkip[i];
+                    }
+#ifdef EVEN_LZ
+					}
+#endif
+                }
+                if (minv != r3 && minv < r2) {
+                    lzopt += r3 - minv;
+                    lzlen[i] = mini;
+                    r3 = minv;
+                }
+            }
+        }
+
+        if (r2 <= r1) {
+            if (r2 <= r3) {
+                length[i] = r2;
+                mode[i]   = RLE;
+            } 
+            else {
+                length[i] = r3;
+                mode[i]   = LZ77;
+            }
+        } 
+        else {
+            if (r3 <= r1) {
+                length[i] = r3;
+                mode[i]   = LZ77;
+            } 
+            else {
+                length[i] = r1;
+                mode[i]   = LITERAL;
+            }
+        }
+        if (lzlen2 && lzlen2[i] > 3) {
+            r3 = escBits + 2*maxGamma + 16 + LenValue(lzlen2[i]-1) + length[i + lzlen2[i]];
+            //r3 = LenDLz(lzlen2[i], lzpos2[i]) + length[i + lzlen2[i]];
+            if (r3 < length[i]) {
+                length[i] = r3;
+                mode[i]   = DLZ;
+            }
+        }
+    }
+    return length[0];
+}
+
+
+/*
+    The algorithm in the OptimizeEscape() works as follows:
+    1) Only unpacked bytes are processed, they are marked
+       with MMARK. We proceed from the end to the beginning.
+       Variable A (old/new length) is updated.
+    2) At each unpacked byte, one and only one possible
+       escape matches. A new escape code must be selected
+       for this case. The optimal selection is the one which
+       provides the shortest number of escapes to the end
+       of the file,
+        i.e. A[esc] = 1+min(A[0], A[1], .. A[states-1]).
+       For other states A[esc] = A[esc];
+       If we change escape in this byte, the new escape is
+       the one with the smallest value in A.
+    3) The starting escape is selected from the possibilities
+       and mode 0 is restored to all mode 3 locations.
+
+ */
+
+//=============================================================================
+//
+//=============================================================================
+int OptimizeEscape(int *startEscape, int *nonNormal) {
+    int  i, /*j,*/ states = (1<<escBits);
+    long other = 0;
+    long a[256]; /* needs int/long */
+    long b[256]; /* Remembers the # of escaped for each */
+    int  esc8 = 8-escBits;
+
+    for (i=0; i<256; i++) b[i] = a[i] = -1;
+
+    if (states>256) {
+        fprintf(stderr, "Escape optimize: only 256 states (%d)!\n",states);
+        return 0;
+    }
+
+    /* Mark those bytes that are actually outputted */
+    for (i=0; i<inlen; ) {
+        switch (mode[i]) {
+            case DLZ:
+                other++;
+                i += lzlen2[i];
+                break;
+
+            case LZ77:
+                other++;
+                i += lzlen[i];
+                break;
+
+            case RLE:
+                other++;
+                i += rle[i];
+                break;
+
+            /*case LITERAL:*/
+            default:
+                mode[i++] = MMARK; /* mark it used so we can identify it */
+                break;
+        }
+    }
+
+#ifdef WEIRD_ORIGINAL_ESC
+	/* note : this ESC control is OK, but doesn't comply with on-calc GTPk */
+    for (i=inlen-1; i>=0; i--) {
+        /* Using a table to skip non-normal bytes does not help.. */
+        if (mode[i] == MMARK) {
+            int k = (indata[i] >> esc8);
+
+            /* Change the tag values back to normal */
+            mode[i] = LITERAL;
+
+            /*
+                k are the matching bytes,
+                minv is the minimum value,
+                minp is the minimum index
+             */
+
+            newesc[i] = (minp << esc8);
+            a[k] = minv + 1;
+            b[k] = b[minp] + 1;
+            if (k==minp) {
+                /* Minimum changed -> need to find a new minimum */
+                /* a[k] may still be the minimum */
+                minv++;
+                for (k=states-1; k>=0; k--) {
+                    if (a[k] < minv) {
+                        minv = a[k];
+                        minp = k;
+                        /*
+                            There may be others, but the first one that
+                            is smaller than the old minimum is equal to
+                            any other new minimum.
+                         */
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /* Select the best value for the initial escape */
+    if (startEscape) {
+        i = inlen;      /* make it big enough */
+        for (j=states-1; j>=0; j--) {
+            if (a[j] <= i) {
+                *startEscape = (j << esc8);
+                i = a[j];
+            }
+        }
+    }
+    if (nonNormal)
+        *nonNormal = other;
+    return b[startEscape ? (*startEscape>>esc8) : 0];
+#else
+	{
+	/* this fairly simple (but efficient) algo comes from GTPk */
+	char esc_used[256];
+	int esc_rem=states-1;
+	int lastesc=-1,escaped=0;
+	int k;
+	memset(esc_used,0,256);
+    for (i=0; i<inlen; i++) {
+        if (mode[i] == MMARK) {
+            k = (indata[i] >> esc8);
+
+            mode[i] = LITERAL;
+
+			if (!esc_used[k] && !esc_rem--) {
+				memset(esc_used,0,256);
+				esc_rem=states-1;
+				escaped++;
+	            if (lastesc>=0) newesc[lastesc] = (k << esc8);
+				else if (startEscape) *startEscape = (k << esc8);
+				lastesc=i;
+			} else {
+				esc_used[k]=1;
+            }
+        }
+    }
+	for (k=0;;k++) {
+		if (!esc_used[k]) {
+	        if (lastesc>=0) newesc[lastesc] = (k << esc8);
+			else if (startEscape) *startEscape = (k << esc8);
+			break;
+		}
+	}
+	newesc[0] = *startEscape;
+    if (nonNormal)
+        *nonNormal = other;
+    return escaped;
+	}
+#endif
+}
+
+
+//=============================================================================
+// Initialize the RLE byte code table according to all RLE's found so far O(n)
+//=============================================================================
+void InitRle(int flags) {
+    int p, mr, mv, i;
+
+    for (i=1; i<32; i++) {
+        mr = -1;
+		mv = 0;
+
+        for (p=0; p<256; p++) {
+            if (rleHist[p] > mv) {
+                mv = rleHist[p];
+                mr = p;
+            }
+        }
+        if (mr>=0) {
+            rleValues[i] = mr;
+            rleHist[mr] = -1;
+        } else
+            break;
+    }
+    InitRleLen();
+}
+
+
+//=============================================================================
+// Initialize the RLE byte code table according to RLE's actually used O(n) 
+//=============================================================================
+void OptimizeRle(int flags) {
+    int p, mr, mv, i;
+
+    if ((flags & F_NORLE)) {
+        rleUsed = 0;
+        return;
+    }
+    if (flags & F_STATS) fprintf(stderr, "RLE Byte Code Re-Tune, RLE Ranks:\n");
+
+    for (p=0; p<256; p++) rleHist[p] = 0;
+
+    for (p=0; p<inlen; ) {
+        switch (mode[p]) {
+            case DLZ: 
+                p += lzlen2[p];
+                break;
+            case LZ77: 
+                p += lzlen[p];
+                break;
+
+            case RLE: 
+                rleHist[indata[p]]++;
+                p += rle[p];
+                break;
+
+            default:
+                p++;
+                break;
+        }
+    }
+
+    for (i=1; i<32; i++) {
+        mr = -1;
+//        mv = 0;
+//        mv = (LenValue(i)+8 <= 14)?0:1;
+		mv = 1;
+
+        for (p=0; p<256; p++) {
+            if (rleHist[p] > mv) {
+                mv = rleHist[p];
+                mr = p;
+            }
+        }
+        if (mr>=0) {
+            rleValues[i] = mr;
+            if (flags & F_STATS) {
+                fprintf(stderr, " %2d.0x%02x %-3d ", i, mr, mv);
+                if (!((i - 1) % 6)) fprintf(stderr, "\n");
+            }
+            rleHist[mr] = -1;
+        } 
+        else {
+            break;
+        }
+    }
+    rleUsed = i-1;
+	if (rleUsed)
+		for (;i<32;i++)
+			rleValues[i]=rleValues[i-1];
+
+    if (flags & F_STATS)
+        if (((i - 1) % 6)!=1) fprintf(stderr, "\n");
+    InitRleLen();
+}
+
+
+int outlen;
+
+//=============================================================================
+//
+//=============================================================================
+int PackLz77(int lzsz, int flags, int *startEscape,int endAddr, int memEnd, int type) 
+{
+    int i, j, p, headerSize;
+    int escape;
+    unsigned char *hashValue;
+    unsigned char *a;
+    int k;
+
+    unsigned short *lastPair;
+
+    int rescan = 0;
+
+#ifndef NO_XVERBOSE
+	int vescape;
+#endif
+
+
+
+    if (lzsz < 0 || lzsz > lrange) {
+        fprintf(stderr, "LZ range must be from 0 to %d (was %d). Set to %d.\n",
+                lrange, lzsz, lrange);
+        lzsz = lrange;
+    }
+    if (lzsz > 65535) {
+        fprintf(stderr,
+                "LZ range must be from 0 to 65535 (was %d). Set to 65535.\n",
+                lzsz);
+        lzsz = 65535;
+    }
+    if (!lzsz) fprintf(stderr, "Warning: zero LZ range. Only RLE packing used.\n");
+
+    InitRleLen();
+    length = (int *)calloc(sizeof(int), inlen + 1);
+    mode   = (unsigned char  *)calloc(sizeof(unsigned char),  inlen);
+    rle    = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+    elr    = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+    lzlen  = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+    lzpos  = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+    if ((type & FIXF_DLZ)) {
+        lzlen2  = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+        lzpos2  = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+    } 
+    else {
+        lzlen2 = lzpos2 = NULL;
+    }
+    newesc    = (unsigned char  *)calloc(sizeof(unsigned char),  inlen);
+    backSkip  = (unsigned short *)calloc(sizeof(unsigned short), inlen);
+    hashValue = (unsigned char  *)malloc(inlen);
+    lastPair  = (unsigned short *)calloc(sizeof(unsigned short), 256*256);
+
+    /* error checking */
+    if (!length || !mode || !rle || !elr || !lzlen || !lzpos || !newesc ||
+        !lastPair || !backSkip
+        || ((type & FIXF_DLZ) && (!lzlen2 || !lzpos2))
+        || !hashValue) 
+    {
+        fprintf(stderr, "Memory allocation failed!\n");
+        goto errorexit;
+    }
+
+    i = 0;
+    j = 0;
+    a = indata + inlen;
+    for (p=inlen-1; p>=0; p--) {
+        k = j;
+        j = i;
+        i = *--a;       /* Only one read per position */
+        hashValue[p] = i*3 + j*5 + k*7; /* 7.95 % */
+    }
+
+    /* Detect all RLE and LZ77 jump possibilities */
+    for (p=0; p<inlen; p++) {
+        if (!(p & 2047)) {
+            fprintf(stderr, "\r%d ", p);
+            fflush(stderr);     /* for SAS/C */
+        }
+        /* check run-length code - must be done, LZ77 search needs it! */
+        if (rle[p] <= 0) {
+            unsigned char *a = indata + p;
+            int val = *a++; /* if this were uchar, it would go to stack..*/
+            int top = inlen - p;
+            int rlelen = 1;
+
+            /* Loop for the whole RLE */
+            while (rlelen<top && *a++ == (unsigned char)val) rlelen++;
+
+            if (rlelen>=2) {
+                rleHist[indata[p]]++;
+
+                for (i=rlelen-1; i>=0; i--) {
+                    rle[p+i] = rlelen-i;
+                    elr[p+i] = i;       /* For RLE backward skipping */
+                }
+
+            }
+        }
+
+        /* check LZ77 code */
+        if (p+rle[p]+1<inlen) {
+            int bot = p - lzsz, maxval, maxpos, rlep = rle[p];
+            unsigned char hashCompare = hashValue[p];
+
+            /*
+                There's always 1 equal byte, although it may
+                not be marked as RLE.
+             */
+            if (rlep <= 0)
+                rlep = 1;
+            if (bot < 0)
+                bot = 0;
+            bot += (rlep-1);
+
+            /*
+                First get the shortest possible match (if any).
+                If there is no 2-byte match, don't look further,
+                because there can't be a longer match.
+             */
+            i = (int)lastPair[ (indata[p]<<8) | indata[p+1] ] -1;
+            if (i>=0 && i>=bot) {
+                /* Got a 2-byte match at least */
+                maxval = 2;
+                maxpos = p-i;
+
+                /*
+                    A..AB       rlep # of A's, B is something else..
+
+                    Search for bytes that are in p + (rlep-1), i.e.
+                    the last rle byte ('A') and the non-matching one
+                    ('B'). When found, check if the rle in the compare
+                    position (i) is long enough (i.e. the same number
+                    of A's at p and i-rlep+1).
+
+                    There are dramatically less matches for AB than for
+                    AA, so we get a huge speedup with this approach.
+                    We are still guaranteed to find the most recent
+                    longest match there is.
+                 */
+
+                i = (int)lastPair[(indata[p+(rlep-1)]<<8) | indata[p+rlep]] -1;
+                while (i>=bot /* && i>=rlep-1 */) {   /* bot>=rlep-1, i>=bot  ==> i>=rlep-1 */
+
+                    /* Equal number of A's ? */
+                    if (!(rlep-1) || rle[i-(rlep-1)]==rlep) {   /* 'head' matches */
+                        /* rlep==1 ==> (rlep-1)==0 */
+                        /* ivanova.run: 443517 rlep==1,
+                           709846 rle[i+1-rlep]==rlep */
+
+                        /*
+                            Check the hash values corresponding to the last
+                            two bytes of the currently longest match and
+                            the first new matching(?) byte. If the hash
+                            values don't match, don't bother to check the
+                            data itself.
+                         */
+                        if (
+                            hashValue[i+maxval-rlep-1] == hashCompare
+                           ) {
+                            unsigned char *a = indata + i+2;    /* match  */
+                            unsigned char *b = indata + p+rlep-1+2;/* curpos */
+                            int topindex = inlen-(p+rlep-1);
+
+                            /* the 2 first bytes ARE the same.. */
+                            j = 2;
+                            while (j < topindex && *a++==*b++)
+                                j++;
+
+                            if (j + rlep-1 > maxval) {
+                                int tmplen = j+rlep-1, tmppos = p-i+rlep-1;
+
+                                if (tmplen > maxlzlen)
+                                    tmplen = maxlzlen;
+
+                                /* Accept only versions that really are shorter */
+                                if (tmplen*8 - LenLz(tmplen, tmppos) >
+                                    maxval*8 - LenLz(maxval, maxpos)) {
+                                    maxval = tmplen;
+                                    maxpos = tmppos;
+                                    hashCompare = hashValue[p+maxval-2];
+                                }
+                                if (maxval == maxlzlen)
+                                    break;
+                            }
+                        }
+                    }
+                    if (!backSkip[i])
+                        break; /* No previous occurrances (near enough) */
+                    i -= (int)backSkip[i];
+                }
+
+                /*
+                    If there is 'A' in the previous position also,
+                    RLE-like LZ77 is possible, although rarely
+                    shorter than real RLE.
+                 */
+                if (p && rle[p-1] > maxval) {
+                    maxval = rle[p-1] - 1;
+                    maxpos = 1;
+                }
+                /*
+                    Last, try to find as long as possible match
+                    for the RLE part only.
+                 */
+                if (maxval < maxlzlen && rlep > maxval) {
+                    bot = p - lzsz;
+                    if (bot < 0)
+                        bot = 0;
+
+                    /* Note: indata[p] == indata[p+1] */
+                    i = (int)lastPair[indata[p]*257] -1;
+                    while (/* i>= rlep-2 &&*/ i>=bot) {
+                        if (elr[i] + 2 > maxval) {
+                            maxval = min(elr[i] + 2, rlep);
+                            maxpos = p - i + (maxval-2);
+                            if(maxval == rlep)
+                                break; /* Got enough */
+                        }
+                        i -= elr[i];
+                        if (!backSkip[i])
+                            break; /* No previous occurrances (near enough) */
+                        i -= (int)backSkip[i];
+                    }
+                }
+                if (p+maxval > inlen) {
+                    fprintf(stderr,"Error @ %d, lzlen %d, pos %d - exceeds inlen\n",p, maxval, maxpos);
+                    maxval = inlen - p;
+                }
+                if (maxpos<=256 || maxval > 2) {
+                    if (maxpos < 0) fprintf(stderr, "Error @ %d, lzlen %d, pos %d\n",p, maxval, maxpos);
+                    lzlen[p] = (maxval<maxlzlen)?maxval:maxlzlen;
+/*#ifdef EVEN_LZ
+					if (maxpos&1)
+						fprintf(stderr,"Error: misalign in maxpos\n");
+#endif*/
+                    lzpos[p] = maxpos;
+                }
+            }
+        }
+
+        /* check LZ77 code again, ROT1..255 */
+        if ((type & FIXF_DLZ) && p+rle[p]+1<inlen) {
+        int rot;
+
+        for (rot = 1; rot < 255; rot++) {
+            int bot = p - /*lzsz*/256, maxval, maxpos, rlep = rle[p];
+            unsigned char valueCompare = (indata[p+2] + rot) & 0xff;
+
+            if (rlep <= 0) rlep = 1;
+            if (bot < 0)   bot = 0;
+            bot += (rlep-1);
+
+            i = (int)lastPair[ (((indata[p] + rot) & 0xff)<<8) |
+                                ((indata[p+1] + rot) & 0xff) ] -1;
+            if (i>=0 && i>=bot) {
+                maxval = 2;
+                maxpos = p-i;
+
+                /*
+                    A..AB       rlep # of A's, B is something else..
+
+                    Search for bytes that are in p + (rlep-1), i.e.
+                    the last rle byte ('A') and the non-matching one
+                    ('B'). When found, check if the rle in the compare
+                    position (i) is long enough (i.e. the same number
+                    of A's at p and i-rlep+1).
+
+                    There are dramatically less matches for AB than for
+                    AA, so we get a huge speedup with this approach.
+                    We are still guaranteed to find the most recent
+                    longest match there is.
+                 */
+
+                i = (int)lastPair[(((indata[p+(rlep-1)] + rot) & 0xff)<<8) |
+                                   ((indata[p+rlep] + rot) & 0xff)] -1;
+                while (i>=bot /* && i>=rlep-1 */) {   /* bot>=rlep-1, i>=bot  ==> i>=rlep-1 */
+
+                    /* Equal number of A's ? */
+                    if (!(rlep-1) || rle[i-(rlep-1)]==rlep) {   /* 'head' matches */
+                        /* rlep==1 ==> (rlep-1)==0 */
+                        /* ivanova.run: 443517 rlep==1,
+                           709846 rle[i+1-rlep]==rlep */
+
+                        /*
+                            Check the hash values corresponding to the last
+                            two bytes of the currently longest match and
+                            the first new matching(?) byte. If the hash
+                            values don't match, don't bother to check the
+                            data itself.
+                         */
+                        if (indata[i+maxval-rlep+1] == valueCompare) {
+                            unsigned char *a = indata + i+2;    /* match  */
+                            unsigned char *b = indata + p+rlep-1+2;/* curpos */
+                            int topindex = inlen-(p+rlep-1);
+
+                            /* the 2 first bytes ARE the same.. */
+                            j = 2;
+                            while (j < topindex && *a++==((*b++ + rot) & 0xff))
+                                j++;
+
+                            if (j + rlep-1 > maxval) {
+                                int tmplen = j+rlep-1, tmppos = p-i+rlep-1;
+
+                                if (tmplen > maxlzlen)
+                                    tmplen = maxlzlen;
+
+                                /* Accept only versions that really are shorter */
+                                if (tmplen*8 - LenLz(tmplen, tmppos) >
+                                    maxval*8 - LenLz(maxval, maxpos)) {
+                                    maxval = tmplen;
+                                    maxpos = tmppos;
+
+                                    valueCompare = (indata[p+maxval] + rot) & 0xff;
+                                }
+                                if (maxval == maxlzlen)
+                                    break;
+                            }
+                        }
+                    }
+                    if (!backSkip[i])
+                        break; /* No previous occurrances (near enough) */
+                    i -= (int)backSkip[i];
+                }
+
+                if (p+maxval > inlen) {
+                    fprintf(stderr,"Error @ %d, lzlen %d, pos %d - exceeds inlen\n",p, maxval, maxpos);
+                    maxval = inlen - p;
+                }
+                if (maxval > 3 && maxpos <= 256 &&
+                    (maxval > lzlen2[p] ||
+                     (maxval == lzlen2[p] && maxpos < lzpos2[p]))) {
+                    if (maxpos < 0)
+                        fprintf(stderr, "Error @ %d, lzlen %d, pos %d\n",p, maxval, maxpos);
+                    lzlen2[p] = (maxval<maxlzlen)?maxval:maxlzlen;
+                    lzpos2[p] = maxpos;
+                }
+            }
+        }
+        if (lzlen2[p] <= lzlen[p] || lzlen2[p] <= rle[p]) {
+            lzlen2[p] = lzpos2[p] = 0;
+        }
+        }
+
+        /* Update the two-byte history ('hash table') &
+           backSkip ('linked list') */
+        if (p+1<inlen) {
+            int index = (indata[p]<<8) | indata[p+1];
+            int ptr = p - (lastPair[index]-1);
+
+            if (ptr > p || ptr > 0xffff)
+                ptr = 0;
+
+            backSkip[p] = ptr;
+            lastPair[index] = p+1;
+        }
+    }
+    if ((flags & F_NORLE)) {
+        for (p=1; p<inlen; p++) {
+            if (rle[p-1]-1 > lzlen[p]) {
+                lzlen[p] = (rle[p]<maxlzlen)?rle[p]:maxlzlen;
+                lzpos[p] = 1;
+            }
+        }
+        for (p=0; p<inlen; p++) {
+            rle[p] = 0;
+        }
+    }
+    fprintf(stderr, "\r             \r");	/* clean up the display */
+    fflush(stderr);
+/*    fprintf(stderr, "\rChecked: %d \n", p);
+    fflush(stderr);     */
+
+
+    /* Initialize the RLE selections */
+    InitRle(flags);
+
+    /* Check the normal bytes / all ratio */
+    if ((flags & F_AUTO)) {
+        int mb, mv;
+
+        if (flags & F_VERBOSE) {
+            fprintf(stderr, "Selecting the number of escape bits.. ");
+            fflush(stderr);
+        }
+
+        /*
+            Absolute maximum number of escaped bytes with
+            the escape optimize is 2^-n, where n is the
+            number of escape bits used.
+
+            This worst case happens only on equal-
+            distributed normal bytes (01230123..).
+            This is why the typical values are so much smaller.
+         */
+
+        mb = 0;
+        mv = 8*OUT_SIZE;
+        for (escBits=1; escBits<9; escBits++) {
+            int escaped, other = 0, c;
+
+            escMask = (0xff00>>escBits) & 0xff;
+
+            /* Find the optimum path for selected escape bits (no optimize) */
+            OptimizeLength(0);
+
+            /* Optimize the escape selections for this path & escBits */
+            escaped = OptimizeEscape(&escape, &other);
+
+            /* Compare value: bits lost for escaping -- bits lost for prefix */
+            c = (escBits+3)*escaped + other*escBits;
+            if (flags & F_STATS) {
+                fprintf(stderr, " %d:%d", escBits, c);
+                fflush(stderr); /* for SAS/C */
+            }
+            if (c < mv) {
+                mb = escBits;
+                mv = c;
+            } else {
+                /* minimum found */
+                break;
+            }
+            if (escBits==4 && (flags & F_STATS)) fprintf(stderr, "\n");
+        }
+        if (mb==1) {    /* Minimum was 1, check 0 */
+            int escaped;
+
+            escBits = 0;
+            escMask = 0;
+
+            /* Find the optimum path for selected escape bits (no optimize) */
+            OptimizeLength(0);
+            /* Optimize the escape selections for this path & escBits */
+            escaped = OptimizeEscape(&escape, NULL);
+
+            if ((flags & F_STATS)) {
+                fprintf(stderr, " %d:%d", escBits, 3*escaped);
+                fflush(stderr); /* for SAS/C */
+            }
+            if (3*escaped < mv) {
+                mb = 0;
+                /* mv = 3*escaped; */
+            }
+        }
+        if ((flags & F_STATS)) fprintf(stderr, "\n");
+
+        if (flags & F_VERBOSE) fprintf(stderr, "Selected %d-bit escapes\n", mb);
+        escBits = mb;
+        escMask = (0xff00>>escBits) & 0xff;
+    }
+
+
+    if (!(flags & F_NOOPT)) {
+        if (flags & F_VERBOSE) {
+            fprintf(stderr, "Optimizing LZ77 and RLE lengths...");
+            fflush(stderr);
+        }    
+    }
+
+    /* Find the optimum path (optimize) */
+    OptimizeLength((flags & F_NOOPT)?0:1);
+    if (flags & F_STATS) {
+        if (!(flags & F_NOOPT)) fprintf(stderr, " gained %d units.\n", lzopt/8);
+    } 
+    else {
+        //fprintf(stderr, "\n");
+    }
+
+    if (1 || (flags & F_AUTOEX)) {
+        long lzstat[5] = {0,0,0,0,0}, i, cur = 0, old = extraLZPosBits;
+
+        if (flags & F_VERBOSE) {
+            fprintf(stderr, "Selecting LZPOS LO length.. ");
+            fflush(stderr); 
+        }
+
+        for (p=0; p<inlen; ) {
+            switch (mode[p]) {
+            case LZ77: 
+                extraLZPosBits = 0;
+                lzstat[0] += LenLz(lzlen[p], lzpos[p]);
+                extraLZPosBits = 1;
+                lzstat[1] += LenLz(lzlen[p], lzpos[p]);
+                extraLZPosBits = 2;
+                lzstat[2] += LenLz(lzlen[p], lzpos[p]);
+                extraLZPosBits = 3;
+                lzstat[3] += LenLz(lzlen[p], lzpos[p]);
+                extraLZPosBits = 4;
+                lzstat[4] += LenLz(lzlen[p], lzpos[p]);
+                p += lzlen[p];
+                break;
+            case DLZ:
+                p += lzlen2[p];
+                break;
+            case RLE:
+                p += rle[p];
+                break;
+
+            default: 
+                p++;
+                break;
+            }
+        }
+        for (i=0; i<5; i++) {
+            if (flags & F_STATS) fprintf(stderr, " %ld:%ld", i + 8, lzstat[i]);
+
+            if (lzstat[i] < lzstat[cur]) cur = i;
+        }
+        extraLZPosBits = (flags & F_AUTOEX)?cur:old;
+
+        if (flags & F_STATS) fprintf(stderr, "\n");
+
+        if (flags & F_VERBOSE) {
+            fprintf(stderr, "Selected %d-bit LZPOS LO part\n",extraLZPosBits + 8);
+            if (cur != old) fprintf(stderr,"Note: Using option -p%ld you may get better results.\n",cur);                
+        }
+        /* Find the optimum path (optimize) */
+        if (extraLZPosBits != old) OptimizeLength((flags & F_NOOPT)?0:1);
+    }
+    if (1) {
+        long stat[4] = {0,0,0,0};
+
+        for (p=0; p<inlen; ) {
+            switch (mode[p]) {
+            case LZ77: 
+                if ((lzpos[p] >> 8)+1 > (1<<maxGamma))
+                    stat[3]++;
+                if (lzlen[p] > (1<<maxGamma))
+                    stat[0]++;
+                p += lzlen[p];
+                break;
+
+            case RLE: 
+                if (rle[p] > (1<<(maxGamma-1))) {
+                    if (rle[p] <= (1<<maxGamma))
+                        stat[1]++;
+
+                }
+                p += rle[p];
+                break;
+            case DLZ:
+                p += lzlen2[p];
+                break;
+            default: 
+                p++;
+                break;
+            }
+        }
+        /* TODO: better formula.. */
+        if (maxGamma < 7 && stat[0] + stat[1] + stat[3] > 10) {
+            if (flags & F_VERBOSE) fprintf(stderr,"Note: Using option -m%d you may get better results.\n",maxGamma+1);
+        }
+        if (maxGamma > 5 && stat[0] + stat[1] + stat[3] < 4) {
+            if (flags & F_VERBOSE) fprintf(stderr,"Note: Using option -m%d you may get better results.\n",maxGamma-1);
+        }
+    }
+
+    /* Optimize the escape selections */
+    OptimizeEscape(&escape, NULL);
+    if (startEscape) *startEscape = escape;
+    OptimizeRle(flags); /* Retune the RLE selections */
+
+#ifdef NO_XVERBOSE
+    if (flags & F_VERBOSE) {
+        int oldEscape = escape;
+        if (flags & F_VERBOSE) printf("normal RLE  LZLEN LZPOS(absolute)\n\n");
+
+        for (p=0; p<inlen; ) {
+            switch (mode[p]) {
+            case LZ77:
+                mode[p - lzpos[p]] |= MMARK; /* Was referred to by lz77 */
+                p += lzlen[p];
+                break;
+            case RLE:
+                p += rle[p];
+                break;
+            case DLZ:
+                mode[p - lzpos2[p]] |= MMARK; /* Was referred to by lz77 */
+                p += lzlen2[p];
+                break;
+        /*  case LITERAL:
+            case MMARK:*/
+            default:
+                p++;
+                break;
+            }
+        }
+
+        j = 0;
+        for (p=0; p<inlen; p++) {
+            switch (mode[p]) {
+            case MMARK | DLZ:
+            case DLZ:
+                if (j==p) {
+                    if (flags & F_VERBOSE) printf(">");
+                    j += lzlen2[p];
+                } else
+                    printf(" ");
+                if (lzpos2) {
+                    if (flags & F_VERBOSE) printf(" %04x*%03d*+%02x", lzpos2[p], lzlen2[p],(indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                }
+                if (flags & F_VERBOSE) printf(" 001   %03d   %03d  %04x(%04x)  %02x %s\n",
+                                              rle[p],lzlen[p],lzpos[p],p-lzpos[p],indata[p],
+                                              (mode[p] & MMARK)?"#":" ");
+                break;
+            case MMARK | LITERAL:
+            case LITERAL:
+                if (flags & F_VERBOSE) {
+                    if (j==p) printf(">");
+                    else      printf(" ");
+
+                    if (lzpos2) {
+                        printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p],
+                               (indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                    }
+                }
+                if (j==p) {
+                    if (flags & F_VERBOSE) {
+                        printf("*001*  %03d   %03d  %04x(%04x)  %02x %s %02x",
+                               rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                               (mode[p] & MMARK)?"#":" ", newesc[p]);
+                    }
+                    if ((indata[p] & escMask) == escape) {
+                        escape = newesc[p];
+                        if (flags & F_VERBOSE) printf("«");
+                    }
+                    if (flags & F_VERBOSE) printf("\n");
+                    j += 1;
+                } else {
+                    if (flags & F_VERBOSE) printf("*001*  %03d   %03d  %04x(%04x)  %02x %s %02x\n",
+                                                  rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                                                  (mode[p] & MMARK)?"#":" ", newesc[p]);
+                }
+                break;
+            case MMARK | LZ77:
+            case LZ77:
+                if (j==p) {
+                    if (flags & F_VERBOSE) printf(">");
+                    j += lzlen[p];
+                } else
+                    if (flags & F_VERBOSE) printf(" ");
+                if (lzpos2) {
+                    if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p],
+                                                  (indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                }
+                if (flags & F_VERBOSE) printf(" 001   %03d  *%03d* %04x(%04x)  %02x %s\n",
+                                              rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                                              (mode[p] & MMARK)?"#":" ");
+                break;
+            case MMARK | RLE:
+            case RLE:
+                if (j==p) {
+                    if (flags & F_VERBOSE) printf(">");
+                    j += rle[p];
+                } else
+                    if (flags & F_VERBOSE) printf(" ");
+                if (lzpos2) {
+                    if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p],
+                                                  (indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                }
+                if (flags & F_VERBOSE) printf(" 001  *%03d*  %03d  %04x(%04x)  %02x %s\n",
+                                              rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                                              (mode[p] & MMARK)?"#":" ");
+                break;
+            default:
+                j++;
+                break;
+            }
+            mode[p] &= ~MMARK;
+        }
+        escape = oldEscape;
+    }
+#endif
+
+#ifndef NO_XVERBOSE
+	  if (flags & F_VERBOSE) {
+        for (p=0; p<inlen; ) {
+            switch (mode[p]) {
+            case LZ77:
+                mode[p - lzpos[p]] |= MMARK; /* Was referred to by lz77 */
+                p += lzlen[p];
+                break;
+            case RLE:
+                p += rle[p];
+                break;
+            case DLZ:
+                mode[p - lzpos2[p]] |= MMARK; /* Was referred to by lz77 */
+                p += lzlen2[p];
+                break;
+        /*  case LITERAL:
+            case MMARK:*/
+            default:
+                p++;
+                break;
+            }
+        }
+        j = 0;
+		vescape=escape;
+	  }
+#endif
+    for (p=0; p<inlen; ) {
+#ifndef NO_XVERBOSE
+	  if (flags & F_VERBOSE) {
+            switch (mode[p]) {
+            case MMARK | DLZ:
+            case DLZ:
+                if (j==p) {
+                    if (flags & F_VERBOSE) printf(">");
+                    j += lzlen2[p];
+                } else
+                    printf(" ");
+                if (lzpos2) {
+                    if (flags & F_VERBOSE) printf(" %04x*%03d*+%02x", lzpos2[p], lzlen2[p],(indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                }
+                if (flags & F_VERBOSE) printf(" 001   %03d   %03d  %04x(%04x)  %02x %s\n",
+                                              rle[p],lzlen[p],lzpos[p],p-lzpos[p],indata[p],
+                                              (mode[p] & MMARK)?"#":" ");
+                break;
+            case MMARK | LITERAL:
+            case LITERAL:
+                if (flags & F_VERBOSE) {
+                    if (j==p) printf(">");
+                    else      printf(" ");
+
+                    if (lzpos2) {
+                        printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p],
+                               (indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                    }
+                }
+                if (j==p) {
+                    if (flags & F_VERBOSE) {
+                        printf("*001*  %03d   %03d  %04x(%04x)  %02x %s %02x",
+                               rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                               (mode[p] & MMARK)?"#":" ", newesc[p]);
+                    }
+                    if ((indata[p] & escMask) == vescape) {
+                        vescape = newesc[p];
+                        if (flags & F_VERBOSE) printf("«");
+                    }
+                    if (flags & F_VERBOSE) printf("\n");
+                    j += 1;
+                } else {
+                    if (flags & F_VERBOSE) printf("*001*  %03d   %03d  %04x(%04x)  %02x %s %02x\n",
+                                                  rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                                                  (mode[p] & MMARK)?"#":" ", newesc[p]);
+                }
+                break;
+            case MMARK | LZ77:
+            case LZ77:
+                if (j==p) {
+                    if (flags & F_VERBOSE) printf(">");
+                    j += lzlen[p];
+                } else
+                    if (flags & F_VERBOSE) printf(" ");
+                if (lzpos2) {
+                    if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p],
+                                                  (indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                }
+                if (flags & F_VERBOSE) printf(" 001   %03d  *%03d* %04x(%04x)  %02x %s\n",
+                                              rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                                              (mode[p] & MMARK)?"#":" ");
+                break;
+            case MMARK | RLE:
+            case RLE:
+                if (j==p) {
+                    if (flags & F_VERBOSE) printf(">");
+                    j += rle[p];
+                } else
+                    if (flags & F_VERBOSE) printf(" ");
+                if (lzpos2) {
+                    if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p],
+                                                  (indata[p] - indata[p-lzpos2[p]]) & 0xff);
+                }
+                if (flags & F_VERBOSE) printf(" 001  *%03d*  %03d  %04x(%04x)  %02x %s\n",
+                                              rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p],
+                                              (mode[p] & MMARK)?"#":" ");
+                break;
+            default:
+                j++;
+                break;
+            }
+            mode[p] &= ~MMARK;
+	  }
+#endif
+        switch (mode[p]) {
+        case LITERAL: /* normal */
+            length[p] = outPointer;
+
+            OutputNormal(&escape, indata+p, newesc[p]);
+            p++;
+            break;
+
+        case DLZ:
+            for (i=0; i<lzlen2[p]; i++) length[p+i] = outPointer;
+
+            PutNBits((escape>>(8-escBits)), escBits);   
+            PutValue(lzlen2[p]-1);
+            PutValue((2<<maxGamma)-1); 
+            PutNBits((indata[p] - indata[p-lzpos2[p]]) & 0xff, 8);
+            PutNBits(((lzpos2[p]-1) & 0xff) ^ 0xff, 8);
+            gainedDLz += 8*lzlen2[p] -(escBits + LenValue(lzlen2[p]-1) + 2*maxGamma + 16);
+            timesDLz++;
+            p += lzlen2[p];
+            break;
+
+        case LZ77: /* lz77 */
+
+            /* Not possible for smaller backSkip table
+               (the table is overwritten during previous use) */
+            /* Re-search matches to get the closest one */
+            if (lzopt && lzlen[p] > 2 && lzlen[p] > rle[p]) {
+                int bot = p - lzpos[p] + 1, i;
+                unsigned short rlep = rle[p];
+
+                if (!rlep)
+                    rlep = 1;
+                if (bot < 0)
+                    bot = 0;
+                bot += (rlep-1);
+
+                i = p - (int)backSkip[p];
+                while (i>=bot /* && i>=rlep-1 */) {
+                    /* Equal number of A's ? */
+                    if (rlep==1 || rle[i-rlep+1]==rlep) {       /* 'head' matches */
+                        unsigned char *a = indata + i+1;        /* match  */
+                        unsigned char *b = indata + p+rlep-1+1; /* curpos */
+                        int topindex = inlen-(p+rlep-1);
+
+                        j = 1;
+                        while (j < topindex && *a++==*b++)
+                            j++;
+
+                        if (j + rlep-1 >= lzlen[p]) {
+                            int tmppos = p-i+rlep-1;
+#ifdef EVEN_LZ
+							if (!(tmppos&1)) {
+#endif
+
+                            rescan +=
+                                LenLz(lzlen[p], lzpos[p]) -
+                                LenLz(lzlen[p], tmppos);
+#ifdef EVEN_LZ
+							if (tmppos&1)
+								fprintf(stderr,"Error: misalign in tmppos\n");
+#endif
+                            lzpos[p] = tmppos;
+                            break;
+#ifdef EVEN_LZ
+							}
+#endif
+                        }
+                    }
+                    if (!backSkip[i])
+                        break; /* No previous occurrances (near enough) */
+                    i -= (int)backSkip[i];
+                }
+            }
+
+            for (i=0; i<lzlen[p]; i++)
+                length[p+i] = outPointer;
+            OutputLz(&escape, lzlen[p], lzpos[p], indata+p-lzpos[p], p);
+            p += lzlen[p];
+            break;
+
+        case RLE: /* rle */
+            for (i=0; i<rle[p]; i++)
+                length[p+i] = outPointer;
+            OutputRle(&escape, indata+p, rle[p]);
+            p += rle[p];
+            break;
+
+        default: /* Error Flynn :-) */
+            p++;
+            fprintf(stderr, "Internal error: mode %d\n", mode[p]);
+            break;
+        }
+    }
+    OutputEof(&escape);
+
+    i = inlen;
+    for (p=0; p<inlen; p++) {
+        int pos = (inlen - outPointer) + (int)length[p] - p;
+        i = min(i, pos);
+    }
+    if (i<0)
+        reservedBytes = -i + 2;
+    else
+        reservedBytes = 0;
+
+    headerSize = sizeof(PackedHeader) + rleUsed;
+
+    outlen = outPointer;   /* we don't count the header... */
+
+errorexit:
+    if (rle)       free(rle);
+    if (elr)       free(elr);
+    if (lzlen)     free(lzlen);
+    if (lzpos)     free(lzpos);
+    if (length)    free(length);
+    if (mode)      free(mode);
+    if (newesc)    free(newesc);
+    if (lastPair)  free(lastPair);
+    if (backSkip)  free(backSkip);
+    if (hashValue) free(hashValue);
+    return 0;
+}
+
+#define NO_HEX_CHARACTER       255
+
+//=============================================================================
+// converts hexdigit to number
+//=============================================================================
+unsigned char hex2int(unsigned char c) {
+    c = tolower(c);
+
+    if (c >= 'a' && c <= 'f') return c - 'a' + 10;    
+    if (c >= '0' && c <= '9') return c - '0';
+    return NO_HEX_CHARACTER;
+}
+
+
+//=============================================================================
+// converts hex text into binary
+//=============================================================================
+int ConvertText2Bin(unsigned char* ib,int origlen) {
+    int           pos;
+    int           cnt = 0;
+    int           searchforendofline = 0;
+    int           len_after_convert  = 0;
+    unsigned char val = 0;
+    unsigned char actual;
+        
+    len_after_convert = 0;
+    for (pos = 0; pos < origlen;pos++) {
+        if (searchforendofline) {
+            if (ib[pos] == '\n') searchforendofline = 0;
+            continue;
+        }
+        if (ib[pos] == '/') {
+            cnt = 0;
+            if (pos < origlen-1 && ib[pos+1] == '/') searchforendofline = 1;
+            continue;
+        }
+
+        actual = hex2int(ib[pos]);
+        if (actual == NO_HEX_CHARACTER) {
+            cnt = 0;
+            continue;
+        }
+        if (cnt == 0) {
+            val = actual*16;
+            cnt++;
+        }
+        else {
+            val += actual;
+            cnt=0;
+            ib[len_after_convert++] = val;
+        }
+    }
+    return(len_after_convert);
+}
+
+void *GTPackDo(void *buf,unsigned short *buflen) {
+    int   startEscape;
+    char *ptr;
+
+//    unsigned long timeused = clock();
+
+    lrange    = LRANGE;
+    maxlzlen  = MAXLZLEN;
+    maxrlelen = MAXRLELEN;
+
+    InitValueLen();
+    
+	indata = buf;
+	inlen = *buflen;
+	PackLz77(lrange, F_AUTO|F_AUTOEX, &startEscape, 1234, 12345, 0);
+	free(indata);
+	{
+		int i;
+		PackedHeader	cth;
+		RLEEntries		re;
+
+		cth.origsize_lo = inlen & 0xff;
+		cth.origsize_hi = (inlen >> 8);
+		memcpy(cth.magic,"GTPk",4);
+		cth.compsize_lo = (outlen + rleUsed + sizeof(PackedHeader)) & 0xff;
+		cth.compsize_hi = (outlen + rleUsed + sizeof(PackedHeader)) >> 8;
+		cth.esc1		= (startEscape >> (8-escBits));
+		cth.esc2		= escBits;
+		cth.extralz 	= extraLZPosBits;
+		cth.rleentries	= rleUsed;
+
+		for(i=0; i<rleUsed; i++) re.value[i] = rleValues[i+1];
+
+		indata = malloc((*buflen=sizeof(PackedHeader)+cth.rleentries+outlen));
+		ptr = indata;
+		memcpy(ptr, &cth, sizeof(PackedHeader)), ptr+=sizeof(PackedHeader);
+		memcpy(ptr, &re, cth.rleentries), ptr+=cth.rleentries;
+		memcpy(ptr, outBuffer, outlen), ptr+=outlen;
+	}
+	return indata;
+}
+
+
+//#############################################################################
+//###################### NO MORE FAKES BEYOND THIS LINE #######################
+//#############################################################################
+//
+//=============================================================================
+// Revision History
+//=============================================================================
+//
+// $Log: ttpack.c,v $
+// Revision 1.5  2005/08/04 21:27:43  Paul Froissart
+// adapted for XPak
+//
+// Revision 1.4  2000/08/23 20:10:56  Thomas Nussbaumer
+// header corrected
+//
+// Revision 1.3  2000/08/23 20:10:17  Thomas Nussbaumer
+// adapted to automatic version display (revtools.h)
+//
+// Revision 1.2  2000/08/20 15:30:11  Thomas Nussbaumer
+// minor correction of header
+//
+// Revision 1.1  2000/08/16 23:05:59  Thomas Nussbaumer
+// initial version
+//
+//

+ 99 - 0
gtc/src/gtpack/packhead.h

@@ -0,0 +1,99 @@
+/******************************************************************************
+*
+* original project name:    TIGCC Tools Suite 
+* file name:		    packhead.h
+* initial date:		    14/08/2000
+* authors:		    thomas.nussbaumer@gmx.net 
+*			    Paul Froissart
+* description:              header definition of compressed data
+*
+* $Id: packhead.h,v 1.3 2000/08/20 15:24:28 Thomas Nussbaumer Exp $
+*
+******************************************************************************/
+
+#ifndef __PACKHEAD_H__
+#define __PACKHEAD_H__
+
+#ifndef EVEN_LZ
+#define MAGIC_CHAR1     'P'
+#define MAGIC_CHAR2     'k'
+#else
+#define MAGIC_CHAR1     'P'
+#define MAGIC_CHAR2     'x'
+#endif
+
+#define MAX_RLE_ENTRIES 31
+
+#define COMPACT
+//#define OLD_HDR
+
+#ifdef OLD_HDR
+// size = 8 bytes
+typedef struct {
+    unsigned char origsize_hi; // original size lowbyte
+    unsigned char origsize_lo; // original size highbyte
+//    unsigned char magic1;      // must be equal to MAGIC_CHAR1
+//    unsigned char magic2;      // must be equal to MAGIC_CHAR2
+//    unsigned char compsize_lo; // compressed size lowbyte
+//    unsigned char compsize_hi; // compressed size lowbyte
+    unsigned char esc1;        // escape >> (8-escBits)
+//    unsigned char notused3;
+//    unsigned char notused4;
+    unsigned char esc2;        // escBits
+    unsigned char gamma1;      // maxGamma + 1
+    unsigned char gamma2;      // (1<<maxGamma)
+    unsigned char extralz;     // extraLZPosBits
+//    unsigned char notused1;
+//    unsigned char notused2;
+    unsigned char rleentries;  // rleUsed
+} PackedHeader;
+#else
+// size = 12 bytes
+typedef struct {
+    char magic[4];
+    unsigned char origsize_hi; // original size lowbyte
+    unsigned char origsize_lo; // original size highbyte
+    unsigned char compsize_hi; // compressed size lowbyte
+    unsigned char compsize_lo; // compressed size highbyte
+    unsigned char esc2;        // escBits
+    unsigned char esc1;        // escape >> (8-escBits)
+    unsigned char extralz;     // extraLZPosBits
+    unsigned char rleentries;  // rleUsed
+} PackedHeader;
+#endif
+
+
+#define GetUnPackedSize(p)  (unsigned int)((p)->origsize_lo | ((p)->origsize_hi << 8))
+#define IsPacked(p)         ((p)->magic1 == MAGIC_CHAR1 && (p)->magic2 == MAGIC_CHAR2)
+
+
+typedef struct { 
+    unsigned char value[MAX_RLE_ENTRIES];
+} RLEEntries;
+
+
+#endif
+
+
+//#############################################################################
+//###################### NO MORE FAKES BEYOND THIS LINE #######################
+//#############################################################################
+//
+//=============================================================================
+// Revision History
+//=============================================================================
+//
+// $Log: packhead.h,v $
+// Revision 1.4  2005/08/04 21:27:43  Paul Froissart
+// adapted for XPak
+//
+// Revision 1.3  2000/08/20 15:24:28  Thomas Nussbaumer
+// macros to get unpacked size and to check if packed added
+//
+// Revision 1.2  2000/08/16 23:08:55  Thomas Nussbaumer
+// magic characters changed to TP ... t(igcc tools) p(acked file)
+//
+// Revision 1.1  2000/08/14 22:49:57  Thomas Nussbaumer
+// initial version
+//
+// 

+ 108 - 0
gtc/src/gtpack/revtools.h

@@ -0,0 +1,108 @@
+/******************************************************************************
+*
+* project name:    TIGCC Tools Suite 
+* file name:       revtools.h
+* initial date:    23/08/2000
+* author:          thomas.nussbaumer@gmx.net 
+* description:     macros for automatic handling of version number output
+*                  which is in sync with the CVS version number
+*
+* examine one of the pctools source codes to see how it works ;-)
+*
+* [NO CVS ID HERE BY INTENTION]
+*
+******************************************************************************/
+
+//-----------------------------------------------------------------------------
+// [Usage]
+//
+// (1) include this file into your tool
+//
+//
+// (2) AFTER (!!) all includes put the following lines into your source code:
+//
+// #ifdef CVS_FILE_REVISION
+// #undef CVS_FILE_REVISION
+// #endif
+// ----------------------------------------------------------------------------
+// DON'T EDIT THE NEXT REVISION BY HAND! THIS IS DONE AUTOMATICALLY BY THE
+// CVS SYSTEM !!!
+// ----------------------------------------------------------------------------
+// #define CVS_FILE_REVISION "$Revision$"
+//
+// It must be placed AFTER (!!) all includes otherwise the macros may be
+// expanded wrong where you use them. For example: if you have added the above
+// lines at the top of your file and include afterwards a file which does
+// the same, the version of the included file will be used further due to the
+// #undef CVS_FILE_REVISION. Everything clear?
+//
+//
+// (3) to output the cvs revision number you can now to a simple:
+// 
+// printf(CVSREV_PRINTPARAMS)
+//
+// if your file has, for example, the revision 1.3 the following string will
+// be printed:  v1.03
+//
+// the prefix before the subversion is used to get equal-sized output strings
+// for mainversions between 1 ... 9 and subversion between 1 .. 99
+//
+// if your program leaves that range and you need to have equal-sized output
+// strings you have to implement it by your own by using the
+// CVSREV_MAIN and CVSREV_SUB macros which returns the main and sub versions
+// as plain integers. if there is something wrong with your revision string
+// CVSREV_MAIN and/or CVSREV_SUB will deliver 0, which is no valid CVS main
+// or subversion number.
+//
+// i will suggest that you use the CVS system. its simple to handle, keeps
+// track of your revisions and their history and with the smart macros below
+// you haven't to worry anymore about the version output strings of your
+// program. if you want a special version number you can force CVS at every
+// time to give this version number to your program (0 is not allowed as
+// main and subversion number - thats the only pity)
+//
+// within this tools suite every tool will use the automatic version handling
+// but the tool suite version number itself will be handled "by hand".  
+// this number shouldn't change that quickly as with the tools.
+//
+//-----------------------------------------------------------------------------
+#ifndef __REV_TOOLS_H__
+#define __REV_TOOLS_H__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+//-----------------------------------------------------------------------------
+// just used internally
+//-----------------------------------------------------------------------------
+#define CVS_TRUNC_PREFIX    ((strlen((CVS_FILE_REVISION))<=11) ? 0 : (CVS_FILE_REVISION+11))
+#define CVS_FIND_COMMA      (strchr(CVS_TRUNC_PREFIX,'.'))
+#define CVSREV_MAIN         (int)(!(CVS_TRUNC_PREFIX) ? 0 : atoi(CVS_TRUNC_PREFIX))
+#define CVSREV_SUB          (int)(!(CVS_TRUNC_PREFIX) ? 0 : (!(CVS_FIND_COMMA) ? 0 : atoi(CVS_FIND_COMMA+1)))
+
+//-----------------------------------------------------------------------------
+// NOTE: THE FOLLOWING MACRO WILL ONLY HANDLE MAIN VERSION < 10 AT CONSTANT 
+//       LENGTH !!!
+//       (subversions from 1 .. 99 are mapped to 01 .. 99)
+//
+// the following macro may be used to setup a printf(),sprintf() or fprintf() 
+// call
+//-----------------------------------------------------------------------------
+#define CVSREV_PRINTPARAMS  "v%d.%02d",CVSREV_MAIN,CVSREV_SUB
+
+
+#define PRINT_ID(name)  fprintf(stderr,"\n");fprintf(stderr, name" ");\
+                        fprintf(stderr,CVSREV_PRINTPARAMS);\
+                        fprintf(stderr," - TIGCC Tools Suite v"TTV_MAIN TTV_SUB"\n" \
+                                       "(c) thomas.nussbaumer@gmx.net " TTV_DATE"\n\n");
+
+
+
+
+
+
+#endif
+
+//#############################################################################
+//###################### NO MORE FAKES BEYOND THIS LINE #######################
+//#############################################################################

+ 48 - 0
gtc/src/gtpack/tt.h

@@ -0,0 +1,48 @@
+/******************************************************************************
+*
+* project name:    TIGCC Tools Suite 
+* file name:       tt.h
+* initial date:    13/08/2000
+* author:          thomas.nussbaumer@gmx.net 
+* description:     generic definitions for TIGCC Tools Suite
+*
+* $Id: tt.h,v 1.3 2000/08/23 20:29:43 Thomas Nussbaumer Exp $
+*
+******************************************************************************/
+
+#ifndef __TT_H__
+#define __TT_H__
+
+#define CALC_TI89    0
+#define CALC_TI92P   1
+
+#define SIGNATURE_TI89   "**TI89**"
+#define SIGNATURE_TI92P  "**TI92P*" 
+
+#define DEFAULT_FOLDER   "main"
+
+#define DEFAULT_ITEMS_PER_LINE  10
+
+#endif
+
+//#############################################################################
+//###################### NO MORE FAKES BEYOND THIS LINE #######################
+//#############################################################################
+//
+//=============================================================================
+// Revision History
+//=============================================================================
+//
+// $Log: tt.h,v $
+// Revision 1.3  2000/08/23 20:29:43  Thomas Nussbaumer
+// added a 'P' to the TI92p definitions
+//
+// Revision 1.2  2000/08/23 01:04:41  Thomas Nussbaumer
+// corrected signature of TI92p
+//
+// Revision 1.1  2000/08/13 20:24:16  Thomas Nussbaumer
+// initial version
+//
+//
+//
+//

+ 49 - 0
gtc/src/gtpack/ttunpack.h

@@ -0,0 +1,49 @@
+/******************************************************************************
+*
+* project name:    TIGCC Tools Suite 
+* file name:       ttunpack.h
+* initial date:    14/08/2000
+* author:          thomas.nussbaumer@gmx.net 
+* description:     defines of errorcodes of decompression routine and its
+*                  declaration
+* $Id: ttunpack.h,v 1.2 2000/08/20 15:26:21 Thomas Nussbaumer Exp $
+*
+******************************************************************************/
+
+#ifndef __TTUNPACK_H__
+#define __TTUNPACK_H__
+
+#define K_GAMMA 1
+#define M_GAMMA 0
+
+#define ERRPCK_OKAY             0
+#define ERRPCK_NOESCFOUND     248
+#define ERRPCK_ESCBITS        249  
+#define ERRPCK_MAXGAMMA       250
+#define ERRPCK_EXTRALZP       251
+#define ERRPCK_NOMAGIC        252 
+#define ERRPCK_OUTBUFOVERRUN  253
+#define ERRPCK_LZPOSUNDERRUN  254
+
+int _tt_Decompress(unsigned char *src, unsigned char *dest);
+#define UnPack _tt_Decompress
+
+#endif
+
+
+//#############################################################################
+//###################### NO MORE FAKES BEYOND THIS LINE #######################
+//#############################################################################
+//
+//=============================================================================
+// Revision History
+//=============================================================================
+//
+// $Log: ttunpack.h,v $
+// Revision 1.2  2000/08/20 15:26:21  Thomas Nussbaumer
+// prefix of unpack routine (_tt_) corrected
+//
+// Revision 1.1  2000/08/14 22:49:57  Thomas Nussbaumer
+// initial version
+//
+// 

+ 53 - 0
gtc/src/gtpack/ttversion.h

@@ -0,0 +1,53 @@
+/******************************************************************************
+*
+* project name:    TIGCC Tools Suite 
+* file name:       ttversion.h
+* initial date:    13/08/2000
+* author:          thomas.nussbaumer@gmx.net 
+* description:     TIGCC Tools Suite version definitions
+*
+* $Id: ttversion.h,v 1.7 2000/10/01 14:59:22 Thomas Nussbaumer Exp $
+*
+******************************************************************************/
+
+#ifndef __TTVERSION_H__
+#define __TTVERSION_H__
+
+#define TTV_MAIN   "0.95"
+#define TTV_SUB    ""
+#define TTV_DATE   "01/10/2000"
+
+#endif
+
+//#############################################################################
+//###################### NO MORE FAKES BEYOND THIS LINE #######################
+//#############################################################################
+//
+//=============================================================================
+// Revision History
+//=============================================================================
+//
+// $Log: ttversion.h,v $
+// Revision 1.7  2000/10/01 14:59:22  Thomas Nussbaumer
+// generic commit
+//
+// Revision 1.6  2000/08/27 23:52:39  Thomas Nussbaumer
+// forcing version to 0.41
+//
+// Revision 1.5  2000/08/23 20:31:37  Thomas Nussbaumer
+// next version step
+//
+// Revision 1.4  2000/08/23 01:05:59  Thomas Nussbaumer
+// next version step
+//
+// Revision 1.3  2000/08/16 23:09:15  Thomas Nussbaumer
+// version actualized to 0.15
+//
+// Revision 1.2  2000/08/13 20:26:12  Thomas Nussbaumer
+// version now 0.10 (preview release)
+//
+// Revision 1.1  2000/08/13 16:02:13  Thomas Nussbaumer
+// initial version
+//
+//
+//

+ 22 - 0
gtc/src/identity.h

@@ -0,0 +1,22 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) volatilizing a value
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef __IDENTITY
+#define __IDENTITY
+void *identity(void *x) {
+	return x;
+}
+#endif
+// vim:ts=4:sw=4

+ 434 - 0
gtc/src/init.c

@@ -0,0 +1,434 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * initialisations
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#define USE_MEMMGT
+#include	"cglbdec.h"
+
+long 	inittype(TYP *,TYP **);
+static long 	initstruct(TYP *,TYP **), initarray(TYP *,TYP **), initunion(TYP *,TYP **);
+static int		initchar(), initshort(), initlong(), initpointer();
+#ifndef NOFLOAT
+static int		initfloat();
+#ifdef DOUBLE
+static int		initdouble();
+#endif
+#endif
+static struct enode *constexpr();
+extern TYP *copy_type(TYP *s);
+
+TYP *copy_type_global(TYP *tp) {
+	TYP *tp2;
+	temp_local++;
+	global_flag++;
+	tp2=copy_type(tp);
+	global_flag--;
+	temp_local--;
+	return tp2;
+}
+
+void doinit(struct sym *sp, int align) {
+	nl();
+	if (lastst != assign)
+		genstorage(sp, align);
+	else {
+		struct slit *strtab_old=strtab;
+		int glob = global_flag;
+		int no_locblk = !locblk;
+/*		if (lineid>=0x100)
+			bkpt();*/
+		strtab = 0;
+		global_flag = 0;
+		tmp_use();
+		temp_local++;
+		global_strings++;
+		dseg(); 				/* select data segment */
+		put_align(align);
+#ifndef AS
+		if (sp->storage_class == sc_static)
+			put_label((unsigned int) sp->value.i);
+		else
+			g_strlab(sp->name);
+#else
+#ifdef PC
+#define gnu_hook(x,y) ((x)?(x):(y))
+#else
+#define gnu_hook(x,y) ((x)?:(y))
+#endif
+		if (sp->storage_class == sc_static) {
+			extern int glblabel;
+			put_label(gnu_hook(sp->value.splab,sp->value.splab=nxtglabel()));
+		} else
+			put_label(splbl(sp));
+#endif
+		getsym();
+		(void) inittype(sp->tp,&sp->tp);
+/*		if (strtab)
+			bkpt();*/
+		if (strtab)
+			dumplits();
+		global_strings--;
+		temp_local--;
+		tmp_free(); /* just in case, but shouldn't get used because of temp_local */
+		if (no_locblk && locblk)
+			rel_local();
+		global_flag = glob;
+		strtab = strtab_old;
+	}
+}
+
+long inittype(TYP *tp,TYP **tpp) {
+	int 			brace_seen = 0;
+	long			nbytes;
+	if (lastst == begin) {
+		brace_seen = 1;
+		getsym();
+	}
+	switch (tp->type) {
+	  case bt_char:
+	  case bt_uchar:
+		nbytes = initchar();
+		break;
+	  case bt_short:
+	  case bt_ushort:
+		nbytes = initshort();
+		break;
+	  case bt_pointer:
+		if (tp->val_flag)
+			nbytes = initarray(tp,tpp);
+		else {
+			nbytes = initpointer();
+		}
+		break;
+	  case bt_ulong:
+	  case bt_long:
+		nbytes = initlong();
+		break;
+#ifndef NOFLOAT
+	  case bt_float:
+		nbytes = initfloat();
+		break;
+#ifdef DOUBLE
+	  case bt_double:
+		nbytes = initdouble();
+		break;
+#endif
+#endif
+	  case bt_struct:
+		nbytes = initstruct(tp,tpp);
+		break;
+	  case bt_union:
+		nbytes = initunion(tp,tpp);
+		break;
+	  default:
+		error(ERR_NOINIT);
+		nbytes = 0;
+	}
+	if (brace_seen)
+		needpunc(end);
+	return nbytes;
+}
+
+/*void modf_btp(TYP *new_btp,TYP *tp) {
+	tp=copy_type(tp);
+	tp->btp=new_btp;
+	modf(tp,modfp);
+}*/
+
+extern unsigned int pos;
+static long initarray(TYP *tp,TYP **tpp) {
+	long			nbytes;
+	char		   *p;
+	int 			len;
+#ifdef AS
+	unsigned int max_pos=pos;
+#endif
+//	tmp_use();
+	nbytes = 0;
+	if (lastst == sconst && (tp->btp->type == bt_char ||
+							 tp->btp->type == bt_uchar)) {
+		len = lstrlen;
+		nbytes = len;
+		p = laststr;
+		while (len--)
+			genbyte(*p++);
+		if (!tp->size)	/* if tp->size!=0, then the padding stuff takes care of it */
+			genbyte(0), nbytes++;
+		while (nbytes < tp->size)
+			genbyte(0), nbytes++;
+		getsym();				/* skip sconst */
+	} else if (lastst == kw_incbin) {
+		FILE *fp; int size;
+#ifndef PC
+		unsigned char type;
+#endif
+/*		getsym();
+		if (lastst!=sconst)
+			error(ERR_SYNTAX);*/
+		skipspace();
+		if (lastch!='"')
+			error(ERR_SYNTAX);
+		getch();
+		getidstr();
+		if (lastch!='"')
+			error(ERR_SYNTAX);
+		getch();
+		getsym();
+		fp=fopen(lastid,"rb");
+		if (!fp)
+			uerr(ERR_CANTOPEN,lastid);
+#ifdef PC
+		p=malloc(100000);
+		size=fread(p,1,100000,fp);
+#else
+		p=*(char **)fp;
+		size=*(unsigned short *)p;
+		type=p[size+1];
+		if (type==0xF3 || type==0xE0) size--;
+		else if (type==0xF8) { size--; do size--; while (p[size+1]); }
+#endif
+		if (tp->size && size>tp->size) size=tp->size;
+		nbytes=size;
+		while (size--) genbyte(*p++);
+		while (nbytes<tp->size) {
+			genbyte(0);
+			nbytes++;
+		}
+	} else if (lastst == end)
+		goto pad;
+	else {
+		int i,additional,size;
+		for (i=0;;) {
+			additional=0;
+			if (lastst == openbr) {
+				getsym(); {
+				int j=intexpr();
+				long diff=tp->btp->size*(j-i);
+				if (lastst == dots) {
+					getsym();
+					additional=intexpr()-j;
+				}
+				if (lastst != closebr) error(ERR_SYNTAX);
+				else {
+					getsym();
+					if (lastst == assign) getsym();
+					if (i<j) {
+						nbytes += diff;
+						while (diff--)
+							genbyte(0);
+						i=j;
+					} else if (j<i) {
+	#ifdef AS
+						move_pos(diff); nbytes+=diff; i=j;
+	#else
+	//					uwarn("brackets not supported in non-AS mode");
+	#endif
+					}
+				}
+			}}
+			if (additional>=0) {
+				nbytes += (size=inittype(tp->btp,NULL)); i++;
+#ifdef AS
+				while (additional--) rewrite(size), nbytes+=size, i++;
+#endif
+			}
+	#ifdef AS
+			if (pos>max_pos) max_pos=pos;
+	#endif
+			if (lastst == comma)
+				getsym();
+			if (lastst == end || lastst == semicolon) {
+			  pad:
+	#ifdef AS
+				if (pos<max_pos) move_pos(max_pos-pos), nbytes+=max_pos-pos;
+	#endif
+				while (nbytes < tp->size) {
+					genbyte(0);
+					nbytes++;
+				}
+				break;
+			}
+			if (tp->size > 0 && nbytes >= tp->size)
+				break;
+		}
+	}
+#if 0
+	if (tp->size == 0)
+		tp->size = nbytes;
+	if (nbytes > tp->size)
+		error(ERR_INITSIZE);
+#else
+	if (tp->size && nbytes > tp->size)
+		error(ERR_INITSIZE);
+	if (tp->size != nbytes && tpp)
+		/* fix the symbol's size, unless tpp=0 (item of a struct/union or array) */
+		tp = copy_type_global(tp),
+		*tpp = tp,
+		tp->size = nbytes;	// we need this for the 'sizeof' operator...
+#endif
+//	tmp_free();
+	return nbytes;
+}
+
+static long initunion(TYP *tp,TYP **tpp) {
+	struct sym	   *sp;
+	long			nbytes;
+	
+	int brace_seen = 0;
+	if (lastst == begin) {
+		brace_seen = 1;
+		getsym();
+	}
+
+	sp = tp->lst.head;
+/*
+ * Initialize the first branch
+ */
+	if (sp == 0)
+		return 0;
+	nbytes = inittype(sp->tp,NULL);
+	while (nbytes < tp->size) {
+		genbyte(0);
+		nbytes++;
+	}
+
+	if (tp->size != nbytes && tpp)
+		tp = copy_type_global(tp),
+		*tpp = tp,
+		tp->size = nbytes;	// we need this for the 'sizeof' operator...
+
+	if (brace_seen)
+		needpunc(end);
+}
+
+static long initstruct(TYP *tp,TYP **tpp) {
+	struct sym	   *sp;
+	long			nbytes;
+	nbytes = 0;
+	sp = tp->lst.head;			/* start at top of symbol table */
+	if (lastst != end)
+		while (sp != 0) {
+			while (nbytes < sp->value.i) {	/* align properly */
+				nbytes++;
+				genbyte(0);
+			}
+			nbytes += inittype(sp->tp,NULL);
+			if (lastst == comma)
+				getsym();
+			if (lastst == end || lastst == semicolon)
+				break;
+			sp = sp->next;
+		}
+	while (nbytes < tp->size) {
+		genbyte(0);
+		nbytes++;
+	}
+	if (tp->size != nbytes && tpp)
+		tp = copy_type_global(tp),
+		*tpp = tp,
+		tp->size = nbytes;	// we need this for the 'sizeof' operator...
+
+	return tp->size;
+}
+
+static int initchar() {
+	genbyte((int) intexpr());
+	return 1;
+}
+
+static int initshort() {
+	genword((int) intexpr());
+	return 2;
+}
+
+static int initlong() {
+/*
+ * We allow longs to be initialized with pointers now.
+ * Thus, we call constexpr() instead of intexpr.
+ */
+#if 0
+/*
+ * This is more strict
+ */
+	genlong(intexpr());
+	return 4;
+#endif
+	genptr(constexpr());
+	return 4;
+}
+
+#ifndef NOFLOAT
+static int initfloat() {
+#ifndef NOFLOAT
+	double			floatexpr();
+#ifdef PC
+	genfloat(floatexpr());
+#else
+#ifndef BCDFLT
+	genptr(floatexpr());
+#else
+	genfloat(floatexpr());
+#endif
+#endif
+#endif
+#ifdef NOFLOAT
+	genptr(0l);
+#endif
+	return 4;
+}
+
+#ifdef DOUBLE
+static int initdouble() {
+#ifdef NOFLOAT
+	int i;
+	for (i=0; i< tp_double.size; i++)
+		genbyte(0);
+#endif
+#ifndef NOFLOAT
+	double floatexpr();
+	gendouble(floatexpr());
+#endif
+	return tp_double.size;
+}
+#endif
+#endif
+
+static int initpointer() {
+	genptr(constexpr());
+	return 4;
+}
+
+static struct enode *constexpr() {
+	struct enode *ep;
+	struct typ	 *tp;
+/*	if (lineid==0x1e0)
+		bkpt();*/
+	tp=exprnc(&ep);
+	if (tp == 0) {
+		error(ERR_EXPREXPECT);
+		return 0;
+	}
+	opt0(&ep);
+	if (!tst_const(ep)) {
+		error(ERR_CONSTEXPECT);
+		return 0;
+	}
+	return ep;
+}
+// vim:ts=4:sw=4

+ 96 - 0
gtc/src/intexpr.c

@@ -0,0 +1,96 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * integer expression routines
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifndef NOFLOAT
+#include	"ffplib.h"
+#endif
+
+#ifndef NOFLOAT
+double floatexpr() {
+/* floating point expression */
+	struct enode   *ep;
+	struct typ	   *tp;
+
+	tp = exprnc(&ep);
+	if (tp == 0) {
+		error(ERR_FPCON);
+		return (double) 0;
+	}
+
+	opt0(&ep);
+
+	if (ep->nodetype == en_icon)
+#ifdef PC
+		return (double) ep->v.i;
+#else
+		return ffpltof(ep->v.i);
+#endif
+
+	if (ep->nodetype == en_fcon)
+		return ep->v.f;
+
+	error (ERR_SYNTAX);
+	return (double) 0;
+}
+#endif /* !NOFLOAT */
+
+long intexpr() {
+	struct enode   *ep;
+	struct typ	   *tp;
+	long val;
+
+	tmp_use();
+	tp = exprnc(&ep);
+	if (tp == 0) {
+		error(ERR_INTEXPR);
+		return 0;
+	}
+	opt0(&ep);
+
+	if (ep->nodetype != en_icon) {
+		error(ERR_SYNTAX);
+		return 0;
+	}
+	val=ep->v.i;
+	tmp_free();
+	return val;
+}
+
+#if 0
+long intexpr_notemp() {
+	struct enode   *ep;
+	struct typ	   *tp;
+
+	tp = exprnc(&ep);
+	if (tp == 0) {
+		error(ERR_INTEXPR);
+		return 0;
+	}
+	opt0(&ep);
+
+	if (ep->nodetype != en_icon) {
+		error(ERR_SYNTAX);
+		return 0;
+	}
+	return ep->v.i;
+}
+#endif
+// vim:ts=4:sw=4

+ 532 - 0
gtc/src/memmgt.c

@@ -0,0 +1,532 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * memory management
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#define USE_MEMMGT
+#include	"cglbdec.h"
+
+int		glbsize CGLOB,	/* size left in current global block */
+		locsize CGLOB,	/* size left in current local block */
+		tmpsize CGLOB,	/* size left in current temp block */
+		glbindx CGLOB,	/* global index */
+		locindx CGLOB,	/* local index */
+		tmpindx CGLOB;	/* temp index */
+
+int 	temp_mem CGLOB,temp_local CGLOB;
+#ifdef MIN_TEMP_MEM
+int		min_temp_mem CGLOB;
+#endif
+
+#ifdef PC
+int glbmem CGLOB,locmem CGLOB;
+#endif
+
+int		max_mem CGLOB,	/* statistics... */
+		glo_mem CGLOB;
+
+struct blk *locblk CGLOB,	/* pointer to local block list */
+	   *glbblk CGLOB,		/* pointer to global block list */
+	   *tmpblk CGLOB;		/* pointer to temporary block list */
+
+#ifdef PC
+//void *calloc();
+#endif
+static void _err_attr error_memory() {
+	uerrc2("not enough memory to compile function '%s'",func_sp->name);
+}
+int *_xalloc(int siz) {
+	struct blk *bp;
+	char *rv;
+	if (temp_local)	/* this is NOT perfect, but it's close to being so :) */
+		goto glb_xalloc;
+/*	if (locmem>=50000)
+		bkpt();*/
+/*	if (siz>=1000)
+		bkpt();*/
+#ifdef MIN_TEMP_MEM
+	if (temp_mem<=min_temp_mem) {
+#else
+	if (!temp_mem) {
+#endif
+	glb_xalloc:
+		if (global_flag) {
+	#ifdef PC
+			glbmem += siz;
+	#endif
+			if (glbsize >= siz) {
+				rv = &(glbblk->m[glbindx]);
+				glbsize -= siz;
+				glbindx += siz;
+/*				if ((long)rv==0x789388)
+					bkpt();*/
+				return (int *) rv;
+			} else {
+	//			bp = (struct blk *) calloc(1, (int) sizeof(struct blk));
+				bp = (struct blk *) malloc(sizeof(struct blk));
+				if (!bp) {
+#ifdef PC
+					msg("not enough memory.\n");
+					_exit(1);
+#else
+					error_memory();
+					fatal("Not enough global memory");
+#endif
+				}
+				memset(bp, 0, sizeof(struct blk));
+				glo_mem++;
+				bp->next = glbblk;
+				glbblk = bp;
+				glbsize = BLKLEN - siz;
+				glbindx = siz;
+				return (int *) glbblk->m;
+			}
+		} else {						/* not global */
+	#ifdef PC
+			locmem += siz;
+	#endif
+			if (locsize >= siz) {
+				rv = &(locblk->m[locindx]);
+				locsize -= siz;
+				/*if ((long)rv==0x7f86bc)
+					bkpt();*/
+				locindx += siz;
+	#ifdef PC
+				if (0x80000000&(long)rv)
+					fatal("A DIRTY HACK FAILED ON YOUR CONFIG. "
+						"LOOK AT OUT68K_AS.C TO SOLVE THE PROBLEM");
+	#endif
+/*				if (func_sp) infunc("chk_curword")
+					if ((long)rv==0x7b4bf8)
+						bkpt();*/
+/*				if ((long)rv==0x7e5cd0)
+					bkpt();*/
+				return (int *) rv;
+			} else {
+	//			bp = (struct blk *) calloc(1, (int) sizeof(struct blk));
+				bp = (struct blk *) malloc(sizeof(struct blk));
+				if (!bp) {
+#ifdef PC
+					msg("not enough local memory.\n");
+					_exit(1);
+#else
+					error_memory();
+					fatal("Not enough local memory");
+#endif
+				}
+				memset(bp, 0, sizeof(struct blk));
+				bp->next = locblk;
+				locblk = bp;
+				locsize = BLKLEN - siz;
+				locindx = siz;
+				return (int *) locblk->m;
+			}
+		}
+	} else {
+		if (tmpsize >= siz) {
+			rv = &(tmpblk->m[tmpindx]);
+			tmpsize -= siz;
+			tmpindx += siz;
+			return (int *) rv;
+		} else {
+//			bp = (struct blk *) calloc(1, (int) sizeof(struct blk));
+			bp = (struct blk *) malloc(sizeof(struct blk));
+			if (!bp) {
+#ifdef PC
+				msg("not enough temporary memory.\n");
+				_exit(1);
+#else
+				error_memory();
+				fatal("Not enough temporary memory");
+#endif
+			}
+/*			if (bp==0x789364)
+				bkpt();*/
+			memset(bp, 0, sizeof(struct blk));
+			bp->next = tmpblk;
+			tmpblk = bp;
+			tmpsize = BLKLEN - siz;
+			tmpindx = siz;
+			return (int *) tmpblk->m;
+		}
+	}
+}
+
+int blk_free(struct blk *bp1) {
+	int blkcnt = 0;
+	struct blk *bp2;
+	while (bp1) {
+		bp2 = bp1->next;
+		(void) free((char *) bp1);
+		blkcnt++;
+		bp1 = bp2;
+	}
+	return blkcnt;
+}
+
+#ifdef DUAL_STACK
+typedef struct _ds_block {
+	void *lo,*hi;
+	struct _ds_block *pop;
+	void *popstackptr;
+} DS_BLOCK;
+static DS_BLOCK *ds_current CGLOB;
+void *dualstack CGLOB;
+void *ds_currentlo CGLOB,*ds_currenthi CGLOB;
+
+#ifdef PC
+int n_ds_allocations CGLOB;
+#endif
+void ds_allocatleast(unsigned int size) {
+	size+=DS_BSIZE;
+	DS_BLOCK *ds_new = malloc(sizeof(DS_BLOCK)+size);
+	ds_new->lo = (void *)(ds_new+1);
+	ds_new->hi = (void *)((char *)ds_new->lo+size);
+	ds_new->pop = ds_current;
+	ds_new->popstackptr = dualstack;
+	ds_current = ds_new;
+	ds_currentlo = ds_current->lo;
+	ds_currenthi = ds_current->hi;
+	dualstack = ds_currentlo;
+#ifdef PC
+	n_ds_allocations++;
+#endif
+}
+void ds_free(void) {
+	DS_BLOCK *ds_old = ds_current;
+	ds_current = ds_old->pop;
+	ds_currentlo = ds_current ? ds_current->lo : 0;
+	ds_currenthi = ds_current ? ds_current->hi : 0;
+	dualstack = ds_old->popstackptr;
+	free(ds_old);
+}
+void rel_dualstack(void) {
+	while (ds_current)
+		ds_free();
+#ifdef PC
+	//msg2("  performed %d dual-stack-related allocations\n",n_ds_allocations);
+#endif
+}
+#endif
+
+#define VERBOSE
+#ifdef GARBAGE_COLLECT
+void d_enode(struct enode **node) {
+	struct enode *dest,*ep=*node;
+	if (!ep) return;
+	if (ep->nodetype==en_icon) { *node=mk_icon(ep->v.i); return; }
+	dest=xalloc((int)sizeof(struct enode), ENODE);
+	memcpy(dest,ep,sizeof(struct enode));
+	*node=dest;
+	switch (ep->nodetype) {
+		case en_land: case en_lor:
+		case en_asand: case en_asor: case en_asxor:
+		case en_aslsh: case en_asrsh:
+		case en_asmul: case en_asmod: case en_asdiv:
+		case en_asadd: case en_assub:
+		case en_gt: case en_ge:
+		case en_lt: case en_le:
+		case en_eq: case en_ne:
+		case en_cond: case en_assign:
+		case en_and: case en_or: case en_xor:
+		case en_lsh: case en_rsh:
+		case en_mul: case en_mod: case en_div:
+		case en_add: case en_sub:
+		case en_fcall: case en_void:
+			d_enode(&ep->v.p[1]);
+		case en_deref:
+		case en_ainc: case en_adec:
+		case en_uminus: case en_not: case en_compl:
+		case en_ref:
+		case en_cast:	/* hum hum */
+		case en_fieldref:
+			d_enode(&ep->v.p[0]);
+		case en_tempref:
+		case en_autocon:
+		case en_labcon:
+		case en_nacon:
+		case en_fcon:
+			return;
+		case en_compound:
+			d_snode(&ep->v.st);
+			return;
+		default:
+			ierr(D_ENODE,1);
+	}
+}
+
+void d_snode(struct snode **node) {
+	struct snode *dest,*block=*node;
+	if (!block) return;
+	dest=xalloc((int)sizeof(struct snode), SNODE);
+	memcpy(dest,block,sizeof(struct snode));
+	*node=dest;
+	while (block != 0) {
+		switch (block->stype) {
+		  case st_return:
+		  case st_expr:
+			d_enode(&block->exp);
+			break;
+		  case st_loop:
+			d_enode(&block->exp);
+			d_snode(&block->s1);
+			d_enode(&block->v2.e);
+			break;
+		  case st_while:
+		  case st_do:
+			d_enode(&block->exp);
+			d_snode(&block->s1);
+			break;
+		  case st_for:
+			d_enode(&block->exp);
+			d_enode(&block->v1.e);
+			d_snode(&block->s1);
+			d_enode(&block->v2.e);
+			break;
+		  case st_if:
+			d_enode(&block->exp);
+			d_snode(&block->s1);
+			d_snode(&block->v1.s);
+			break;
+		  case st_switch:
+			d_enode(&block->exp);
+			d_snode(&block->v1.s);
+			break;
+		  case st_case:
+		  case st_default:
+			d_snode(&block->v1.s);
+			break;
+		  case st_compound:
+		  case st_label:
+			d_snode(&block->s1);
+		  case st_goto:
+		  case st_break:
+		  case st_continue:
+			break;
+		  case st_asm:
+			d_amode(&(struct amode *)block->v1.i);
+			break;
+		  default:
+			ierr(D_SNODE,1);
+		}
+		block = block->next;
+	}
+}
+
+void d_amode(struct amode **node) {
+	struct amode *dest,*mode=*node;
+	if (!mode) return;
+	dest=xalloc((int)sizeof(struct amode), AMODE);
+	memcpy(dest,mode,sizeof(struct amode));
+	*node=dest;
+	d_enode(&dest->offset);
+}
+extern struct ocode *_peep_head;
+void d_ocodes(void) {
+	struct ocode *dest=NULL,**node=&_peep_head,*instr;
+	while ((instr=*node)) {
+		instr->back=dest;
+		dest=xalloc((int)sizeof(struct ocode), OCODE);
+		memcpy(dest,instr,sizeof(struct ocode));
+		*node=dest;
+		d_amode(&dest->oper1);
+		d_amode(&dest->oper2);
+		node=&dest->fwd;
+	}
+	*node=NULL;
+}
+
+extern struct snode *dump_stmt;
+void collect(int g) {
+	struct blk *blk=glbblk;
+	glbsize=glbindx=0;
+	glbblk=NIL_BLK;
+	alloc_dump(g);
+	// dump snodes & most enodes
+//	d_snode(&dump_stmt);
+	// dump ocodes & amodes & the rest of enodes
+//	d_ocodes();
+	// dump most syms & most strs & typs & tables & the rest of syms & a few strs
+	d_table(&gsyms); d_table(&gtags); d_table(&defsyms);
+	// dump slits & the rest of strs
+//	
+	// no dump is needed for cse's since it is a cooperative garbage-collection
+}
+#endif
+
+int _k_=0;
+void tmp_use() {
+	temp_mem++;
+	_k_++;
+}
+void tmp_free() {
+	if (!--temp_mem && tmpblk) {
+#ifdef PC
+		int n=0;
+#endif
+#ifndef LIFO_TMP_FREE
+		/* Maybe I'm wrong, but I think that this solution
+		 * is quite bad for the TIOS heap manager... */
+		struct blk *nxt;
+		while ((nxt=tmpblk->next))
+	#ifdef PC
+			n++,
+	#endif
+				free(tmpblk),tmpblk=nxt;
+#else
+		struct blk *nxt=tmpblk->next,*tofree;
+		while (nxt)
+	#ifdef PC
+			n++,
+	#endif
+				tofree=nxt, nxt=nxt->next, free(tofree);
+#endif
+#ifdef _DBG_SHOW_TEMPMEM
+		printf("*");
+#ifdef PC
+		printf("(%dk)",n*BLKLEN/1024);
+//		getchar();
+#endif
+#endif
+		tmpsize = BLKLEN;
+		tmpindx = 0;
+		memset(tmpblk,0,BLKLEN);
+		/*blk_free(tmpblk);
+		tmpblk = 0;
+		tmpsize = 0;*/
+	}
+}
+
+void rel_local() {
+	unsigned int mem;
+#ifndef AS
+#define pos 0
+#else
+	extern unsigned int pos;
+#endif
+#ifdef PC
+#ifdef GARBAGE_COLLECT
+	collect(0);
+#endif
+#ifdef LISTING
+	alloc_dump(0);
+#endif
+#endif
+	if ((mem=blk_free(locblk))+glo_mem+(2*pos)/BLKLEN > (unsigned int)max_mem) {
+		max_mem = mem+glo_mem+(2*pos)/BLKLEN;
+		/*if (max_mem>330/4)
+			bkpt();*/
+	}
+#ifndef AS
+#undef pos
+#endif
+#ifdef PC
+	locmem = 0;
+#endif
+	locblk = 0;
+	locsize = 0;
+//#ifndef PC
+#ifndef GTDEV
+#ifdef PC
+	if (verbose)
+#endif
+		msg2("%d kb\n", (int)(mem * BLKLEN/1024));
+#endif
+//#endif
+#ifdef VERBOSE
+#ifdef LISTING
+#if 0
+	if (list_option)
+		msg2(" releasing %2d kb local tables.\n",
+				mem * BLKLEN/1024);
+#endif
+#endif
+#endif
+}
+
+void rel_global() {
+	int mem;
+	if ((mem=blk_free(glbblk)) > max_mem)
+		max_mem = mem;
+#ifdef PC
+	glbmem = 0;
+#endif
+	glo_mem = 0;
+	glbblk = 0;
+	glbsize = 0;
+	blk_free(tmpblk);
+	tmpblk = 0;
+	tmpsize = 0;
+#ifdef PC
+#ifdef LISTING
+	alloc_dump(1);
+#endif
+#endif
+#ifdef VERBOSE
+#ifdef LISTING
+	if (list_option)
+		msg2(" releasing %2d kb global tables.\n",
+				mem * BLKLEN/1024);
+#endif
+#ifdef DUAL_STACK
+	//if (ds_current)
+	//	msg("oops, a dual stack remains\n");
+	rel_dualstack();
+#endif
+#ifndef GTDEV
+#ifdef PC
+	if (verbose) {
+		msg2("Max memory request : %d kb\n",
+				(int)(max_mem * BLKLEN/1024));
+		msg("\n");
+		if (max_mem * BLKLEN/1024<150)
+			msg("On-calc portability : very good\n");
+		else if (max_mem * BLKLEN/1024<230)
+			msg("On-calc portability : good\n");
+		else if (max_mem * BLKLEN/1024<290)
+			msg("On-calc portability : questionable\n");
+		else if (max_mem * BLKLEN/1024<360)
+			msg("On-calc portability : difficult without splitting\n");
+		else
+			msg("On-calc portabilty : impossible without splitting\n");
+		msg("\n");
+	}
+#endif
+#endif
+#endif
+	max_mem = 0;
+}
+
+void clean_up() {
+	blk_free(tmpblk);
+	blk_free(locblk);
+	blk_free(glbblk);
+#ifdef DUAL_STACK
+	//if (ds_current)
+	//	msg("oops, a dual stack remains\n");
+	rel_dualstack();
+#endif
+	temp_mem = 0;
+	glbblk = locblk = tmpblk = 0;
+/*#ifdef OPTIMIZE_BSS
+	free(bssdata);
+#endif*/
+}
+
+#undef VERBOSE
+// vim:ts=4:sw=4

+ 887 - 0
gtc/src/optimize.c

@@ -0,0 +1,887 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * optimization
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+static	void fold_const();
+
+void dooper(struct enode **node) {
+/*
+ * dooper will execute a constant operation in a node and modify the node to
+ * be the result of the operation.
+ */
+	struct enode   *ep = *node;
+	enum(e_node) 	type = ep->nodetype;
+
+#define ep0 ep->v.p[0]
+#define ep1 ep->v.p[1]
+#define epi ep->v.i
+#define epf ep->v.f
+#define ulong unsigned long
+
+	ep->nodetype = ep0->nodetype;
+	if (ep0->nodetype == en_fcon) {
+#ifndef NOFLOAT
+		switch (type) {
+		  case en_uminus:
+#ifdef PC
+			epf = - ep0->v.f;
+#else
+			epf = ep0->v.f;
+			if (epf) epf^=0x80;
+#endif
+			break;
+		  case en_not:
+			ep->nodetype = en_icon;
+			epi = (ep0->v.f) ? 0 : 1;
+			break;
+		  case en_add:
+#ifdef PC
+			epf = ep0->v.f + ep1->v.f;
+#else
+			epf = ffpadd(ep0->v.f, ep1->v.f);
+#endif
+			break;
+		  case en_sub:
+#ifdef PC
+			epf = ep0->v.f - ep1->v.f;
+#else
+			epf = ffpsub(ep0->v.f, ep1->v.f);
+#endif
+			break;
+		  case en_mul:
+#ifdef PC
+			epf = ep0->v.f * ep1->v.f;
+#else
+			epf = ffpmul(ep0->v.f, ep1->v.f);
+#endif
+			break;
+		  case en_div:
+			if (ep1->v.f == 0) {
+				uwarn("division by zero");
+				ep->nodetype = en_div;
+			} else {
+#ifdef PC
+				epf = ep0->v.f / ep1->v.f;
+#else
+				epf = ffpdiv(ep0->v.f, ep1->v.f);
+#endif
+			}
+			break;
+		  case en_eq:
+			ep->nodetype = en_icon;
+			epi = (ep0->v.f == ep1->v.f) ? 1 : 0;
+			break;
+		  case en_ne:
+			ep->nodetype = en_icon;
+			epi = (ep0->v.f != ep1->v.f) ? 1 : 0;
+			break;
+		  case en_land:
+			ep->nodetype = en_icon;
+			epi = (ep0->v.f && ep1->v.f) ? 1 : 0;
+			break;
+		  case en_lor:
+			ep->nodetype = en_icon;
+			epi = (ep0->v.f || ep1->v.f) ? 1 : 0;
+			break;
+		  case en_lt:
+			ep->nodetype = en_icon;
+#ifdef PC
+			epi = (ep0->v.f < ep1->v.f) ? 1 : 0;
+#else
+			epi = (ffpcmp_c(ep0->v.f, ep1->v.f) < 0) ? 1 : 0;
+#endif
+			break;
+		  case en_le:
+			ep->nodetype = en_icon;
+#ifdef PC
+			epi = (ep0->v.f <= ep1->v.f) ? 1 : 0;
+#else
+			epi = (ffpcmp_c(ep0->v.f, ep1->v.f) <= 0) ? 1 : 0;
+#endif
+			break;
+		  case en_gt:
+			ep->nodetype = en_icon;
+#ifdef PC
+			epi = (ep0->v.f > ep1->v.f) ? 1 : 0;
+#else
+			epi = (ffpcmp_c(ep0->v.f, ep1->v.f) > 0) ? 1 : 0;
+#endif
+			break;
+		  case en_ge:
+			ep->nodetype = en_icon;
+#ifdef PC
+			epi = (ep0->v.f >= ep1->v.f) ? 1 : 0;
+#else
+			epi = (ffpcmp_c(ep0->v.f, ep1->v.f) >= 0) ? 1 : 0;
+#endif
+			break;
+		  default:
+			ep->nodetype = type;
+			iwarn(DOOPER,1);
+			break;
+		}
+#endif /* NOFLOAT */
+		return;
+	}
+	/*
+	 * Thus, ep0->nodetype is en_icon
+	 * We have to distinguish unsigned long from the other cases
+	 *
+	 * Since we always store in ep->v.i, it is
+	 * ASSUMED THAT (long) (ulong) ep->v.i == ep->v.i always
+	 */
+	if (ep0->etype == bt_ulong || ep0->etype == bt_pointer) {
+		switch (type) {
+		  case en_uminus:
+			epi = - ep0->v.i;
+			break;
+		  case en_not:
+			epi = ((ulong) ep0->v.i) ? 0 : 1;
+			break;
+		  case en_compl:
+			epi = ~ (ulong) ep0->v.i;
+			epi = strip_icon(epi, ep->etype);
+			break;
+		  case en_add:
+			epi = (ulong) ep0->v.i + (ulong) ep1->v.i;
+			break;
+		  case en_sub:
+			epi = (ulong) ep0->v.i - (ulong) ep1->v.i;
+			break;
+		  case en_mul:
+			epi = (ulong) ep0->v.i * (ulong) ep1->v.i;
+			break;
+		  case en_div:
+			if ((ulong) ep1->v.i == 0) {
+				uwarn("division by zero");
+				ep->nodetype = en_div;
+			} else {
+				epi = (ulong) ep0->v.i / (ulong) ep1->v.i;
+			}
+			break;
+		  case en_mod:
+			if ((ulong) ep1->v.i == 0) {
+				uwarn("division by zero");
+				ep->nodetype = en_mod;
+			} else {
+				epi = (ulong) ep0->v.i % (ulong) ep1->v.i;
+			}
+			break;
+		  case en_and:
+			epi = (ulong) ep0->v.i & (ulong) ep1->v.i;
+			break;
+		  case en_or:
+			epi = (ulong) ep0->v.i | (ulong) ep1->v.i;
+			break;
+		  case en_xor:
+			epi = (ulong) ep0->v.i ^ (ulong) ep1->v.i;
+			break;
+		  case en_eq:
+			epi = ((ulong) ep0->v.i == (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_ne:
+			epi = ((ulong) ep0->v.i != (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_land:
+			epi = ((ulong) ep0->v.i && (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_lor:
+			epi = ((ulong) ep0->v.i || (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_lt:
+			epi = ((ulong) ep0->v.i < (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_le:
+			epi = ((ulong) ep0->v.i <= (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_gt:
+			epi = ((ulong) ep0->v.i > (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_ge:
+			epi = ((ulong) ep0->v.i >= (ulong) ep1->v.i) ? 1 : 0;
+			break;
+		  case en_lsh:
+#ifdef MINIMAL_SIZES
+			epi = (ulong) ep0->v.i << (char) ep1->v.i;
+#else
+			epi = (ulong) ep0->v.i << (ulong) ep1->v.i;
+#endif
+			break;
+		  case en_rsh:
+#ifdef MINIMAL_SIZES
+			epi = (ulong) ep0->v.i >> (char) ep1->v.i;
+#else
+			epi = (ulong) ep0->v.i >> (ulong) ep1->v.i;
+#endif
+			break;
+		  default:
+			ep->nodetype = type;
+			iwarn(DOOPER,2);
+			break;
+		}
+	} else {
+		switch (type) {
+		  case en_uminus:
+			epi = - ep0->v.i;
+			break;
+		  case en_not:
+			epi = (ep0->v.i) ? 0 : 1;
+			break;
+		  case en_compl:
+			epi = ~ ep0->v.i;
+			epi = strip_icon(epi, type);
+			break;
+		  case en_add:
+			epi = ep0->v.i + ep1->v.i;
+			break;
+		  case en_sub:
+			epi = ep0->v.i - ep1->v.i;
+			break;
+		  case en_mul:
+			epi = ep0->v.i * ep1->v.i;
+			break;
+		  case en_div:
+			if (ep1->v.i == 0) {
+				uwarn("division by zero");
+				ep->nodetype = en_div;
+			} else {
+				epi = ep0->v.i / ep1->v.i;
+			}
+			break;
+		  case en_mod:
+			if (ep1->v.i == 0) {
+				uwarn("division by zero");
+				ep->nodetype = en_mod;
+			} else {
+				epi = ep0->v.i % ep1->v.i;
+			}
+			break;
+		  case en_and:
+			epi = ep0->v.i & ep1->v.i;
+			break;
+		  case en_or:
+			epi = ep0->v.i | ep1->v.i;
+			break;
+		  case en_xor:
+			epi = ep0->v.i ^ ep1->v.i;
+			break;
+		  case en_eq:
+			epi = (ep0->v.i == ep1->v.i) ? 1 : 0;
+			break;
+		  case en_ne:
+			epi = (ep0->v.i != ep1->v.i) ? 1 : 0;
+			break;
+		  case en_land:
+			epi = (ep0->v.i && ep1->v.i) ? 1 : 0;
+			break;
+		  case en_lor:
+			epi = (ep0->v.i || ep1->v.i) ? 1 : 0;
+			break;
+		  case en_lt:
+			epi = (ep0->v.i < ep1->v.i) ? 1 : 0;
+			break;
+		  case en_le:
+			epi = (ep0->v.i <= ep1->v.i) ? 1 : 0;
+			break;
+		  case en_gt:
+			epi = (ep0->v.i > ep1->v.i) ? 1 : 0;
+			break;
+		  case en_ge:
+			epi = (ep0->v.i >= ep1->v.i) ? 1 : 0;
+			break;
+		  case en_lsh:
+#ifdef MINIMAL_SIZES
+			epi = ep0->v.i << (char)ep1->v.i;
+#else
+			epi = ep0->v.i << ep1->v.i;
+#endif
+			break;
+		  case en_rsh:
+#ifdef MINIMAL_SIZES
+			epi = ep0->v.i >> (char)ep1->v.i;
+#else
+			epi = ep0->v.i >> ep1->v.i;
+#endif
+			break;
+		  default:
+			ep->nodetype = type;
+			iwarn(DOOPER,3);
+			break;
+		}
+	}
+#undef ep0
+#undef ep1
+#undef epi
+#undef epf
+#undef ulong
+}
+
+int pwrof2(long i) {
+/*
+ * return which power of two i is or -1.
+ */
+	int 			p;
+	long			q;
+	q = 2;
+	p = 1;
+	while (q > 0) {
+		if (q == i)
+			return p;
+		q <<= 1;
+		++p;
+	}
+	return -1;
+}
+
+long mod_mask(long i) {
+/*
+ * make a mod mask for a power of two.
+ */
+	long			m;
+	m = 0;
+	while (i--)
+		m = (m << 1) | 1;
+	return m;
+}
+
+void opt0(struct enode **node) {
+/*
+ * opt0 - delete useless expressions and combine constants.
+ *
+ * opt0 will delete expressions such as x + 0,
+ *	x - 0,
+ *	x * 0,
+ *	x * 1,
+ *	0 / x,
+ *	x / 1,
+ *	x % (1<<3),
+ *	etc from the tree pointed to by node and combine obvious
+ * constant operations. It cannot combine name and label constants but will
+ * combine icon type nodes.
+ */
+	struct enode   *ep;
+
+#define ep0 ep->v.p[0]
+#define ep1 ep->v.p[1]
+
+	long			val, sc;
+	enum(e_node) 	typ;
+	ep = *node;
+	if (ep == 0)
+		return;
+	typ = ep->nodetype;
+	switch (typ) {
+	  case en_ref:
+	  case en_fieldref:
+	  case en_ainc:
+	  case en_adec:
+	  case en_deref:
+		opt0(&ep0);
+		break;
+	  case en_uminus:
+	  case en_compl:
+		opt0(&ep0);
+		/*
+		 * This operation applied twice is a no-op
+		 */
+		if (ep0->nodetype == typ) {
+			*node = ep0->v.p[0];
+			break;
+		}
+		if (ep0->nodetype == en_icon || ep0->nodetype == en_fcon)
+			dooper(node);
+		break;
+	  case en_not:
+		opt0(&ep0);
+		if (ep0->nodetype == en_icon || ep0->nodetype == en_fcon)
+			dooper(node);
+		break;
+	  case en_add:
+	  case en_sub:
+		opt0(&ep0);
+		opt0(&ep1);
+		/*
+		 *	a + (-b)  =  a - b
+		 *	a - (-b)  =  a + b
+		 *	(-a) + b  =  b - a
+		 */
+		if (ep1->nodetype == en_uminus) {
+			ep1 = ep1->v.p[0];
+			ep->nodetype = typ = (typ == en_add) ? en_sub : en_add;
+		}
+		if (ep0->nodetype == en_uminus && typ == en_add) {
+			ep0 = ep0->v.p[0];
+			swap_nodes(ep);
+			ep->nodetype = typ = en_sub;
+		}
+		/*
+		 * constant expressions
+		 */
+		if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) ||
+			(ep0->nodetype == en_fcon && ep1->nodetype == en_fcon))   {
+			dooper(node);
+			break;
+		}
+		/*infunc("DrawNumberOfClock")
+			bkpt();*/
+		/* the following would bug, as :
+		    short my_array[2]={12,570};
+		    int i=2;
+		    while (i--) printf("%d",my_array[i]);
+		  wouldn't print 570 correctly... */
+#ifdef BUGGY_AND_ANYWAY_NOT_COMPAT_WITH_NO_OFFSET_AUTOCON
+		if (typ == en_add) {
+			if (ep1->nodetype == en_autocon)
+				swap_nodes(ep);
+		}
+#endif
+		if (ep0->nodetype == en_icon) {
+			if (ep0->v.i == 0) {
+				if (typ == en_sub) {
+					ep0 = ep1;
+					ep->nodetype = typ = en_uminus;
+				} else
+					*node = ep1;
+				break;
+#ifdef PREFER_POS_VALUES
+			} else if (ep0->nodetype==en_add && ep0->v.i<0) {
+				ep0->v.i=-ep0->v.i;
+				swap_nodes(ep);
+				ep->nodetype=en_sub;
+#endif
+			}
+		} else if (ep1->nodetype == en_icon) {
+#ifdef BUGGY_AND_ANYWAY_NOT_COMPAT_WITH_NO_OFFSET_AUTOCON
+			if (ep0->nodetype == en_autocon && typ == en_add) {
+				ep0->v.i += ep1->v.i;
+				*node = ep0;
+				break;
+			}
+#endif
+			if (ep1->v.i == 0) {
+				*node = ep0;
+				break;
+#ifdef PREFER_POS_VALUES
+			} else if (ep1->v.i<0) {
+				ep->nodetype^=1;
+				ep1->v.i=-ep1->v.i;
+#endif
+			}
+		}
+		break;
+	  case en_mul:
+		opt0(&ep0);
+		opt0(&ep1);
+		/*
+		 * constant expressions
+		 */
+		if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) ||
+			(ep0->nodetype == en_fcon && ep1->nodetype == en_fcon))  {
+			dooper(node);
+			break;
+		}
+		if (ep0->nodetype == en_icon) {
+			val = ep0->v.i;
+			if (val == 0) {
+				*node = ep0;
+				break;
+			}
+			if (val == 1) {
+				*node = ep1;
+				break;
+			}
+			sc = pwrof2(val);
+			if (sc IS_VALID) {
+				swap_nodes(ep);
+				ep1->v.i = sc;
+				ep->nodetype = en_lsh;
+			}
+		} else if (ep1->nodetype == en_icon) {
+			val = ep1->v.i;
+			if (val == 0) {
+				*node = ep1;
+				break;
+			}
+			if (val == 1) {
+				*node = ep0;
+				break;
+			}
+			sc = pwrof2(val);
+			if (sc IS_VALID) {
+				ep1->v.i = sc;
+				ep->nodetype = en_lsh;
+			}
+		}
+		break;
+	  case en_div:
+		opt0(&ep0);
+		opt0(&ep1);
+		/*
+		 * constant expressions
+		 */
+		if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) ||
+			(ep0->nodetype == en_fcon && ep1->nodetype == en_fcon))  {
+			dooper(node);
+			break;
+		}
+		if (ep0->nodetype == en_icon) {
+			if (ep0->v.i == 0) {		/* 0/x */
+				*node = ep0;
+				break;
+			}
+		} else if (ep1->nodetype == en_icon) {
+			val = ep1->v.i;
+			if (val == 1) { 	/* x/1 */
+				*node = ep0;
+				break;
+			}
+			sc = pwrof2(val);
+			if (sc IS_VALID) {
+				ep1->v.i = sc;
+				ep->nodetype = en_rsh;
+			}
+		}
+		break;
+	  case en_mod:
+		opt0(&ep0);
+		opt0(&ep1);
+		/*
+		 * constant expressions
+		 */
+		if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) ||
+			(ep0->nodetype == en_fcon && ep1->nodetype == en_fcon))  {
+			dooper(node);
+			break;
+		}
+		if (ep1->nodetype == en_icon) {
+			sc = pwrof2(ep1->v.i);
+			if (sc IS_VALID) {
+				ep1->v.i = mod_mask(sc);
+				ep->nodetype = en_and;
+			}
+		}
+		break;
+	  case en_land:
+	  case en_lor:
+#if 0	/* perhaps this isn't *that* useful... and ep0/ep1 are long to access */
+		opt0(&ep0);
+		opt0(&ep1);
+		if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) ||
+			(ep0->nodetype == en_fcon && ep1->nodetype == en_fcon))
+			dooper(node);
+		else {
+			typ = (typ==en_lor);
+			if (ep0->nodetype == en_icon) {
+				if ((!ep0->v.i)!=typ)	/* absorbing element */
+					ep = ep0;
+				else	/* "neutral" element */
+					//ep = ep1;	-> not quite, should be !!x
+					(void)0;
+			} else if (ep1->nodetype == en_icon) {
+				if ((!ep1->v.i)!=typ)	/* absorbing element */
+					ep->nodetype = en_void, ep1->v.i=typ;
+				else	/* "neutral" element */
+					//ep = ep0;	-> not quite, should be !!x
+					(void)0;
+			}
+		}
+		break;
+#else
+		/* FALL THROUGH */
+#endif
+	  case en_and:
+	  case en_or:
+	  case en_xor:
+	  case en_eq:
+	  case en_ne:
+	  case en_lt:
+	  case en_le:
+	  case en_gt:
+	  case en_ge:
+		opt0(&ep0);
+		opt0(&ep1);
+		/*
+		 * constant expressions
+		 */
+		if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) ||
+			(ep0->nodetype == en_fcon && ep1->nodetype == en_fcon))
+			dooper(node);
+		break;
+	  case en_lsh:
+	  case en_rsh:
+		opt0(&ep0);
+		opt0(&ep1);
+		if (ep0->nodetype == en_icon && ep1->nodetype == en_icon) {
+			dooper(node);
+			break;
+		}
+		/*
+		 * optimize a << 0 and a >> 0
+		 */
+		if (ep1->nodetype == en_icon && ep1->v.i == 0)
+			*node = ep0;
+		break;
+	  case en_cond:
+		opt0(&ep0);
+		opt0(&ep1);
+		if (ep0->nodetype == en_icon) {
+			if (ep0->v.i) {
+				if (ep1->v.p[0]) *node=ep1->v.p[0];
+				else *node=ep0;
+			} else
+				*node=ep1->v.p[1];
+		}
+		break;
+	  case en_asand:
+	  case en_asor:
+	  case en_asxor:
+	  case en_asadd:
+	  case en_assub:
+	  case en_asmul:
+	  case en_asdiv:
+	  case en_asmod:
+	  case en_asrsh:
+	  case en_aslsh:
+	  case en_fcall:
+	  case en_void:
+	  case en_assign:
+		opt0(&ep0);
+		opt0(&ep1);
+		break;
+		/* now handled in expr.c */
+	  case en_cast:
+		opt0(&ep0);
+		if (ep0->nodetype == en_icon) {
+#ifndef NOFLOAT
+			if (ep->etype != bt_float
+#ifdef DOUBLE
+				&& ep->etype != bt_double
+#endif
+					) {
+#endif
+				ierr(OPT0,1);
+/*				ep->nodetype = en_icon;
+				ep->v.i = ep0->v.i;*/
+#ifndef NOFLOAT
+			} else {
+#ifdef XCON_DOESNT_SUPPORT_FLOATS
+#error Fix me now :)
+#endif
+				ep->nodetype = en_fcon;
+#ifdef PC
+				ep->v.f = (double)ep0->v.i;
+#else
+#ifndef BCDFLT
+				ep->v.f = ffpltof(ep0->v.i);
+#else
+				ep->v.f = (double)ep0->v.i;
+#endif
+#endif
+			}
+#endif
+		}
+		/* perhaps BUGGY */
+		else if ((ep0->nodetype == en_labcon || ep0->nodetype == en_nacon)
+			&& ep->esize<=ep0->esize) {
+			ep0->etype = ep->etype;
+			ep0->esize = ep->esize;
+			ep=ep0;
+			*node=ep;
+		}
+#ifndef NOFLOAT
+		else if (ep0->nodetype == en_fcon && bt_integral(ep->etype)) {
+			ep->nodetype = en_icon;
+#ifdef PC
+			ep->v.i = (long)ep0->v.f;
+#else
+			ep->v.i = ffpftol(ep0->v.f);
+#endif
+		}
+#endif
+		break;
+	  /*case en_icon:
+	  case en_fcon:
+	  case en_labcon:
+	  case en_nacon:
+	  case en_autocon:
+	  case en_tempref:
+		break;
+	  default:
+		uwarn("Didn't optimize nodetype %d. Please send me your source code.",typ);*/
+	}
+
+#undef ep0
+#undef ep1
+}
+
+static long xfold(struct enode *node) {
+/*
+ * xfold will remove constant nodes and return the values to the calling
+ * routines.
+ */
+	long			i;
+	if (node == 0)
+		return 0;
+	switch (node->nodetype) {
+	  case en_icon:
+		i = node->v.i;
+		node->v.i = 0;
+		return i;
+	  case en_add:
+		return xfold(node->v.p[0]) + xfold(node->v.p[1]);
+	  case en_sub:
+		return xfold(node->v.p[0]) - xfold(node->v.p[1]);
+	  case en_mul:
+		if (node->v.p[0]->nodetype == en_icon)
+			return xfold(node->v.p[1]) * node->v.p[0]->v.i;
+		else if (node->v.p[1]->nodetype == en_icon)
+			return xfold(node->v.p[0]) * node->v.p[1]->v.i;
+		else {
+			fold_const(&node->v.p[0]);
+			fold_const(&node->v.p[1]);
+			return 0;
+		}
+		/*
+		 * CVW: This seems wrong to me... case en_lsh: if(
+		 * node->v.p[0]->nodetype == en_icon ) return xfold(node->v.p[1]) <<
+		 * node->v.p[0]->v.i; else if( node->v.p[1]->nodetype == en_icon )
+		 * return xfold(node->v.p[0]) << node->v.p[1]->v.i; else return 0;
+		 */
+	  case en_uminus:
+		return -xfold(node->v.p[0]);
+	  case en_lsh:
+	  case en_rsh:
+	  case en_div:
+	  case en_mod:
+	  case en_asadd:
+	  case en_assub:
+	  case en_asmul:
+	  case en_asdiv:
+	  case en_asmod:
+	  case en_and:
+	  case en_land:
+	  case en_or:
+	  case en_lor:
+	  case en_xor:
+	  case en_asand:
+	  case en_asor:
+	  case en_asxor:
+	  case en_void:
+	  case en_fcall:
+	  case en_assign:
+	  case en_eq:
+	  case en_ne:
+	  case en_lt:
+	  case en_le:
+	  case en_gt:
+	  case en_ge:
+		fold_const(&node->v.p[0]);
+		fold_const(&node->v.p[1]);
+		return 0;
+	  case en_ref:
+	  case en_fieldref:
+	  case en_compl:
+	  case en_not:
+	  case en_deref:
+		fold_const(&node->v.p[0]);
+		return 0;
+		/*
+		 * This is not stricly legal: (long)(x+10) * 4l might not be the same
+		 * as (long)(x) * 4l + 40l but it is the same as long as no overflows
+		 * occur
+		 */
+	  case en_cast:
+#ifdef DONTDEF
+		return xfold(node->v.p[0]);
+#endif
+		/*
+		 * Well, sometimes I prefer purity to efficiency
+		 * It is a matter of taste how you decide here....
+		 */
+		fold_const(&node->v.p[0]);
+		return 0;
+	}
+	return 0;
+}
+
+static void fold_const(struct enode **node) {
+/*
+ * reorganize an expression for optimal constant grouping.
+ */
+	struct enode   *ep;
+	long			i;
+	ep = *node;
+	if (ep == 0)
+		return;
+	if (ep->nodetype == en_add) {
+		if (ep->v.p[0]->nodetype == en_icon) {
+			ep->v.p[0]->v.i += xfold(ep->v.p[1]);
+			return;
+		} else if (ep->v.p[1]->nodetype == en_icon) {
+			ep->v.p[1]->v.i += xfold(ep->v.p[0]);
+			return;
+		}
+	} else if (ep->nodetype == en_sub) {
+		if (ep->v.p[0]->nodetype == en_icon) {
+			ep->v.p[0]->v.i -= xfold(ep->v.p[1]);
+			return;
+		} else if (ep->v.p[1]->nodetype == en_icon) {
+			ep->v.p[1]->v.i -= xfold(ep->v.p[0]);
+			return;
+		}
+	}
+	i = xfold(ep);
+	if (i != 0) {
+/*
+ * strip_icon is in fact harmless here since this value is
+ * just added to *node
+ * consider in 16-bit mode:
+ *
+ * int day, year;
+ * day = 365 * (year - 1970);
+ *
+ * and look at the code, which is transformed to
+ *
+ * day = 365*year + 1846;
+ *
+ * which works if the multiplication returns the lower 16 bits of
+ * the result correctly.
+ */
+		i = strip_icon(i, (*node)->etype);
+		ep = mk_icon(i);
+		ep->etype = (*node)->etype;
+		ep->esize = (*node)->esize;
+		ep = mk_node(en_add, *node, ep);
+		ep->etype = (*node)->etype;
+		ep->esize = (*node)->esize;
+		*node = ep;
+	}
+}
+
+void opt4(struct enode **node) {
+/*
+ * apply all constant optimizations.
+ */
+	/* opt0(node); */
+	fold_const(node);
+	opt0(node);
+}
+// vim:ts=4:sw=4

+ 3017 - 0
gtc/src/out68k_as.c

@@ -0,0 +1,3017 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * assembled binary output
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+#ifdef PC
+void nl(void) {
+}
+#define nl() while (0)
+#endif
+
+#ifdef SECURIZED_ALIGN
+#define put_align(__a) while (0)
+#else
+#define put_align(__a) put_align2()
+#endif
+
+#ifdef PC
+#define tabs "\t"
+#else
+#define tabs " "
+#endif
+
+#define N_TAB 64
+#define N_TAB_LOG 6
+typedef struct _ltab {
+	struct _ltab *nxt;
+	unsigned int t[N_TAB];
+} LTAB;
+#define N_REF 8
+#define N_REF_LOG 3
+typedef struct _ref {
+	unsigned int r[N_REF];
+	struct _ref *nxt;		// very important to be afterwards : if nxt==NULL, then r[N_REF]==0
+} REF;
+typedef struct _gtab {
+	struct _gtab *nxt;
+	unsigned int t[N_TAB];
+	REF			*r[N_TAB];
+} GTAB;
+
+typedef struct _rtype {
+	REF *r0,*r;
+} RTYPE;
+typedef struct _func {
+	RTYPE rt;
+	unsigned int f;
+	struct _func *nxt;
+} FUNC;
+typedef struct _xtab {
+	struct _xtab *nxt;
+	RTYPE		*t[N_TAB];
+} XTAB;
+
+FILE		   *output CGLOB;
+unsigned char  *bin CGLOB;
+struct slit    *strtab CGLOB;
+long			lc_bss CGLOB;
+xstatic int		lc_stk CGLOB,uses_lc_stk CGLOB;
+xstatic char		odd CGLOB;			// for put_align
+xstatic int		extlabel CGLOB;
+int				glblabel CGLOB;
+struct ocode   *scope_head CGLOB;
+unsigned int	pos CGLOB,bin_size CGLOB;
+int				nostub_mode CGLOB;
+#ifdef EXE_OUT
+int				exestub_mode CGLOB;
+#else
+#define exestub_mode 0
+#endif
+LTAB		   *loc_tab CGLOB;
+GTAB		   *glb_tab CGLOB;
+XTAB		   *ext_tab CGLOB;
+LTAB		   *exp_tab CGLOB;	// warning : the content is the exported label (but not the offset)
+FUNC		   *rom_funcs CGLOB;
+#ifdef RAM_CALLS
+FUNC		   *ram_funcs CGLOB;
+#endif
+RTYPE			reloc_tab CGLOBL,bss_tab CGLOBL;
+HTABLE			alsyms CGLOBL;
+TABLE			libsyms CGLOBL;	// (FUNC *)sym->value.i
+
+#ifdef SIZE_STATS
+xstatic unsigned int c_compiler_sz CGLOB;
+#endif
+
+#ifdef MC680X0
+/* variable initialization */
+enum e_gt {
+	nogen, bytegen, wordgen, longgen, floatgen
+};
+enum e_sg {
+	noseg, codeseg, dataseg
+};
+
+
+char		   *outlate();
+#ifndef NOFLOAT
+#ifdef PC
+unsigned long double2ffp();
+#else
+#define double2ffp(__x) (__x)
+#endif
+#endif
+void wrt2(short x);
+void set_label(int lab,unsigned int pos);
+unsigned int lab_src(int n);
+void put_label(int lab);
+void put_align2(void);
+
+enum(e_gt)		gentype;
+enum(e_sg)		curseg;
+int 			outcol;
+
+#define BIN_STEP 128
+
+void out_init() {
+//	fputs("gtc_compiled:\n", output);
+	curseg = noseg;
+	gentype = nogen;
+	outcol = 0;
+	lc_stk = 0;
+	odd = 0;
+	extlabel = -1;
+	glblabel = -32768;
+	scope_head = 0;
+	pos = 4;
+	hashinit(&alsyms);
+	reloc_tab.r = 0;
+	bss_tab.r = 0;
+	libsyms.tail = libsyms.head = 0;
+	rom_funcs = 0;
+#ifdef RAM_CALLS
+	ram_funcs = 0;
+#endif
+	loc_tab = 0;
+	glb_tab = 0;
+	ext_tab = 0;
+	nostub_mode = 0;
+#ifdef EXE_OUT
+	exestub_mode = 0;
+#endif
+	bin = malloc(bin_size = BIN_STEP);
+	pos = 4;
+	put_label(label("gtc_compiled"));
+#ifdef SIZE_STATS
+	c_compiler_sz=0;
+#endif
+}
+
+char *unres_name(int lab) {
+	SYM *ttail; int crc=N_HASH;;
+	while (crc--) {
+		ttail=alsyms.h[crc].tail;
+		while (ttail) {
+			if ((short)ttail->value.splab==(short)lab)
+				return ttail->name;
+			ttail = ttail->prev;
+		}
+	}
+	return 0;
+}
+void scan_unresolved() {
+	GTAB *t=glb_tab; int l=0x8000;
+	while (t) {
+		REF **r=t->r; int n;
+		n=N_TAB;
+		while (n--) {
+			if (*r++)
+				uerrc2("unresolved symbol '%s'",unres_name(l));
+			l++;
+		}
+		t=t->nxt;
+	}
+}
+
+int eval_rt(RTYPE *r) {
+	int n=1;
+	REF *p=r->r0,*q=r->r;
+	while (p!=q)
+		n+=N_REF,p=p->nxt;
+	if (p) {
+		unsigned int *a=p->r;
+		while (*a++) n++;
+	}
+	return n;
+}
+unsigned int eval_functab(FUNC *f) {
+	int n=1;
+	while (f)
+		n+=1+eval_rt(&f->rt),f=f->nxt;
+	return n+n;
+}
+unsigned int eval_libs() {
+	int n=2;
+	SYM *sp=libsyms.head;
+	while (sp)
+		n+=10+eval_functab((FUNC *)sp->value.i),sp=sp->next;
+//	return 2;
+	return n;
+}
+unsigned int eval_export() {
+	int i=N_TAB,n=i;
+	int *a;
+	if (!exp_tab)
+		return 0;
+	a=exp_tab->t;
+	while (i--)
+		if (*a++) n=i;
+	return (1+N_TAB-n)<<1;
+}
+
+#ifdef PC
+xstatic unsigned char *hdr CGLOB,*hdrp CGLOB;
+#else
+xstatic unsigned short *hdr CGLOB,*hdrp CGLOB;
+#endif
+xstatic short hshift CGLOB;
+#ifdef PC
+void _wri(unsigned short x) {
+	unsigned char hi=(char)(x>>8),lo=(char)x;
+	*hdrp++=hi;
+	*hdrp++=lo;
+}
+void _ovwri(unsigned int i,unsigned short x) {
+	unsigned char hi=(char)(x>>8),lo=(char)x;
+	if (i&1) fatal("ODD OVWRI");
+	hdr[i+0]=hi;
+	hdr[i+1]=lo;
+}
+void _orwri(unsigned int i,unsigned short x) {
+	unsigned char hi=(char)(x>>8),lo=(char)x;
+	if (i&1) fatal("ODD ORWRI");
+	hdr[i+0]|=hi;
+	hdr[i+1]|=lo;
+}
+#define wri(x) (_wri((unsigned short)(x)))
+#define ovwri(i,x) (_ovwri(i,(unsigned short)(x)))
+#define orwri(i,x) (_orwri(i,(unsigned short)(x)))
+#else
+#define wri(x) (*hdrp++=x)
+#define ovwri(i,x) (*(unsigned short *)((char *)hdr+i)=x)
+#define orwri(i,x) (*(unsigned short *)((char *)hdr+i)|=x)
+#endif
+void write_rt(RTYPE *r) {
+	REF *p=r->r0;
+	while (p) {
+		unsigned int x,*a=p->r; int n;
+		if ((p=p->nxt)) {
+			n=N_REF; while (n--) wri((*a++)+hshift);
+		} else
+			while ((x=*a++)) wri(x+hshift);
+	}
+	wri(0);
+}
+void write_reloc(
+#ifdef OBJ_OUT
+				 int directly_to_bin
+#else
+			#define directly_to_bin 0
+#endif
+				 ) {
+	RTYPE *r=&reloc_tab;
+	REF *p=r->r0;
+	while (p) {
+		unsigned int x,*a=p->r; int n;
+		if ((p=p->nxt)) {
+			n=N_REF; while (n--) {
+				x=*a++;
+				directly_to_bin?wrt2(x+hshift+2):wri(x+hshift);
+	#ifdef PC
+				{ short a=bin[x+2]<<8;
+				a+=bin[x+3]+hshift;		/* logically, shouldn't overflow... */
+				bin[x+2]=(unsigned char)(a>>8);
+				bin[x+3]=(unsigned char)(a);
+				}
+	#else
+				*(long *)(bin+x)+=hshift;
+	#endif
+			}
+		} else
+			while ((x=*a++)) {
+	#ifdef PC
+				{ short a=bin[x+2]<<8;
+				a+=bin[x+3]+hshift;		/* logically, shouldn't overflow... */
+				bin[x+2]=(unsigned char)(a>>8);
+				bin[x+3]=(unsigned char)(a);
+				}
+	#else
+				*(long *)(bin+x)+=hshift;
+	#endif
+				directly_to_bin?wrt2(x+hshift+2):wri(x+hshift);
+			}
+	}
+	directly_to_bin?wrt2(0):wri(0);
+}
+#undef directly_to_bin
+void write_functab(FUNC *f0) {
+	int n=0; FUNC *f=f0;
+	while (f)
+		n++,f=f->nxt;
+	wri(n-1);
+	f=f0;
+	while (f)
+		wri(f->f),write_rt(&f->rt),f=f->nxt;
+}
+void write_libs() {
+	int n=0;
+	SYM *sp=libsyms.head;
+//	wri(0); return;
+	while (sp)
+		n++,sp=sp->next;
+	wri(n);
+	sp=libsyms.head;
+	while (sp) {
+		memset(hdrp,0,8);
+		strcpy((char *)hdrp,sp->name);
+		hdrp+=8/sizeof(*hdrp);
+		wri(0);
+		sp=sp->next;
+	}
+	sp=libsyms.head;
+	while (sp)
+		write_functab((FUNC *)sp->value.i),sp=sp->next;
+}
+unsigned int qlab_src(int n);
+void write_export(unsigned int l) {
+	int *a=exp_tab->t,x;
+	l=(l>>1)-1;
+	wri((short)l);
+	while (l--) {
+		if ((x=*a++))
+			x=qlab_src(x)+hshift;
+		wri(x);
+	}
+}
+
+#ifdef EXE_OUT
+typedef struct {
+	short t;			// type
+	unsigned short loc;	// location, offset based on relocated output
+} EXE_ITEM;
+int
+#ifdef PC
+#ifdef _MSC_VER
+__cdecl
+#endif
+#else
+CALLBACK
+#endif
+exe_compare(const void *a,const void *b) {
+	return ((EXE_ITEM *)a)->loc-((EXE_ITEM *)b)->loc;
+}
+void *GTPackDo(void *buf,unsigned int *buflen);
+#include "out68k_exe.h"
+#endif
+
+readonly char pgm_init[0x1A]={0x61,0,0,0,'6','8','k','P'};
+readonly char lib_init[0x1A]={0x4E,0x75,0x4E,0x75,'6','8','k','L'};
+readonly char pgm_stub[0xA]={0x2F,0x38,0x00,0x34,0x66,0x02,0x50,(char)0x8F,0x4E,0x75};
+void wrt2(short x);
+void wrt1(char x);
+void out_close() {
+#ifdef PC
+	int calctype_used[]={0,0,0};
+	char *calc_symbols[]={"USE_TI89","USE_TI92PLUS","USE_V200"};
+	int calc,specific=1,something;
+	for (something=0;!something;specific=0)
+		for (calc=0;calc<3;calc++)
+			if (!specific || search(calc_symbols[calc],-1,&defsyms))
+				calctype_used[calc]++,something++;
+#endif
+	if (bin) {
+		/*
+		 * 0x1A+(2+10*nLibs+2*(nLibs+nLibCalls+nLibFuncs))+(2+2+2*(nRomFuncs+nRomCalls))
+		 * +2+2+(4+nBSS*2)+(2+nExport*2)
+		 * +0xA+(nReloc+1)*2
+		 *  =
+		 * 0x1A+(2+10*nLibs+nLibs(eval(Lib)))+(2+eval(rom))
+		 * +2+2+(4+nBSS*2)+(2+nExport*2)
+		 * +0xA+eval_rt(reloc_tab)*2
+		 *  =
+		 * 0x1A+(2+eval_libs())+(2+eval(rom))
+		 * +2+2+(4+nBSS*2)+(2+nExport*2)
+		 * +0xA+eval_rt(reloc_tab)*2
+		 */
+		SYM *mainsym;
+		unsigned int rom=eval_functab(rom_funcs)-2,lib=eval_export();
+#ifdef RAM_CALLS
+		unsigned int ram=eval_functab(ram_funcs)-2;
+#else
+#define ram 0
+#endif
+#ifdef OBJ_OUT
+		int object=!!search("_GENERIC_ARCHIVE",-1,&defsyms);
+		if (!object) {
+#endif
+			int nostub=search("_nostub",-1,&alsyms) || search("_nostub",-1,&gsyms)
+				|| search("_nostub",-1,&defsyms) || nostub_mode;
+#ifdef EXE_OUT
+			int exestub=!!search("EXE_OUT",-1,&defsyms);
+			if (exestub) nostub=0;
+#else
+#define exestub 0
+#endif
+			debug('+');
+			if (nostub) {
+				if (ram || rom) fatal("RAM/ROM_CALL in _nostub");
+				if (libsyms.head) fatal("Libraries in _nostub");
+				if (bss_tab.r) fatal("BSS in _nostub");
+				hshift=0;
+#ifdef EXE_OUT
+			} else if (exestub) {
+				if (ram) fatal("RAM_CALL in EXE format");
+				if (libsyms.head) fatal("Libraries in exe format");
+#endif
+			} else {
+				hdrp=hdr=malloc((hshift=0x1A-4+(eval_libs())+(rom?rom+4:2)
+					+(ram?ram+4:2)+(eval_rt(&reloc_tab)<<1)+(bss_tab.r?4+(eval_rt(&bss_tab)<<1):0)
+						+(lib)+(lib?0:0xA))+4);
+				if (!hdr)
+					fatal("memory");
+				memcpy(hdr,lib?lib_init:pgm_init,0x1A);
+				hdrp+=0x1A/sizeof(*hdrp);
+				write_libs();	// import table
+				wri(rom);	// ROM table
+				if (rom) write_functab(rom_funcs);
+		#ifdef RAM_CALLS
+				wri(ram);	// RAM table
+				if (ram) write_functab(ram_funcs);
+		#else
+				wri(0);	// no RAM table
+		#endif
+		#ifdef OBJ_OUT
+				write_reloc(0);	// reloc table
+		#else
+				write_reloc();	// reloc table
+		#endif
+				if (bss_tab.r) {
+					ovwri(0x14,(char *)hdrp-(char *)hdr);	// BSS table
+					wri(lc_bss>>16),wri(lc_bss);
+					write_rt(&bss_tab);
+				}
+				if (lib) {
+					ovwri(0x16,(char *)hdrp-(char *)hdr);	// export table
+					write_export(lib);
+				}
+				if (!lib) {
+					ovwri(0x02,(char *)hdrp-(char *)hdr-2);	// stub
+					memcpy(hdrp,pgm_stub,0xA);
+					hdrp+=0xA/sizeof(*hdrp);
+				}
+		#ifdef PC
+				if (hdrp!=hdr+(hshift+4)/sizeof(*hdrp))
+					ierr(LINK_MISPL,1);
+		#endif
+				/* link with file */
+				if ((mainsym=search("VERSION",-1,&defsyms))) {
+
+					ovwri(0x10,1<<8);
+				}
+			}
+			mainsym=NULL;
+			if (!lib && ((!nostub && !exestub) || !search("NO_MAIN",-1,&defsyms))) {
+				if (!(mainsym=search("_main",-1,&alsyms)) && !(mainsym=search("__main",-1,&alsyms)))
+					fatal("_main not found");
+				if (!nostub && !exestub) {
+					ovwri(0x0C,qlab_src(mainsym->value.splab)+hshift);
+					if (!!search("NO_SCREEN",-1,&defsyms))
+						orwri(0x10,(1<<2));
+				}
+			}
+			scan_unresolved();
+
+			/* finally, write the output to the file */
+			if (nostub) {
+				if (!mainsym)
+					memmove(bin,bin+4,pos-4),pos-=4,hshift=-4;
+				else {
+			#ifdef PC
+					bin[0]=0x60,bin[1]=0x00;
+					bin[2]=(unsigned char)((qlab_src(mainsym->value.splab)-2)>>8);
+					bin[3]=(unsigned char)((qlab_src(mainsym->value.splab)-2));
+			#else
+					*(short *)bin=0x6000;
+					*(short *)(bin+2)=qlab_src(mainsym->value.splab)-2;
+			#endif
+					hshift=0;
+				}
+				put_align2();
+				wrt2(0);
+			   {
+				RTYPE *r=&reloc_tab;
+				REF *p=r->r0;
+				while (p) {
+					unsigned int x,*a=p->r; int n;
+					if ((p=p->nxt)) {
+						n=N_REF; while (n--) {
+				#ifdef PC
+							{ short z=bin[(x=*a++)+2+hshift]<<8;
+							z+=bin[x+3+hshift]+hshift;
+							wrt2(z);
+							}
+				#else
+							wrt2(*(unsigned short *)(bin+(x=*a++)+2+hshift)+hshift);
+				#endif
+							if (*(unsigned short *)(bin+x+hshift)!=0)
+								uerrc("invalid _nostub relocation");
+							*(unsigned short *)(bin+x+2+hshift)=0;
+							wrt2((unsigned short)(x+hshift));
+						}
+					} else
+						while ((x=*a++)) {
+				#ifdef PC
+							{ short z=bin[x+2+hshift]<<8;
+							z+=bin[x+3+hshift]+hshift;
+							wrt2(z);
+							}
+				#else
+							wrt2(*(unsigned short *)(bin+x+2+hshift)+hshift);
+				#endif
+							if (*(unsigned short *)(bin+x+hshift)!=0)
+								uerrc("invalid _nostub relocation");
+							*(unsigned short *)(bin+x+2+hshift)=0;
+							wrt2((unsigned short)(x+hshift));
+						}
+				}
+			   }
+				wrt1((char)0xF3);
+				rel_global();
+		#ifndef PC
+				fwrite(bin,1,pos,output);
+		#endif
+#ifdef EXE_OUT
+			} else if (exestub) {
+#ifdef TWIN_COMPILE
+				if (twinc_necessary) {
+					rel_global();
+					goto close_it;	// don't lose time compressing...
+				} else {
+#endif
+			#define EXE_END -1
+			#define EXE_PROGRELOC 0
+			#define EXE_BSSRELOC 1
+			#define EXE_ROMRELOC 2
+			#define EXE_ROMRELOC_NOJSR (0x100|EXE_ROMRELOC)
+				EXE_ITEM *exe_data=calloc(6000,sizeof(EXE_ITEM));	/* 12 kb */
+				EXE_ITEM *exe_ptr=exe_data;
+				int exe_num;
+				if (!exe_data)
+					fatal("Memory");
+				memmove(bin,bin+4,pos-4),pos-=4;
+			   {
+				RTYPE *r=&reloc_tab;
+				REF *p=r->r0;
+				while (p) {
+					unsigned int x,*a=p->r; int n;
+					if ((p=p->nxt)) {
+						n=N_REF; while (n--) {
+							exe_ptr->t=EXE_PROGRELOC;
+							exe_ptr->loc=(*a++)-4;
+							exe_ptr++;
+						}
+					} else
+						while ((x=*a++)) {
+							exe_ptr->t=EXE_PROGRELOC;
+							exe_ptr->loc=x-4;
+							exe_ptr++;
+						}
+				}
+			   }
+			   {
+				FUNC *f=rom_funcs;
+				while (f) {
+					RTYPE *r=&f->rt;
+					REF *p=r->r0;
+					while (p) {
+						unsigned int x,*a=p->r; int n;
+						if ((p=p->nxt)) {
+							n=N_REF; while (n--) {
+								exe_ptr->t=EXE_ROMRELOC;
+								exe_ptr->loc=(*a++)-4;
+								if (*(long *)(bin+exe_ptr->loc))
+									fatal("Invalid ROM_CALL");
+								bin[exe_ptr->loc+2]=f->f>>8;
+								bin[exe_ptr->loc+3]=f->f&255;
+								if (bin[exe_ptr->loc-2]==0x4e
+									&& bin[exe_ptr->loc-1]==0xb9)
+									exe_ptr->loc-=2;
+								else bin[exe_ptr->loc+2]|=0x80,exe_ptr->t=EXE_ROMRELOC_NOJSR;
+								exe_ptr++;
+							}
+						} else
+							while ((x=*a++)) {
+								exe_ptr->t=EXE_ROMRELOC;
+								exe_ptr->loc=x-4;
+								if (*(long *)(bin+exe_ptr->loc))
+									fatal("Invalid ROM_CALL");
+								bin[exe_ptr->loc+2]=f->f>>8;
+								bin[exe_ptr->loc+3]=f->f&255;
+								if (bin[exe_ptr->loc-2]==0x4e
+									&& bin[exe_ptr->loc-1]==0xb9)
+									exe_ptr->loc-=2;
+								else bin[exe_ptr->loc+2]|=0x80,exe_ptr->t=EXE_ROMRELOC_NOJSR;
+								exe_ptr++;
+							}
+					}
+					f=f->nxt;
+				}
+			   }
+				exe_ptr->t=-1; exe_ptr->loc=pos; exe_ptr++;
+				exe_num=exe_ptr-exe_data;
+				qsort(exe_data,exe_num,sizeof(EXE_ITEM),exe_compare);
+			   {
+				long relocated_size;
+				unsigned short last_pos=0; unsigned char *ptr=bin,*out=bin;
+				char *reloc_ptr=(char *)exe_data,*last_esc=NULL;
+				int last_esc_num=0;
+				int i=exe_num; exe_ptr=exe_data;
+				while (i--) {
+					unsigned char *dest_ptr=bin+exe_ptr->loc;
+					unsigned short delta; short type;
+#ifdef PC
+#define g16(p) (p+=2,(p[-2]<<8)+p[-1])
+#define rd16(p) ((p[0]<<8)+p[1])
+#define w16(p,v) (*p++=(v)>>8,*p++=(v)&255,(void)0)
+#else
+#define g16(p) (*((int *)p)++)
+#define rd16(p) (*((int *)p))
+#define w16(p,v) (g16(p)=(v))
+#endif
+					while (ptr<dest_ptr) {
+						/*if (ptr==&bin[0xaca])
+							bkpt();	// [off_nr$9c] */
+						w16(out,rd16(ptr));
+#ifndef OLD_LOADER_WITHOUT_BRANCHES
+						if (!ptr[1] && (ptr[0]&0xF0)==0x60) {
+							//printf(".");
+							ptr+=2;
+							goto relative_optimize;
+						}
+#endif
+						if ((g16(ptr)&63)==0x3A) {
+#ifndef OLD_LOADER_WITHOUT_BRANCHES
+						relative_optimize:
+#endif
+							if (ptr>=dest_ptr) break;
+							w16(out,rd16(ptr)+((char *)ptr-(char *)bin));
+							ptr+=2;
+						}
+					}
+					delta=(exe_ptr->loc-last_pos)+2;
+					last_pos=exe_ptr->loc;
+					if ((delta&1))
+						uerrc("invalid relocation offset");
+					delta>>=1;
+					switch ((type=exe_ptr->t)) {	// we *NEED* to save exe_ptr->t as it will be lost
+						case EXE_PROGRELOC:
+							if (g16(ptr))
+								uerrc("invalid _nostub relocation");
+							w16(out,rd16(ptr)-4);	// parameters to w16 can't have side-fx...
+							ptr+=2;
+							last_pos+=4;
+							break;
+						case EXE_ROMRELOC:
+							ptr+=4;
+							w16(out,rd16(ptr));	// parameters to w16 can't have side-fx...
+							ptr+=2;
+							last_pos+=6;
+							break;
+						case EXE_ROMRELOC_NOJSR:
+							ptr+=2;
+							w16(out,rd16(ptr));	// parameters to w16 can't have side-fx...
+							ptr+=2;
+							last_pos+=4;
+							break;
+					}
+					if (delta<128)
+						*reloc_ptr++=delta&255;
+					else *reloc_ptr++=128|(delta>>8),*reloc_ptr++=delta&255;
+					if (!last_esc_num--)
+						last_esc=reloc_ptr,*reloc_ptr++=0,last_esc_num=3;
+					if (type IS_INVALID) {
+						*reloc_ptr++=0;
+						break;
+					}
+					(*last_esc)|=type<<(last_esc_num<<1);
+					exe_ptr++;
+				}
+				rel_global();
+				exe_num=reloc_ptr-(char*)exe_data;
+				*reloc_ptr=0;							/* (same remark as below...) */
+				reloc_ptr=realloc(exe_data,exe_num+1);	/* we don't know if we will need padding... */
+				relocated_size=pos;
+				pos=out-bin;
+				bin=realloc(bin,pos);
+#if 0
+				{
+					unsigned int i;
+					for (i=0; i<pos; i++)
+						printf("0x%x,\n",(int)bin[i]);
+				}
+#endif
+				bin=GTPackDo(bin,&pos);
+				if (((exe_num+pos)&1)) exe_num++;
+				{ unsigned short loader_offset=(8-2)+12+pos+exe_num+(bss_tab.r?6:0)+6;
+				char header[8];
+				char exe_hdr[12]={0,1,0,0,0,0,0,0,0,0,0,0};
+				if (loader_offset<=32767) {
+					header[0]=0x60,header[1]=0x00;
+					header[2]=loader_offset>>8,header[3]=loader_offset&255;
+					*(long *)(header+4)=0;
+				} else {
+			#ifdef PC
+					const unsigned char header32[8]=
+			#else
+					memcpy(header,(char[])
+			#endif
+						{0x41,0xFA,0x7F,0xF2,0x4E,0xE8,0x80,0x0C}
+			#ifdef PC
+					; memcpy(header,header32, 8);
+			#else
+						, 8);
+			#endif
+					loader_offset+=(0x800C-2);
+					header[6]=loader_offset>>8,header[7]=loader_offset&255;
+					loader_offset-=(0x800C-2);	// restore it for future use
+				}
+				bin=realloc(bin,8+12+pos+exe_num+(bss_tab.r?exeloadersize_bss:exeloadersize_nobss));
+				if (!bin)
+					fatal("Memory");
+				memmove(bin+8+12,bin,pos);
+				memcpy(bin,header,8);
+				exe_hdr[2]=pos>>8,exe_hdr[3]=pos&255;
+				exe_hdr[5]=(char)((relocated_size>>16)&255),
+					exe_hdr[6]=(char)((relocated_size>>8)&255),
+					exe_hdr[7]=(char)(relocated_size&255);
+				if (bss_tab.r)
+					fatal("BSS in exes are not implemented");
+				memcpy(bin+8,exe_hdr,12);
+				memcpy(bin+8+12+pos,reloc_ptr,exe_num);
+				free(reloc_ptr);
+				memcpy(bin+8+12+pos+exe_num,bss_tab.r?exeloader_bss:exeloader_nobss,
+					bss_tab.r?exeloadersize_bss:exeloadersize_nobss);
+#ifdef PC
+				if (verbose) {
+					msg2("RAM required during execution   : %5u bytes\n",(unsigned int)relocated_size);
+					msg2("Memory required for EXE program : %5u bytes\n",8+12+pos+exe_num);
+					msg2("Memory required for EXE loader  : %5u bytes\n",bss_tab.r?exeloadersize_bss:exeloadersize_nobss);
+				}
+#endif
+				pos=8+12+pos+exe_num+(bss_tab.r?exeloadersize_bss:exeloadersize_nobss);
+				bin[pos-3]=(loader_offset+22+2)>>8,bin[pos-2]=(loader_offset+22+2)&255;
+#ifdef PC
+				if (verbose)
+					msg2("Total program size              : %5u bytes\n",pos);
+#endif
+				}
+			   }
+		#ifndef PC
+				fwrite(bin,1,pos,output);
+		#endif
+#ifdef TWIN_COMPILE
+				}
+#endif
+#endif
+			} else {
+				rel_global();
+				put_align2();
+				wrt2(0);
+				wrt1((char)0xF3);
+		#ifdef PC
+				if (!(bin=realloc(bin,bin_size+=hshift)))
+					fatal("Memory");
+				memmove(bin+hshift+4,bin+4,pos-4);
+				memcpy(bin,hdr,hshift+4);
+				pos+=hshift;
+		#else
+				fwrite(hdr,1,hshift+4,output);
+				fwrite(bin+4,1,pos-4,output);
+		#endif
+				free(hdr);
+			}
+#ifdef OBJ_OUT
+		} else {
+			unsigned int len;
+			int j;
+			if (pos&1)
+				wrt1(0);
+			len=pos-4;
+
+			/* reloc table */
+			hshift=-4;
+			write_reloc(1);
+
+			/* export table */
+			j=N_HASH;
+			while (j--) {
+				SYM *sp = gsyms.h[j].head;
+				while (sp) {
+					if ((sp->storage_class == sc_external && sp->used) ||
+						(sp->storage_class == sc_global && sp->value.splab)) {
+#ifdef PC
+						if (!lab_src(sp->value.splab))
+							fatal("UNDEF LABEL");	// should this happen ?
+#endif
+						wrt2(lab_src(sp->value.splab)-2/*fix offset for object format*/);
+					}
+					sp = sp->next;
+				}
+			}
+			wrt2(0);
+			j=N_HASH;
+			while (j--) {
+				SYM *sp = gsyms.h[j].head;
+				while (sp) {
+					if ((sp->storage_class == sc_external && sp->used) ||
+						(sp->storage_class == sc_global && sp->value.i != -1)) {
+						char *s=sp->name;
+						do
+							wrt1(*s);
+						while (*s++);
+					}
+					sp = sp->next;
+				}
+			}
+			if (pos&1)
+				wrt1(0);
+
+			/* import table */
+			{
+			GTAB *t=glb_tab;
+			while (t) {
+				REF **r=t->r; int m=N_TAB;
+				while (m--) {
+					REF *q;
+					if ((q=*r++)) {
+						while (q) {
+							unsigned int p,*a=q->r;
+							int n=N_REF;
+							while (n--) {
+								if (!(p=*a++))
+									goto ref_done;
+								if (p&1)
+									fatal("Negative reloc in object output");
+								// warning, this is a 16-bit reloc, but we have to store it as a 32-bit one
+						#define offs_convert(p) (p-2/*since 16->32 bit*/-4/*convert bin[] offsets to final object offsets*/)
+								if (!offs_convert(p))
+									fatal("Word reloc at beginning");
+								wrt2(offs_convert(p));
+						#undef  offs_convert
+							}
+							q=q->nxt;
+						}
+					ref_done:
+						wrt2(0);
+					}
+				}
+				t=t->nxt;
+			}
+			}
+			wrt2(0);
+			{
+			GTAB *t=glb_tab; int l=0x8000;
+			while (t) {
+				REF **r=t->r; int m=N_TAB;
+				while (m--) {
+					if (*r++) {
+						char *s=unres_name(l);
+						do
+							wrt1(*s);
+						while (*s++);
+					}
+					l++;
+				}
+				t=t->nxt;
+			}
+			}
+			if (pos&1)
+				wrt1(0);
+			wrt2(0);	// leave space for future BSS extension
+			hdr=bin; // hack pawa =)
+			ovwri(0x0,pos-4);
+			ovwri(0x2,len+2);
+		#ifndef PC
+			wrt1(0);
+			wrt1('E');
+			wrt1('X');
+			wrt1('T');
+			wrt1(0);
+			wrt1(0xF8);
+			fwrite(bin,1,pos,output);
+		#endif
+		}
+#endif
+	#ifdef PC
+		{
+#ifdef OBJ_OUT
+			if (!object) {
+#endif
+				char *extensions[]={".89z",".9xz",".v2z"};
+				for (calc=0;calc<3;calc++) {
+					if (calctype_used[calc]) {
+						unsigned int tifilelen;
+						extern char *calcfolder;
+						char *tifile=create_ti_file(calc,0x21,calcname,calcfolder,bin,pos,&tifilelen);
+						char *buffer; FILE *fp;
+						buffer=alloca(strlen(outputname)+strlen(extensions[calc])+1);
+						strcpy(buffer,outputname);
+						strcat(buffer,extensions[calc]);
+						if (!(fp=fopen(buffer,"wb")))
+							fatal("Could not open output file.");
+						fwrite(tifile,1,tifilelen,fp);
+						free(tifile);
+						fclose(fp);
+					}
+				}
+#ifdef OBJ_OUT
+			} else {
+				char buffer[100]; FILE *fp;
+				strcpy(buffer,calcname);
+				strcat(buffer,".ext");
+				if (!(fp=fopen(buffer,"wb")))
+					fatal("Could not open output file.");
+				fwrite(bin,1,pos,fp);
+				fclose(fp);
+			}
+#endif
+		}
+	#endif
+	#ifdef TWIN_COMPILE
+	close_it:
+	#endif
+		free(bin);
+		bin=0;
+	}
+}
+
+void bin_chk(unsigned int pos) {
+	while (bin_size<pos)
+		if (!(bin=realloc(bin,bin_size+=BIN_STEP)))
+			fatal("Memory");
+}
+
+void lab_set(int n,unsigned int v) {
+	int i=(n&0x7FFF)>>N_TAB_LOG;
+	LTAB *p=local(n)?loc_tab:(LTAB *)glb_tab,*o;
+	debugf("lab_set(%x,%x)\n",n,v);
+	global_flag+=n&0x8000;
+	if (!p) {
+		if (local(n))
+			loc_tab=p=(LTAB *)xalloc(sizeof(LTAB),_TAB);
+		else glb_tab=(GTAB *)(p=(LTAB *)xalloc(sizeof(GTAB),_TAB));
+	}
+	while (i--)
+		if (!(p=(o=p)->nxt))
+			o->nxt=p=(LTAB *)xalloc(local(n)?sizeof(LTAB):sizeof(GTAB),_TAB);
+	global_flag&=0x7FFF;
+#ifndef PC
+	n&=N_TAB-1;
+	p->t[n]=v;
+#else
+	i=n&(N_TAB-1);
+	p->t[i]=v;
+#endif
+}
+
+#ifdef PC
+/* that's what we use if we want the storage to be persistent, even if we call it from a
+ * temp_mem location
+ */
+void *xallocnt(int s,int m) {
+	void *p;
+	temp_local++;
+	p=xalloc(s,m);
+	temp_local--;
+	return p;
+}
+/* xallocnt in global mode */
+void *xallocntg(int s,int m) {
+	void *p;
+	global_flag++;
+	p=xallocnt(s,m);
+	global_flag--;
+	return p;
+}
+#else
+#define xallocnt(s,m) _xallocnt(s)
+void *_xallocnt(int s) {
+	void *p;
+	temp_local++;
+	p=xalloc(s,0);
+	temp_local--;
+	return p;
+}
+#define xallocntg(s,m) _xallocnt(s)
+void *_xallocntg(int s) {
+	void *p;
+	global_flag++;
+	p=xallocnt(s,0);
+	global_flag--;
+	return p;
+}
+#endif
+unsigned int lab_src(int n) {
+	int i=(n&0x7FFF)>>N_TAB_LOG;
+	LTAB *p=local(n)?loc_tab:(LTAB *)glb_tab,*o;
+	debugfq("lab_src(%x)",n);
+	global_flag+=n&0x8000;
+	if (!p) {
+		if (local(n))
+			loc_tab=p=(LTAB *)xallocnt(sizeof(LTAB),_TAB);
+		else glb_tab=(GTAB *)(p=(LTAB *)xallocntg(sizeof(GTAB),_TAB));
+	}
+	while (i--)
+		if (!(p=(o=p)->nxt))
+			o->nxt=p=(LTAB *)(local(n)?xallocnt(sizeof(LTAB),_TAB):xallocntg(sizeof(GTAB),_TAB));
+	global_flag&=0x7FFF;
+	n&=N_TAB-1;
+	debugf("=%x\n",p->t[n]);
+	return p->t[n];
+}
+
+RTYPE **xt_find(int n) {
+	int i=(n=(int)((short)~n))>>N_TAB_LOG;
+	XTAB *p=ext_tab,*o;
+	global_flag++;
+	if (!p)
+		ext_tab=p=(XTAB *)xalloc(sizeof(XTAB),_TAB);
+	while (i--)
+		if (!(p=(o=p)->nxt))
+			o->nxt=p=(XTAB *)xalloc(sizeof(XTAB),_TAB);
+	global_flag--;
+	n&=N_TAB-1;
+	return &p->t[n];
+}
+
+int *exp_find(int n) {
+	int i=n>>N_TAB_LOG;
+	LTAB *p=exp_tab,*o;
+	global_flag++;
+	if (!p)
+		exp_tab=p=(LTAB *)xalloc(sizeof(LTAB),_TAB);
+	while (i--)
+		if (!(p=(o=p)->nxt))
+			o->nxt=p=(LTAB *)xalloc(sizeof(LTAB),_TAB);
+	global_flag--;
+	n&=N_TAB-1;
+	return (int *)&p->t[n];
+}
+
+/*void loc_clear() {
+	LTAB *p=loc_tab,*o;
+	while (p) {
+		memset(p->t,0,sizeof(p->t));
+		p=p->nxt;
+	}
+}*/
+
+unsigned int qlab_src(int n) {
+	int i=(n&0x7FFF)>>N_TAB_LOG;
+	LTAB *p=local(n)?loc_tab:(LTAB *)glb_tab;
+	n&=N_TAB-1;
+	while (i--) p=p->nxt;
+	return p->t[n];
+}
+
+REF *ref_add(REF *r,unsigned int v) {
+	unsigned int *a;
+	debugf("ref_add(%lx,%x)\n",r,v);
+	a=r->r;
+	while (*a++);
+	if (a>(unsigned int *)&r->nxt) {
+		global_flag++;
+		(r=r->nxt=(REF *)xalloc(sizeof(REF),_REF+REF_ADD))->r[0]=v;
+		global_flag--;
+	} else a[-1]=v;
+	return r;
+}
+
+REF **glb_ref(int n) {
+	int i=(n&0x7FFF)>>N_TAB_LOG;
+	GTAB *p=glb_tab;
+	n&=N_TAB-1;
+	while (i--)
+		p=p->nxt;
+	return &p->r[n];
+}
+
+void lab_add_ref(int n,unsigned int r) {
+	int i=(n&0x7FFF)>>N_TAB_LOG;
+	GTAB *p=glb_tab; REF **ro;
+	debugf("lab_add_r(%x,%x)\n",n,r);
+#ifndef PC
+//	asm("0: jbra 0b");
+#endif
+	if (local(n))
+		uerrc2("local label not found: '%s'",unres_name(n));
+	global_flag++;
+	n&=N_TAB-1;
+	while (i--)
+		p=p->nxt;
+	ro=&p->r[n];
+	if (!*ro)
+		*ro=(REF *)xalloc(sizeof(REF),_REF+LAB_ADD_REF);
+	while ((*ro)->nxt)
+		ro=&(*ro)->nxt;
+	global_flag--;
+	ref_add(*ro,r);
+}
+void rt_add_ref(RTYPE *rt,unsigned int r) {	// effectively appends reloc to reloc table
+	debugf("rt_add_r(%lx,%x)\n",rt,r);
+	if (!rt->r) {
+		global_flag++;
+		rt->r0=rt->r=(REF *)xalloc(sizeof(REF),_REF+RT_ADD_REF);
+		global_flag--;
+	}
+	rt->r=ref_add(rt->r,r);
+}
+FUNC *func_search(FUNC **f0,unsigned int f) {
+	while (*f0)
+		if ((*f0)->f==f) break;
+		else f0=&(*f0)->nxt;
+	if (*f0) return *f0;
+	global_flag++;
+	*f0=(FUNC *)xalloc(sizeof(FUNC),_RT);
+	global_flag--;
+	(*f0)->f=f;
+	return *f0;
+}
+
+typedef struct gv_ret {
+	long i;
+	int ir,xr,tr;	// Internal/eXternal/Total Relocation count
+} GV;
+int get_value(struct enode *ep,GV *r,unsigned int rp,int m) {
+	int lab; unsigned int p;
+	r->ir=0; r->xr=0;
+  gv_restart:
+	switch (ep->nodetype) {
+	  case en_autocon:
+	  case en_icon:
+#ifndef NOFLOAT
+#ifndef PC
+	  case en_fcon:
+#endif
+#endif
+		r->i=ep->v.i;
+		r->tr=0;
+		break;
+#ifndef NOFLOAT
+#ifdef PC
+#ifndef BCDFLT
+	  case en_fcon:
+		r->i=double2ffp(ep->v.f);
+		r->tr=0;
+		break;
+#endif
+#endif
+#endif
+	  case en_labcon:
+	  case en_nacon:
+		lab=ep->v.enlab;
+		r->tr=1;
+		if (global(lab)) {
+			r->ir=1;
+			if (!(p=lab_src(lab))) {
+				if (rp)
+					lab_add_ref(lab,(rp+2)+m);
+				r->i=0;
+				return 1;
+			} else
+				r->i=p;
+		} else {
+			if (m) uerrc("negative external reference");
+			r->i=0,r->xr=1;
+			if (rp) {
+				RTYPE *rt=*xt_find(lab);
+				if (((long)rt)&0x80000000) {	// DIRTY, but no hidden bug possible (cf xalloc)
+					r->i=((long)rt)&0x7FFFFFFF;		// BSS ref
+					rt_add_ref(&bss_tab,rp);
+				} else rt_add_ref(rt,rp);			// lib/ROM ref
+			}
+			return 1;
+		}
+		break;
+	  case en_add:
+	  case en_sub:
+		{
+			GV a,b;
+			int res=get_value(ep->v.p[0],&a,rp,m);
+			res|=get_value(ep->v.p[1],&b,rp,ep->nodetype==en_sub?1-m:m);
+			r->xr=a.xr+b.xr;
+			r->tr=a.tr+b.tr;
+			if (ep->nodetype==en_sub) {
+				if (b.xr)
+					uerrc("negative external reference");
+				r->i=a.i-b.i,r->ir=a.ir-b.ir;
+			} else
+				r->i=a.i+b.i,r->ir=a.ir+b.ir;
+			return res;
+		}
+		break;
+	  case en_uminus:
+		m=1-m;
+		ep=ep->v.p[0];
+		goto gv_restart;
+	  default:
+		uerrc("invalid expression");
+	}
+	return 0;
+}
+int involved_lab(struct enode *ep) {
+  gv_restart:
+	switch (ep->nodetype) {
+	  case en_autocon:
+	  case en_icon:
+#ifndef NOFLOAT
+#ifdef PC
+	  case en_fcon:
+#endif
+#endif
+		return -1;
+	  case en_labcon:
+	  case en_nacon:
+		return ep->v.enlab;
+	  case en_add:
+	  case en_sub:
+		return max(involved_lab(ep->v.p[0]),involved_lab(ep->v.p[1]));
+	  case en_uminus:
+		ep=ep->v.p[0];
+		goto gv_restart;
+	  default:
+		uerrc("invalid expression");
+	}
+	return -1;
+}
+
+xstatic int rel CGLOB, is_long CGLOB;
+long get_long(struct enode *ep,unsigned int rp) {
+	GV v;
+	get_value(ep,&v,rp,0);
+	if (v.ir) {
+		rt_add_ref(&reloc_tab,rp);
+		if (v.ir!=1)
+			uerr(ERRA_INVALIDREL);
+	}
+	rel=v.ir+v.xr;
+	return v.i;
+}
+short get_pcword(struct enode *ep,unsigned int rp) {
+	GV v;
+	int no_check=get_value(ep,&v,rp-2,0);
+	if (v.ir!=1 || v.xr)
+		uerr(ERRA_INVALIDREL);
+	if (!no_check) {
+		v.i -= rp;
+		if (v.i>32767L || v.i<-32768L)
+#ifdef TWIN_COMPILE
+		{
+			if (!twinc_necessary) uwarn("twin compilation required");
+			twinc_necessary=1;
+			*twinc_info++=involved_lab(ep);
+			*twinc_info++=rp;
+		}
+#else
+			uerrc("PC-relative mode not allowed here");
+#endif
+//		v.i += rp;
+		return (short)v.i;
+	} else
+		return (short)v.i-(short)rp;
+}
+short get_word(struct enode *ep,unsigned int rp,int sign) {
+	GV v;
+	int no_check=get_value(ep,&v,rp-2,0);
+	if (v.ir || v.xr)
+		uerr(ERRA_INVALIDREL);
+	/* otherwise this would bug with myval&0xFFFF7FFF which is converted to and.w */
+	if (!no_check && (v.i>(sign?32767L:65535L) || v.i<(sign?-32768L:-65535L)))
+//	if (!no_check && (v.i>(sign?32767L:65535L) || v.i<-32768L))
+		uerrc("value can't fit in a word");
+	return (short)v.i;
+}
+long get_offs(struct enode *ep,unsigned int rp) {
+	GV v; int l=0;
+	get_value(ep,&v,0,0);
+	if (v.ir || v.xr)
+		l=1;
+	if (v.i>32767L || v.i<-32768L)
+		l=1;
+	if ((is_long=l))
+		return get_long(ep,rp);
+	else return get_word(ep,rp,1);
+}
+unsigned char get_byte(struct enode *ep) {
+	GV v;
+	get_value(ep,&v,0,0);
+	if (v.tr)
+		uerr(ERRA_INVALIDREL);
+	if ((unsigned long)(((unsigned long)v.i)+128)>255)
+		uerrc("value can't fit in a byte");
+	return (unsigned char)v.i;
+}
+unsigned short get_quick(struct enode *ep) {
+	GV v;
+	get_value(ep,&v,0,0);
+	if (v.tr)
+		uerr(ERRA_INVALIDREL);
+	if ((unsigned long)(((unsigned long)v.i)-1)>=8)
+		uerrc("value can't fit in a quick constant");
+	if (v.i==8)
+		v.i=0;
+	return (unsigned short)v.i;
+}
+
+enum {
+	oi_move=1,
+	oi_moveq=oi_move+8,
+	oi_clr=oi_moveq+1,
+	oi_lea=oi_clr+1,
+	oi_add=oi_lea+1,
+	oi_addi=oi_add+4,
+	oi_addq=oi_addi+1,
+	oi_sub=oi_addq+1,
+	oi_subi=oi_sub+4,
+	oi_subq=oi_subi+1,
+	oi_muls=oi_subq+1,
+	oi_mulu=oi_muls+1,
+	oi_divs=oi_mulu+1,
+	oi_divu=oi_divs+1,
+	oi_and=oi_divu+1,
+	oi_andi=oi_and+3,
+	oi_or=oi_andi+1,
+	oi_ori=oi_or+3,
+	oi_eor=oi_ori+1,
+	oi_eori=oi_eor+2,
+	oi_lsl=oi_eori+1,
+	oi_lsr=oi_lsl+3,
+	oi_jmp=oi_lsr+3,
+	oi_jsr=oi_jmp+1,
+	oi_movem=oi_jsr+1,
+	oi_rts=oi_movem+3,
+	oi_bra=oi_rts+1,
+	oi_bsr=oi_bra+1,
+	oi_beq=oi_bsr+1,
+	oi_bne=oi_beq+1,
+	oi_bhs=oi_bne+1,
+	oi_bge=oi_bhs+1,
+	oi_bhi=oi_bge+1,
+	oi_bgt=oi_bhi+1,
+	oi_bls=oi_bgt+1,
+	oi_ble=oi_bls+1,
+	oi_blo=oi_ble+1,
+	oi_blt=oi_blo+1,
+	oi_tst=oi_blt+1,
+	oi_ext=oi_tst+1,
+	oi_swap=oi_ext+1,
+	oi_neg=oi_swap+1,
+	oi_not=oi_neg+1,
+	oi_cmp=oi_not+1,
+	oi_link=oi_cmp+5,
+	oi_unlk=oi_link+1,
+	oi_label=oi_unlk+1,
+	oi_pea=oi_label+0,
+	oi_cmpi=oi_pea+1,
+	oi_dbra=oi_cmpi+1,
+	oi_asr=oi_dbra+1,
+	oi_bset=oi_asr+3,
+	oi_bclr=oi_bset+4,
+	oi_bchg=oi_bclr+4,
+	_oi_asm=oi_bchg+4,
+	_oi_adj=_oi_asm+0,
+#ifndef ASM
+	__oi_end=_oi_adj+0
+#endif
+#ifdef ASM
+	/* ASM-only */
+	oi_asl=_oi_adj+0,
+	oi_rol=oi_asl+3,
+	oi_ror=oi_rol+3,
+	oi_roxl=oi_ror+3,
+	oi_roxr=oi_roxl+3,
+	oi_btst=oi_roxr+3,
+	oi_exg=oi_btst+4,
+	oi_dc=oi_exg+4,
+	oi_ds=oi_dc+1,
+	oi_dcb=oi_ds+1,
+	oi_bvs=oi_dcb+1,
+	oi_bvc=oi_bvs+1,
+	oi_bpl=oi_bvc+1,
+	oi_bmi=oi_bpl+1,
+	oi_trap=oi_bmi+1,
+	oi_negx=oi_trap+1,
+	oi_addx=oi_negx+1,
+	oi_subx=oi_addx+2,
+	oi_chk=oi_subx+2,
+	oi_even=oi_chk+1,
+	oi_dbeq=oi_even+1,
+	oi_dbne=oi_dbeq+1,
+#ifndef LIGHT_DBXX_AND_SXX
+	oi_dbhs=oi_dbne+1,
+	oi_dbge=oi_dbhs+1,
+	oi_dbhi=oi_dbge+1,
+	oi_dbgt=oi_dbhi+1,
+	oi_dbls=oi_dbgt+1,
+	oi_dble=oi_dbls+1,
+	oi_dblo=oi_dble+1,
+	oi_dblt=oi_dblo+1,
+	oi_dbvs=oi_dblt+1,
+	oi_dbvc=oi_dbvs+1,
+	oi_dbpl=oi_dbvc+1,
+	oi_dbmi=oi_dbpl+1,
+	oi_st=oi_dbmi+1,
+	oi_sf=oi_st+1,
+	oi_seq=oi_sf+1,
+	oi_sne=oi_seq+1,
+	oi_shs=oi_sne+1,
+	oi_sge=oi_shs+1,
+	oi_shi=oi_sge+1,
+	oi_sgt=oi_shi+1,
+	oi_sls=oi_sgt+1,
+	oi_sle=oi_sls+1,
+	oi_slo=oi_sle+1,
+	oi_slt=oi_slo+1,
+	oi_svs=oi_slt+1,
+	oi_svc=oi_svs+1,
+	oi_spl=oi_svc+1,
+	oi_smi=oi_spl+1,
+	oi_tas=oi_smi+1,
+	__oi_end=oi_tas+1
+#else
+	__oi_end=oi_dbne+1
+#endif
+#endif
+};
+
+readonly unsigned char opi[_op_max+2]={
+	oi_move, oi_moveq, oi_clr, oi_lea, oi_add, oi_addi, oi_addq, oi_sub, oi_subi, oi_subq,
+	oi_muls, oi_mulu, oi_divs, oi_divu, oi_and, oi_andi, oi_or, oi_ori, oi_eor, oi_eori,
+	oi_lsl, oi_lsr, oi_jmp, oi_jsr, oi_movem,
+	oi_rts, oi_bra, oi_bsr, oi_beq, oi_bne, oi_bhs, oi_bge, oi_bhi,
+	oi_bgt, oi_bls, oi_ble, oi_blo, oi_blt, oi_tst, oi_ext, oi_swap, oi_neg, oi_not, oi_cmp,
+	oi_link, oi_unlk, oi_label, oi_pea, oi_cmpi, oi_dbra, oi_asr,
+	oi_bset, oi_bclr, oi_bchg, _oi_asm, _oi_adj,
+#ifdef ASM
+	/* ASM-only */
+	oi_asl, oi_rol, oi_ror, oi_roxl, oi_roxr, oi_btst, oi_exg, oi_dc, oi_ds, oi_dcb,
+	oi_bvs, oi_bvc, oi_bpl, oi_bmi, oi_trap, oi_negx, oi_addx, oi_subx, oi_chk, oi_even,
+	oi_dbeq, oi_dbne,
+#ifndef LIGHT_DBXX_AND_SXX
+	oi_dbhs, oi_dbge, oi_dbhi, oi_dbgt, oi_dbls, oi_dble, oi_dblo, oi_dblt,/* unsigned, signed */
+	oi_dbvs, oi_dbvc, oi_dbpl, oi_dbmi,
+	oi_st,  oi_sf,  oi_seq, oi_sne,
+	oi_shs, oi_sge, oi_shi, oi_sgt, oi_sls, oi_sle, oi_slo, oi_slt,	/* unsigned, signed */
+	oi_svs, oi_svc, oi_spl, oi_smi, oi_tas,
+#endif
+#endif
+	__oi_end
+};
+
+typedef struct _opcode {
+	char impl,nargs,model,lenf;
+	unsigned short bo;
+	int a1,a2;
+} OPCODE;
+enum {
+	M_BASIC, M_BASICSWAPPED, M_BRANCH, M_DC, M_ALIGN
+};
+enum { L_0=1<<0, L_1=1<<1, L_2=1<<2, L_4=1<<4 };
+enum {
+	A_DREG=0x1,
+	A_AREG=0x2,
+	A_MEM0=0x4,
+	A_MEM=0x84,
+	A_PCR=0x8,
+	A_IMM=0x10,
+	A_MASK1=0x20,
+	A_MASK2=0x40,
+	A_ADEC=0x80,
+	D_RAW2=0x0100,	// |= %00000000 00000000 +WORD
+	D_RAW=0x0200,	// |= %00000000 00000000 (+DAT)
+	D_LOW=0x0400,	// |= %00000000 dddddddd
+	D_EA2=0x0800,	// |= %0000nnnm mm000000 (+DAT)
+	D_SZ3=0x3000,	// |= %00000000 0S000000 (argument-independent)
+	D_SZ2=0x1000,	// |= %0000000S 00000000 (argument-independent)
+	D_SZ=0x2000,	// |= %00000000 ss000000 (argument-independent)
+	D_Q=0x4000,		// |= %0000qqq0 00000000
+	D_EA=0x8000,	// |= %00000000 00mmmnnn (+DAT)
+};
+#define A_CCR A_MASK1
+#define A_SR A_MASK2
+#define A_USP A_MASK1
+/* we have to implement A_CCR and A_SR like that to avoid the use
+ * of a longword for flags... */
+#define A_SRC A_DREG|A_AREG|A_MEM|A_PCR|A_IMM
+#define A_SRC2 A_DREG|A_MEM|A_PCR|A_IMM
+#define A_DST A_DREG|A_AREG|A_MEM
+#define A_DST2 A_DREG|A_MEM
+
+// for each enum(e_op) value :
+readonly OPCODE ops[]={
+	// op_label
+	{0},
+	// op_move
+	{1,2,M_BASIC,L_2,0x3000,A_SRC|D_EA,A_DST|D_EA2},	// movea is in fact the same instruction
+	{1,2,M_BASIC,L_4,0x2000,A_SRC|D_EA,A_DST|D_EA2},
+	{1,2,M_BASIC,L_1,0x1000,A_SRC2|D_EA,A_DST2|D_EA2}, // move.b does not accept aregs
+	{1,2,M_BASIC,L_2,0x44C0,A_SRC2|D_EA,A_CCR},
+	{1,2,M_BASIC,L_2,0x46C0,A_SRC2|D_EA,A_SR},
+	{1,2,M_BASIC,L_2,0x40C0,A_SR,A_DST2|D_EA},
+	{1,2,M_BASIC,L_4,0x4E60,A_AREG|D_LOW,A_USP},
+	{1,2,M_BASIC,L_4,0x4E68,A_USP,A_AREG|D_LOW},
+	// op_moveq
+	{1,2,M_BASIC,L_0+L_4,0x7000,A_IMM|D_LOW,A_DREG|D_Q},
+	// op_clr
+	{1,1,M_BASIC,L_1+L_2+L_4,0x4200,A_DST2|D_EA|D_SZ},
+	// op_lea
+	{1,2,M_BASIC,L_0,0x41C0,A_MEM|A_PCR|D_EA,A_AREG|D_Q},
+	// op_add
+	{1,2,M_BASIC,L_1+L_2+L_4,0xD000,A_SRC|D_EA|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xD100,A_DREG|D_Q|D_SZ,A_MEM|D_EA},
+	{1,2,M_BASIC,    L_2+L_4,0xD0C0,A_SRC|D_EA|D_SZ2,A_AREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0600,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_addi
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0600,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_addq
+	{1,2,M_BASIC,L_1+L_2+L_4,0x5000,A_IMM|D_Q|D_SZ,A_DST|D_EA},
+	// op_sub
+	{1,2,M_BASIC,L_1+L_2+L_4,0x9000,A_SRC|D_EA|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x9100,A_DREG|D_Q|D_SZ,A_MEM|D_EA},
+	{1,2,M_BASIC,    L_2+L_4,0x90C0,A_SRC|D_EA|D_SZ2,A_AREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0400,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_subi
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0400,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_subq
+	{1,2,M_BASIC,L_1+L_2+L_4,0x5100,A_IMM|D_Q|D_SZ,A_DST|D_EA},
+	// op_muls
+	{1,2,M_BASIC,L_2,0xC1C0,A_SRC2|D_EA,A_DREG|D_Q},
+	// op_mulu
+	{1,2,M_BASIC,L_2,0xC0C0,A_SRC2|D_EA,A_DREG|D_Q},
+	// op_divs
+	{1,2,M_BASIC,L_2,0x81C0,A_SRC2|D_EA,A_DREG|D_Q},
+	// op_divu
+	{1,2,M_BASIC,L_2,0x80C0,A_SRC2|D_EA,A_DREG|D_Q},
+	// op_and
+	{1,2,M_BASIC,L_1+L_2+L_4,0xC000,A_SRC2|D_EA|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xC100,A_DREG|D_Q|D_SZ,A_MEM|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0200,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_andi
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0200,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_or
+	{1,2,M_BASIC,L_1+L_2+L_4,0x8000,A_SRC2|D_EA|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x8100,A_DREG|D_Q|D_SZ,A_MEM|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0000,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_ori
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0000,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_eor
+	{1,2,M_BASIC,L_1+L_2+L_4,0xB100,A_DREG|D_Q|D_SZ,A_DST2|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0A00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_eori
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0A00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_lsl
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE108,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE128,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE3C0,A_MEM|D_EA},
+	// op_lsr
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE008,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE028,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE2C0,A_MEM|D_EA},
+	// op_jmp
+	{1,1,M_BASIC,L_0,0x4EC0,A_MEM|A_PCR|D_EA},
+	// op_jsr
+	{1,1,M_BASIC,L_0,0x4E80,A_MEM|A_PCR|D_EA},
+	// op_movem - contains a little hack : default size is .l, so we separe L_4 from L_2.
+	//   Uses M_BASICSWAPPED because when 'uses_link' is set, the link reg needs to be after
+	//   the reg mask.
+	{1,2,M_BASIC,L_4,0x4880,A_MASK1|D_RAW|D_SZ3,A_MEM|D_EA},	/* LBUG : A_MEM&~POST_I */
+	{1,2,M_BASIC,L_2,0x4880,A_MASK1|D_RAW|D_SZ3,A_MEM|D_EA},	/* LBUG : A_MEM&~POST_I */
+	{1,2,M_BASICSWAPPED,L_2+L_4,0x4C80,A_MASK2|D_RAW,A_MEM0|D_EA|D_SZ3},
+	// op_rts
+	{1,0,M_BASIC,L_0,0x4E75},
+	// op_bra
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6000},
+	// op_bsr
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6100},
+	// op_beq
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6700},
+	// op_bne
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6600},
+	// op_bhs
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6400},
+	// op_bge
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6C00},
+	// op_bhi
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6200},
+	// op_bgt
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6E00},
+	// op_bls
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6300},
+	// op_ble
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6F00},
+	// op_blo
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6500},
+	// op_blt
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6D00},
+	// op_tst
+	{1,1,M_BASIC,L_1+L_2+L_4,0x4A00,A_DST2|D_EA|D_SZ},
+	// op_ext
+	{1,1,M_BASIC,L_2+L_4,0x4880,A_DREG|D_EA|D_SZ3},
+	// op_swap
+	{1,1,M_BASIC,L_4,0x4840,A_DREG|D_EA},
+	// op_neg
+	{1,1,M_BASIC,L_1+L_2+L_4,0x4400,A_DST2|D_EA|D_SZ},
+	// op_not
+	{1,1,M_BASIC,L_1+L_2+L_4,0x4600,A_DST2|D_EA|D_SZ},
+	// op_cmp
+	{1,2,M_BASIC,L_1+L_2+L_4,0xB000,A_SRC2|D_EA|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,    L_2+L_4,0xB000,A_AREG|D_EA|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,    L_2+L_4,0xB0C0,A_SRC|D_EA|D_SZ2,A_AREG|D_Q},
+/*	{1,2,M_BASIC,    L_2    ,0xB100,A_SRC2|D_EA|D_SZ,A_AREG|D_Q},
+	{1,2,M_BASIC,        L_4,0xB1C0,A_SRC2|D_EA|D_SZ,A_AREG|D_Q},*/
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0C00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xB108,A_MEM0|D_LOW|D_SZ,A_MEM0|D_Q},	// hum; other modes than A_AINC will generate an internal error (#8451/8452)
+	// op_link
+	{1,2,M_BASIC,L_2,0x4E50,A_AREG|D_LOW,A_IMM|D_RAW},
+	// op_unlk
+	{1,1,M_BASIC,L_2,0x4E58,A_AREG|D_LOW},
+	// op_pea
+	{1,1,M_BASIC,L_0,0x4840,A_MEM|A_PCR|D_EA},
+	// op_cmpi
+	{1,2,M_BASIC,L_1+L_2+L_4,0x0C00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA},
+	// op_dbra
+	{1,2,M_BRANCH,L_2,0x51C8,A_DREG|D_LOW},
+	// op_asr
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE000,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE020,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE0C0,A_MEM|D_EA},
+	// op_bset
+	{1,2,M_BASIC,L_0+L_1,0x08C0,A_IMM|D_RAW2,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x08C0,A_IMM|D_RAW2,A_DREG|D_EA},
+	{1,2,M_BASIC,L_0+L_1,0x01C0,A_DREG|D_Q,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x01C0,A_DREG|D_Q,A_DREG|D_EA},
+	// op_bclr
+	{1,2,M_BASIC,L_0+L_1,0x0880,A_IMM|D_RAW2,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x0880,A_IMM|D_RAW2,A_DREG|D_EA},
+	{1,2,M_BASIC,L_0+L_1,0x0180,A_DREG|D_Q,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x0180,A_DREG|D_Q,A_DREG|D_EA},
+	// op_bchg
+	{1,2,M_BASIC,L_0+L_1,0x0840,A_IMM|D_RAW2,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x0840,A_IMM|D_RAW2,A_DREG|D_EA},
+	{1,2,M_BASIC,L_0+L_1,0x0140,A_DREG|D_Q,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x0140,A_DREG|D_Q,A_DREG|D_EA},
+#ifdef ASM
+	/* ASM-only */
+	// op_asl
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE100,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE120,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE1C0,A_MEM|D_EA},
+	// op_rol
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE118,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE138,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE7C0,A_MEM|D_EA},
+	// op_ror
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE018,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE038,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE6C0,A_MEM|D_EA},
+	// op_roxl
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE110,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE130,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE5C0,A_MEM|D_EA},
+	// op_roxr
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE010,A_IMM|D_Q|D_SZ,A_DREG|D_EA},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xE030,A_DREG|D_Q|D_SZ,A_DREG|D_EA},
+	{1,1,M_BASIC,L_2,0xE4C0,A_MEM|D_EA},
+	// op_btst
+	{1,2,M_BASIC,L_0+L_1,0x0800,A_IMM|D_RAW2,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x0800,A_IMM|D_RAW2,A_DREG|D_EA},
+	{1,2,M_BASIC,L_0+L_1,0x0100,A_DREG|D_Q,A_MEM|D_EA},
+	{1,2,M_BASIC,L_0+L_4,0x0100,A_DREG|D_Q,A_DREG|D_EA},
+	// op_exg
+	{1,2,M_BASIC,L_0+L_4,0xC140,A_DREG|D_LOW,A_DREG|D_Q},
+	{1,2,M_BASIC,L_0+L_4,0xC148,A_AREG|D_LOW,A_AREG|D_Q},
+	{1,2,M_BASIC,L_0+L_4,0xC188,A_AREG|D_LOW,A_DREG|D_Q},
+	{1,2,M_BASIC,L_0+L_4,0xC188,A_DREG|D_Q,A_AREG|D_LOW},
+	// op_dc
+	{1,1,M_DC,0,-1},
+	// op_ds
+	{1,1,M_DC,0,0},
+	// op_dcb
+	{1,2,M_DC,0,1},
+	// op_bvs
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6900},
+	// op_bvc
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6800},
+	// op_bpl
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6A00},
+	// op_bmi
+	{1,1,M_BRANCH,L_0+L_1+L_2,0x6B00},
+	// op_trap
+	{1,1,M_BASIC,L_0,0x4E40,A_IMM|D_LOW},
+	// op_negx
+	{1,1,M_BASIC,L_1+L_2+L_4,0x4000,A_DST2|D_EA|D_SZ},
+	// op_addx
+	{1,2,M_BASIC,L_1+L_2+L_4,0xD100,A_DREG|D_LOW|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0xD108,A_ADEC|D_LOW|D_SZ,A_ADEC|D_Q},
+	// op_subx
+	{1,2,M_BASIC,L_1+L_2+L_4,0x9100,A_DREG|D_LOW|D_SZ,A_DREG|D_Q},
+	{1,2,M_BASIC,L_1+L_2+L_4,0x9108,A_ADEC|D_LOW|D_SZ,A_ADEC|D_Q},
+	// op_chk
+	{1,2,M_BASIC,L_2,0x4180,A_SRC2|D_EA,A_DREG|D_Q},
+	// op_even
+	{1,0,M_ALIGN,L_0,2},
+	// op_dbeq
+	{1,2,M_BRANCH,L_2,0x57C8,A_DREG|D_LOW},
+	// op_dbne
+	{1,2,M_BRANCH,L_2,0x56C8,A_DREG|D_LOW},
+#ifndef LIGHT_DBXX_AND_SXX
+	// op_dbhs
+	{1,2,M_BRANCH,L_2,0x54C8,A_DREG|D_LOW},
+	// op_dbge
+	{1,2,M_BRANCH,L_2,0x5CC8,A_DREG|D_LOW},
+	// op_dbhi
+	{1,2,M_BRANCH,L_2,0x52C8,A_DREG|D_LOW},
+	// op_dbgt
+	{1,2,M_BRANCH,L_2,0x5EC8,A_DREG|D_LOW},
+	// op_dbls
+	{1,2,M_BRANCH,L_2,0x53C8,A_DREG|D_LOW},
+	// op_dble
+	{1,2,M_BRANCH,L_2,0x5FC8,A_DREG|D_LOW},
+	// op_dblo
+	{1,2,M_BRANCH,L_2,0x55C8,A_DREG|D_LOW},
+	// op_dblt
+	{1,2,M_BRANCH,L_2,0x5DC8,A_DREG|D_LOW},
+	// op_dbvs
+	{1,2,M_BRANCH,L_2,0x59C8,A_DREG|D_LOW},
+	// op_dbvc
+	{1,2,M_BRANCH,L_2,0x58C8,A_DREG|D_LOW},
+	// op_dbpl
+	{1,2,M_BRANCH,L_2,0x5AC8,A_DREG|D_LOW},
+	// op_dbmi
+	{1,2,M_BRANCH,L_2,0x5BC8,A_DREG|D_LOW},
+	// op_st
+	{1,1,M_BASIC,L_1,0x50C0,A_DST2|D_EA},
+	// op_sf
+	{1,1,M_BASIC,L_1,0x51C0,A_DST2|D_EA},
+	// op_seq
+	{1,1,M_BASIC,L_1,0x57C0,A_DST2|D_EA},
+	// op_sne
+	{1,1,M_BASIC,L_1,0x56C0,A_DST2|D_EA},
+	// op_shs
+	{1,1,M_BASIC,L_1,0x54C0,A_DST2|D_EA},
+	// op_sge
+	{1,1,M_BASIC,L_1,0x5CC0,A_DST2|D_EA},
+	// op_shi
+	{1,1,M_BASIC,L_1,0x52C0,A_DST2|D_EA},
+	// op_sgt
+	{1,1,M_BASIC,L_1,0x5EC0,A_DST2|D_EA},
+	// op_sls
+	{1,1,M_BASIC,L_1,0x53C0,A_DST2|D_EA},
+	// op_sle
+	{1,1,M_BASIC,L_1,0x5FC0,A_DST2|D_EA},
+	// op_slo
+	{1,1,M_BASIC,L_1,0x55C0,A_DST2|D_EA},
+	// op_slt
+	{1,1,M_BASIC,L_1,0x5DC0,A_DST2|D_EA},
+	// op_svs
+	{1,1,M_BASIC,L_1,0x59C0,A_DST2|D_EA},
+	// op_svc
+	{1,1,M_BASIC,L_1,0x58C0,A_DST2|D_EA},
+	// op_spl
+	{1,1,M_BASIC,L_1,0x5AC0,A_DST2|D_EA},
+	// op_smi
+	{1,1,M_BASIC,L_1,0x5BC0,A_DST2|D_EA},
+	// op_tas
+	{1,1,M_BASIC,L_1,0x4AC0,A_DST2|D_EA},
+#endif
+#endif
+};
+
+void wrt4(long x) {
+	if (odd) fatal("ALIGN");
+	bin_chk(pos+=4);
+#ifdef PC
+	bin[pos-4]=(unsigned char)(x>>24);
+	bin[pos-3]=(unsigned char)(x>>16);
+	bin[pos-2]=(unsigned char)(x>>8);
+	bin[pos-1]=(unsigned char)(x);
+#else
+	*(long *)(bin+pos-4)=x;
+#endif
+#ifdef PC
+	if ((pos^odd)&1)
+		fatal("INT/ODD");
+#endif
+}
+void wrt2(short x) {
+	if (odd) fatal("ALIGN");
+	bin_chk(pos+=2);
+#ifdef PC
+	bin[pos-2]=(unsigned char)(x>>8);
+	bin[pos-1]=(unsigned char)(x);
+#else
+	*(short *)(bin+pos-2)=x;
+#endif
+#ifdef PC
+	if ((pos^odd)&1)
+		fatal("INT/ODD");
+#endif
+}
+void wrt1(char x) {
+	bin_chk(pos+=1);
+#ifdef PC
+	bin[pos-1]=(unsigned char)(x);
+#else
+	*(char *)(bin+pos-1)=x;
+#endif
+	odd=~odd;
+#ifdef PC
+	if ((pos^odd)&1)
+		fatal("INT/ODD");
+#endif
+}
+void fill(int n) {
+	if (odd) wrt1(0);
+	bin_chk(pos+=n);
+	memset(bin+pos-n,0,n);
+	odd = -(n&1);
+}
+void move_pos(long diff) {	/* caution : only works in overwrite mode */
+	odd^=-(diff&1);
+	pos+=diff;
+}
+void rewrite(long size) {
+	bin_chk(pos+=size);
+	memcpy(bin+(pos-size),bin+(pos-2*size),size);
+	odd^=-(size&1);
+#ifdef PC
+	if ((pos^odd)&1)
+		fatal("INT/ODD");
+#endif
+}
+
+readonly int sz_table[]={0,0,0,0,0,2,2,2,0,0,2,2,2,2,4,0,0,0};
+
+readonly struct enode zero={en_icon,0,0,{0},0,0};
+readonly struct amode am_null={am_direct,(struct enode *)&zero,0,0,0,0};
+#define ip_lab (((struct lbls *)ip)->lab)
+void pass1() {
+	struct ocode *ip=scope_head;
+	OPCODE *op;
+	unsigned int vpos=pos;
+	while (ip) {
+		int opt,sz,n,f;
+		struct amode *ap;
+		int c=opi[ip->opcode],nm=opi[ip->opcode+1]-c;
+		int orig_len=ip->length;
+		int argnum_ok=0;
+/*		if (ip->opcode==_op_adj) {
+			sz=0; opt=0; c=-1;
+			goto ok;
+		}*/
+		err_cur_line=ip->line;
+		if (!nm) {
+			if (ip->opcode!=op_label)
+				fatal("P1: UNIMPL");
+			{
+			if (!local(ip_lab) && lab_src(ip_lab)) {
+				char *name=unres_name(ip_lab);
+				while (ip && ip->opcode==op_label) ip=ip->fwd;
+				if (ip) err_cur_line=ip->line-1;
+				else err_assembly=0;
+				uerrc2("label '%s' redefined",name);
+			}
+			lab_set(ip_lab,vpos);
+			ip->opcode=0;
+			sz=0;
+			goto ok_lab;
+			}
+		}
+		nm--; do {
+			opt=0;
+			op=(OPCODE *)&ops[c];
+			if ((!(n=op->nargs) && ip->oper1) || (n==1 && (!ip->oper1 || ip->oper2))
+				|| (n==2 && !ip->oper2))
+				goto nxt;
+			argnum_ok++;
+			ip->length=orig_len;
+			switch (op->model) {
+			  case M_BASICSWAPPED:	/* caution : assumes that it is the sole M_BASICSWAPPED */
+				ap=ip->oper1;		/*      and that it is placed at the very end...        */
+				ip->oper1=ip->oper2;
+				ip->oper2=ap;
+				/* FALLTHROUGH */
+			  case M_BASIC:
+				if (!((f=op->lenf) & (1<<ip->length))) {
+					if (!ip->length) {
+						if (!(f & (1<<2))) {
+							if (!(f & (1<<4)))
+								ip->length=1;
+							else ip->length=4;
+						} else ip->length=2;
+					} else goto nxt;
+				}
+				sz=2;
+				ap=ip->oper1;
+				f=op->a1;
+				while (n--) {
+					int m=ap->mode;
+					if (!(f&
+						(m<am_indx2?
+							(m<am_ainc?
+								(m==am_dreg?A_DREG
+								:(m==am_areg?A_AREG
+								:A_MEM0)
+								)
+							:
+								(m==am_indx?
+								A_MEM0
+								:(ip->length?(m==am_ainc?A_MEM0:A_ADEC):0)
+								)
+							)
+						:
+							(m<am_mask1?
+								(m==am_immed?A_IMM:A_MEM0)
+								: (m<am_pcrel?(m==am_mask2?A_MASK2:A_MASK1)
+									:(m==am_pcrel?A_PCR:
+							(m<am_sr?A_MEM0:(m==am_sr?A_SR:(m==am_ccr?A_CCR:A_USP)))))
+							)
+						)
+					))
+						goto nxt;
+#ifdef TWIN_COMPILE
+					{int tclab,tcoff;
+					/*if (twinc_prev)
+						bkpt();*/
+#endif
+					if (m==am_direct) {
+						if ((f&A_PCR) && ((ap->offset->nodetype==en_labcon
+							|| ap->offset->nodetype==en_nacon) &&
+#ifndef LARGE_MODEL
+								global(ap->offset->v.enlab)
+#else
+								local(ap->offset->v.enlab)
+#endif
+#ifdef TWIN_COMPILE
+								&& (!twinc_prev ||
+									((tclab=twinc_prev[0],tcoff=twinc_prev[1],
+									twinc_prev+=2,
+									tclab!=ap->offset->v.enlab||abs(tcoff-vpos)>=5000)
+									&& (twinc_prev-=2,1)))
+#endif
+									)) {
+							/*if (ap->offset->v.enlab==0xFFFF8032)
+								bkpt();*/
+							m=am_pcrel;
+						} else {
+							get_offs(ap->offset,0);
+							if (is_long)
+								m=am_dirl;
+							else m=am_dirw;
+						}
+						ap = *(ap==ip->oper1 ? &ip->oper1 : &ip->oper2) = copy_addr(ap);
+							/* this is because the same operand might be either pcrel or
+							  dirl, depending on the instruction/place of the operand */
+						ap->mode=m;
+					}
+#ifdef TWIN_COMPILE
+					}
+#endif
+					if (f&D_RAW2)
+						sz+=2;
+					else if ((f&D_RAW) && m==am_immed)
+						sz+=(ip->length+1)&-2;
+					else if (!(f&(D_Q|D_LOW)))
+						sz+=(m==am_immed?(ip->length+1)&-2:sz_table[m]);
+					ap=ip->oper2;
+					f=op->a2;
+				}
+				break;
+			  case M_BRANCH:
+				if (n==1) {	// Bcc
+					if (ip->oper1->offset->nodetype!=en_labcon
+						&& ip->oper1->offset->nodetype!=en_nacon)
+//						fatal("BRANCH");
+						uerrc("invalid branch");
+					n=ip->oper1->offset->v.enlab;
+					if (!global(n))
+//						fatal("XT BRANCH");
+						uerrc("invalid branch");
+					if (ip->length==2) opt=0,sz=4;
+					else {
+						if ((f=lab_src(n))) {
+							f-=vpos;
+							opt=(f>129 || f<-126);	// all branches are backwards so we needn't
+													//  handle branches to next stmt in this pass
+						} else opt=1;
+						sz=2+(opt<<1);
+					}
+				} else {	// DBcc
+					if ((ip->oper2->offset->nodetype!=en_labcon
+						&& ip->oper2->offset->nodetype!=en_nacon)
+						|| (ip->oper1->mode!=am_dreg))
+//						fatal("DBRANCH");
+						uerrc("invalid branch");
+					n=ip->oper2->offset->v.enlab;
+					if (!global(n))
+//						fatal("XT BRANCH");
+						uerrc("invalid branch");
+					sz=4;
+				}
+				break;
+#ifdef ASM
+			  case M_DC:
+				f=ip->length-2;
+				if (f<=0) f++;	// f=log_2(ip->length)
+				if (ip->oper1->mode!=am_direct)
+//					fatal("DC");
+					uerrc("invalid declaration");
+				sz=1;
+				if (((short)op->bo)>=0) {
+					if (ip->oper1->offset->nodetype!=en_icon)
+						uerrc("invalid declaration");
+					sz=ip->oper1->offset->v.i;
+					if (op->bo && ip->oper2->mode!=am_direct)
+						uerrc("invalid declaration");
+				}
+				sz<<=f;
+				if (sz>=128)
+					uerrsys("too many elements in 'dc' instruction; use C arrays");
+				break;
+			  case M_ALIGN:
+				sz=0;
+				if (vpos&1) {
+					sz=1;
+					c=oi_dc;
+					ip->length=1;
+					ip->oper1=(struct amode *)&am_null;
+				}
+				break;
+			  default:
+				fatal("P1");
+				sz=0;
+				break;
+#endif
+			}
+			goto ok;
+		nxt:
+			c++;
+		} while (nm--);
+		if (!argnum_ok)
+			uerrc2("instruction requires %d arguments",n);
+		uerrc("invalid address modes");
+		return;
+//		fatal("P1: INVALID");
+	ok:
+#ifdef SIZE_STATS
+		if (!ip->opt)	/* not from an asm() statement */
+			c_compiler_sz+=sz;	/* note this is approximative, but close to reality */
+#endif
+		ip->opt=opt;
+		ip->sz=sz;
+		ip->opcode=c;
+	ok_lab:
+		ip=ip->fwd;
+		vpos+=sz;
+	}
+}
+
+void pass2() {
+	struct ocode *ip=scope_head;
+	unsigned int vpos=pos,opos=vpos,s;
+	OPCODE *op;
+	while (ip) {
+		if (ip->opcode>0) {
+			s=ip->sz;
+			if (ip->opt) {
+				op=(OPCODE *)&ops[ip->opcode];
+				switch (op->model) {
+				  case M_BASIC: case M_BASICSWAPPED:
+					break;
+				  case M_BRANCH: {	// this is necessarily a Bcc since ip->opt==1
+					int n=ip->oper1->offset->v.enlab;
+					long f=qlab_src(n);
+					if (!f) break;	// global label not found
+					if ((unsigned int)f>opos) // we HAVE TO compare with opos (since opos>=vpos)
+						f-=opos+2;	// <- here, f is afterwards, so relative to old pos
+					else f-=vpos+2;
+					/* the case of the next stmt branch :
+					 * PASS 1 : the label is unknown, so opt=1 and ip->sz=4
+					 * PASS 2 : qlab_src(n)-opos==4, so here, f==2 (rather than f==0) */
+					if (f!=2 && f>=-128 && f<=127)
+						ip->sz=2;
+					else if (f>=-32768 && f<=32767)
+						ip->sz=4;
+					else err_cur_line=ip->line, uerrc("branch size can't fit in a word");
+				   } break;
+				}
+			}
+			opos+=s, vpos+=ip->sz;
+		} else if (!ip->opcode)	{// op_label
+/*			if (vpos==0x2642)
+				printf("rjo");*/
+			lab_set(ip_lab,vpos);
+		}
+/*		else {	// _op_adj
+			
+		}*/
+		ip=ip->fwd;
+	}
+}
+
+int movem(short x) {
+	int n=0;
+	while (x) {
+		if (x<0) n++;
+		x+=x;
+	}
+	return n;
+}
+
+void pass3() {
+	struct ocode *ip=scope_head;
+#ifdef PC
+	unsigned int opos=pos;
+#endif
+	OPCODE *op;
+	while (ip) {
+		int n,f;
+		struct amode *ap;
+		short code;
+		if (ip->opcode>0) {
+			err_cur_line=ip->line;
+			op=(OPCODE *)&ops[ip->opcode];
+			n=op->nargs;
+			switch (op->model) {
+			  case M_BASIC: case M_BASICSWAPPED: {
+				int ds=0,ds2=0; int len=ip->length;
+#ifdef PC
+				long dc=0xdddddddd,dc2=0xdddddddd;
+#else
+				long dc=dc,dc2=dc2;
+#endif
+				unsigned int vpos=pos+2;
+				code=op->bo;
+				ap=ip->oper1;
+				f=op->a1;
+#ifndef USE_LINK
+				if (n)
+					if (ap->preg==STACKPTR-8) {
+						if (ap->mode==am_ainc) {	// for <op> (a7)+,...
+							lc_stk-=len+(len&1);
+						} else if (ap->mode==am_adec)
+							lc_stk+=len+(len&1);			// for clr  -(a7)
+					}
+#endif
+				while (n--) {
+					if ((f&D_SZ3)==D_SZ3) {
+						if (len==4) code|=0x40;
+					} else if (f&D_SZ)
+						code|=(len==2?0x40:(len==4?0x80:0x00));
+					else if ((f&D_SZ2) && len==4)
+						code|=0x100;
+					if (f&D_EA)
+						switch (ap->mode) {
+						  case am_areg:
+						  case am_ind:
+						  case am_ainc:
+						  case am_adec:
+							code+=ap->mode<<3;
+						  case am_dreg:
+							code+=ap->preg;
+							break;
+						  case am_indx:
+#ifndef USE_LINK
+							if (ap->preg==FRAMEPTR-8) {
+								if (uses_link)
+									ap->preg+=TRUE_FRAMEPTR-FRAMEPTR;
+								else {
+									ap->preg+=STACKPTR-FRAMEPTR;
+									ap->offset->v.i += lc_stk - (ap->offset->v.i>0 ? 4 : 0);
+									uses_lc_stk = 1;
+								}
+							}
+#endif
+							code+=0x28+ap->preg;
+							ds=1; dc=get_word(ap->offset,vpos,1);
+							break;
+						  case am_pcrel:
+							code+=0x3A;
+							ds=1; dc=get_pcword(ap->offset,vpos); // rel to vpos, not pos!
+							break;
+						  case am_dirw:
+							code+=0x38;
+							ds=1; dc=get_word(ap->offset,vpos,1);
+							break;
+						  case am_dirl:
+							code+=0x39;
+							ds=2; dc=get_long(ap->offset,vpos);
+							break;
+						  case am_immed:
+							code+=0x3C;
+							ds=(1+len)>>1;
+							if (ds==1) dc=get_word(ap->offset,vpos,0);
+							else dc=get_long(ap->offset,vpos);
+							break;
+						  case am_indx2:
+							code+=0x30+ap->preg;
+							ds=1;
+							dc=get_byte(ap->offset)+((short)ap->sreg<<12)+
+								(ap->slen==4?0x0800:0x0000);
+							break;
+						  case am_indx3:
+							code+=0x30+ap->preg;
+							ds=1;
+							dc=get_byte(ap->offset)+((short)ap->sreg<<12)+
+								(ap->slen==4?0x8800:0x8000);
+							break;
+#ifdef PC
+						  default:
+							ierr(PASS3,1);
+#endif
+						}
+					else if (f&D_EA2)
+						switch (ap->mode) {
+						  case am_areg:
+						  case am_ind:
+						  case am_ainc:
+						  case am_adec:
+							code+=ap->mode<<6;
+						  case am_dreg:
+							code+=((short)ap->preg)<<9;
+							break;
+						  case am_indx:
+#ifndef USE_LINK
+							if (ap->preg==FRAMEPTR-8) {
+								if (uses_link)
+									ap->preg+=TRUE_FRAMEPTR-FRAMEPTR;
+								else {
+									ap->preg+=STACKPTR-FRAMEPTR;
+									ap->offset->v.i += lc_stk - (ap->offset->v.i>0 ? 4 : 0);
+									uses_lc_stk = 1;
+								}
+							}
+#endif
+							code+=(0x28<<3)+((short)ap->preg<<9);
+							ds=1; dc=get_word(ap->offset,vpos,1);
+							break;
+/*						  case am_pcrel:
+							code+=(0x38<<3)+(0x02<<9);
+							ds=1; dc=get_pcword(ap->offset,vpos); // rel to vpos, not pos!
+							break;*/
+						  case am_dirw:
+							code+=0x38<<3;
+							ds=1; dc=get_word(ap->offset,vpos,1);
+							break;
+						  case am_dirl:
+							code+=(0x38<<3)+(0x01<<9);
+							ds=2; dc=get_long(ap->offset,vpos);
+							break;
+						  case am_indx2:
+							code+=(0x30<<3)+(ap->preg<<9);
+							ds=1;
+							dc=get_byte(ap->offset)+((short)ap->sreg<<12)+
+								(ap->slen==4?0x0800:0x0000);
+							break;
+						  case am_indx3:
+							code+=(0x30<<3)+(ap->preg<<9);
+							ds=1;
+							dc=get_byte(ap->offset)+((short)ap->sreg<<12)+
+								(ap->slen==4?0x8800:0x8000);
+							break;
+#ifdef PC
+						  default:
+							ierr(PASS3,2);
+#endif
+						}
+					else if (f&D_Q)
+						switch (ap->mode) {
+						  case am_areg:
+						  case am_dreg:
+						  case am_ainc:
+						  case am_adec:
+							code+=((unsigned short)ap->preg)<<9;
+							break;
+						  case am_immed:
+							code+=get_quick(ap->offset)<<9;
+							break;
+#ifdef PC
+						  default:
+							ierr(PASS3,3);
+#endif
+						}
+					else if (f&D_LOW)
+						switch (ap->mode) {
+						  case am_areg:
+						  case am_dreg:
+						  case am_adec:
+						  case am_ainc:
+							code+=ap->preg;
+							break;
+						  case am_immed:
+							code+=get_byte(ap->offset);
+							break;
+#ifdef PC
+						  default:
+							ierr(PASS3,4);
+#endif
+						}
+					else if (f&D_RAW)
+						switch (ap->mode) {
+						  case am_immed:
+							if (len==4)
+								ds=2,dc=get_long(ap->offset,vpos);
+							else
+								ds=1,dc=get_word(ap->offset,vpos,0);
+							break;
+						  case am_mask1:
+						  case am_mask2:
+							ds=1; dc=ap->offset->v.i;
+							break;
+#ifdef PC
+						  default:
+							ierr(PASS3,5);
+#endif
+						}
+					else if (f&D_RAW2)
+						ds=1,dc=get_word(ap->offset,vpos,0);
+					ap=ip->oper2;
+					f=op->a2;
+					vpos+=ds<<1;
+					if (n) {
+						ds2=ds,dc2=dc,ds=0;
+#ifndef USE_LINK
+						if (ap->preg==STACKPTR-8) {
+							if (ap->mode==am_adec) {	// for <op> ...,-(a7)
+								if (ip->oper1->mode==am_mask1)
+									lc_stk+=movem((short)ip->oper1->offset->v.i)<<(len>>1);
+								else lc_stk+=len+(len&1);
+							}
+							else if (ap->mode==am_ainc && ip->oper1->mode==am_mask2)
+								lc_stk-=movem((short)ip->oper1->offset->v.i)<<(len>>1);
+						}
+#endif
+					}
+				}
+#ifndef USE_LINK
+				if (code==0x4FEF				// lea x(a7),a7
+					|| (code&0xF13F)==0x500F	// addq.* #x,a7
+					|| (code&0xFEFF)==0xDEFC)	// add.* #x,a7
+					lc_stk-=ip->oper1->offset->v.i;
+				else if ((code&0xF13F)==0x510F	// subq.* #x,a7
+					|| (code&0xFEFF)==0x9EFC)	// sub.* #x,a7
+					lc_stk+=ip->oper1->offset->v.i;
+				else if (((code&0xFFC0)==0x4840 && (code&0x0038/*!swap*/)))	// pea <ea>
+					lc_stk+=4;
+#endif
+				wrt2(code);
+				if (--ds2>=0) {
+					if (!ds2) wrt2((short)dc2);
+					else wrt4(dc2);
+				}
+				if (--ds>=0) {
+					if (!ds) wrt2((short)dc);
+					else wrt4(dc);
+				}
+			   } break;
+			  case M_BRANCH: {
+				unsigned int vpos=pos+2;
+				code=op->bo;
+				if (ip->oper2)	// DBcc
+					n=ip->oper2->offset->v.enlab, code+=ip->oper1->preg;
+				else n=ip->oper1->offset->v.enlab;	// Bcc
+				if ((f=qlab_src(n))) {
+					if (ip->sz==2)
+						wrt2(code|=(f-vpos)&0xFF);
+					else
+						wrt2(code),wrt2((short)(f-vpos));
+				} else
+					wrt2(code),wrt2((short)-(short)vpos),lab_add_ref(n,vpos);
+			   } break;
+			  case M_DC: {
+				struct enode *ep=ip->oper1->offset;
+				n=1;
+				if (((short)op->bo)>=0) {
+					n=ip->oper1->offset->v.i;
+					if (op->bo)
+						ep=ip->oper2->offset;
+					else ep=(struct enode *)&zero;
+				}
+				f=ip->length-2;
+				while (n--) {
+					if (f<0) {
+						GV v;
+						get_value(ep,&v,0,0);
+						if (v.tr)
+							uerr(ERRA_INVALIDREL);
+						if (v.i>255 || v.i<-128)
+							uerrc("result can't fit in a byte");
+						wrt1((char)v.i);
+					} else if (!f) wrt2(get_word(ep,pos,0));
+					else wrt4(get_long(ep,pos));
+				}
+			   } break;
+			}
+#ifdef PC
+			opos+=ip->sz;
+			if (pos!=opos) {
+//				printf("%d",oi_ds);
+				ierr(PASS3,6);
+			}
+#endif
+		}
+/*		else if (ip->opcode) {	// _op_adj
+			
+		}*/
+		else if (!ip->opcode) {	// op_label
+//#ifdef PC
+//			if (pos!=qlab_src(ip_lab))
+//				 ierr(PASS3,7);
+//#endif
+			if (pos!=qlab_src(ip_lab))
+				uerrc2("label '%s' defined twice",unres_name(ip_lab));
+			if (!local(ip_lab)) {
+				lab_set(ip_lab,0);	// 'unset' it so there will be no error...
+				set_label(ip_lab,pos);
+			}
+		}
+		ip=ip->fwd;
+	}
+}
+
+void scope_flush(void) {
+	err_assembly=1;
+	pass1();
+	pass2();
+	pass3();
+	err_assembly=0;
+	if (uses_lc_stk && lc_stk) {
+		uwarn("stack displacement of %d: compiler bug?",(int)lc_stk);
+		iwarn(WARN_LC_STK,1);
+	}
+	scope_head = 0;
+	loc_tab = 0;
+}
+
+void scope_init(void) {
+	if (scope_head) scope_flush();
+	lc_stk = 0;
+	uses_lc_stk = 0;
+	nextlabel = 1;
+	loc_tab = 0;
+}
+
+void local_clean(void) {	/* remove local symbols from alsyms -- to be called just before rel_local */
+	HTABLE *tab=&alsyms;
+	SYM *ttail,**prv;
+	struct htab *root;
+	int i;
+	if (!tab->hash)
+		ierr(TABLE_HASH,2);
+#ifdef PC
+	if (tab->hash!=0x2489)
+		ierr(TABLE_HASH,1);
+#endif
+	i=N_HASH;
+	while (i--) {
+		prv=&((root=&tab->h[i])->tail);
+		while ((ttail=*prv)) {
+			if (local(ttail->value.splab)) {
+//				*prv = ttail->prev;
+				if (ttail->next) ttail->next->prev = ttail->prev;
+				if (ttail->prev) ttail->prev->next = ttail->next;
+//				ttail->next = prv;
+				if (root->tail==ttail) root->tail=ttail->prev;
+				if (root->head==ttail) root->head=ttail->next;
+/*				if (!root->tail)
+					root->head=0;*/
+			}
+			prv = &(ttail->prev);
+		}
+	}
+}
+
+int label(char *s) {
+	int lab; SYM *sp;
+/*	if (!strcmp(s,"__L_plane") || !strcmp(s,"__D_plane"))
+		bkpt();*/
+	if (!(sp=search(s,-1,&alsyms))) {
+		if (s[0]!='\\')
+			global_flag++;
+		sp=(SYM *)xalloc((int)sizeof(SYM),_SYM);
+		sp->name=strsave(s);
+		if (s[0]=='\\')
+			lab_src(sp->value.splab=lab=nxtlabel());
+		else if (internal(s))
+			lab_src(sp->value.splab=lab=nxtglabel());
+		else
+			sp->value.splab=lab=extlabel--;
+		insert(sp,&alsyms);
+		if (s[0]!='\\')
+			global_flag--;
+	} else
+		lab=sp->value.splab;
+	debugf("label(%s)=%x\n",s,lab);
+#ifdef PC
+/*	if (lab==0x806d)
+		bkpt();*/
+	if (!*s)
+		return lab;
+#endif
+	return lab;
+}
+
+void set_label(int lab,unsigned int pos) {
+	/*if ((unsigned short)lab==0x8014)
+		bkpt();*/
+	debugf("set_lab(%x,%x)\n",lab,pos);
+	if (lab_src(lab)) uerrc("label redefinition");
+	if (global(lab)) {
+		lab_set(lab,pos);
+		if (!local(lab)) {
+			REF **rp,*r;
+			unsigned int p,*a; int n;
+			r=*(rp=glb_ref(lab));
+			while (r) {
+				a=r->r;
+				n=N_REF;
+				while (n--) {
+					if (!(p=*a++))
+						goto ref_done;
+#ifdef PC
+					{ int m=p&1; short a,olda;
+					p-=m;
+					a=(bin[p]<<8)+bin[p+1],olda=a;
+					if (m) {
+						if ((a-=pos)>0 && olda) fatal("PC RANGE 3");
+					} else if ((a+=pos)<0 && olda) fatal("PC RANGE 2");
+					bin[p]=(unsigned char)(a>>8);
+					bin[p+1]=(unsigned char)(a);
+					}
+#else
+					if (p&1) {
+						short *z=(short *)(bin+(p&-2));
+						if (*z && ((*z)-=pos)>0)
+							fatal("PC RANGE 3");
+						else (*z)-=pos;
+					} else if ((*(short *)(bin+p)+=pos)<0 && *(short *)(bin+p)!=pos)
+						fatal("PC RANGE 2");
+#endif
+				}
+				r=r->nxt;
+			}
+		  ref_done:
+			*rp=0;
+		}
+	}
+	else debugf(" --local\n");
+}
+
+void put_label(int lab) {
+/*
+ * output a compiler generated label.
+ */
+#ifdef NO_OUT
+	return;
+#endif
+	set_label(lab,pos);
+}
+
+void g_strlab(char *s) {
+/*
+ * generate a named label.
+ */
+#ifdef NO_OUT
+	return;
+#endif
+	put_label(label(s));
+}
+
+void genbyte(int val) {
+#ifdef NO_OUT
+	return;
+#endif
+	wrt1((char)val);
+}
+
+void genword(int val) {
+#ifdef NO_OUT
+	return;
+#endif
+	put_align2();
+	wrt2((short)val);
+}
+
+typedef struct _pc_bcd_s {
+	short exponent;
+	unsigned char mantissa[8];
+} _pc_bcd;
+#ifndef NOFLOAT
+void genfloat(double val) {
+#ifndef BCDFLT
+	put_align2();
+	wrt4(double2ffp(val));
+#else
+	BCD bcd;
+	double2bcd(val,&bcd);
+	wrt2(bcd.exponent);
+#ifdef PC
+	{
+		int i;
+		for (i=0;i<BCDLEN;i++)
+			wrt1(bcd.mantissa[i]);
+	}
+#else
+	wrt4(((long *)bcd.mantissa)[0]);
+	wrt4(((long *)bcd.mantissa)[1]);
+#endif
+#endif
+}
+
+#ifdef DOUBLE
+void gendouble(double val) {
+	genfloat(val);
+}
+#endif
+#endif
+
+void genptr(struct enode *node) {
+#ifdef NO_OUT
+	return;
+#endif
+	put_align2();
+	wrt4(get_long(node,pos));
+}
+
+#ifdef PC
+extern int forbid_bss;
+#endif
+void genstorage(struct sym *sp, int align) {
+	long size = sp->tp->size;
+#ifdef NO_OUT
+	return;
+#endif
+#ifdef PC
+#define no_bss (nostub_mode || forbid_bss)
+#else
+#define no_bss nostub_mode
+#endif
+	if (align!=1) put_align2();
+	size=(size+1)&-2;	// round size
+	if (sp->value.splab) {
+		if (no_bss) {	/* that's OK in _nostub mode :) */
+			if (lab_src(sp->value.splab))
+				return;
+		} else
+			uerrc2("BSS redeclaration of '%s' : use 'extern' for prototyping",sp->name);
+	} else if (no_bss) {
+			if (sp->storage_class==sc_static)
+				sp->value.splab=nxtglabel();
+			else
+				sp->value.splab=label(sp->name);
+		}
+	if (no_bss) {
+		put_label(sp->value.splab);
+		fill(size);
+	} else {
+		*(long *)xt_find(sp->value.splab=extlabel--)=lc_bss|0x80000000;	// DIRTY, but no hidden
+		lc_bss+=size;													//  bug possible
+	}																	//  (cf xalloc)
+#if 0
+	remain = size % AL_DEFAULT;
+	if (remain != 0)
+		size = size + AL_DEFAULT - remain;
+	if (sp->storage_class == sc_static) {
+		fprintf(output, "L%ld:" tabs "ds.b %ld\n", sp->value.i, size);
+		lc_bss += sp->tp->size;
+	 } else
+		fprintf(output, "L%d:" tabs "ds.b %ld\n", label(sp->name),size);
+#endif
+#undef no_bss
+}
+
+void dumplits() {
+/*
+ * dump the string literal pool.
+ */
+	char		   *cp;
+	int 			len;
+/*
+ * The ACK assembler may produce a .text section of an uneven length.
+ * This will eventually bomb the linker when it tries to relocate
+ * something in a following (.data) section, which then is misaligned
+ * as a whole in memory (perhaps this is just a bug in the linker).
+ *
+ * To avoid this (it can only happen if the string pool is the last
+ * thing dumped to the assembler file) we count the total number of
+ * bytes in the string pool and emit a zero filler byte if that
+ * number was uneven.
+ * This is perhaps an ugly hack, but in virtually all of the cases
+ * this filler byte is inserted anyway by the assembler when
+ * doing the alignment necessary for the next function body.
+ */
+//	long			count=0;
+
+	while (strtab != 0) {
+		cseg();
+		nl();
+		put_label((unsigned int) strtab->label);
+		cp = strtab->str;
+		len = strtab->len;
+		//count += (len+1);
+		while (len--)
+			wrt1(*cp++);
+		wrt1(0);
+		strtab = strtab->next;
+	}
+	put_align2();
+}
+
+
+void put_align2(void) {
+/* align the following data to 2 */
+	if (odd) wrt1(0);
+}
+/*put_align(align)
+	int 			align;
+// align the following data
+{
+	switch (align) {
+	  case 1:
+		break;
+	  case 2:
+		if (odd) wrt1(0);
+	}
+}*/
+
+#ifdef LISTING
+void put_external(char *s) {
+/* put the definition of an external name in the ouput file */
+
+}
+void put_global(char *s) {
+/* put the definition of a global name in the output file */
+
+}
+#endif
+
+/*cseg()
+{
+	if (curseg != codeseg) {
+		nl();
+#ifdef PC
+		fputs(tabs ".text\n", output);
+#endif
+		curseg = codeseg;
+	}
+}*/
+/*dseg()
+{
+	if (curseg != dataseg) {
+		nl();
+#ifdef PC
+		fputs(tabs ".data\n", output);
+#endif
+		curseg = dataseg;
+	}
+}*/
+
+int radix16(char c) {
+	if (isdigit(c))
+		return c - '0';
+/*	if (c >= 'a' && c <= 'z')
+		return c - 'a' + 10;*/
+	if (c >= 'A' && c <= 'Z')
+		return c - 'A' + 10;
+	return -1;
+}
+int hexatoi(char *s) {
+	int x=0;
+	if (strlen(s)>3) return -1;
+	while (*s) {
+		int y=radix16(*s++);
+		if (y<0) return -1;
+		x<<=4; x+=y;
+	}
+	return x;
+}
+
+int internal(char *s) {
+	int n=0;
+	char c,old=0,*p;
+	if (*s == '.')
+		return 1;
+	p=s;
+	while ((c=*p++)) {
+		if (n==10) {
+			if (((
+#ifdef FLINE_RC
+				!fline_rc && 
+#endif
+					!strncmp(s,"_ROM_CALL_",10)))
+#ifdef RAM_CALLS
+				|| !strncmp(s,"_RAM_CALL_",10)
+#endif
+				) {
+				int f=hexatoi(p-1);
+				if (f<0)
+					goto cont;
+				*xt_find(extlabel)=&(func_search(
+#ifdef RAM_CALLS
+					s[2]=='O' ? &rom_funcs : &ram_funcs
+#else
+					&rom_funcs
+#endif
+					,f))->rt;
+				return 0;
+			}
+		}
+		if (n==export_pfx_len) {
+			if (!strncmp(s,export_pfx,n)) {
+				int f=hexatoi(p);
+				if (f<0)
+					goto cont3;
+				*exp_find(f)=glblabel;
+				return 1;
+			}
+		}
+		if (c=='_' && n && old=='_' && *p=='0') {
+			SYM *sp;
+			int f=hexatoi(p+1);
+			if (f<0)
+				goto cont2;
+			p[-2]=0;
+			if (!(sp=search(s,-1,(HTABLE *)&libsyms))) {
+				global_flag++;
+				sp=(SYM *)xalloc((int)sizeof(SYM),_SYM);
+				sp->name=strsave(s);
+				insert(sp,(HTABLE *)&libsyms);
+				global_flag--;
+			}
+			*xt_find(extlabel)=&(func_search((FUNC **)&sp->value.i,f))->rt;
+			p[-2]='_';
+			return 0;
+		}
+	cont:
+	cont2:
+	cont3:
+		old=c; n++;
+	}
+	return 1;
+}
+
+#ifdef PCH
+unsigned char *_end_of(short *p) {	/* works endian-independently */
+	while (*p++);
+	return (unsigned char *)p;
+}
+unsigned char *_end_of2(short *p) {	/* works endian-independently */
+	while (*p++ || *p);
+	return (unsigned char *)(p+1);
+}
+#define end_of(p) _end_of((short *)(p))
+#define end_of2(p) _end_of2((short *)(p))
+
+
+#ifndef isidch
+#ifdef PC
+static int isidch(char c) {
+	return (c>='0'&&c<='9') || (c>='A'&&c<='Z') || (c>='a'&&c<='z')
+		|| c == '_' || c == '$';
+}
+#else
+#define isidch(___c) ({register short __c=(___c); \
+(__c>='0'&&__c<='9') || (__c>='A'&&__c<='Z') || (__c>='a'&&__c<='z') || __c=='_' || __c=='$';})
+#endif
+#endif
+
+int pchsearch(char *id,int mode);
+#define lscan(x) pchsearch(x,PCHS_ADD)
+#define lexpand(x) (x)
+/*#define lscan (void)lexpand
+void macro_expansion(char *in,char *inbound);
+char lexp_buf[100];
+char *lexpand(char *s) {
+	char c,*p=lexp_buf;
+	strcpy(p,s);
+	macro_expansion(p,&lexp_buf[100]);
+	if (*p>='0' && *p<='9')
+		return s;
+	while ((c=*p++))
+		if (!isidch(c)) return s;
+	return lexp_buf;
+}*/
+
+#ifdef PC
+#define g16(p) (p+=2,(p[-2]<<8)+p[-1])
+#define r16(o) ((ext[o]<<8)+ext[o+1])
+#define align(strp) if ((strp-ext)&1) strp++
+#else
+#define g16(p) (*((int *)p)++)
+#define r16(o) (*(int *)(ext+o))
+#define align(strp) if (((short)((long)strp))&1) strp++
+#endif
+void extscan(unsigned char *ext) {
+	int codeOff=r16(0);
+	unsigned char *offp=ext+codeOff,*strp;
+	/* reloc table */
+	offp=end_of(offp);
+	/* export table */
+	strp=end_of(offp);
+	while (g16(offp))
+		while (*strp++);
+	align(strp);
+	/* import table */
+	offp=strp; strp=end_of2(offp);
+	while (*(short *)offp) {
+		lscan(strp);
+		offp=end_of(offp);
+		while (*strp++);
+	}
+}
+
+#undef off		// for TI-GCC :D
+#ifdef PC
+#define add_offs(val,offs) do { \
+				short a=bin[offs+0]<<8; \
+				a+=bin[offs+1]; \
+				a+=val; \
+				bin[offs+0]=(unsigned char)(a>>8); \
+				bin[offs+1]=(unsigned char)(a); \
+			} while (0)
+#else
+#define add_offs(val,offs) (*(short *)(bin+offs)+=val)
+#endif
+
+void extload(unsigned char *ext) {
+	int codeOff=r16(0); unsigned int wriOff;
+	SYM *sp;
+	if (odd) wrt1(0);
+/*#ifdef PC
+	if (codeOff>=0x2000)
+		printf("gfio");
+#endif*/
+	/* In the following case, either the .ext has already been loaded, either
+	 * there is a conflict, in which case the error will arise at the end
+	 * (what's more, it allows for overriding of the default functions) */
+	sp=search(end_of(end_of(ext+codeOff)),-1,&alsyms);
+	if (sp && lab_src(sp->value.splab))
+		return;
+	wriOff=pos-2;			/* since offsets are based on ext::$00, not on ext::$02=code */
+	bin_chk(pos+=codeOff-2);
+	memcpy(bin+pos-codeOff+2,ext+2,codeOff-2);
+  {
+	/* reloc table */
+	unsigned short off; unsigned char *offp=ext+codeOff;
+	while ((off=g16(offp))) {
+		rt_add_ref(&reloc_tab,off+wriOff);
+		add_offs(wriOff+2,off+wriOff+2);
+	}
+   {
+	/* export table */
+	unsigned char *strp=end_of(offp);
+	while ((off=g16(offp))) {
+		set_label(label(strp),off+wriOff);
+		while (*strp++);
+	}
+	align(strp);
+	/* import table */
+	offp=strp; strp=end_of2(offp);
+	while (*(short *)offp) {
+		int n=label(lexpand(strp)); unsigned int p=lab_src(n);
+		while ((off=g16(offp))) {
+			off+=wriOff;
+			if (p) {
+#ifdef PC
+				unsigned short a=bin[off+2]<<8;
+				a+=bin[off+3];
+				a+=p;
+				bin[off+2]=(unsigned char)(a>>8);
+				bin[off+3]=(unsigned char)(a);
+#else
+				*(short *)(bin+off+2)+=p;
+#endif
+	/*			if (ip->sz==2)
+					wrt2(code|=(f-vpos)&0xFF);
+				else wrt2(code),wrt2((short)(f-vpos));*/
+			} else
+				lab_add_ref(n,off+2);
+			rt_add_ref(&reloc_tab,off);
+		}
+		while (*strp++);
+	}
+   }
+  }
+}
+#endif
+
+#endif /* MC680X0 */
+// vim:ts=4:sw=4

+ 71 - 0
gtc/src/out68k_exe.h

@@ -0,0 +1,71 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * EXE loader
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define exeloadersize_bss (-1)
+readonly unsigned char exeloader_bss[1];
+#define exeloadersize_nobss sizeof(exeloader_nobss)
+readonly unsigned char exeloader_nobss[]={
+    0x4f,0xef,0x00,0x30,0x4e,0x75,0x20,0x78,0x00,0xc8,0x0c,0xa0,0x54,0x8f,0x4e,0x75,
+    0x66,0xf8,0x42,0x67,0x2f,0x08,0x48,0xe7,0x1f,0x3e,0x47,0xf9,0x00,0x00,0x00,0x00,
+    0x7a,0xf2,0xda,0x8b,0x24,0x78,0x00,0xc8,0x76,0x00,0x36,0x2b,0x00,0x0c,0x2f,0x13,
+    0x20,0x6a,0x02,0x48,0x4e,0x90,0x58,0x8f,0x3f,0x00,0x67,0xc4,0x20,0x6a,0x02,0x58,
+    0x4e,0x90,0x3e,0x1f,0x28,0x48,0x22,0x4c,0xd3,0xd3,0x93,0xc3,0x2c,0x09,0x41,0xeb,
+    0x00,0x08,0x4e,0xba,0x01,0x2c,0x20,0x46,0x22,0x4c,0x70,0x00,0x30,0x23,0x47,0xf3,
+    0x08,0x0a,0x61,0x00,0x00,0x9e,0x3f,0x47,0x00,0x2c,0x48,0x54,0x3f,0x3c,0x00,0x0a,
+    0x42,0xa7,0x20,0x6a,0x01,0xb0,0x4e,0x90,0x5c,0x8f,0x26,0x08,0x78,0x00,0x08,0x28,
+    0x00,0x02,0x00,0x0a,0x67,0x10,0x3f,0x28,0x00,0x0c,0x20,0x6a,0x02,0x58,0x4e,0x90,
+    0x54,0x8f,0xba,0x88,0x67,0x0a,0x20,0x6a,0x01,0xb4,0x4e,0x90,0x26,0x08,0x66,0xde,
+    0x48,0xe7,0x1f,0x3e,0x48,0x7a,0x00,0x52,0x20,0x78,0x00,0xc8,0x0c,0xa0,0x00,0x00,
+    0x03,0xe8,0x65,0x48,0x26,0x6f,0x00,0x2c,0x20,0x08,0xe1,0x98,0x6b,0x12,0x0c,0x57,
+    0x00,0x04,0x64,0x38,0x26,0x7c,0x00,0x03,0xe0,0x00,0x58,0x57,0x58,0x6f,0x00,0x2c,
+    0xef,0x98,0x72,0x70,0xc2,0x80,0x52,0x81,0x48,0x41,0xe3,0x99,0x24,0x17,0x2f,0x01,
+    0x2f,0x01,0x4f,0xef,0xff,0xf4,0x4e,0x4c,0x46,0xfc,0x27,0x00,0x2f,0x02,0x42,0x67,
+    0x76,0x0f,0x20,0x78,0x00,0xac,0x4e,0xd0,0x4f,0xef,0x00,0x14,0x4c,0xdf,0x7c,0xf9,
+    0x4e,0x75,0x48,0xe7,0x18,0x1c,0x72,0x00,0x70,0x00,0x10,0x1b,0x67,0x00,0x00,0x6c,
+    0x6a,0x06,0xd0,0x00,0xef,0x48,0x10,0x1b,0x55,0x40,0x65,0x2e,0x60,0x02,0x32,0xd8,
+    0x38,0x10,0x76,0xc0,0x86,0x44,0x5c,0x43,0x67,0x0e,0xc8,0x7c,0xf0,0xff,0xb8,0x7c,
+    0x60,0x00,0x57,0xc8,0xff,0xea,0x66,0x10,0x53,0x40,0x65,0x0c,0x32,0xd8,0x36,0x09,
+    0x96,0x4c,0x97,0x50,0x51,0xc8,0xff,0xd8,0x32,0xd8,0x51,0xc9,0x00,0x06,0x58,0x41,
+    0x14,0x1b,0x4a,0x13,0x67,0x24,0xd4,0x02,0x65,0x0e,0x42,0x59,0x32,0xd8,0x20,0x0c,
+    0xd4,0x02,0xd1,0xa9,0xff,0xfc,0x60,0xa0,0xd4,0x02,0x30,0x18,0x6b,0x04,0x32,0xfc,
+    0x4e,0xb9,0xe5,0x48,0x22,0xf2,0x00,0x00,0x60,0x8e,0x4c,0xdf,0x38,0x18,0x4e,0x75,
+    0x48,0xe7,0x1f,0x3e,0x7a,0xff,0x42,0x05,0x47,0xfa,0x01,0x70,0x50,0x88,0x70,0x00,
+    0x10,0x18,0x38,0x00,0x72,0x00,0x12,0x18,0x3c,0x41,0xd0,0x40,0x36,0x33,0x00,0x02,
+    0x70,0x08,0x90,0x44,0x38,0x40,0x24,0x48,0x12,0x18,0xd2,0x41,0x4b,0xf3,0x10,0x02,
+    0x70,0x00,0x10,0x18,0xd0,0xc0,0x7e,0x00,0x9e,0x44,0x6a,0x08,0x50,0x47,0x16,0x86,
+    0x3c,0x13,0x1c,0x18,0x32,0x06,0xee,0x69,0xc2,0x43,0xb2,0x4e,0x67,0x14,0x9e,0x4c,
+    0x6a,0x08,0x50,0x47,0x16,0x86,0x3c,0x13,0x1c,0x18,0x32,0x06,0xee,0x69,0x12,0xc1,
+    0x60,0xd6,0x61,0x4e,0x4a,0x41,0x67,0x00,0x00,0x8e,0x30,0x02,0x61,0x44,0x0c,0x42,
+    0x00,0xff,0x66,0x06,0x4c,0xdf,0x7c,0xf8,0x4e,0x75,0x53,0x42,0x12,0x12,0x67,0x08,
+    0xe3,0x6a,0x61,0x60,0xc2,0x55,0x84,0x41,0x16,0x82,0x32,0x13,0x74,0xff,0xb3,0x42,
+    0x61,0x58,0x14,0x01,0x47,0xf1,0x28,0x00,0x12,0xdb,0x51,0xc8,0xff,0xfc,0x47,0xfa,
+    0x00,0xda,0x60,0x94,0x61,0x44,0x82,0x45,0x12,0xf1,0x10,0x00,0x12,0xf1,0x10,0x00,
+    0x60,0x86,0x72,0xff,0x51,0xcf,0x00,0x0a,0x50,0x47,0x16,0x86,0x3c,0x13,0x1c,0x18,
+    0x52,0x41,0x0f,0x06,0x57,0xcf,0xff,0xfa,0x66,0xee,0x9e,0x41,0x6a,0x08,0x50,0x47,
+    0x16,0x86,0x3c,0x13,0x1c,0x18,0x34,0x06,0xee,0x6a,0x03,0xc2,0xd2,0x41,0xc4,0x73,
+    0x10,0x04,0x4e,0x75,0x9e,0x41,0x6a,0x08,0x50,0x47,0x16,0x86,0x3c,0x13,0x1c,0x18,
+    0x32,0x06,0xee,0x69,0x4e,0x75,0x51,0xcf,0x00,0x0a,0x50,0x47,0x16,0x86,0x3c,0x13,
+    0x1c,0x18,0x0f,0x06,0x67,0x9e,0x51,0xcf,0x00,0x0a,0x50,0x47,0x16,0x86,0x3c,0x13,
+    0x1c,0x18,0x0f,0x06,0x66,0x20,0x32,0x04,0x61,0xca,0xc2,0x43,0x30,0x0e,0x3c,0x41,
+    0x32,0x0c,0xe3,0x68,0x61,0xbe,0x34,0x0c,0xd4,0x42,0xc2,0x73,0x20,0x02,0x80,0x41,
+    0x12,0xc0,0x60,0x00,0xff,0x04,0x61,0x00,0xff,0x7a,0x30,0x02,0x0c,0x40,0x00,0x80,
+    0x6d,0x10,0x72,0x01,0x61,0x9e,0x10,0x01,0x61,0x00,0xff,0x68,0x53,0x02,0xe1,0x4a,
+    0x80,0x42,0x61,0x00,0xff,0x5e,0x04,0x42,0x00,0x20,0x6a,0x06,0x14,0x32,0x20,0x21,
+    0x60,0x0e,0xe7,0x4a,0x72,0x03,0x61,0x00,0xff,0x7c,0x02,0x41,0x00,0x07,0x84,0x41,
+    0x12,0xc2,0x51,0xc8,0xff,0xfc,0x60,0x00,0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x01,
+    0x00,0x03,0x00,0x07,0x00,0x0f,0x00,0x1f,0x00,0x3f,0x00,0x7f,0x00,0xff,0x01,0xff,
+    0x03,0xff,0x07,0xff,0x0f,0xff,0x1f,0xff,0x3f,0xff,0x7f,0xff,0x00,0x00,0x00,0x0c,
+    0x00,0x1c,0xf3,
+};

+ 53 - 0
gtc/src/pch.h

@@ -0,0 +1,53 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * PCH management definitions
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef PCH_H
+#define PCH_H
+
+typedef struct {
+	TI_LONG magic;
+	TI_SHORT h_off;	// offset to .H section
+	TI_SHORT ext_off;	// offset to .EXT table (int ext_table[nExt])
+	TI_SHORT dic_off;	// offset to dictionnary ((char[]) sPk_table[])
+	TI_SHORT nID;
+} PCH_HEAD;
+
+#define PCH_HEAD_SIZE 12
+
+#define PCHID_MASK 0xFFF
+#define PCHID_MACRO 0x8000
+#define PCHID_VAMAC 0x4000
+#define PCHID_PACKED 0x2000
+
+#ifndef PC
+char *__attribute__((stkparm)) sUnpack(char *in,char *out,char *dic);
+#else
+char *sUnpack(char *in,char *out,char *dic);
+#endif
+
+/* GTC-only */
+extern FILE			*pchfile[];
+extern char			*pchdata[];
+extern char			*pchtab[];
+extern char			pchname[][15];
+extern char         pchrequired[];
+extern int 			pchnum;
+#define pchhead ((PCH_HEAD **)pchdata)
+
+/* PchMaker-only */
+extern int			def_is_packed;
+
+#endif
+// vim:ts=4:sw=4

+ 1291 - 0
gtc/src/peep68k.c

@@ -0,0 +1,1291 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * peephole optimizations
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#define NEWLAB
+//#define NO_PEEP
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifndef NOFLOAT
+#include	"ffplib.h"
+#endif
+
+#ifdef MC680X0
+
+extern struct enode *regexp[REGEXP_SIZE];
+struct ocode *_peep_head CGLOB;
+extern struct ocode *scope_head;
+#ifdef SPEED_OPT
+int speed_opt_value CGLOB;
+#endif
+#ifndef VCG
+struct ocode *peep_head CGLOB;
+#else
+struct ocode *vcg_peep_head[VCG_MAX+1] CGLOBL;
+struct ocode *vcg_peep_tail[VCG_MAX+1] CGLOBL;
+int vcg_lvl CGLOB;
+#define peep_head vcg_peep_head[vcg_lvl]
+#define peep_tail vcg_peep_tail[vcg_lvl]
+#endif
+xstatic struct ocode *next_ip CGLOB;
+xstatic struct ocode *last_param_pop CGLOB;
+
+#define getop1(__ip) (__ip->oper1->offset->v.i)
+#define getoplab(__ip) (__ip->oper1->offset->v.enlab)
+#define getop2(__ip) (__ip->oper2->offset->v.i)
+#ifdef NEWLAB
+#define getlab(__ip) (((struct lbls *)__ip)->lab)
+#else
+#define getlab(__ip) (__ip->oper1->offset->v.i)
+#endif
+/*static enum(e_op) revcond[] = { op_bne, op_beq, op_bge, op_bgt, op_ble, op_blt,
+							   op_bls, op_blo, op_bhs, op_bhi };*/
+xstatic readonly enum(e_op) revcond[] =
+	{
+		op_bne, op_beq, op_blo, op_blt, op_bls, op_ble, op_bhi, op_bgt, op_bhs, op_bge
+	};
+
+void add_peep(struct ocode *new_ocode);
+void opt3(void);
+
+void g_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2) {
+/*
+ * generate a code sequence into the peep list.
+ */
+	struct ocode   *new_ocode;
+	new_ocode = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE+G_CODE);
+	new_ocode->opcode = op;
+	new_ocode->length = len;
+	if ((unsigned int)len>4 || len==3)
+		ierr(G_CODE,1);
+	new_ocode->oper1 = ap1;
+	new_ocode->oper2 = ap2;
+#ifdef PC
+/*	if (op>=op_add && op<=op_subq && ap1->mode>am_areg && ap2->mode>am_areg
+		&& ap1->mode!=am_immed)
+		fatal("INVALID INSTRUCTION");
+	if ((long)new_ocode==0x7a6314)
+		bkpt();*/
+/*	if (lineid==1157)
+		bkpt();*/
+#endif
+#ifdef DB_POSSIBLE
+	new_ocode->line=lineid;
+#endif
+	add_peep(new_ocode);
+}
+
+void g_coder(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2) {
+/*
+ * generate a code sequence and put it in front of the list
+ */
+	struct ocode   *new_ocode;
+	new_ocode = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE+G_CODE);
+	new_ocode->opcode = op;
+	new_ocode->length = len;
+	new_ocode->oper1 = ap1;
+	new_ocode->oper2 = ap2;
+#ifdef DB_POSSIBLE
+	new_ocode->line=lineid;
+#endif
+	if (peep_head == 0) {
+		/* must use add_peep to take care of peep_tail */
+		add_peep(new_ocode);
+	} else {
+		new_ocode->back  = 0;
+		new_ocode->fwd   = peep_head;
+		peep_head->back = new_ocode;
+		peep_head  = new_ocode;
+		/* peep_tail does not change */
+	}
+}
+
+/* should be in add_peep(), but SConvert would put it in the text */
+/*  segment, preventing it from being modified */
+#ifndef VCG
+xstatic struct ocode *peep_tail CGLOB;
+#endif
+
+void add_peep(struct ocode *new_ocode) {
+/*
+ * add the ocode pointed to by new to the peep list.
+ */
+	if (peep_head == 0) {
+		peep_head = peep_tail = new_ocode;
+	} else {
+		new_ocode->back = peep_tail;
+		peep_tail->fwd = new_ocode;
+		peep_tail = new_ocode;
+	}
+#ifndef NOFLOAT
+	if (new_ocode->opcode==op_jsr && new_ocode->oper1->mode==en_nacon) {
+		struct enode *ep=new_ocode->oper1->offset;
+		char *s=ep->v.ensp;
+		if (!strcmp("iround",s) || !strcmp("uround",s) || !strcmp("ifloor",s)) {
+			int lab=nxtlabel();
+#ifdef AS
+			ep->v.enlab=label(
+#endif
+				ep->v.ensp=strsave(s[0]=='i'?str(ffpftol):str(ffpftou))
+#ifdef AS
+			)
+#endif
+			;
+			g_code(s[1]=='r'?op_bhs:op_bge, 1, mk_label(lab), NIL_AMODE);
+			g_code(s[1]=='r'?op_addq:op_subq, 4, mk_immed(1),
+				(struct amode *) xalloc((int) sizeof(struct amode), AMODE));
+			#ifdef NO_CALLOC
+			#error Above line bugs.
+			#endif
+			g_label(lab);
+		}
+	}
+#endif
+}
+
+extern unsigned int pos;
+void g_label(unsigned int labno) {
+/*
+ * add a compiler-generated label to the peep list.
+ */
+#ifdef NEWLAB
+	struct lbls *new_ocode;
+/*	if (pos==0x25D2 && labno==1)
+		printf("ghio");*/
+	new_ocode = (struct lbls *) xalloc((int) sizeof(struct lbls), OCODE+G_LABEL);
+	new_ocode->opcode = op_label;
+	new_ocode->lab = labno;
+	add_peep((struct ocode *)new_ocode);
+#else
+	struct ocode   *new_ocode;
+	new_ocode = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE+G_LABEL);
+	new_ocode->opcode = op_label;
+	new_ocode->oper1 = mk_immed((long) labno);
+	add_peep(new_ocode);
+#endif
+}
+
+void flush_peep() {
+/*
+ * output all code and labels in the peep list.
+ */
+#ifndef AS
+	register struct ocode *ip;
+	register int line;
+#endif
+#ifdef SHOWSTEP
+	printf("\npeep");
+#endif
+	opt3(); 					/* do the peephole optimizations */
+#ifdef SHOWSTEP
+	printf(" ok ");
+	printf("\nflush");
+#endif
+	_peep_head=peep_head;
+#ifndef AS
+	ip = peep_head;
+	line = -1;
+	if (DEBUG && func_sp)
+		fprintf(output,"; function '%s'\n",func_sp->name);
+	while (ip != 0) {
+		if (ip->opcode == op_label)
+			put_label((unsigned int) getlab(ip));
+		else {
+	#ifdef DB_POSSIBLE
+			if (DEBUG && line!=ip->line)
+				fprintf(output,"; line %d\n",line=ip->line);
+	#endif
+			put_code(ip->opcode, ip->length, ip->oper1, ip->oper2);
+		}
+		ip = ip->fwd;
+	}
+	if (DEBUG)
+		fprintf(output,"; end of function\n");
+#else
+	scope_head = peep_head;
+#endif
+	peep_head = 0;
+#ifdef SHOWSTEP
+	printf(" ok ");
+#endif
+}
+
+static void peep_delete(struct ocode *ip) {
+/*
+ * delete an instruction referenced by ip
+ */
+	if (ip == 0)
+		ierr(PEEP_DELETE,1);
+
+	if (ip->back) {
+		if ((ip->back->fwd = ip->fwd) != 0)
+			ip->fwd->back = ip->back;
+		next_ip = ip->back;
+	} else {
+		if ((peep_head = ip->fwd) != 0)
+			peep_head->back = 0;
+		next_ip = peep_head;
+	}
+}
+
+static void peep_pea(struct ocode *ip) {
+/*
+ * changes lea <ea>,An + pea (An) to pea <ea>
+ *	The value of An is not needed (An is scratch register)
+ * CAVEAT code generator modifier!
+ */
+	struct ocode   *prev;
+	if (ip->oper1->mode != am_ind)
+		return;
+	if ((prev = ip->back) == 0)
+		return;
+	if (prev->opcode == op_lea && prev->oper2->preg == ip->oper1->preg
+		&& ip->oper1->preg <= MAX_ADDR) {
+		prev->opcode = op_pea;
+		prev->oper2 = 0;
+		peep_delete(ip);
+	}
+}
+
+static void peep_lea(struct ocode *ip) {
+/*
+ * changes lea <ea>,An + move.l An,Am   to lea <ea>,Am
+ *  -- the value of An is not needed (An scratch, Am typically tempref)
+ * and     lea <ea>,An + move.* (An),An to move.* <ea>,An
+ * CAVEAT code generator modifier!
+ */
+	struct ocode   *next;
+	reg_t reg;
+  restart:
+	if ((next = ip->fwd) == 0
+#if defined(AS) && defined(ASM)
+		|| next->opt
+#endif
+	)
+		return;
+	if (next->opcode == op_move && ip->oper2->preg <= MAX_ADDR &&
+		next->oper1->mode == am_areg && next->oper1->preg == ip->oper2->preg
+		&& next->oper2->mode == am_areg && next->oper2->preg > MAX_ADDR) {
+		ip->oper2 = next->oper2;
+		peep_delete(next);
+		goto restart;
+	}
+	/* lea <ea>,An + move.* (An),An => move.* <ea>,An */
+	if (next->opcode == op_move && next->oper1->mode == am_ind)
+		if (((reg=next->oper1->preg) == ip->oper2->preg) && next->oper2->mode == am_areg &&
+		(reg==next->oper2->preg)) {
+		ip->opcode = op_move;
+		ip->length = next->length;
+		peep_delete(next);
+	}
+}
+
+static void peep_move(struct ocode *ip) {
+/*
+ * peephole optimization for move instructions.
+ * makes quick immediates when possible (redundant for most assemblers).
+ * changes move #0 to clr except on address registers
+ * changes move #0 to address registers to sub An,An
+ * changes long moves to address registers to short when possible.
+ * changes move immediate/areg to stack to pea.
+ * changes move immediate to An to lea.
+ * deletes move <ea>,<ea> (The code generator does not know that this sets
+ *						   the flags, and it is necessary for peep_and
+ *						   to work correctly if ea is am_dreg)
+ */
+	struct enode   *ep;
+#ifdef ADVANCED_MEMORY_MOVE
+	struct ocode *next;
+#endif
+
+	if (equal_address(ip->oper1, ip->oper2) &&
+/*
+ * move.w An,An changes the contents of An through sign extension
+ */
+	   (ip->oper1->mode != am_areg || ip->length != 2)) {
+		peep_delete(ip);
+		return;
+	}
+	if ((ip->oper1->mode == am_areg || ip->oper1->mode == am_immed)
+		&& ip->oper2->mode == am_adec && ip->oper2->preg == 7
+		&& ip->length == 4) {
+		ip->opcode = op_pea;
+		ip->length = 0;
+		ip->oper1 = copy_addr(ip->oper1);
+		am_doderef(ip->oper1->mode);
+		ip->oper2 = 0;
+		return;
+	}
+//#if 0
+#ifdef ADVANCED_TEMP_REGS
+#ifndef INFINITE_REGISTERS
+	if (ip->oper1->mode==am_dreg && ip->oper1->preg<=MAX_DATA
+		&& ip->oper2->mode==am_dreg) {
+		struct ocode *ip_save=ip;
+		reg_t a=ip->oper1->preg,b=ip->oper2->preg,s=ip->length;
+		struct amode *ap,*destap=ip->oper2;
+		/* BUGGY: we should check if da isn't used afterwards...
+		 *  Currently, g_assign does in such way that it returns Db
+		 * rather than Da, so it should work fine in most cases,
+		 * but it might fail eg with custom asm statements */
+		ip=ip->back;
+		while (ip) {
+			switch (ip->opcode) {
+			  case op_label:
+			  case op_jsr:
+			  case op_bxx:
+			  case op_dbxx:
+			  case op_dc:	// this might mean op_jsr...
+				return;
+			  case op_ext:
+				if (ip->oper1->mode==am_dreg && ip->oper1->preg==a) {
+					s=ip->length>>1;
+					break;
+				}
+				if ((ap=ip->oper1) && ap->mode==am_dreg && ap->preg==b) {
+#ifdef PC
+					if (ip->length && ip->length<=s)
+						fatal("OP DISCARDED BY ASSIGNMENT");
+					else
+#endif
+						return;
+				}
+				break;
+			  case op_clr:
+				ap=ip->oper1;
+				goto check_ok;
+			  case op_move:
+			  case op_moveq:
+			  case op_lea:
+				ap=ip->oper2;
+			check_ok:
+				if (ap->mode==am_dreg && ap->preg==a) {
+					if (ip->length && ip->length<s) return;
+					else goto ok_atr;
+				}
+				//break;
+			  default:
+				if ((ap=ip->oper1) && ((ap->mode==am_dreg && ap->preg==b) ||
+						(ap->mode==am_indx2 && ap->sreg==b)))
+					return;
+				if ((ap=ip->oper2) && ap->mode==am_indx2 && ap->sreg==b)
+					return;
+				if ((ap=ip->oper2) && ap->mode==am_dreg && ap->preg==b) {
+#ifdef PC
+					if (ip->length && ip->length<=s)
+						fatal("OP DISCARDED BY ASSIGNMENT");
+					else
+#endif
+						return;
+				}
+			}
+			ip=ip->back;
+		}
+		ierr(UNINIT_TEMP,1);
+	  ok_atr:
+		next_ip=ip;
+		ip=ip_save;
+		while (ip!=next_ip) {
+			if (ip->oper1 && ip->oper1->mode==am_dreg && ip->oper1->preg==a)
+				ip->oper1=destap;
+			if (ip->oper2 && ip->oper2->mode==am_dreg && ip->oper2->preg==a)
+				ip->oper2=destap;
+			ip=ip->back;
+		}
+		if (ip->opcode==op_clr)
+			ip->oper1=destap;
+		else ip->oper2=destap;
+		return;
+	}
+#endif
+#endif
+#ifdef ADVANCED_MEMORY_MOVE
+	/* try to use post-increment where possible                           */
+	/* (might be improved to allow for interstitial instructions, but
+	    beware of modifications of _any_ of _both_ indexing registers...) */
+	if (ip->oper2->mode == am_indx && (next=ip->fwd) && next->opcode==op_move
+		&& next->oper2->mode == am_indx && next->oper2->preg == ip->oper2->preg
+		&& next->oper2->offset->v.i-ip->oper2->offset->v.i==ip->length) {
+		int reg=-1;
+#ifndef INFINITE_REGISTERS
+		if (arsearch(0,ip))
+			reg=8;
+		else if (arsearch(1,ip))
+			reg=9;
+#endif
+		if (reg IS_VALID) {
+			struct ocode *load = xalloc(sizeof(struct ocode),OCODE);
+			long offs; struct amode *ap;
+			load->opcode=op_lea;
+			load->oper1=ip->oper2;
+			load->oper2=mk_reg(reg);
+			load->line=ip->line;
+			load->back=ip->back;
+			load->fwd=ip;
+			load->back->fwd=load;
+			ip->back=load;
+			next=ip;
+			reg=ip->oper2->preg;
+			offs=ip->oper2->offset->v.i;
+			ap=mk_reg(reg); ap->mode=am_ainc;
+			do {
+				next->oper2=ap;
+				offs+=next->length;
+				next=next->fwd;
+			} while (next->opcode==op_move && next->oper2->preg==reg
+				&& next->oper2->mode==am_indx
+				&& next->oper2->offset->v.i==offs);
+		}
+	}
+#endif
+	if (ip->oper1->mode != am_immed)
+		return;
+#ifdef ADVANCED_MEMORY_MOVE
+	/* optimize contiguous -(an)/(an)+ assignments */
+   restart_advmove:
+	if (am_is_increment(ip->oper2->mode) && ip->length<=2 && (next=ip->fwd)
+		&& next->opcode==op_move && ip->oper1->offset->nodetype==en_icon
+		&& next->oper1->mode == am_immed && next->oper2->mode==ip->oper2->mode
+		&& next->length==ip->length
+		&& next->oper1->offset->nodetype==en_icon) {
+		unsigned short a,b;	/* very important *not* to be long's !!! */
+		a=(unsigned short)ip->oper1->offset->v.i,b=(unsigned short)next->oper1->offset->v.i;
+		if (ip->oper2->mode==am_adec)
+			b=a,a=(unsigned short)next->oper1->offset->v.i;
+		ip->oper1=copy_addr(ip->oper1);
+		ip->oper1->offset =
+			mk_icon((ip->length==2?((long)a<<16)|b:(long)(unsigned short)((a<<8)|(unsigned char)b)));
+		ip->length<<=1;
+		peep_delete(next);
+		if (ip->back->opcode==op_move) {
+			next_ip=ip->back;
+			return;
+		} else goto restart_advmove;
+		/*
+		 move.b #0,(a0)+ <-
+		 move.b #0,(a0)+
+		 move.b #0,(a0)+
+		 move.b #0,(a0)+
+		->
+		 move.w #0,(a0)+ <-
+		 move.b #0,(a0)+
+		 move.b #0,(a0)+
+		->
+		 clr.w (a0)+
+		 move.b #0,(a0)+ <-
+		 move.b #0,(a0)+
+		->
+		 clr.w (a0)+     <-
+		 move.w #0,(a0)+
+		->
+		 clr.w (a0)+     <-
+		 move.w #0,(a0)+
+		->
+		 move.l #0,(a0)+ <-
+		->
+		 clr.l (a0)+     <-
+		*/
+	}
+#endif
+
+	ep = ip->oper1->offset;
+	if (ip->oper2->mode == am_areg && ep->nodetype == en_icon) {
+		if (ep->v.i == 0) {
+			ip->length = 4;
+			ip->opcode = op_sub;
+			ip->oper1 = ip->oper2;
+		} else if (-32768 <= ep->v.i && ep->v.i <= 32767)
+			ip->length = 2;
+		return;
+	}
+	if (ip->oper2->mode == am_dreg && ep->nodetype == en_icon
+		&& -128 <= ep->v.i && ep->v.i <= 127) {
+		ip->opcode = op_moveq;
+		ip->length = 0;
+		return;
+	}
+	if (ep->nodetype == en_icon && ep->v.i == 0) {
+		ip->opcode = op_clr;
+		ip->oper1 = ip->oper2;
+		ip->oper2 = 0;
+		return;
+	}
+	if (ip->oper2->mode == am_areg && ip->length == 4) {
+		next_ip = ip;
+		ip->opcode = op_lea;
+		ip->length = 0;
+		ip->oper1 = copy_addr(ip->oper1);
+		ip->oper1->mode = am_direct;
+		return;
+	}
+}
+
+int equal_address(struct amode *ap1, struct amode *ap2) {
+/*
+ * compare two address nodes and return true if they are equivalent.
+ */
+	if (ap1 == 0 || ap2 == 0)
+		return 0;
+	if (ap1->mode != ap2->mode)
+		return 0;
+	switch (ap1->mode) {
+	  case am_areg:
+	  case am_dreg:
+	  case am_ind:
+		return ap1->preg == ap2->preg;
+	  case am_indx:
+		return ap1->preg == ap2->preg &&
+			   ap1->offset->nodetype == en_icon &&
+			   ap2->offset->nodetype == en_icon &&
+			   ap1->offset->v.i == ap2->offset->v.i;
+	  case am_indx2:
+	  case am_indx3:
+		return
+			ap1->preg == ap2->preg &&
+			ap1->sreg == ap2->sreg &&
+			ap1->slen == ap2->slen &&
+			ap1->offset->nodetype == en_icon &&
+			ap2->offset->nodetype == en_icon &&
+			ap1->offset->v.i == ap2->offset->v.i;
+	}
+	return 0;
+}
+
+static void peep_movem(struct ocode *ip) {
+/*
+ * peephole optimization for movem instructions. movem instructions are used
+ * to save registers on the stack. if 1 or 2 registers are being saved we
+ * can convert the movem to move instructions.
+ */
+	int i,mask,n,t,a,b=0;
+	struct ocode *root;
+
+#ifdef PC
+	a=1234;	/* prevent a warning from being output - we can afford this on PC :) */
+#endif
+
+	if (ip->oper1->mode == am_mask1)
+		mask = getop1(ip);
+	else mask = getop2(ip);
+
+	t=1,n=2,i=16;
+	while (i--) {
+		if (mask & t) {
+			b=a,a=i;
+			if (--n<0) return;
+		}
+		t<<=1;
+	}
+	root=ip;
+	ip->opcode = op_move;
+	if ((i=1-n)) {
+		struct ocode *new_ocode = (struct ocode *)
+			xalloc((int) sizeof(struct ocode), OCODE);
+		new_ocode->opcode = op_move;
+		new_ocode->length = ip->length;
+		new_ocode->oper1 = copy_addr(ip->oper1);
+		new_ocode->oper2 = copy_addr(ip->oper2);
+#ifdef DB_POSSIBLE
+		new_ocode->line=ip->line;
+#endif
+		new_ocode->back = ip;
+		if ((new_ocode->fwd=ip->fwd))
+			ip->fwd->back=new_ocode;
+		ip->fwd=new_ocode;
+	}
+	do {
+		if (ip->oper1->mode == am_mask1) {
+				if ((ip->oper1->preg = a) >= 8) {
+					ip->oper1->mode = am_areg;
+					ip->oper1->preg -= 8;
+#ifdef INFINITE_REGISTERS
+					ip->oper1->preg += TAREGBASE-AREGBASE;
+#endif
+				} else {
+					ip->oper1->mode = am_dreg;
+#ifdef INFINITE_REGISTERS
+					ip->oper1->preg += TDREGBASE;
+#endif
+				}
+			} else {
+				if ((ip->oper2->preg = 15 - a) >= 8) {
+					ip->oper2->mode = am_areg;
+					ip->oper2->preg -= 8;
+#ifdef INFINITE_REGISTERS
+					ip->oper2->preg += TAREGBASE-AREGBASE;
+#endif
+				} else {
+					ip->oper2->mode = am_dreg;
+#ifdef INFINITE_REGISTERS
+					ip->oper2->preg += TDREGBASE;
+#endif
+				}
+		}
+		ip=ip->fwd;
+		a=b;
+	} while (i--);
+	next_ip=root;	/* optimize move.l An,-(a7) => pea (An) */
+}
+
+int drsearch(int r,struct ocode *ip) {
+	while ((ip=ip->fwd)) {
+		struct amode *ap=ip->oper1;
+		int n=0;
+		do {
+			switch (ap->mode) {
+				case am_dreg:
+					if (ap->preg==r)
+						return n && op_destroy(ip->opcode);
+				case am_areg:
+				case am_ind: case am_adec: case am_ainc: case am_indx:
+				case am_indx3:
+					break;
+				case am_indx2:
+					if (ap->sreg==r)
+						return 0;
+					break;
+			}
+			n++;
+		} while ((ap=ip->oper2));
+	}
+	return 1;
+}
+
+int arsearch(int r,struct ocode *ip) {
+	struct amode *ap; int n,z;
+//	printf("$%d",r);
+	z=0;
+	while ((ip=ip->fwd) && ip->opcode!=op_rts) {
+		if (ip->opcode==op_label) continue;
+#ifdef INFINITE_REGISTERS
+		if (ip->opcode==_op_cleanup_for_external_call) continue;
+#endif
+		z++;
+		ap=ip->oper1;
+		n=0;
+		do {
+			switch (ap->mode) {
+				case am_areg:
+					if (ap->preg==r) {
+//						printf("*%d ",z);
+						return n && op_destroy(ip->opcode);
+					}
+				case am_dreg:
+					break;
+				case am_indx3:
+					if (ap->sreg==r) {
+//						printf("-%d ",z);
+						return 0;
+					}
+					/* FALL THROUGH */
+				case am_ind: case am_adec: case am_ainc: case am_indx:
+				case am_indx2:
+					if (ap->preg==r) {
+//						printf("-%d ",z);
+						return 0;
+					}
+					break;
+			}
+			n++;
+		} while ((ap=ip->oper2) && n==1);
+	}
+//	printf("/%d ",z);
+	return 1;
+}
+
+static void peep_addsub(struct ocode *ip, enum (e_op) op) {
+/*
+ * peephole optimization for add/sub instructions.
+A* changes add/sub.* Rn,An; move (An),X			to move 0(An,+/- Rn.*),X
+A* changes add/sub.* Rn,An; move x(An),X		to move x(An,+/- Rn.*),X
+A* changes add/sub   #x,An; move 0(An,Rn.*),X	to move x(An,+/- Rn.*),X
+ * makes quick immediates out of small constants (redundant for most as's).
+ * change add/sub immediate to address registers to lea where possible
+A* and try to avoid operand volatilizing when doing so
+ */
+	struct enode   *ep;
+	struct ocode   *next=ip->fwd;
+#ifdef ADV_OPT
+	int reg;
+	if (next
+#ifdef AS
+		&& !next->opt
+#endif
+		&& next->opcode==op_move
+		&& ip->oper2->mode==am_areg && (reg=ip->oper2->preg)==next->oper1->preg
+		&& arsearch(reg,next)) {
+		int sub=op-op_add,ok=0,sz=ip->length,sreg=ip->oper1->preg;
+		long offs=next->oper1->offset?getop1(next):0;
+/*		infunc("InitLevel")
+			bkpt();*/
+		ok=next->oper1->mode;
+		if (ip->oper1->mode==am_dreg || ip->oper1->mode==am_areg) {
+			if (ok==am_ind)
+				offs=0;
+			else if (ok!=am_indx)
+				ok=0;
+			/* if we do the conversion, select am_indx2/3 appropriately */
+			if (ok)
+				ok=ip->oper1->mode-am_dreg+am_indx2;
+		} else if (ip->oper1->mode==am_immed) {
+			sz=next->oper1->slen;
+			sreg=next->oper1->sreg;
+			offs=getop1(ip);
+			if (sub) offs=-offs;
+			sub=0;
+			if (ok==am_indx3)
+				sreg+=AREGBASE;
+			else if (ok!=am_indx3)
+				ok=0;
+		} else ok=0;
+		if (ok && offs>=-128 && offs<128) {
+			if (sub) ip->opcode=op_neg,ip->oper2=NULL;
+			else peep_delete(ip);
+			next->oper1=copy_addr(next->oper1);
+			next->oper1->mode=ok;
+			next->oper1->slen=sz;
+			next->oper1->sreg=sreg;
+			next->oper1->offset=mk_icon(offs);
+			return;
+		}
+	}
+#endif
+	if (ip->oper2->preg == STACKPTR-AREGBASE && ip->length == 2) {	/* alloca... */
+		last_param_pop = NULL;
+	}
+	if (ip->oper1->mode == am_immed) {
+		ep = ip->oper1->offset;
+		if (ip->oper2->mode != am_areg)
+			ip->opcode = op+op_addi-op_add;
+		if (ep->nodetype != en_icon)
+			return;
+#ifdef POP_OPT
+		if (ip->oper2->preg == STACKPTR-AREGBASE && 
+			ip->oper2->mode == am_areg && ip->length == 4) {	/* parameter popping */
+			if (last_param_pop)
+				ep->v.i+=getop1(last_param_pop), peep_delete(last_param_pop);
+			last_param_pop = ip;
+		}
+#endif
+/*		if (!ep->v.i) {			// unnecessary
+			peep_delete(ip);
+			return;
+		}*/
+		if (1 <= ep->v.i && ep->v.i <= 8) {
+			ip->opcode = op+op_addq-op_add;
+			return;
+		}
+		if (-8 <= ep->v.i && ep->v.i <= -1) {
+			ip->opcode = op==op_add?op_subq:op_addq;
+			ep->v.i = -ep->v.i;
+			return;
+		}
+		if (ip->oper2->mode == am_areg && isshort(ep)) {
+			ip->oper1 = copy_addr(ip->oper1);
+			ip->oper1->mode = am_indx;
+			ip->oper1->preg = ip->oper2->preg;
+			if (op==op_sub) ip->oper1->offset=mk_icon(-getop1(ip));
+			ip->length = 0;
+			ip->opcode = op_lea;
+			next_ip = ip;
+#ifdef ADV_OPT
+			if (ip->back && ip->back->opcode==op_move && ip->back->oper2->mode==am_areg
+				&& ip->back->oper2->preg==ip->oper1->preg
+				&& ip->back->oper1->mode==am_areg
+				&& arsearch(ip->oper1->preg,ip))
+					ip->oper1->preg=ip->back->oper1->preg, peep_delete(ip->back);
+#endif
+			return;
+		}
+	}
+}
+
+static void peep_and(struct ocode *ip) {
+/*
+ * conversion of unsigned data types often yields statements like
+ * move.b source,d0 +  andi.l #255,d0
+ * which should be converted to
+ * clr.l d0 + move.b source,d0
+ * deletes and #-1
+ */
+	struct ocode   *prev;
+	int 			size;
+	long			arg;
+	if (ip->oper1->mode != am_immed ||
+		ip->oper1->offset->nodetype != en_icon)
+		return;
+	arg = getop1(ip);
+	/*
+	 * and #-1 does only set flags, which the code generator does not know
+	 */
+	if (arg == -1) {
+		peep_delete(ip);
+		return;
+	}
+	if (ip->oper1->mode != am_immed ||
+		(arg != 255 && arg != 65535))
+		return;
+
+	size = (arg == 255) ? 1 : 2;
+
+	/* move.b <ea>,dn; and.* #$FF,dn	à condition que <ea> != x(An,Dn) */
+	/* move.w <ea>,dn; and.* #$FFFF,dn	à condition que <ea> != x(An,Dn) */
+	if ((prev = ip->back) == 0 || prev->length != size
+		|| prev->opcode != op_move
+		|| ip->oper2->mode != am_dreg || prev->oper2->mode != am_dreg
+		|| ip->oper2->preg != prev->oper2->preg
+		||		(prev->oper1->mode == am_indx2 &&
+				 prev->oper1->sreg == prev->oper2->preg))
+		return;
+
+	prev->length = ip->length;
+	ip->length = size;
+	prev->opcode = op_clr;
+	ip->opcode = op_move;
+	ip->oper1 = prev->oper1;
+	prev->oper1 = prev->oper2;
+	prev->oper2 = 0;
+
+	next_ip = prev;
+}
+
+static void peep_clr(struct ocode *ip) {
+/*
+ * removes consecutive clr-statements
+ *
+ */
+	struct ocode   *prev;
+
+	if ((prev = ip->back) == 0 || prev->opcode != op_clr ||
+		!equal_address(ip->oper1, prev->oper1))
+		return;
+
+	if (prev->length < ip->length)
+		prev->length = ip->length;
+
+	peep_delete(ip);
+}
+
+static void peep_cmp(struct ocode *ip) {
+/*
+ * peephole optimization for compare instructions.
+ * changes compare #0 to tst
+ *
+ */
+	struct enode   *ep;
+	if (ip->oper1->mode != am_immed)
+		return;
+	ep = ip->oper1->offset;
+	if (ip->oper2->mode == am_areg)
+		/* cmpa.w extents the first argument automatically */
+	{
+		if (isshort(ep))
+			ip->length = 2;
+		return;
+	}
+	ip->opcode = op_cmpi;
+	if (ep->nodetype != en_icon || ep->v.i != 0)
+		return;
+	ip->oper1 = ip->oper2;
+	ip->oper2 = 0;
+	ip->opcode = op_tst;
+	next_ip = ip;
+}
+
+static void peep_tst(struct ocode *ip) {
+/*
+ * deletes a tst instruction if the flags are already set.
+ */
+	struct ocode   *prev,*next;
+	enum(e_op) op;
+	prev = ip->back;
+	if (prev == 0)
+		return;
+/*
+ * All the following cases used to be checked with an obscure
+ * if-statement. There was an error in it that caused prev->oper2->mode
+ * to be referenced even if prev->opcode is op_clr. (This yields a NIL-
+ * pointer reference.
+ * I threw all this stuff away and replaced it by this case-statement.
+ * This is much more readable.
+ */
+	switch (prev->opcode) {
+		case op_label:
+		case op_dc:
+		case _op_asm:
+		case _op_adj:
+/*
+ * List all pseudo-instructions here. Of course, they do not do
+ * anything.
+ */
+			return;
+
+		case op_move:
+/*
+ * A move TO an address register does not set the flags
+ */
+			if (prev->oper2->mode == am_areg)
+				return;
+		case op_moveq:
+		case op_clr:
+		case op_ext:
+/*
+ * All other move and clr instructions set the flags according to
+ * the moved operand, which is prev->oper1
+ */
+			if (equal_address(prev->oper1, ip->oper1))
+				break;
+			if (equal_address(prev->oper2, ip->oper1))
+				break;
+			return;
+		case op_btst: case op_bset: case op_bclr: case op_bchg:
+		case op_cmp:
+			/* these instructions affect the flags in a non-standard way */
+		case op_swap:/*[longword test]*/
+			/* FALL THROUGH */
+		case op_exg:
+			/* these instructions don't affect the flags */
+			return;
+		default:
+/*
+ * All instructions that have a target set the flags according to the
+ * target (prev->oper2)
+ * Note that equal_address may be called with a NIL pointer -> OK for clr
+ */
+			next = ip->fwd;
+			if (next && ((op=next->opcode)==op_beq || op==op_bne)
+				&& !(next->fwd && (op=next->fwd->opcode)>=_op_bcond_min && op<=_op_bxx_max))
+					if (equal_address(prev->oper2, ip->oper1))
+						break;
+			return;
+	}
+/*
+ * We come here if the flags are already set, thus the tst
+ * instruction can be deleted.
+ */
+	if (ip->length==prev->length)
+		peep_delete(ip);
+}
+
+static void peep_uctran(struct ocode *ip) {
+/*
+ * peephole optimization for unconditional transfers. deletes instructions
+ * which have no path. applies to bra, jmp, and rts instructions.
+ */
+	while (ip->fwd != 0 && ip->fwd->opcode != op_label)
+		peep_delete(ip->fwd);
+	next_ip=ip->fwd;
+}
+
+static void peep_bxx(struct ocode *ip) {
+/*
+ * optimizes conditional branch over a bra.
+ */
+	struct ocode   *next = ip->fwd;
+	if (next && next->opcode == op_bra) {
+	   /* peep_uctran increases the 'hit' probability */
+		peep_uctran(next);
+		while ((next = next->fwd) && next->opcode == op_label)
+		  if (getoplab(ip) == getlab(next)) {
+			/* bxx \lab | bra \out | ... | \lab:
+			 *  => (peep_uctran)
+			 * bxx \lab | bra \out | \lab:
+			 *  =>
+			 * byy \out | \lab:
+			 */
+			ip->fwd->opcode = revcond[(int)ip->opcode - (int)_op_bcond_min];
+			ip=ip->fwd;
+			peep_delete(ip->back);
+			break;
+		  }
+	}
+	if (ip->opcode==op_bhs && ip->back && ip->back->opcode==op_subq
+		&& ip->back->oper1->offset->v.i==1 /* since oper1->mode is am_immed->en_icon */
+		&& ip->back->oper2->mode==am_dreg)
+			ip->opcode=op_dbra,
+			ip->oper2=ip->oper1,
+			ip->oper1=ip->back->oper2,
+			peep_delete(ip->back);
+}
+
+static void peep_label(struct ocode *ip) {
+/*
+ * if a label is followed by a branch to another label, the
+ * branch statement can be deleted when the label is moved
+ */
+	struct ocode   *prev, *next, *target;
+	long			label;
+	last_param_pop = NULL;	// reset function parameter popping optimization
+	prev = ip->back;
+
+	if ((next = ip->fwd) == 0 || next->opcode != op_bra || next->oper1->offset->nodetype!=en_labcon)
+		return;
+	/*
+	 * To make this fast, assume that the label number is really
+	 * getoplab(next)
+	 */
+	label = getoplab(next);
+	if (label == getlab(ip))
+		return;
+	target = peep_head;
+	/*
+	 * look for the label
+	 */
+	while (target != 0) {
+		if (target->opcode == op_label
+			&& getlab(target) == label)
+			break;
+		target = target->fwd;
+	}
+	/* we should have found it */
+	if (target == 0) {
+#ifdef VCG
+		if (vcg_lvl==VCG_MAX)
+#endif
+			iwarn(PEEP_LABEL,1);
+		return;
+	}
+	/* move label */
+	peep_delete(ip);
+	ip->fwd = target->fwd;
+	ip->back = target;
+	target->fwd = ip;
+	if (ip->fwd != 0)
+		ip->fwd->back = ip;
+	/* possibly remove branches */
+	/* in fact, prev is always != 0 if peep_delete has succeeded */
+	if (prev != 0) {
+		if (prev->opcode == op_bra || prev->opcode == op_jmp
+			|| prev->opcode == op_rts)
+			peep_uctran(prev);
+		else if (prev->opcode == op_label)
+			next_ip=prev;	/* so that peep_label will be called once again (this label
+							 *  might be aliased by other ones) */
+	}
+}
+
+void opt3(void) {
+/*
+ * peephole optimizer. This routine calls the instruction specific
+ * optimization routines above for each instruction in the peep list.
+ */
+//#define NO_PEEP
+#ifndef NO_PEEP
+	struct ocode   *ip;
+	enum(e_op) instr;
+	next_ip = peep_head;
+	if (!opt_option)
+		return;
+	instr=-1;
+	last_param_pop = NULL;
+	while (next_ip != 0) {
+/*		if (ip->opcode==instr)
+			if (!(ip = ip->fwd)) break;
+		instr=ip->opcode;*/
+		ip = next_ip;
+		next_ip = ip->fwd;
+#ifdef AS
+		if (ip->opcode!=op_label && ip->opt)
+			continue;
+#endif
+		switch (ip->opcode) {
+		  case op_move:
+			peep_move(ip);
+			break;
+		  case op_movem:
+			peep_movem(ip);
+			break;
+		  case op_pea:
+			peep_pea(ip);
+			break;
+		  case op_lea:
+			peep_lea(ip);
+			break;
+		  case op_ext: {	/* ext.l Dn ; add/sub Dn,Am (where Dn is a word) */
+			struct ocode *nxt=ip->fwd; reg_t reg;
+			if (!nxt || (nxt->opcode!=op_add && nxt->opcode!=op_sub)
+#if defined(AS) && defined(ASM)
+				|| nxt->opt
+#endif
+				|| ip->length!=4 || nxt->oper1->mode!=am_dreg
+				|| (reg=nxt->oper1->preg)!=ip->oper1->preg
+				|| nxt->oper2->mode!=am_areg
+				|| (reg>MAX_DATA && regexp[reg_t_to_regexp(reg)]->esize==4))
+				break;
+			peep_delete(ip);
+			nxt->length=2;
+			} break;
+		  case op_add:
+		  case op_sub:
+			peep_addsub(ip,ip->opcode);
+			//peep_add/peep_sub(ip);
+			break;
+		  case op_and:
+			peep_and(ip);
+			break;
+		  case op_clr:
+			peep_clr(ip);
+			break;
+		  case op_cmp:
+			peep_cmp(ip);
+			break;
+		  case op_tst:
+			peep_tst(ip);
+			break;
+		  case op_beq:
+		  case op_bne:
+		  case op_bgt:
+		  case op_bge:
+		  case op_blt:
+		  case op_ble:
+		  case op_blo:
+		  case op_bls:
+		  case op_bhi:
+		  case op_bhs:
+			peep_bxx(ip);
+			/* FALL THROUGH */
+			last_param_pop = NULL;	// reset function parameter popping optimization
+			break;
+		  case op_dbxx:
+			last_param_pop = NULL;	// reset function parameter popping optimization
+			break;
+		  case op_bra:
+			last_param_pop = NULL;	// reset function parameter popping optimization
+			peep_uctran(ip);
+			/* delete branches to the following statement */
+			{
+				struct ocode   *p = ip->fwd;
+				long			label = getoplab(ip);
+				while (p != 0 && p->opcode == op_label) {
+					if (getlab(p) == label) {
+						peep_delete(ip);
+						ip = 0;
+						break;
+					}
+					p = p->fwd;
+				}
+			}
+			if (!ip)
+				break;
+#ifdef SPEED_OPT
+			if (next_ip && speed_opt_value>0) {	/* then it's necessarily a label, due to peep_uctran */
+				int i,lab=getoplab(ip);
+				struct ocode *p=peep_head,*s,*e;
+				do {
+					if (p->opcode==op_label && getlab(p)==lab) break;
+				} while ((p=p->fwd));
+				if (!p) break;
+				s=p;
+				lab=getlab(next_ip);
+				i=speed_opt_value;
+				/* NOTE : we ought never stop copying on a 'bra', but rather go on */
+				do {
+					if (!(p=p->fwd)) goto bad;
+					if (p->opcode==op_label) i++;	/* don't count it as an instruction */
+					else if (p->opcode>=_op_bcond_min && p->opcode<=_op_bxx_max
+						&& getoplab(p)==lab) {
+						break;
+					} else if (p->opcode==op_bra || p->opcode==op_jmp || p->opcode==op_rts)
+						break;
+#ifndef ALLOW_TWIN_STACK_OPS
+					else {
+						struct amode *ap=p->oper1;
+						if (ap && ap->mode==am_ainc && ap->preg==7)
+							goto bad;
+						ap=p->oper2;
+						if (ap && (ap->mode==am_areg || ap->mode==am_adec) && ap->preg==7)
+							goto bad;
+					}
+#endif
+				} while (i--);
+				if (i>=0) {
+					struct ocode *prv,*nxt;
+					e=p;
+					p=s;
+					prv=ip->back;
+					next_ip=prv;
+					nxt=ip->fwd;
+					peep_delete(ip);
+					do {
+						p=p->fwd;
+						if (p->opcode!=op_label) {
+							struct ocode *n=(struct ocode *)
+								xalloc(sizeof(struct ocode), OCODE);
+							*n=*p;
+							if (p==e && p->opcode>op_bra) { /* we assume that op_jmp<op_bra */
+															/*  and op_rts<op_bra           */
+								struct ocode *pn=p->fwd,*nl;
+								int dlab;
+								if (pn->opcode==op_label) dlab=getlab(pn);
+								else {
+									dlab=nxtlabel();
+								#ifdef NEWLAB
+									nl = (struct ocode *) xalloc((int) sizeof(struct lbls), OCODE);
+									nl->opcode = op_label;
+									((struct lbls *)nl)->lab = dlab;
+								#else
+									nl = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE);
+									nl->opcode = op_label;
+									nl->oper1 = mk_immed((long)dlab);
+								#endif
+									p->fwd=nl;
+									nl->back=p;
+									nl->fwd=pn;
+									pn->back=nl;
+								}
+								n->opcode=revcond[p->opcode-_op_bcond_min];
+								n->oper1=mk_label(dlab);
+							}
+							n->back=prv;
+							prv->fwd=n;
+							prv=n;
+						}
+					} while (p!=e);
+					prv->fwd=nxt;
+					nxt->back=prv;
+					next_ip=next_ip->fwd;
+				}
+			}
+bad:
+#endif
+			break;
+		  case op_jmp:
+		  case op_rts:
+			last_param_pop = NULL;	// reset function parameter popping optimization
+			peep_uctran(ip);
+			break;
+		  case op_label:
+			peep_label(ip);
+			break;
+		  case _op_adj:
+			peep_delete(ip);
+			/* FALL THROUGH */
+		  case _op_asm:
+			last_param_pop = NULL;	// reset function parameter popping optimization
+			break;
+		}
+	}
+#endif
+}
+#ifdef VCG
+#include "vcg.c"
+#endif
+
+#endif /* MC680X0 */
+// vim:ts=4:sw=4

+ 572 - 0
gtc/src/preproc.c

@@ -0,0 +1,572 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * preprocessor
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#define USE_MEMMGT
+#include	"cglbdec.h"
+#ifdef PCH
+#include	"pch.h"
+#endif
+
+extern char *curname;
+extern char *lptr;
+char *inclname[10];
+FILE *inclfile[10];
+int inclifreldepth[10];
+int incldepth CGLOB;
+#ifdef PCH
+FILE			*pchfile[20];
+char			*pchdata[20] CGLOBL;
+char			*pchtab[20];
+#ifdef REQ_MGT
+char			 pchname[20][15];
+char             pchrequired[20];
+#endif
+int 			pchnum CGLOB;
+#endif
+int inclline[10];
+int lineno CGLOB;
+int lineid CGLOB;
+int prevlineid CGLOB;
+int flags CGLOB;
+#ifdef PC
+int verbose CGLOB;
+#endif
+#ifdef PC
+int verbosity CGLOB;
+#endif
+int ifdepth CGLOB;
+int ifreldepth CGLOB;
+int ifcount[MAX_IF_DEPTH];
+int ifval[MAX_IF_DEPTH];
+int ifhas[MAX_IF_DEPTH];
+int ifskip CGLOB, ifsd CGLOB;
+
+HTABLE defsyms CGLOBL;
+
+extern int getline(int f);
+
+extern TYP *expression();
+extern unsigned char id_are_zero;
+
+int doinclude(
+#ifdef PCH
+		  int pch
+#endif
+			  );
+
+extern enum(e_sym) forbid;
+xstatic int pp_old_forbid CGLOB;
+xstatic int pp_old_crc CGLOB;
+xstatic char pp_old_id[MAX_ID_LEN+1];
+
+/*static int mem_if=0,mem_def=0;
+#define MEM_USE(x,s) mem_##x-=glbmem; s mem_##x+=glbmem;*/
+
+int ppquit() {
+	if (pp_old_forbid IS_VALID) {
+		forbid=pp_old_forbid;
+		if (pp_old_forbid==id) memcpy(lastid,pp_old_id,MAX_ID_LEN+1), lastcrc=pp_old_crc;
+	}
+#ifdef MACRO_PPDIR
+	if (*lptr) lptr=strchr(lptr,'\n')+1;
+	if (!*lptr) return getline(incldepth == 0);
+	else return 0;
+#else
+	return getline(incldepth == 0);
+#endif
+}
+
+#if 0
+char *strend(char *s) {
+	while (*s++);
+	return s-1;
+}
+#endif
+
+int preprocess() {
+	if ((pp_old_forbid=forbid)==id) memcpy(pp_old_id,lastid,MAX_ID_LEN+1), pp_old_crc=lastcrc,
+		forbid=-1;
+	++lptr; // skip '#'
+	lastch = ' ';
+	getch();
+	getsym();				/* get first word on line */
+	if(lastst != id && lastst != kw_if && lastst != kw_else) {
+		uerrc("preprocessor command expected");
+		return ppquit();
+	}
+/*	if (!strcmp(curname,"compat.h") && lineno>=23)
+		bkpt();*/
+/*	if (!strcmp(curname,"messages.c") && lineno>=0)
+		bkpt();*/
+	if (lastst == kw_if /*!strcmp(lastid,"if")*/ || !strcmp(lastid,"elif")) {
+		struct enode *ep; TYP *tp; enum(e_bt) typ;
+		int v=lastst==kw_if;
+		if (!v) ifskip=ifhas[ifdepth];
+		if (ifskip) return doif(-1,v);
+#ifndef MACRO_PPDIR
+		strcpy(lptr," ] ");	// so that getsym() in the new expression will
+		getsym();			//  not read any new line
+#else
+	{
+		char *q=strchr(lptr,'\n');
+		memmove(q+3,q,strlen(q)+1);
+		memcpy(q," ] ",3);
+		getsym();
+	}
+#endif
+		tmp_use();
+		id_are_zero++;
+		tp=expression(&ep);
+		id_are_zero--;
+		if (!tp || lastst!=closebr) error(ERR_EXPREXPECT);
+		else if ((typ=tp->type)==bt_void || typ==bt_pointer) error(ERR_INTEGER);
+		else {
+			opt0(&ep);
+			if (ep->nodetype!=en_icon) error(ERR_CONSTEXPECT);
+			else { int w=doif(ep->v.i!=0,v); tmp_free(); return w; }
+		}
+		tmp_free();
+		return ppquit();
+	} else if (!strcmp(lastid,"ifdef") || !strcmp(lastid,"ifndef")) {
+		int v=lastid[2]!='d';
+		if (ifskip) return doif(-1,1);
+		skipspace();
+		if ((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z')
+			|| lastch=='_' || lastch=='$') {
+			getidstr();
+			return doif(v ^ !!search(lastid,lastcrc,&defsyms),1);
+		} else error(ERR_IDEXPECT);
+		return ppquit();
+	} else if (lastst == kw_else/*!strcmp(lastid,"else")*/) {
+		if (!ifreldepth) uerrc("'#else' unexpected");
+		else if (!ifskip || ifdepth<=ifsd) {
+			if (--ifcount[ifdepth]!=0) uerrc("'#else' unexpected");
+			else ifskip = ifval[ifdepth];
+		}
+		return ppquit();
+	} else if (!strcmp(lastid,"endif")) {
+		if (!ifreldepth) uerrc("'#endif' unexpected");
+		else {
+			ifdepth--, ifreldepth--;
+			if (ifdepth<ifsd) ifskip=0;
+			if (!ifskip) ifskip = ifcount[ifdepth] - ifval[ifdepth];
+		}
+		return ppquit();
+	} else if (ifskip)
+		return ppquit();	// ignore all other preproc directives
+	else if (!strcmp(lastid,"include"))
+#ifdef PCH
+		return doinclude(0);
+#else
+		return doinclude();
+#endif
+#ifdef PCH
+	else if (!strcmp(lastid,"header") || !strcmp(lastid,"headeropt"))
+		return doinclude(lastid[sizeof("header")-1]?-1:1);
+#endif
+	else if (!strcmp(lastid,"define"))
+		return dodefine(1);
+#ifdef MACRO_PPDIR
+	else if (!strcmp(lastid,"macro"))
+		return dodefine(-1);
+#endif
+	else if (!strcmp(lastid,"undef"))
+		return dodefine(0);
+	else if (!strcmp(lastid,"pragma")) {
+		getsym();
+		if (lastst==id && !strcmp(lastid,"lang")) {
+			int not_flag=0;
+			getsym();
+			needpunc(openpa);
+			while (lastst==id || lastst==not) {
+				if (lastst==not) not_flag^=1;
+				else {
+					if (!strcmp(lastid,"ansi")) {
+						if (not_flag) uwarn("'!' ignored"); flags=flags_ansi;
+					} else if (!strcmp(lastid,"gtc")) {
+						if (not_flag) uwarn("'!' ignored"); flags=flags_fullgtc;
+					} else {
+						int opt;
+						if (!strcmp(lastid,"mid_decl")) opt=X_MID_DECL;
+						else if (!strcmp(lastid,"comp_string")) opt=X_COMP_STRING;
+						else if (!strcmp(lastid,"lang_ext")) opt=X_LANG_EXT;
+						else { uwarn("invalid '#pragma'"); break; }
+						if (not_flag) flags &= ~opt;
+						else flags |= opt;
+					}
+					not_flag = 0;
+				}
+				getsym();
+			}
+			if (lastst!=closepa) uerr(ERR_PUNCT,')');
+/*		} else if (!strcmp(lastid,"poison")) {
+			while (1) {
+				getsym();
+				if (*/
+		} else if (lastst==id && !strcmp(lastid,"opt")) {
+			getsym();
+			needpunc(openpa);
+			while (lastst==id) {
+#ifdef SPEED_OPT
+				if (!strcmp(lastid,"speed"))
+					speed_opt_value = 1;
+				else if (!strcmp(lastid,"normal"))
+					speed_opt_value = 0;
+				else if (!strcmp(lastid,"size"))
+					speed_opt_value = -1;
+				else if (!strcmp(lastid,"uberspeed"))
+					speed_opt_value = 3;
+				else
+					uwarn("invalid '#pragma'");
+#endif
+				getsym();
+			}
+			if (lastst!=closepa) uerr(ERR_PUNCT,')');
+		} else uwarn("unknown '#pragma' type");
+		return ppquit();
+	} else if (!strcmp(lastid,"warning")) {
+		uwarn("#warning: %.*s",strlen(lptr)-1,lptr); return ppquit();
+	} else if (!strcmp(lastid,"error")) {
+		uerr(ERR_CUSTOM,lptr); return ppquit();
+	} else {
+		uerrc("preprocessor command expected");
+		return ppquit();
+	}
+}
+
+#ifdef PC
+extern char *incfolders[10];
+extern int incfoldernum;
+#endif
+
+#ifdef PC
+#ifdef _WIN32
+#define DIR_SEPARATOR_STRING "\\"
+#else
+#ifdef UNIXOID
+#define DIR_SEPARATOR_STRING "/"
+#else
+#error Please define a directory separator for your platform.
+#endif
+#endif
+#endif
+
+#ifdef PC
+void verbose_print_searchdirs() {
+	int n=incfoldernum;
+	while (n--)
+		fprintf(stderr,"search directory: '%s'\n",incfolders[n]);
+}
+void verbose_print_include(char *filename) {
+	int i;
+	for (i=0; i<incldepth; i++)
+		fprintf(stderr,"  ");
+	fprintf(stderr,"include file '%s'\n",filename);
+}
+#endif
+FILE *xfopen(char *f,char *m,int sys) {
+	FILE *fp;
+#ifdef PC
+	char b[300];
+	int n=incfoldernum;
+#define xfopen_try(z) do { if ((fp=fopen(z,m))) { if (verbosity&VERBOSITY_PRINT_INCLUDES) verbose_print_include(z); return fp; } } while (0)
+#else
+	char b[50];
+#define xfopen_try(z) do { if ((fp=fopen(z,m))) return fp; } while (0)
+#endif
+	if (!sys) xfopen_try(f);
+#ifdef PC
+	while (n--) {
+		sprintf(b,"%s"DIR_SEPARATOR_STRING"%s",incfolders[n],f);
+		xfopen_try(b);
+	}
+#else
+	sprintf(b,"gtchdr\\%s",f);
+	xfopen_try(b);
+	sprintf(b,"gtc\\%s",f);
+	xfopen_try(b);
+#endif
+	xfopen_try(f);
+	return NULL;
+}
+
+#ifdef GTDEV
+void progr_initforcurfile() {
+#if 0
+	long pos=ftell(input);
+	fseek(input,0,SEEK_END);
+	progr_coeff=(100l<<16)/(int)ftell(input);
+	fseek(input,pos,SEEK_SET);
+#else
+	progr_coeff=(100l<<16)/peek_w(input->base);
+#endif
+	progr_readtonow=0;
+}
+#endif
+int doinclude(
+#ifdef PCH
+		  int pch
+#endif
+			  ) {
+	int rv; char c;
+	strcat(lptr,"  ");
+	skipspace();
+	if ((c=lastch-'"') && c!='<'-'"')
+		goto incl_err;
+	getch();
+	if (!((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z')
+		|| lastch=='_' || lastch=='$' || lastch=='\\'))
+		goto incl_err;
+	getidstr();				/* get file to include, without extension */
+#ifdef PCH
+	if (!pch) {
+#endif
+		inclline[incldepth] = lineno;
+		inclifreldepth[incldepth] = ifreldepth;
+#ifdef GTDEV
+		inclread[incldepth] = progr_readtonow;
+		inclcoeff[incldepth] = progr_coeff;
+#endif
+		inclname[incldepth] = curname;
+		inclfile[incldepth++] = input;	/* push current input file */
+	restart_h:
+		input = xfopen(lastid,"r",c);
+		if (!input) {
+			char *tigcclib_aliases = "all\0alloc\0args\0asmtypes\0assert\0bascmd\0basfunc\0basop\0cert\0compat\0ctype\0default\0dialogs\0dll\0error\0estack\0events\0files\0flash\0float\0gdraw\0graph\0graphing\0gray\0homescr\0intr\0kbd\0limits\0link\0math\0mem\0menus\0nostub\0peekpoke\0printf\0romsymb\0rsa\0setjmp\0sprites\0statline\0stdarg\0stddef\0stdio\0stdlib\0string\0system\0textedit\0timath\0unknown\0values\0vat\0version\0wingraph\0";
+			while (*tigcclib_aliases)
+				if (
+			#ifdef PC
+						!strncmp(lastid,tigcclib_aliases,strlen(tigcclib_aliases)) && !strcmp(lastid+strlen(tigcclib_aliases),".h")
+			#else
+						!strcmp(lastid,tigcclib_aliases)
+			#endif
+				   ) {
+			#ifdef PC
+					strcpy(lastid,"tigcclib.h");
+			#else
+					strcpy(lastid,"tigcclib");
+			#endif
+					goto restart_h;
+				} else {
+					while (*tigcclib_aliases++);
+				}
+//			input = inclfile[--incldepth];
+			uerr(ERR_CANTOPEN,lastid);
+//			_exit(18);
+		}
+		ifreldepth = 0;
+#ifdef GTDEV
+		progr_initforcurfile();
+#endif
+		global_flag++;
+		curname = strsave(lastid);
+		global_flag--;
+#ifdef PCH
+	} else {
+		char b[30];
+#ifdef REQ_MGT
+		int i=pchnum;
+		while (i--)
+			if (!strcmp(lastid,pchname[i]))
+				goto done;
+#endif
+#ifdef PC
+		sprintf(b,"%s.pch",lastid);
+#else
+		sprintf(b,"zheader\\%s",lastid);
+#endif
+		if (!(pchfile[pchnum] = xfopen(b, "rb", c))) {
+			if (pch<0)
+				goto done;
+			uerr(ERR_CANTOPEN,b);
+//			_exit(18);
+		}
+#ifdef REQ_MGT
+		strcpy(pchname[pchnum],lastid);
+		pchrequired[pchnum]=0;
+#endif
+#ifdef PC
+		pchdata[pchnum] = malloc(150000);
+		fread(pchdata[pchnum],1,150000,pchfile[pchnum]);
+		if (w2ul(pchhead[pchnum]->magic)!=
+			((long)'P'<<24)+((long)'C'<<16)+((long)'H'<<8)
+				|| !(pchtab[pchnum] = malloc(w2us(pchhead[pchnum]->nID)))) {
+			fclose(pchfile[pchnum]);
+			goto incl_err;
+		}
+#define w2s(x) ((short)w2us(x))
+#else
+		if (w2ul(((PCH_HEAD *)(pchdata[pchnum] = *(char **)(pchfile[pchnum])))->magic)!=
+			((long)'P'<<24)+((long)'C'<<16)+((long)'H'<<8)
+				|| !(pchtab[pchnum] = malloc((short)pchhead[pchnum]->nID))) {
+			fclose(pchfile[pchnum]);
+			goto incl_err;
+		}
+#define w2s(x) ((short)(x))
+#endif
+		memset(pchtab[pchnum],0,w2s(pchhead[pchnum]->nID));
+		pchnum++;
+	}
+#endif
+done:
+	if (lastch=='.') getch(),getidstr();
+	c=c?'>':'"';
+	if (lastch!=c)
+		uerr(ERR_PUNCT,c);
+	rv = getline(incldepth == 1);
+#ifdef PCH
+	if (!pch)
+#endif
+		lineno = 1; 	   /* dont list include files */
+	return rv;
+incl_err:
+	error(ERR_INCLFILE);
+	return ppquit();
+}
+
+char *litlate(char *s);
+extern int getch_noppdir;
+int dodefine(int mode) {	// 1: #define, -1 : #macro, 0 : #undef
+	SYM *sp,*ds;
+	int n=0,flags=0;
+/*	getsym();*/
+	skipspace();
+	if ((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z')
+		|| lastch=='_' || lastch=='$') {
+		getidstr();				/* get past #define */
+	} else {
+		error(ERR_DEFINE);
+		return ppquit();
+	}
+	if (!mode) {
+		if (!symremove(lastid,&defsyms))	/* if we didn't unload anything, let's */
+			pchsearch(lastid,PCHS_UNLOAD);	/*  try and unload the symbol */
+		return ppquit();
+	}
+#ifdef AS
+	if (!strcmp(lastid,"NOSTUB"))
+		nostub_mode=1;
+#endif
+#ifdef ASM
+	if (asm_isreserved())
+		flags|=PPSYM_ASM_KEYWORD;
+	if (asm_flag)
+		flags|=PPSYM_DEFINED_IN_ASM;
+#endif
+	++global_flag;			/* always do #define as globals */
+	sp = (SYM *)xalloc((int)sizeof(SYM), _SYM+DODEFINE);
+	sp->name = strsave(lastid);
+	sp->storage_class = sc_define;
+	if (lastch=='(') {
+		TABLE *tp;
+/*		if (lineid==0x1A)
+			bkpt();*/
+		sp->tp=(TYP *)(tp=(TABLE *)xalloc((int)sizeof(TABLE), _TABLE+DODEFINE));
+#ifdef NO_CALLOC
+		tp->hash=0;
+		tp->head=tp->tail=NULL;
+#endif
+		getsym();
+		getsym();
+		if (lastst!=closepa) {
+			while (1) {
+				SYM *arg;
+				n++;
+				if (lastst!=id) error(ERR_IDEXPECT);
+				else {
+					arg=(SYM *)xalloc((int)sizeof(SYM), _SYM+DODEFINE);
+					arg->name=strsave(lastid);
+#ifdef NO_CALLOC
+					arg->tp=NULL;
+#endif
+					insert(arg,(HTABLE *)tp);
+				}
+				getsym();
+				if (lastst!=comma) break;
+				getsym();
+			}
+			if (lastst==dots) { sp->storage_class = sc_vamac; getsym(); }
+			if (lastst!=closepa) needpunc(closepa);
+		}
+		if (!isspace(lastch))	// undo last getch()...
+			lptr--;
+#ifdef NO_CALLOC
+	} else {
+		sp->tp=NULL;
+#endif
+	}
+#ifdef MACRO_PPDIR
+	if (mode<0) {
+		char *s=(char *)alloca(500),*p=s;
+		int n=499;
+		getch_noppdir++;
+		do {
+			if (getch()<0) error(ERR_DEFINE);
+			*p++=(/*lastch=='\n'?'\r':*/lastch);
+		} while (n-- && (lastch!='#' || *lptr!='e' || strncmp(lptr+1,"ndm",3)));
+		getch_noppdir--;
+		if (n<=0) error(ERR_DEFINE);
+		p-=2; // remove '\n' '#'
+		*p++=0;
+		n = p-s;
+		p = (char *)xalloc(n, STR);
+		memcpy(p,s,n);
+		sp->value.s=p;
+	} else
+#endif
+	if (strlen(lptr)>1500)
+		uerrsys("definition too long (1500 characters max)");
+	if (!(sp->value.s = litlate(lptr)))
+		uerrc("unbalanced quotes in #define");
+#ifdef FLINE_RC
+	if (!strcmp(sp->name,"USE_FLINE_ROM_CALLS"))
+		fline_rc=1;
+#endif
+	if ((ds=search(sp->name,-1,&defsyms))) {
+		if (strcmp(sp->value.s,ds->value.s))
+			uwarn("redefinition of macro '%s'",sp->name);
+		symremove(sp->name,&defsyms);
+	}
+	insert(sp,&defsyms);
+	sp->used=n+flags;
+	--global_flag;
+	return ppquit();
+}
+
+// x = result of the test (1 : true, 0 : false, -1 : ignore all branches)
+// c = is it a #if ? (rather than a #elif)
+int doif(int x,int c) {
+	if ((ifreldepth+=c,ifdepth+=c)>MAX_IF_DEPTH) uerrc("too many imbricated '#if's");
+	else if (!ifreldepth) uerrc("'#elif' unexpected");
+	else if (!ifskip || ifdepth<=ifsd) {
+		ifsd=ifdepth;
+		if (c)
+			ifhas[ifdepth] = x;
+		else
+			ifhas[ifdepth] |= x;
+		ifskip = (ifval[ifdepth] = x) - (ifcount[ifdepth] = 1);
+	}
+	if (x<0) {
+		ifhas[ifdepth] = x;
+		ifskip = x;
+	}
+	return ppquit();
+}
+// vim:ts=4:sw=4

+ 329 - 0
gtc/src/protos.h

@@ -0,0 +1,329 @@
+// Auto-generated file, do not edit!
+
+#ifndef PROTOS_H_
+#define PROTOS_H_
+
+enum OptionModes;
+enum e_am;
+enum e_bt;
+enum e_node;
+enum e_op;
+enum e_sc;
+enum e_sym;
+struct _regsimg;
+struct _stackimg;
+struct amode;
+struct bcd;
+struct blk;
+struct cse;
+struct enode;
+struct hstab;
+struct ocode;
+struct snode;
+struct stab;
+struct sym;
+struct typ;
+
+struct typ *shiftop(struct enode **node);
+void local_clean(void);	/* remove local symbols from alsyms -- to be called just before rel_local */
+void g_label(unsigned int labno);
+struct snode *casestmt(void);
+void compile(void);
+void dump_endnode();
+int blk_free(struct blk *bp1);
+int complexity(struct enode *ep);
+void check_table(struct hstab *table);
+struct typ *nameref(struct enode **node);
+int en_dir_cost(struct enode *ep);
+void extscan(unsigned char *ext);
+void genstorage(struct sym *sp, int align);
+void freeregs(struct _regsimg *img);	/* used by g_fcall */
+struct amode *mk_immed(long i);
+char *litlate(char *s);
+struct snode *forstmt(void);
+struct amode *g_xmul(struct enode *node, int flags, enum(e_op) op);
+struct enode *mk_icon(long i);
+void getsym();
+struct typ *equalops(struct enode **node);
+void genfunc(struct snode *stmt);
+struct typ *copy_type(struct typ *s);
+void repcse(struct snode *block);
+int internal(char *s);
+void genbyte(int val);
+struct typ *bitor(struct enode **node);
+void fill(int n);
+void scan(struct snode *block);
+struct snode *retstmt(void);
+void out_init();
+void _scr_main();
+void add_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2, int line);
+char *create_ti_file(int calc,int tigl_type,char *name,char *folder,char *content,unsigned long content_size,unsigned long *ti_file_size);
+long intexpr();
+int bitwise_reduction(unsigned long x,int *size);
+void double2bcd(double d,struct bcd *bcd);
+struct amode *g_aslogic(struct enode *node, int flags, enum(e_op) op);
+long auto_init(long offs,struct typ *typ,struct typ **tpp,int brace_level,int offmod,int stroff);
+void initstack();
+void falsejp(struct enode *node, unsigned int lab);
+int getch();
+int doif(int x,int c);
+void temp_inv(void);
+long inittype(struct typ *tp,struct typ **tpp);
+void do_warning(char *s, ...);
+struct typ *forcefit(struct enode **node1, struct typ *tp1, struct enode **node2, struct typ *tp2);
+void collect(int g);
+int movem(short x);
+void g_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2);
+struct enode *parmlist(struct sym *f);
+int isbyte(struct enode *node);
+void clean_up();
+void getrawid();
+struct typ *deref(struct enode **node, struct typ *tp);
+long strip_icon(long i, enum(e_bt) type);
+void genword(int val);
+int getid(int c);
+void d_snode(struct snode **node);
+struct snode *exprstmt(void);
+struct typ *relation(struct enode **node);
+int integral(struct typ *tp);
+void g_bitmancode(enum(e_op) op,int size,struct amode *ap1,struct amode *ap2);
+struct amode *g_offset(struct amode *ap, int off);
+struct amode *as_fcall(struct enode *node, int flags, char *libname);
+struct snode *contstmt(void);
+int vcg_init();
+long push_param(struct enode *ep);
+int label(char *s);
+struct amode *get_asmparam();
+struct amode *g_fderef(struct enode *node, struct amode *ap0, int flags);
+int req_all_aregs(struct enode *plist,int rp_dn,int rp_an);
+void genstmt(struct snode *stmt);
+int vcg_cost();
+void useregs(struct _regsimg *img);	/* used by g_fcall */
+char *strend(char *s);
+TI_SHORT process_attr();
+void dump_genfunc(struct snode *stmt);
+void getidstr();
+int stringlit(char *s, int len);
+void ds_free(void);
+void scope_init(void);
+void verbose_print_include(char *filename);
+void tmp_use();
+struct sym *symremove(char *na, struct hstab *tab);
+struct sym *search(char *na, int crc, struct hstab *tab);
+void add_label(int lab);
+void dump_startline();
+struct typ *cond_deref(struct enode **node, struct typ *tp);
+struct amode *temp_addr(void);
+struct amode *g_cast2(struct enode *ep, enum(e_bt) typ2, int flags);
+void get_offset(struct amode *ap);
+void scanexpr(struct enode *node, int duse);
+void progr_initforcurfile();
+void move_pos(long diff);	/* caution : only works in overwrite mode */
+void dump_newnode(char *name);
+void fatal(char *message);
+int arsearch(int r,struct ocode *ip);
+void usestack(struct _stackimg *img);	/* used by g_expr::en_compound */
+struct typ *bitand(struct enode **node);
+FILE *xfopen(char *f,char *m,int sys);
+int tst_const(struct enode *node);
+long mod_mask(long i);
+struct amode *mk_strlab(char *s);
+void concat(struct stab *dest,struct stab *src);
+struct amode *temp_data(void);
+void rel_dualstack(void);
+int pwrof2(long i);
+void hashinit(struct hstab *t);
+int eq_type(struct typ *tp1, struct typ *tp2);
+void dodecl(enum(e_sc) defclass);
+struct snode *gotostmt(void);
+void g_coder(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2);
+struct typ *expression(struct enode **node);
+struct snode *breakstmt(void);
+int has_autocon(struct enode *ep);
+struct snode *dostmt(void);
+char *strsave(char *s);
+void opt_compare(struct enode *node);
+struct amode *g_asmod(struct enode *node, int flags);
+int hexatoi(char *s);
+struct ocode *new_code(int s);
+void d_amode(struct amode **node);
+int getline(int listflag);
+void call_library(char *lib_name);
+unsigned long _w2ul(TI_LONG *x);
+int asm_isreserved();
+void dooper(struct enode **node);
+short count_dn_an(struct enode *plist,int rp_dn,int rp_an);
+struct amode *g_compound(struct snode *st, int flags);
+void repexpr(struct enode *node);
+void initpch();
+void genfloat(double val);
+void asm_searchkw();
+struct amode *g_deref(struct enode *node, enum(e_bt) type, int flags, long size);
+int free_data(void);
+int indir_num(struct typ *tp);
+int _getline(int listflag,char *base);
+struct typ *asnop(struct enode **node);
+struct amode *g_fcall(struct enode *node, int flags);
+void warn_usr(char *s,...);
+int tst_ushort(struct enode *node);
+void scope_flush(void);
+void rewrite(long size);
+struct amode *g_aincdec(struct enode *node, int flags, enum(e_op) op);
+void funcbottom(void);
+struct typ *bitxor(struct enode **node);
+struct amode *g_addsub(struct enode *node, int flags, enum(e_op) op);
+struct snode *statement(void);
+void searchkw(void);
+void opt0(struct enode **node);
+void decl(struct hstab *table);		/* table is used only for enum members */
+struct amode *g_index(struct enode *node);
+void g_strlab(char *s);
+struct enode *copynode(struct enode *node);
+void expand_do(char *q,int len,char *in,char *inbound,int need_ds_update);
+unsigned int getconst(enum(e_sym) s,enum(e_sym) e);
+void opt1(struct snode *block);
+long intexpr_notemp();
+int getasm_main();
+unsigned short _w2us(TI_SHORT *x);
+struct amode *g_div(struct enode *node, int flags);
+struct amode *mk_offset(struct enode *node);
+unsigned long desire(struct cse *csp);
+int equalnode(struct enode *node1, struct enode *node2);
+void funcbody(struct sym *sp, char *names[], int nparms);
+struct amode *g_commute(void *func,struct enode *node,int flags,enum(e_op) op,int dummy/*void *reversal*/);
+void add_peep(struct ocode *new_ocode);
+struct snode *ifstmt(void);
+void locate(void);
+void allocate(void);
+size_t option_parse(size_t listc,char **listv,enum(OptionModes) ex_mode);
+void opt3(void);
+long auto_pad(long offs,int len,int offmod);
+struct amode *g_asxor(struct enode *node, int flags);
+void truejp(struct enode *node, unsigned int lab);
+void opt4(struct enode **node);
+void macro_expansion(char *in,char *inbound,int need_ds_update);
+void insert(struct sym *sp,struct hstab *table);
+void dumplits();
+struct amode *g_asdiv(struct enode *node, int flags);
+struct amode *g_mod(struct enode *node, int flags);
+struct amode *copy_addr(struct amode *ap);
+int equal_address(struct amode *ap1, struct amode *ap2);
+void gendouble(double val);
+struct typ *commaop(struct enode **node);
+void swap_nodes(struct enode *node);
+int preprocess();
+void dump_addstr(char *name,char *v);
+struct amode *g_alloca(struct enode *node);
+struct snode *whilestmt(void);
+struct amode *mk_rmask(unsigned int mask);
+struct amode *mk_reg(int r);
+void do_compile();
+void bitwise_optimize(struct enode *ep,long mode);
+void out_close();
+unsigned int getconst2(enum(e_sym) e);
+struct amode *func_result(int flags, long bytes);
+struct amode *g_cast(struct amode *ap, enum(e_bt) typ1, enum(e_bt) typ2, int flags);
+struct amode *g_asmul(struct enode *node, int flags);
+int start_block(int m);	// used in block() (func.c)
+void error(int n);
+void ds_allocatleast(unsigned int size);
+struct typ *forceft2(struct enode **node1, struct typ *tp1, struct enode **node2, struct typ *tp2);
+char *type_str(struct typ *tp);
+struct amode *mk_label(unsigned int lab);
+struct snode *loopstmt(void);
+void asm_getsym();
+void d_ocodes(void);
+void extload(unsigned char *ext);
+void initsym();
+struct amode *g_shift(struct enode *node, int flags, enum(e_op) op);
+void block(struct sym *sp); /* CAUTION : always requires a compound_done() after call */
+struct amode *g_ybin(struct enode *node, int flags, enum(e_op) op);
+struct sym *gsearch(char *na,int crc);
+int cast_ok(struct typ *tp1, struct typ *tp2, int need_physically_compatible);
+void needpunc(enum(e_sym) p);
+struct amode *mk_scratch(long size);
+void dump_genstmt(struct snode *stmt);
+void d_enode(struct enode **node);
+int ap_hasbeenpushed(struct amode *ap);
+struct amode *g_unary(struct enode *node, int flags, enum(e_op) op);
+void append(struct sym **ptr_sp, struct hstab *table);
+void checkstack(void);
+void rel_global();
+void option_parse_all(enum(OptionModes) ex_mode);
+int pchload(char *name,char *data,unsigned int flags,unsigned char *tabp, unsigned char *p0,TI_SHORT *extTab);
+void my_fclose(FILE *f);
+struct typ *andop(struct enode **node);
+struct amode *g_expr(struct enode *node, int flags);
+struct amode *g_assign(struct enode *node, int flags);
+void rel_local();
+struct sym *mk_int(char *name);
+struct snode *asmstmt(void);
+unsigned long double2ffp(double d);
+void decl1(void);
+struct typ *orop(struct enode **node);
+int alignment(struct typ *tp);
+struct amode *g_asshift(struct enode *node, int flags, enum(e_op) op);
+void closepch();
+void castback(long offset, struct typ *tp1, struct typ *tp2);
+void dump_addreg(char *name,int v);
+double floatexpr();
+void freeop(struct amode *ap);
+void err_usr(int m,...);
+struct typ *cast_op(struct enode **ep, struct typ *tp1, struct typ *tp2);
+struct amode *g_asadd(struct enode *node, int flags, enum(e_op) op);
+int tst_short(struct enode *node);
+struct typ *mk_type(enum(e_bt) bt, int siz);
+struct enode *mk_node(enum(e_node) nt, struct enode *v1, struct enode *v2);
+void _repexpr(struct enode **ep);
+struct typ *binlog(struct enode **node, struct typ *(*xfunc)(), enum(e_node) nt, enum(e_sym) sy);
+struct amode *func_result2(int flags, long bytes, int reg);
+struct typ *force_cast_op(struct enode **ep, struct typ *tp1, struct typ *tp2);
+void _exit(int code);
+struct amode *g_mul(struct enode *node, int flags);
+void tmp_free();
+struct snode *switchstmt(void);
+void g_pop(int reg, enum(e_am) rmode, int number);
+struct snode *compound(int no_init);
+int isshort(struct enode *node);
+void flush_peep();
+void put_label(int lab);
+int not_lvalue(struct enode *node);
+struct amode *mk_smask(unsigned int mask);
+int datalit(char *s, int len);
+void verbose_print_searchdirs();
+void structassign(struct amode *ap1, struct amode *ap2, long size, int mode);
+int pchsearch(char *id,int mode);	/* returns 0 if not PCH, 1 if PCH/def, -1 if PCH/init */
+struct snode *labelstmt(void);
+int getsch(int flag);
+struct amode *g_xbin(struct enode *node, int flags, enum(e_op) op);
+void genfuncbegin(void);
+int crcN(char *na);
+struct typ *binop(struct enode **node, struct typ *(*xfunc)(), enum(e_node) nt, enum (e_sym) sy);
+void bsort(struct cse **list);
+int macro_expand(char *id,int crc/* may equal -1 */,char *in,char *oldin,char *inbound,int need_ds_update);
+void g_push(int reg, enum(e_am) rmode, int number);
+int checkcases(struct snode *head);
+struct amode *g_hook(struct enode *node, int flags);
+void insert_macros(char *p);
+struct typ *exprnc(struct enode **node);
+void genptr(struct enode *node);
+int *_xalloc(int siz);
+int castbegin(enum(e_sym) st);
+void skipspace();
+int ppquit();
+void dump_addint(char *name,int v);
+void validate(struct amode *ap);
+int radix36(char c);
+struct amode *mk_legal(struct amode *ap, int flags, long size);
+struct typ *copy_type_global(struct typ *tp);
+void freestack(struct _stackimg *img);	/* used by g_expr::en_compound */
+char *fill_calcvar(char *buffer, char *input);
+int getcache(enum(e_sym) f);
+int vcg_done();
+void put_align2(void);
+int dodefine(int mode);	// 1: #define, -1 : #macro, 0 : #undef
+int drsearch(int r,struct ocode *ip);
+struct typ *conditional(struct enode **node);
+void doinit(struct sym *sp, int align);
+
+#endif

+ 446 - 0
gtc/src/reg68k.c

@@ -0,0 +1,446 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * register allocation
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+/*
+ * Register allocation (for the expression evaluation)
+ * This modules handles the management of scratch registers.
+ * It keeps track of the allocated registers and of the stack
+ */
+
+#ifdef MC680X0
+
+xstatic int		next_data CGLOB, next_addr CGLOB;
+
+#ifndef INFINITE_REGISTERS
+xstatic char		dreg_in_use[MAX_DATA + 1] CGLOBL;
+xstatic char		areg_in_use[MAX_ADDR + 1] CGLOBL;
+
+xstatic struct reg_struct	reg_stack[MAX_REG_STACK + 1] CGLOBL,
+							reg_alloc[MAX_REG_STACK + 1] CGLOBL;
+
+xstatic int		reg_stack_ptr CGLOB;
+xstatic int		reg_alloc_ptr CGLOB;
+#endif
+
+void g_push(int reg, enum(e_am) rmode, int number) {
+#ifndef INFINITE_REGISTERS
+/*
+ * this routine generates code to push a register onto the stack
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_PUSH);
+	ap->preg = reg;
+	ap->mode = rmode;
+	g_code(op_move, 4, ap, push_am);
+	reg_stack[reg_stack_ptr].mode = rmode;
+	reg_stack[reg_stack_ptr].reg = reg;
+	reg_stack[reg_stack_ptr].flag = number;
+	if (reg_alloc[number].flag)
+		ierr(G_PUSH,1);
+	reg_alloc[number].flag = 1;
+	/* check on stack overflow */
+	if (++reg_stack_ptr > MAX_REG_STACK)
+		ierr(G_PUSH,2);
+#else
+	fatal("GPUSH/infinite");
+#endif
+}
+
+void g_pop(int reg, enum(e_am) rmode, int number) {
+#ifndef INFINITE_REGISTERS
+/*
+ * generate code to pop a register from the stack.
+ */
+	struct amode   *ap;
+
+	/* check on stack underflow */
+	if (reg_stack_ptr-- == 0)
+		ierr(G_POP,1);
+	/* check if the desired register really is on stack */
+	if (reg_stack[reg_stack_ptr].flag != number)
+		ierr(G_POP,2);
+	/* check if the register which is restored is really void */
+	if (rmode == am_dreg) {
+		if (dreg_in_use[reg] >= 0)
+			ierr(G_POP,3);
+		dreg_in_use[reg] = number;
+	} else {
+		if (areg_in_use[reg] >= 0)
+			ierr(G_POP,4);
+		areg_in_use[reg] = number;
+	}
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_PUSH);
+	ap->mode = rmode;
+	ap->preg = reg;
+	g_code(op_move, 4, pop_am, ap);
+	/* clear the push_flag */
+	reg_alloc[number].flag = 0;
+#endif
+}
+
+void initstack() {
+/*
+ * this routine should be called before each expression is evaluated to make
+ * sure the stack is balanced and all of the registers are marked free.
+ * This is also a good place to free all 'pseudo' registers in the
+ * stack frame by setting act_scratch to zero
+ */
+#ifndef INFINITE_REGISTERS
+	int 			i;
+	next_data = 0;
+	next_addr = 0;
+	for (i = 0; i <= MAX_DATA; i++)
+		dreg_in_use[i] = -1;
+	for (i = 0; i <= MAX_ADDR; i++)
+		areg_in_use[i] = -1;
+	reg_stack_ptr = 0;
+	reg_alloc_ptr = 0;
+#else
+	next_data = FIRSTREG;
+	next_addr = FIRSTREG;
+#endif
+	act_scratch = 0;
+}
+
+//#if 0
+#ifndef __HAVE_STACK_IMAGE
+#define __HAVE_STACK_IMAGE
+typedef struct _stackimg {
+	int next_data,next_addr;
+#ifndef INFINITE_REGISTERS
+	int reg_alloc_ptr,reg_stack_ptr;
+	char dreg_in_use[MAX_DATA+1];
+	char areg_in_use[MAX_ADDR+1];
+	struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1];
+	int act_scratch;
+#endif
+} STACK_IMAGE;
+#endif
+void usestack(STACK_IMAGE *img) {	/* used by g_expr::en_compound */
+	img->next_data = next_data;
+	img->next_addr = next_addr;
+#ifndef INFINITE_REGISTERS
+	img->act_scratch = act_scratch;
+	img->reg_alloc_ptr = reg_alloc_ptr;
+	img->reg_stack_ptr = reg_stack_ptr;
+	memcpy(img->dreg_in_use, dreg_in_use, MAX_DATA+1);
+	memcpy(img->areg_in_use, areg_in_use, MAX_ADDR+1);
+	memcpy(img->reg_stack, reg_stack, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
+	memcpy(img->reg_alloc, reg_alloc, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
+#endif
+}
+void freestack(STACK_IMAGE *img) {	/* used by g_expr::en_compound */
+	next_data = img->next_data;
+	next_addr = img->next_addr;
+#ifndef INFINITE_REGISTERS
+	act_scratch = img->act_scratch;
+	reg_alloc_ptr = img->reg_alloc_ptr;
+	reg_stack_ptr = img->reg_stack_ptr;
+	memcpy(dreg_in_use, img->dreg_in_use, MAX_DATA+1);
+	memcpy(areg_in_use, img->areg_in_use, MAX_ADDR+1);
+	memcpy(reg_stack, img->reg_stack, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
+	memcpy(reg_alloc, img->reg_alloc, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
+#endif
+}
+//#endif
+
+#ifdef REGPARM
+#ifndef __HAVE_REGS_IMAGE
+#define __HAVE_REGS_IMAGE
+typedef struct _regsimg {
+#ifndef INFINITE_REGISTERS
+	int reg_alloc_ptr,reg_stack_ptr;
+	int next_data,next_addr;
+#endif
+} REGS_IMAGE;
+#endif
+void useregs(REGS_IMAGE *img) {	/* used by g_fcall */
+#ifndef INFINITE_REGISTERS
+	img->reg_alloc_ptr = reg_alloc_ptr;
+	img->reg_stack_ptr = reg_stack_ptr;
+	img->next_data = next_data;
+	img->next_addr = next_addr;
+	next_data = 0;
+	next_addr = 0;
+#endif
+}
+void freeregs(REGS_IMAGE *img) {	/* used by g_fcall */
+#ifndef INFINITE_REGISTERS
+	int i;
+	for (i = 0; i <= MAX_DATA; i++)
+		dreg_in_use[i] = -1;
+	for (i = 0; i <= MAX_ADDR; i++)
+		areg_in_use[i] = -1;
+	reg_alloc_ptr = img->reg_alloc_ptr;
+	reg_stack_ptr = img->reg_stack_ptr;
+	next_data = img->next_data;
+	next_addr = img->next_addr;
+#endif
+}
+#endif
+
+#ifdef PC
+void checkstack(void) {
+#ifndef INFINITE_REGISTERS
+/*
+ * this routines checks if all allocated registers were freed
+ */
+		int i;
+	for (i=0; i<= MAX_DATA; i++)
+		if (dreg_in_use[i] != -1)
+			ierr(CHECKSTACK,1);
+	for (i=0; i<= MAX_ADDR; i++)
+		if (areg_in_use[i] != -1)
+			ierr(CHECKSTACK,2);
+	if (reg_stack_ptr != 0)
+		ierr(CHECKSTACK,5);
+	if (reg_alloc_ptr != 0)
+		ierr(CHECKSTACK,6);
+#endif
+	if (next_data != FIRSTREG)
+		ierr(CHECKSTACK,3);
+	if (next_addr != FIRSTREG)
+		ierr(CHECKSTACK,4);
+}
+#endif
+
+int ap_hasbeenpushed(struct amode *ap) {
+#ifndef INFINITE_REGISTERS
+	return reg_alloc[(int)(ap)->deep].flag;
+#else
+	return 0;
+#endif
+}
+
+void validate(struct amode *ap) {
+#ifndef INFINITE_REGISTERS
+/*
+ * validate will make sure that if a register within an address mode has been
+ * pushed onto the stack that it is popped back at this time.
+ */
+	switch (ap->mode) {
+	  case am_dreg:
+		if (ap->preg <= MAX_DATA && reg_alloc[(int)ap->deep].flag) {
+			g_pop(ap->preg, am_dreg, (int) ap->deep);
+		}
+		break;
+	  case am_indx2:
+		if (ap->sreg <= MAX_DATA && reg_alloc[(int)ap->deep].flag) {
+			g_pop(ap->sreg, am_dreg, (int) ap->deep);
+		}
+		goto common;
+	  case am_indx3:
+		if (ap->sreg <= MAX_ADDR && reg_alloc[(int)ap->deep].flag) {
+			g_pop(ap->sreg, am_areg, (int) ap->deep);
+		}
+		goto common;
+	  case am_areg:
+	  case am_ind:
+	  case am_indx:
+	  case am_ainc:
+	  case am_adec:
+common:
+		if (ap->preg <= MAX_ADDR && reg_alloc[(int)ap->deep].flag) {
+			g_pop(ap->preg, am_areg, (int) ap->deep);
+		}
+		break;
+	}
+#endif
+}
+
+struct amode *temp_data(void) {
+/*
+ * allocate a temporary data register and return it's addressing mode.
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+TEMP_DATA);
+#ifndef INFINITE_REGISTERS
+	if (dreg_in_use[next_data] >= 0)
+		/*
+		 * The next available register is already in use. it must be pushed
+		 */
+		g_push(next_data, am_dreg, dreg_in_use[next_data]);
+	dreg_in_use[next_data] = reg_alloc_ptr;
+#endif
+	ap->mode = am_dreg;
+	ap->preg = next_data;
+#ifndef INFINITE_REGISTERS
+	ap->deep = reg_alloc_ptr;
+	reg_alloc[reg_alloc_ptr].reg = next_data;
+	reg_alloc[reg_alloc_ptr].mode = am_dreg;
+	reg_alloc[reg_alloc_ptr].flag = 0;
+	if (next_data++ == MAX_DATA)
+		next_data = 0;			/* wrap around */
+	if (reg_alloc_ptr++ == MAX_REG_STACK)
+		ierr(TEMP_DATA,1);
+#else
+	next_data++;
+#endif
+	return ap;
+}
+
+struct amode *temp_addr(void) {
+/*
+ * allocate a temporary addr register and return it's addressing mode.
+ */
+	struct amode   *ap;
+	ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+TEMP_ADDR);
+#ifndef INFINITE_REGISTERS
+	if (areg_in_use[next_addr] >= 0)
+		/*
+		 * The next available register is already in use. it must be pushed
+		 */
+		g_push(next_addr, am_areg, areg_in_use[next_addr]);
+	areg_in_use[next_addr] = reg_alloc_ptr;
+#endif
+	ap->mode = am_areg;
+	ap->preg = next_addr;
+#ifndef INFINITE_REGISTERS
+	ap->deep = reg_alloc_ptr;
+	reg_alloc[reg_alloc_ptr].reg = next_addr;
+	reg_alloc[reg_alloc_ptr].mode = am_areg;
+	reg_alloc[reg_alloc_ptr].flag = 0;
+	if (next_addr++ == MAX_ADDR)
+		next_addr = 0;			/* wrap around */
+	if (reg_alloc_ptr++ == MAX_REG_STACK)
+		ierr(TEMP_ADDR,1);
+#else
+	next_addr++;
+#endif
+	return ap;
+}
+
+int free_data(void) {
+/*
+ * returns TRUE if a data register is available at ,,no cost'' (no push).
+ * Used to determine e.g. wether cmp.w #0,An or move.l An,Dm is better
+ */
+#ifndef INFINITE_REGISTERS
+	return (dreg_in_use[next_data] < 0);
+#else
+	return 1;
+#endif
+}
+
+void freeop(struct amode *ap) {
+/*
+ * release any temporary registers used in an addressing mode.
+ */
+	int 			number;
+	if (ap == 0)
+		/* This can happen freeing a NOVALUE result */
+		return;
+	switch (ap->mode) {
+	  case am_dreg:
+		if (ap->preg <= MAX_DATA) {
+			if (next_data-- == 0)
+				next_data = MAX_DATA;
+#ifndef INFINITE_REGISTERS
+			number = dreg_in_use[(int)ap->preg];
+			dreg_in_use[(int)ap->preg] = -1;
+#endif
+			break;
+		}
+		return;
+	  case am_indx2:
+		if (ap->sreg <= MAX_DATA) {
+			if (next_data-- == 0)
+				next_data = MAX_DATA;
+#ifndef INFINITE_REGISTERS
+			number = dreg_in_use[(int)ap->sreg];
+			dreg_in_use[(int)ap->sreg] = -1;
+#endif
+			break;
+		}
+		goto common;
+	  case am_indx3:
+		if (ap->sreg <= MAX_ADDR) {
+			if (next_addr-- == 0)
+				next_addr = MAX_ADDR;
+#ifndef INFINITE_REGISTERS
+			number = areg_in_use[(int)ap->sreg];
+			areg_in_use[(int)ap->sreg] = -1;
+#endif
+			break;
+		}
+		goto common;
+	  case am_areg:
+	  case am_ind:
+	  case am_indx:
+	  case am_ainc:
+	  case am_adec:
+common:
+		if (ap->preg <= MAX_ADDR) {
+			if (next_addr-- == 0)
+				next_addr = MAX_ADDR;
+#ifndef INFINITE_REGISTERS
+			number = areg_in_use[(int)ap->preg];
+			areg_in_use[(int)ap->preg] = -1;
+#endif
+			break;
+		}
+		return;
+	  default:
+		return;
+	}
+#ifndef INFINITE_REGISTERS
+	/* some consistency checks */
+	if (number != ap->deep)
+		ierr(FREEOP,1);
+	/* we should only free the most recently allocated register */
+	if (reg_alloc_ptr-- == 0)
+		ierr(FREEOP,2);
+	if (reg_alloc_ptr != number)
+		ierr(FREEOP,3);
+	/* the just freed register should not be on stack */
+	if (reg_alloc[number].flag)
+		ierr(FREEOP,4);
+#endif
+}
+
+void temp_inv(void) {
+#ifndef INFINITE_REGISTERS
+/*
+ * push any used temporary registers.
+ * This is necessary across function calls
+ * The reason for this hacking is actually that temp_inv should dump
+ * the registers in the correct order,
+ * the least recently allocated register first.
+ * the most recently allocated register last.
+ */
+	int 			i;
+
+	for (i = 0; i < reg_alloc_ptr; i++)
+		if (reg_alloc[i].flag == 0) {
+			g_push(reg_alloc[i].reg, reg_alloc[i].mode, i);
+			/* mark the register void */
+			if (reg_alloc[i].mode == am_dreg)
+				dreg_in_use[reg_alloc[i].reg] = -1;
+			else
+				areg_in_use[reg_alloc[i].reg] = -1;
+		}
+#else
+	g_code(_op_cleanup_for_external_call, 0, NIL_AMODE, NIL_AMODE);
+#endif
+}
+#endif /* MC680X0 */
+// vim:ts=4:sw=4

+ 182 - 0
gtc/src/searchkw.c

@@ -0,0 +1,182 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * keyword searching
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+xstatic readonly struct kwblk {
+	char		   *word;
+	enum(e_sym)		stype;
+#ifndef PC
+	int pad;
+#endif
+}				keywords[] = {
+	{
+		"__asm__", kw_asm
+	}, {
+		"__attribute__", kw_attr
+	}, {
+		"__builtin_constant_p", kwb_constant_p
+	}, {
+		"__c__", kw_c
+	}, {
+		"__count__", kw_count
+	}, {
+		"__eval__", kw_eval
+	}, {
+		"__loop__", kw_loop
+	}, {
+		"__softcast__", kw_softcast
+	}, {
+		"__until__", kw_until
+	}, {
+		"alloca", kw_alloca
+	}, {
+		"asm", kw_asm
+	}, {
+		"auto", kw_auto
+	}, {
+		"break", kw_break
+	}, {
+		"case", kw_case
+	}, {
+		"char", kw_char
+	}, {
+		"const", kw_const
+	}, {
+		"continue", kw_continue
+	}, {
+		"default", kw_default
+	}, {
+		"defined", kw_defined
+	}, {
+		"do", kw_do
+	}, {
+		"double", kw_double
+	}, {
+		"else", kw_else
+	}, {
+		"enum", kw_enum
+	}, {
+		"extern", kw_extern
+	}, {
+		"float", kw_float
+	}, {
+		"for", kw_for
+	}, {
+		"goto", kw_goto
+	}, {
+		"if", kw_if
+	}, {
+		"incbin", kw_incbin
+	}, {
+		"int", kw_int
+	}, {
+		"long", kw_long
+	}, {
+		"loop", kw_loop
+	}, {
+		"register", kw_register
+	}, {
+		"return", kw_return
+	}, {
+		"short", kw_short
+	}, {
+		"signed", kw_signed
+	}, {
+		"sizeof", kw_sizeof
+	}, {
+		"static", kw_static
+	}, {
+		"struct", kw_struct
+	}, {
+		"switch", kw_switch
+	}, {
+		"typedef", kw_typedef
+	}, {
+		"typeof", kw_typeof
+	}, {
+		"union", kw_union
+	}, {
+		"unsigned", kw_unsigned
+	}, {
+		"until", kw_until
+	}, {
+		"void", kw_void
+	}, {
+		"volatile", kw_volatile
+	}, {
+		"while", kw_while
+/*	}, {
+		0, 0*/
+	}
+};
+
+#define kw_N 48
+
+/*
+ * Dichotomic search allows a max of 6 comparisons instead of 50...
+ */
+void searchkw(void) {
+	char *s1,*s2,c;
+	const struct kwblk *kwbp;
+	int a=0,b=kw_N-1,m;
+#ifdef PC
+	if (sizeof(keywords)/sizeof(struct kwblk)!=kw_N)
+		fatal("BUILD ERROR: INVALID KEYWORDS #");
+#endif
+	while (a<=b) {
+		m=(a+b)>>1;
+		kwbp=&keywords[m];
+		s1=lastid;
+		s2=kwbp->word;
+		do {
+			if (!(c=*s2++)) {
+				if (!*s1)
+					lastst = kwbp->stype;
+				if (is_lang_ext(lastst) && lastid[0]!='_' && !(flags&X_LANG_EXT))
+					lastst = id;
+				if (*s1!='u')	// the only case when a kw is the beginning of another one
+					return;		// is 'do' vs 'double'
+			}
+		} while (*s1++==c);
+		if (s1[-1]<c)	// il faut aller plus haut
+			b=m-1;
+		else a=m+1;
+	}
+}
+/*searchkw() // non-dichotomic version
+{
+	char *s1,*s2,c;
+	struct kwblk *kwbp;
+	kwbp = keywords;
+	while (kwbp->word != 0) {
+		s1 = lastid;
+		s2 = kwbp->word;
+		kwbp++;
+		do {
+			if (!(c=*s2++)) {
+				if (!*s1++)
+					lastst = (--kwbp)->stype;
+				return;
+			}
+		} while (*s1++==c);
+	}
+}*/
+// vim:ts=4:sw=4

+ 23 - 0
gtc/src/securecommdef.h

@@ -0,0 +1,23 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * (on-calc) GT-Dev header file
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifndef __SECURECOMMDEF_H
+#define __SECURECOMMDEF_H
+typedef struct {
+	long dummy;
+	void *sft[];
+} SecureTab;
+#endif
+// vim:ts=4:sw=4

+ 952 - 0
gtc/src/stmt.c

@@ -0,0 +1,952 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * statement handling
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifdef PC
+#ifdef SHORT_INT
+#undef int
+#endif
+#include	<ctype.h>
+#ifdef SHORT_INT
+#define int short
+#endif
+#endif
+
+struct enode   *init_node CGLOB;
+
+TYP *lastexpr_tp CGLOB;
+int lastexpr_size CGLOB, lastexpr_type CGLOB;
+
+/*
+ * the statement module handles all of the possible c statements and builds a
+ * parse tree of the statements.
+ *
+ * each routine returns a pointer to a statement parse node which reflects the
+ * statement just parsed.
+ */
+
+
+int start_block(int m) {	// used in block() (func.c)
+	if (m) {
+		needpunc(begin);
+		return 1; // we don't care about the result in this case
+	} else
+		return lastst==begin;
+}
+
+unsigned int getconst(enum(e_sym) s,enum(e_sym) e) {
+	struct enode *en;
+	getsym();
+	if (lastst != s)
+		error(ERR_EXPREXPECT);
+	else {
+		getsym();
+		if (exprnc(&en) == 0)
+			error(ERR_EXPREXPECT);
+		needpunc(e);
+		opt0(&en);
+		if (en->nodetype != en_icon)
+			error(ERR_CONSTEXPECT);
+		else if ((unsigned long)en->v.i>=65536)
+			error(ERR_OUTRANGE);
+		else return en->v.i;
+	}
+	return 0; // make the compiler happy
+}
+unsigned int getconst2(enum(e_sym) e) {
+	struct enode *en;
+	if (exprnc(&en) == 0)
+		error(ERR_EXPREXPECT);
+	needpunc(e);
+	opt0(&en);
+	if (en->nodetype != en_icon)
+		error(ERR_CONSTEXPECT);
+	else if ((unsigned long)en->v.i>=65536)
+		error(ERR_OUTRANGE);
+	else return en->v.i;
+	return 0; // make the compiler happy
+}
+
+struct snode *whilestmt(void) {
+/*
+ * whilestmt parses the c while statement.
+ */
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_while;
+	snp->count = 3;
+	getsym();
+	if (lastst != openpa)
+		error(ERR_EXPREXPECT);
+	else {
+		getsym();
+		if (expression(&(snp->exp)) == 0)
+			error(ERR_EXPREXPECT);
+#ifdef DB_POSSIBLE
+		snp->line=lineid;
+#endif
+		needpunc(closepa);
+		if (lastst == kw_count) snp->count=getconst(openpa,closepa);
+		snp->s1 = statement();
+	}
+	return snp;
+}
+
+struct snode *asmstmt();
+#if !defined(AS) && !defined(ASM)
+struct snode *asmstmt(void) {
+/*
+ * asmstmt parses the gtc c asm statement.
+ */
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_asm;
+	snp->count = 1;
+	getsym();
+	if (lastst != openpa)
+		error(ERR_EXPREXPECT);
+	else {
+		getsym();
+		if (lastst != sconst)
+			error(ERR_SYNTAX);
+		snp->v1.i = (long)strsave(laststr);
+		getsym();
+		if (lastst == colon) {
+			getsym();
+			uwarn("only asm(\"...\") is supported yet");
+			error(ERR_SYNTAX);
+		}
+		needpunc(closepa);
+		needpunc(semicolon);
+	}
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	return snp;
+}
+#endif
+
+//struct enode lp_one = { en_icon, bt_ushort, 2, {1L}, 0, 0};
+xstatic struct enode *lp_one CGLOB;
+struct snode *loopstmt(void) {
+/*
+ * loopstmt parses the gtc c loop statement.
+ */
+	struct snode *snp; TYP *tp;
+	struct enode *exp;
+	int has_count;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_loop;
+	snp->count = 3;
+	has_count = 0;
+	getsym();
+	if (lastst != openpa)
+		error(ERR_EXPREXPECT);
+	else {
+		getsym();
+		if (lastst != id)
+			error(ERR_IDEXPECT);
+		if (!nameref(&(snp->v1.e))) error(ERR_EXPREXPECT);
+		if (lastst != assign)
+			error(ERR_SYNTAX);
+		getsym();
+		if (!(tp=expression(&(snp->exp))))
+			error(ERR_EXPREXPECT);
+		cast_op(&(snp->exp),tp,(TYP *)&tp_ushort);
+#ifdef DB_POSSIBLE
+		snp->line=lineid;
+#endif
+		needpunc(closepa);
+		if (lastst == kw_count) { snp->count=getconst(openpa,closepa); has_count=1; }
+		opt0(&(snp->exp));
+		if (snp->exp->nodetype==en_icon) {
+			unsigned int c=snp->exp->v.i;
+			if (has_count) {
+				if (c!=snp->count)
+					uwarn("loop has an effective count of %u whereas %u precised",
+						c,snp->count);
+			} else snp->count=c;
+		}
+		lp_one = mk_icon(1L);
+		lp_one->etype = bt_ushort; lp_one->esize = 2;
+		snp->exp = exp = mk_node(en_sub,snp->exp,lp_one);
+		exp->etype = bt_ushort; exp->esize = 2;
+		opt4(&(snp->exp));
+		snp->exp = exp = mk_node(en_assign,snp->v1.e,snp->exp);
+		exp->etype = bt_ushort; exp->esize = 2;
+		snp->s1 = statement();
+		if (lastst == kw_until) {
+			getsym();
+			if (!expression(&(snp->v2.e))) error(ERR_EXPREXPECT);
+		} else snp->v2.e=NULL;
+	}
+	return snp;
+}
+
+struct snode *dostmt(void) {
+/*
+ * dostmt parses the c do-while construct.
+ */
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_do;
+	snp->count = 3;
+	getsym();
+	snp->s1 = statement();
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	if (lastst != kw_while)
+		error(ERR_WHILEXPECT);
+	else {
+		getsym();
+		if (lastst != openpa)
+			error(ERR_EXPREXPECT);
+		else {
+			getsym();
+			if (expression(&(snp->exp)) == 0)
+				error(ERR_EXPREXPECT);
+			needpunc(closepa);
+			if (lastst == kw_count) snp->count=getconst(openpa,closepa);
+		}
+		if (lastst != end)
+			needpunc(semicolon);
+	}
+	return snp;
+}
+
+struct snode *forstmt(void) {
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_for;
+	snp->count = 3;
+	getsym();
+	needpunc(openpa);
+	/*if (*/expression(&(snp->exp))/* == 0)
+		snp->exp = 0*/;
+	needpunc(semicolon);
+	/*if (*/expression(&(snp->v1.e))/* == 0)
+		snp->v1.e = 0*/;
+	needpunc(semicolon);
+	/*if (*/expression(&(snp->v2.e))/* == 0)
+		snp->v2.e = 0*/;
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	needpunc(closepa);
+	if (lastst == kw_count) snp->count=getconst(openpa,closepa);
+	snp->s1 = statement();
+	return snp;
+}
+
+struct snode *ifstmt(void) {
+/*
+ * ifstmt parses the c if statement and an else clause if one is present.
+ */
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_if;
+	snp->count=32768;
+	getsym();
+	if (lastst != openpa)
+		error(ERR_EXPREXPECT);
+	else {
+		getsym();
+		if (expression(&(snp->exp)) == 0)
+			error(ERR_EXPREXPECT);
+#ifdef DB_POSSIBLE
+		snp->line=lineid;
+#endif
+		needpunc(closepa);
+		if (lastst == kw_count) {
+			unsigned int i=getconst(openpa,comma),j=getconst2(closepa);
+			snp->count=((unsigned long)i<<16)/(i+j);
+		}
+		snp->s1 = statement();
+		if (lastst == kw_else) {
+			getsym();
+			snp->v1.s = statement();
+		} else {
+#ifdef NO_CALLOC
+			snp->v1.s = 0;
+#endif
+		}
+	}
+	return snp;
+}
+
+/*
+ * consider the following piece of code:
+ *
+ *		switch (i) {
+ *				case 1:
+ *						if (j) {
+ *								.....
+ *						} else
+ *				case 2:
+ *						....
+ *		}
+ *
+ * case statements may be deep inside, so we need a global variable
+ * last_case to link them
+ */
+xstatic struct snode *last_case CGLOB; /* last case statement within this switch */
+
+struct snode *casestmt(void) {
+/*
+ * cases are returned as seperate statements. for normal cases label is the
+ * case value and v1.i is zero. for the default case v1.i is nonzero.
+ */
+	struct snode   *snp,*snp0;
+	snp0 = snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+#ifdef NO_CALLOC
+	snp->s1 = NIL_SNODE;
+#endif
+	if (lastst == kw_case) {
+		long v;
+		getsym();
+		snp->stype = st_case;
+		snp->v2.i = v = intexpr();
+		if (lastst == dots) {	// TODO : make only one 'case' label
+			long max;
+			getsym();
+			if ((max = intexpr()) < v) error(ERR_CASERANGE);
+			else while (v != max) {
+				last_case = last_case->s1 = snp;
+				snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+				last_case->v1.s = snp;
+#ifdef NO_CALLOC
+				snp->s1 = NIL_SNODE;
+#endif
+				snp->stype = st_case;
+				snp->v2.i = ++v;
+			}
+		}
+	} else {
+		/* lastst is kw_default */
+		getsym();
+		/* CVW: statement type needed for analyze etc. */
+		snp->stype = st_default;
+	}
+	last_case = last_case->s1 = snp;
+	needpunc(colon);
+	if (lastst != end)
+		snp->v1.s = statement();
+	return snp0;
+}
+
+int checkcases(struct snode *head) {
+/*
+ * checkcases will check to see if any duplicate cases exist in the case list
+ * pointed to by head.
+ */
+	struct snode   *top, *cur;
+	cur = top = head;
+	while (top != 0) {
+		cur = top->s1;
+		while (cur != 0) {
+			if (cur->stype != st_default && top->stype != st_default
+				&& cur->v2.i == top->v2.i) {
+				uwarn("duplicate case label for value %ld", cur->v2.i);
+				return 1;
+			}
+			if (cur->stype == st_default && top->stype == st_default) {
+				uwarn("duplicate default label");
+				return 1;
+			}
+			cur = cur->s1;
+		}
+		top = top->s1;
+	}
+	return 0;
+}
+
+struct snode *switchstmt(void) {
+	struct snode   *snp;
+	struct snode   *local_last_case;
+	local_last_case = last_case;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	last_case = snp;
+#ifdef NO_CALLOC
+	snp->s1 = 0;
+#endif
+	snp->stype = st_switch;
+	getsym();
+	needpunc(openpa);
+	if ((expression(&(snp->exp))) == 0)
+		error(ERR_EXPREXPECT);
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	needpunc(closepa);
+	needpunc(begin);
+	snp->v1.s = compound(1);
+	if (checkcases(snp->s1))
+		error(ERR_DUPCASE);
+	last_case = local_last_case;
+	return snp;
+}
+
+struct snode *retstmt(void) {
+	struct snode   *snp;
+	TYP 		   *tp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_return;
+	getsym();
+	tp = expression(&(snp->exp));
+	if (snp->exp != 0)
+		(void) cast_op(&(snp->exp), tp, ret_type);
+	if (lastst != end)
+		needpunc(semicolon);
+#ifdef DB_POSSIBLE
+	snp->line=prevlineid;
+#endif
+	return snp;
+}
+
+struct snode *breakstmt(void) {
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_break;
+	getsym();
+	if (lastst != end)
+		needpunc(semicolon);
+#ifdef DB_POSSIBLE
+	snp->line=prevlineid;
+#endif
+	return snp;
+}
+
+struct snode *contstmt(void) {
+	struct snode   *snp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_continue;
+	getsym();
+	if (lastst != end)
+		needpunc(semicolon);
+#ifdef DB_POSSIBLE
+	snp->line=prevlineid;
+#endif
+	return snp;
+}
+
+struct snode *exprstmt(void) {
+/*
+ * exprstmt is called whenever a statement does not begin with a keyword. the
+ * statement should be an expression.
+ */
+	struct snode   *snp;
+	debug('u');
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_expr;
+/*
+ * I have a problem here.
+ * If expression() fails on the first character and does not do a getsym(),
+ * there may be an infinite loop since we will continue coming up here.
+ * Since the compiler will stop after MAX_ERROR_COUNT calls to error(),
+ * this might not be THAT much of a problem.
+ */
+	if (!(lastexpr_tp=expression(&(snp->exp))))
+		error(ERR_EXPREXPECT);
+	else {
+		lastexpr_type=snp->exp->etype;
+		lastexpr_size=snp->exp->esize;
+	}
+	debug('v');
+	if (lastst != end)
+		needpunc(semicolon);
+#ifdef DB_POSSIBLE
+	snp->line=prevlineid;
+#endif
+	debug('w');
+	return snp;
+}
+
+#ifdef AUTOINIT_PAD
+//long auto_init(long offs,TYP *typ,int brace_level,int offmod);
+long auto_pad(long offs,int len,int offmod) {
+	long nbytes=0;
+	while (len>0) {
+		int size;
+		if ((offs+offmod)&1)
+			size=1;
+		else if (len<=2)
+			size=len;
+		else if (len==3)
+			size=2;
+		else size=4;
+
+		{
+		struct enode *ep1,*ep2=mk_icon(0L),*ep3;
+		ep2->esize = size;	/* don't care about the etype, it's set to char */
+
+		ep1 = mk_node(en_autocon, NIL_ENODE, NIL_ENODE);
+		ep1->v.i = offs;
+		ep1->etype = bt_pointer;
+		ep1->esize = 4;
+
+		ep3 = mk_icon((long)offmod);
+		ep3->etype = bt_long;
+		ep3->esize = 4;
+
+		ep1 = mk_node(en_add, ep1, ep3);
+		ep1->etype = bt_pointer;
+		ep1->esize = 4;
+
+		ep1 = mk_node(en_ref, ep1, NIL_ENODE);
+		ep1->esize = size;	/* don't care about the etype, it's set to char */
+
+		ep1 = mk_node(en_assign, ep1, ep2);
+		ep1->esize = size;	/* don't care about the etype, it's set to char */
+
+		if (init_node == 0) {
+			init_node = ep1;
+		} else {
+			init_node = mk_node(en_void, init_node, ep1);
+		}
+		}
+
+		len-=size;
+		nbytes+=size;
+		offmod+=size;
+	}
+	return nbytes;
+}
+#endif
+
+long auto_init(long offs,TYP *typ,TYP **tpp,int brace_level,int offmod,int stroff) {
+/*
+ * generated assignment statements for initialization of auto and register
+ * variables. The initialization is generated like comma operators so a
+ * single statement does all the initializations
+ */
+	struct enode   *ep1, *ep2;
+	struct typ	   *tp;
+	int 			brace_seen = 0;
+	long			nbytes = 0;
+
+auto_init_restart:
+	if (lastst == begin) {
+		brace_level++;
+		brace_seen++;
+		getsym();
+	}
+	if (typ->type==bt_struct && brace_level) {
+		struct sym	   *sp;
+		sp = typ->lst.head;			/* start at top of symbol table */
+		while (sp != 0) {
+/*			infunc("DrawPacmanLogoAndHandleMenu")
+				bkpt();*/
+			nbytes+=auto_init(offs,sp->tp,NULL,brace_level,(int)(offmod+sp->value.i),-1);
+			if (lastst == comma)
+				getsym();
+			if (lastst == end || lastst == semicolon)
+				break;
+			sp = sp->next;
+		}
+#ifdef AUTOINIT_PAD
+		nbytes+=auto_pad(offs,(int)(typ->size-nbytes),offmod+nbytes);	/* negative args are OK for auto_pad */
+#endif
+	} else if (typ->type==bt_union) {
+		typ = (typ->lst.head)->tp;
+		goto auto_init_restart;
+	} else if (typ->val_flag) {
+//		if (!brace_level) error(ERR_SYNTAX);
+		if (lastst != end) {
+			int stroff=-1;
+			if (lastst == sconst && !brace_seen)
+				stroff=0;
+			while (1) {
+				nbytes+=auto_init(offs,typ->btp,NULL,brace_level,(int)(offmod+nbytes),stroff);
+				if (stroff>=0) {
+					stroff++;
+					if (stroff>lstrlen || (stroff==lstrlen && typ->size)) {
+						getsym();
+						break;
+					}
+				} else {
+					if (lastst == comma)
+						getsym();
+					if (lastst == end || lastst == semicolon) break;
+				}
+			}
+		}
+		if (typ->size && nbytes > typ->size)
+			error(ERR_INITSIZE);
+		if (nbytes != typ->size && tpp) {
+			/* fix the symbol's size, unless tpp=0 (item of a struct/union or array) */
+			typ = copy_type(typ);
+			*tpp = typ;
+			typ->size = nbytes;
+		}
+#ifdef AUTOINIT_PAD
+		nbytes+=auto_pad(offs,(int)(typ->size-nbytes),offmod+nbytes);	/* negative args are OK for auto_pad */
+#endif
+	} else {
+		if (stroff<0) {
+		   if (!(tp = exprnc(&ep2)))
+			   error(ERR_ILLINIT);
+		} else
+			ep2=mk_icon(stroff<lstrlen?laststr[stroff]:0), tp=(TYP *)&tp_char;
+		(void) cast_op(&ep2, tp, typ);
+		nbytes=bt_size(typ->type);
+
+/*		if (offs==0xfffffe4e)
+			bkpt();*/
+
+		ep1 = mk_node(en_autocon, NIL_ENODE, NIL_ENODE);
+		ep1->v.i = offs;
+/*		ep1->etype = typ->type; // this is a ridiculous bug that I spent hours finding...
+		ep1->esize = typ->size; */
+		ep1->etype = bt_pointer;
+		ep1->esize = 4;
+
+		if (offmod) {
+			struct enode *ep3 = mk_icon((long)offmod);
+			ep3->etype = bt_long;
+			ep3->esize = 4;
+
+			ep1 = mk_node(en_add, ep1, ep3);
+			ep1->etype = bt_pointer;
+			ep1->esize = 4;
+		}
+
+		ep1 = mk_node(en_ref, ep1, NIL_ENODE);
+		ep1->etype = typ->type;
+		ep1->esize = typ->size;
+
+		ep1 = mk_node(en_assign, ep1, ep2);
+		ep1->etype = typ->type;
+		ep1->esize = typ->size;
+
+#ifdef MID_DECL_IN_EXPR
+		if (middle_decl)
+			md_expr = ep1, md_type = typ;
+			#error fix needed around here...
+		else {
+#endif
+			if (init_node == 0) {
+				init_node = ep1;
+			} else {
+				init_node = mk_node(en_void, init_node, ep1);
+			}
+#ifdef MID_DECL_IN_EXPR
+		}
+#endif
+	}
+	while (brace_seen--)
+		needpunc(end);
+	return nbytes;
+}
+
+struct snode *compound(int no_init) {
+/*
+ * compound processes a block of statements and forms a linked list of the
+ * statements within the block.
+ *
+ * compound expects the input pointer to already be past the begin symbol of the
+ * block.
+ *
+ * If no_init is true, auto initializations are not desirable
+ */
+	struct snode   *head, *tail, *snp;
+//	struct sym	   *local_tail, *local_tagtail;
+	HTABLE			old_lsyms,old_ltags;
+//	hashinit(&symtab);
+/*	local_tail = lsyms.tail;
+	local_tagtail = ltags.tail;*/
+	memcpy(&old_lsyms,&lsyms,sizeof(HTABLE));
+	memcpy(&old_ltags,&ltags,sizeof(HTABLE));
+	dodecl(sc_auto);
+	if (init_node == 0) {
+		head = tail = 0;
+	} else {
+		if (no_init>0) {
+			uwarn("auto initialization not reached");
+		}
+		head = tail = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+		head->stype = st_expr;
+		head->exp = init_node;
+#ifdef NO_CALLOC
+		head->next = 0;
+#endif
+#ifdef DB_POSSIBLE
+		head->line = prevlineid;
+#endif
+	}
+	init_node = 0;
+	while (lastst != end) {
+		if (head == 0)
+			head = tail = statement();
+		else {
+			tail->next = statement();
+			if (tail->next != 0)
+				tail = tail->next;
+		}
+	}
+	if (no_init>=0)
+		getsym();
+#ifdef LISTING
+	if (list_option) {
+/*		if (local_tail != lsyms.tail) {
+			if (local_tail != 0)
+				symtab.head = local_tail->next;
+			else
+				symtab.head = lsyms.head;
+			symtab.tail = lsyms.tail;
+			fprintf(list, "\n*** local symbol table ***\n\n");
+			list_table(&symtab, 0);
+			fprintf(list, "\n");
+		}*/
+		fprintf(list, "\n*** local symbol table ***\n\n");
+		list_table(&lsyms, 0);
+		fprintf(list, "\n");
+/*		if (local_tagtail != ltags.tail) {
+			if (local_tagtail != 0)
+				symtab.head = local_tagtail->next;
+			else
+				symtab.head = ltags.head;
+			symtab.tail = ltags.tail;
+			fprintf(list, "\n*** local structures and unions ***\n\n");
+			list_table(&symtab, 0);
+			fprintf(list, "\n");
+		}*/
+		fprintf(list, "\n*** local structures and unions ***\n\n");
+		list_table(&ltags, 0);
+		fprintf(list, "\n");
+	}
+#endif
+/*	if (local_tagtail != 0) {
+		ltags.tail = local_tagtail;
+		ltags.tail->next = 0;
+	} else {
+		ltags.head = 0;
+		ltags.tail = 0;
+	}
+
+
+	if (local_tail != 0) {
+		lsyms.tail = local_tail;
+		lsyms.tail->next = 0;
+	} else {
+		lsyms.head = 0;
+		lsyms.tail = 0;
+	}*/
+	memcpy(&lsyms,&old_lsyms,sizeof(HTABLE));
+	memcpy(&ltags,&old_ltags,sizeof(HTABLE));
+
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	snp->stype = st_compound;
+	snp->s1 = head;
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	return snp;
+}
+
+extern unsigned int pos;
+struct snode *labelstmt(void) {
+/*
+ * labelstmt processes a label that appears before a statement as a seperate
+ * statement.
+ */
+	struct snode   *snp;
+	struct sym	   *sp;
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	/*if (pos>=0x25C2)
+		printf("jiotrh");*/
+	snp->stype = st_label;
+	if ((sp = search(lastid, lastcrc, &labsyms)) == 0) {
+		sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM);
+		sp->name = strsave(lastid);
+		sp->storage_class = sc_label;
+#ifdef NO_CALLOC
+		sp->tp = 0;
+#endif
+		sp->value.i = nxtlabel();
+		append(&sp, &labsyms);
+	} else {
+		if (sp->storage_class != sc_ulabel)
+			error(ERR_LABEL);
+		else
+			sp->storage_class = sc_label;
+	}
+	getsym();					/* get past id */
+	needpunc(colon);
+	if (sp->storage_class == sc_label) {
+		snp->v2.i = sp->value.i;
+		if (lastst != end)
+			snp->s1 = statement();
+		return snp;
+	}
+	return 0;
+}
+
+struct snode *gotostmt(void) {
+/*
+ * gotostmt processes the goto statement and puts undefined labels into the
+ * symbol table.
+ */
+	struct snode   *snp;
+	struct sym	   *sp;
+	getsym();
+	if (lastst != id) {
+		error(ERR_IDEXPECT);
+		return 0;
+	}
+	snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+	if ((sp = search(lastid, lastcrc, &labsyms)) == 0) {
+		sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM);
+		sp->name = strsave(lastid);
+		sp->value.i = nxtlabel();
+		sp->storage_class = sc_ulabel;
+#ifdef NO_CALLOC
+		sp->tp = 0;
+#endif
+		append(&sp, &labsyms);
+	}
+#ifdef DB_POSSIBLE
+	snp->line=lineid;
+#endif
+	getsym();					/* get past label name */
+	if (lastst != end)
+		needpunc(semicolon);
+	if (sp->storage_class != sc_label && sp->storage_class != sc_ulabel)
+		error(ERR_LABEL);
+	else {
+		snp->stype = st_goto;
+		snp->v2.i = sp->value.i;
+		snp->next = 0;
+		return snp;
+	}
+	return 0;
+}
+
+struct snode *statement(void) {
+/*
+ * statement figures out which of the statement processors should be called
+ * and transfers control to the proper routine.
+ */
+	struct snode   *snp;
+/*	if (lineid==0x20A)
+		bkpt();*/
+	switch (lastst) {
+	  case semicolon:
+		getsym();
+		snp = 0;
+		break;
+	  case kw_char: case kw_short: case kw_unsigned: case kw_long:
+	  case kw_struct: case kw_union: case kw_enum: case kw_void:
+	  case kw_float: case kw_double: case kw_int: case kw_typeof:
+	  case kw_signed: case kw_const: case kw_volatile:
+	  case kw_register: case kw_auto:
+	  case kw_static: case kw_typedef: case kw_extern:
+middle_decl:
+		if (!(flags & X_MID_DECL)) goto default_decl;
+#ifdef OLD_MID_DECL
+		snp = compound(0);
+		if ((int)cached_sym IS_VALID) fatal("CACHE"); // will never happen since no caching is
+												// performed when lastst==begin
+/*		cached_sym2 = cached_sym;*/
+		cached_sym = lastst; cached_lineid = lineid;
+		lastst = end;
+		break;
+#else
+#ifdef MID_DECL
+		/* the following is much cleaner than the old mid_decl handler */
+		dodecl(sc_auto);
+		if (init_node) {
+			snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE);
+			snp->stype = st_expr;
+			snp->exp = init_node;
+#ifdef DB_POSSIBLE
+			snp->line = prevlineid;
+#endif
+			init_node = 0;	// compound resets after calling rather than before...
+		}					//  I find it pretty weird :) (maybe it should be changed?)
+		else snp = 0;
+		break;
+#endif
+#endif
+	  case begin:
+		getsym();
+		snp = compound(0);
+		break;
+	  case kw_if:
+		snp = ifstmt();
+		break;
+	  case kw_while:
+		snp = whilestmt();
+		break;
+	  case kw_for:
+		snp = forstmt();
+		break;
+	  case kw_return:
+		snp = retstmt();
+		break;
+	  case kw_break:
+		snp = breakstmt();
+		break;
+	  case kw_goto:
+		snp = gotostmt();
+		break;
+	  case kw_continue:
+		snp = contstmt();
+		break;
+	  case kw_do:
+		snp = dostmt();
+		break;
+	  case kw_switch:
+		snp = switchstmt();
+		break;
+	  case kw_case:
+	  case kw_default:
+		snp = casestmt();
+		break;
+	  case kw_loop:
+		snp = loopstmt();
+		break;
+	  case kw_count:
+		snp = NULL;
+		error(ERR_EXPREXPECT);
+		break;
+	  case kw_asm:
+		snp = asmstmt();
+		break;
+	  case id:
+		if (!getcache(id) && cached_sym==colon) {
+			snp = labelstmt();
+			break;
+		}
+#if defined(OLD_MID_DECL) || defined(MID_DECL)
+		if (lastsp && lastsp->storage_class == sc_typedef)
+			goto middle_decl;
+#endif
+default_decl:
+		/* else fall through to process expression */
+	  default:
+		snp = exprstmt();
+		break;
+	}
+	if (snp != 0)
+		snp->next = 0;
+	return snp;
+}
+// vim:ts=4:sw=4

+ 91 - 0
gtc/src/sunpack.c

@@ -0,0 +1,91 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * precompiled header string unpacking
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#ifdef PC
+#include <string.h>
+
+char *sUnpack(char *in,char *out,char *dic) {
+	char c; char *out0=out;
+	while ((c=*in++)) {
+		if ((char)c>=0) *out++=c;
+		else {
+			if (c==(char)0x80) *out++=*in++;
+			else if (c==(char)0xFF) {
+				
+			} else {
+				char *dp=dic;
+				c-=(char)0x81;
+				while (c--) {
+					while (*dp++);
+				}
+				strcpy(out,dp);
+				while (*out++); out--;
+			}
+		}
+	}
+	*out++=0;
+	return out0;
+}
+#else
+char *__attribute__((stkparm)) sUnpack(char *in,char *out,char *dic);
+asm(
+"	xdef sUnpack\n"
+"sUnpack:\n"
+"/*	bra.s sUnpack*/\n"
+"	move.l 4(%sp),%a0\n"
+"	move.l 8(%sp),%a1\n"
+"	moveq #126,%d1\n"
+"	moveq #0,%d0\n"
+"	move.b (%a0)+,%d0\n"
+"	beq su_quit\n"
+"	bmi su_special\n"
+"su_copy_lp:\n"
+"	move.b %d0,(%a1)+\n"
+"su_next:\n"
+"	move.b (%a0)+,%d0\n"
+"	bgt su_copy_lp\n"
+"	beq su_quit\n"
+"su_special:\n"
+"	subq.b #1,%d0\n"
+"	bmi su_not_escape\n"
+"	move.b (%a0)+,(%a1)+\n"
+"	bra su_next\n"
+"su_not_escape:\n"
+"	addq.b #2,%d0\n"
+"	bmi su_not_romcall\n"
+"	\n"
+"su_not_romcall:\n"
+"	add.b %d1,%d0\n"
+"	move.l %a0,%d2\n"
+"	move.l 12(%sp),%a0\n"
+"	dbf %d0,su_search_loop\n"
+"	bra su_search_done\n"
+"su_search_loop:\n"
+"	tst.b (%a0)+\n"
+"	bne su_search_loop\n"
+"	dbf %d0,su_search_loop\n"
+"su_search_done:\n"
+"	move.b (%a0)+,(%a1)+\n"
+"	bne su_search_done\n"
+"	subq.w #1,%a1\n"
+"	move.l %d2,%a0\n"
+"	moveq #0,%d0\n"
+"	bra su_next\n"
+"su_quit:\n"
+"	move.b	%d0,(%a1)+\n"
+"	move.l 8(%sp),%a0\n"
+"	rts");
+#endif
+// vim:ts=4:sw=4

+ 343 - 0
gtc/src/symbol.c

@@ -0,0 +1,343 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * symbol handling (insertion & search)
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+#ifdef PCH
+#include	"pch.h"
+#endif
+
+#ifdef EXE_OUT
+#ifndef AS
+int exestub_mode CGLOB;
+#endif
+#endif
+
+HTABLE	gsyms CGLOBL, gtags CGLOBL, lsyms CGLOBL, labsyms CGLOBL, ltags CGLOBL;
+
+void concat(TABLE *dest,TABLE *src) {
+	SYM *sp=src->tail,*sp2;
+	while (sp) {
+		sp2=(SYM *)xalloc((int)sizeof(SYM), _SYM+SYMBOL);
+		*sp2=*sp;
+		insert(sp2,(HTABLE *)dest);
+		sp=sp->prev;
+	}
+}
+
+void hashinit(HTABLE *t) {
+	t->hash=0x2489;
+	memset(t->h,0,sizeof(t->h));
+}
+
+void insert(SYM *sp,HTABLE *table) {
+/*	if (!strcmp(sp->name,"wrong_calc"))
+		uwarn("def!");*/
+	if (!table->hash) {
+		if (!search(sp->name,0,table)) {
+			TABLE *tab=(TABLE *)table;
+			if (!tab->head) {
+				tab->head = tab->tail = sp;
+				sp->prev = 0;
+				sp->used = 0;
+			} else {
+				tab->tail->next = sp;
+				sp->prev = tab->tail;
+				tab->tail = sp;
+				sp->used = 0;
+				tab->tail = sp;
+			}
+			sp->next = 0;
+		}
+		else uerr(ERR_DUPSYM,sp->name);
+	} else {
+		int crc=crcN(sp->name);
+#ifdef EXE_OUT
+		if (table==&defsyms && sp->name[0]=='E' && !strcmp(sp->name,"EXE_OUT"))
+			exestub_mode=1;
+#endif
+		if (!search(sp->name,crc,table)) {
+			struct htab *tab=&table->h[crc];
+			if (!tab->head) {
+				tab->head = tab->tail = sp;
+				sp->prev = 0;
+				sp->used = 0;
+			} else {
+				tab->tail->next = sp;
+				sp->prev = tab->tail;
+				tab->tail = sp;
+				sp->used = 0;
+				tab->tail = sp;
+			}
+			sp->next = 0;
+		}
+		else uerr(ERR_DUPSYM,sp->name);
+	}
+}
+
+struct sym *symremove(char *na, HTABLE *tab) {
+	SYM *ttail,**prv;
+	struct htab *root;
+	char  *s1,*s2,c;
+	if (!tab->hash)
+		ierr(TABLE_HASH,2);
+#ifdef PC
+	if (tab->hash!=0x2489)
+		ierr(TABLE_HASH,1);
+#endif
+	prv=&((root=&tab->h[crcN(na)])->tail);
+	while ((ttail=*prv)) {
+		s1 = ttail->name;
+		s2 = na;
+		while (*s1++==(c=*s2++)) {
+			if (!c) {
+//				*prv = ttail->prev;
+				if (ttail->next) ttail->next->prev = ttail->prev;
+				if (ttail->prev) ttail->prev->next = ttail->next;
+//				ttail->next = prv;
+				if (root->tail==ttail) root->tail=ttail->prev;
+				if (root->head==ttail) root->head=ttail->next;
+/*				if (!root->tail)
+					root->head=0;*/
+				return ttail;
+			}
+		}
+		prv = &(ttail->prev);
+	}
+	return 0;
+}
+
+#ifdef PC
+int crcN(char *na) {
+	unsigned long crc=-1; int n;
+	unsigned char c;
+	c=*na++;
+	do {
+		crc^=c;
+		n=crc&7;
+		crc=(crc>>n)+(crc<<(32-n));
+	} while ((c=*na++));
+	crc^=crc>>16;
+	crc^=crc>>8;
+	return crc & (N_HASH-1);
+}
+#else
+int crcN(char *na);
+asm("crcN:\n"
+"	move.l	4(%sp),%a0\n"
+"	moveq	#-1,%d0\n"
+"	move.b	(%a0)+,%d1\n"
+"crcN_loop:\n"
+"	eor.b	%d1,%d0\n"
+"	moveq	#7,%d1\n"
+"	and.w	%d0,%d1\n"
+"	ror.l	%d1,%d0\n"
+"	move.b	(%a0)+,%d1\n"
+"	bne	crcN_loop\n"
+"	move.w	%d0,%d1\n"
+"	swap	%d0\n"
+"	eor.w	%d1,%d0\n"
+"	move.w	%d0,-(%sp)\n"
+"	move.b	(%sp)+,%d1\n"
+"	eor.b	%d1,%d0\n"
+"	and.w	#" N_HASH_AND ",%d0\n"
+"	rts");
+#endif
+
+/*#ifdef PC*/
+struct sym *search(char *na, int crc, HTABLE *tab) {
+	char  *s1,*s2,c;
+	if (!tab->hash) {
+		SYM *ttail=((TABLE *)tab)->tail;
+		while (ttail) {
+			s1 = ttail->name;
+			s2 = na;
+			while (*s1++==(c=*s2++)) {
+				if (!c) return ttail;
+			}
+			ttail = ttail->prev;
+		}
+		return 0;
+	} else {
+		SYM *ttail;
+#ifdef PC
+		if (tab->hash!=0x2489)
+			ierr(TABLE_HASH,1);
+#endif
+		if (crc<0) crc=crcN(na);
+		ttail=tab->h[crc].tail;
+		while (ttail) {
+			s1 = ttail->name;
+			s2 = na;
+			while (*s1++==(c=*s2++)) {
+				if (!c) return ttail;
+			}
+			ttail = ttail->prev;
+		}
+		return 0;
+	}
+}
+/*#else
+asm("search:
+	move.l	%a2,-(%sp)
+	move.l	8(%sp),%d1
+	move.l	%d1,%a1
+	tst.b	(%a1)
+0:	beq		0b
+	move.l	12(%sp),%a0
+	move.l	%a0,%d0
+	beq	search_end
+search_lp:
+	move.l	(%a0)+,%a2
+	move.l	%d1,%a1
+	cmpm.b	(%a1)+,(%a2)+
+	bne	search_nxt
+search_lp2:
+	move.b	(%a1)+,%d0
+	beq	search_fnd
+	cmp.b	(%a2)+,%d0
+	beq	search_lp2
+search_nxt:
+	move.l	(%a0)+,%a0
+	move.l	%a0,%d0
+	bne	search_lp
+search_end:
+	move.l	(%sp)+,%a2
+	rts
+search_fnd:
+	tst.b	(%a2)+
+	bne		search_nxt
+	subq.l	#4,%a0
+	move.l	(%sp)+,%a2
+	rts");
+#endif*/
+
+struct sym *gsearch(char *na,int crc) {
+	struct sym	   *sp;
+	if (!(sp = search(na, crc, &lsyms)))
+		sp = search(na, crc, &gsyms);
+	return sp;
+}
+
+void append(struct sym **ptr_sp, HTABLE *table) {
+	struct sym	   *sp1, *sp = *ptr_sp;
+	if (table == &gsyms && (sp1 = search(sp->name, -1, table)) != 0) {
+		/*
+		 * The global symbol table has only one level, this means that we
+		 * only check if the new declaration is compatible with the old one
+		 */
+
+		if (!eq_type(sp->tp, sp1->tp))
+			uerr(ERR_REDECL,sp->name);
+		/*
+		 * The new storage class depends on the old and on the new one.
+		 */
+		if (sp->storage_class == sp1->storage_class) {
+			if (sp->storage_class == sc_global) {
+				/*
+				 * This hack sets sp->used to -1 so that decl.c knows to
+				 * suppress storage allocation
+				 */
+				uwarn("global redeclaration of '%s'", sp->name);
+				sp1->used = -1;
+			}
+			*ptr_sp = sp1;		/* caller uses old entry */
+			return;
+		}
+		/*
+		 * since we use compiler generated label for static data, we must
+		 * retain sc_static
+		 */
+		if (sp1->storage_class == sc_static) {
+			*ptr_sp = sp1;		/* caller uses old entry */
+			return;
+		}
+		/*
+		 * if the new storage class is global, we must update sp1 to generate
+		 * the .globl directive at the very end and perhaps the size (e.g.
+		 * for arrays)
+		 */
+		if (sp->storage_class == sc_global) {
+			sp1->storage_class = sc_global;
+			sp1->tp = sp->tp;
+			*ptr_sp = sp1;		/* caller uses old entry */
+			return;
+		}
+		/*
+		 * if the new storage class is static, set it to global (since we may
+		 * have used the ,real' name and cannot use compiler generated names
+		 * for this symbol from now on) and set sp->value.i to -1 to prevent
+		 * it from being exported via .globl directives
+		 */
+		if (sp->storage_class == sc_static) {
+			sp1->storage_class = sc_global;
+			sp1->value.i = -1;
+			*ptr_sp = sp1;		/* caller uses old entry */
+			return;
+		}
+		/*
+		 * last case: global declaration followed by external decl.: just do
+		 * nothing
+		 */
+		*ptr_sp = sp1;			/* caller uses old entry */
+		return;
+	}
+/*	if (table->head == 0) {
+		// The table is empty so far...
+		table->head = table->tail = sp;
+		sp->next = sp->prev = 0;
+		sp->used = 0;
+	} else {
+		table->tail->next = sp;
+		sp->prev = table->tail;
+		table->tail = sp;
+		sp->next = 0;
+		sp->used = 0;
+	}*/
+	if (!table->hash) {
+		TABLE *tab=(TABLE *)table;
+		if (!tab->head) {
+			tab->head = tab->tail = sp;
+			sp->prev = 0;
+			sp->used = 0;
+		} else {
+			tab->tail->next = sp;
+			sp->prev = tab->tail;
+			tab->tail = sp;
+			sp->used = 0;
+			tab->tail = sp;
+		}
+		sp->next = 0;
+	} else {
+		struct htab *tab=&table->h[crcN(sp->name)];
+		if (!tab->head) {
+			tab->head = tab->tail = sp;
+			sp->prev = 0;
+			sp->used = 0;
+		} else {
+			tab->tail->next = sp;
+			sp->prev = tab->tail;
+			tab->tail = sp;
+			sp->used = 0;
+			tab->tail = sp;
+		}
+		sp->next = 0;
+	}
+}
+// vim:ts=4:sw=4

+ 247 - 0
gtc/src/trees.c

@@ -0,0 +1,247 @@
+/*
+ * GTools C compiler
+ * =================
+ * source file :
+ * tree dumping
+ *
+ * Copyright 2001-2004 Paul Froissart.
+ * Credits to Christoph van Wuellen and Matthew Brandt.
+ * All commercial rights reserved.
+ *
+ * This compiler may be redistributed as long there is no
+ * commercial interest. The compiler must not be redistributed
+ * without its full sources. This notice must stay intact.
+ */
+
+#include	"define.h"
+_FILE(__FILE__)
+#include	"c.h"
+#include	"expr.h"
+#include	"gen.h"
+#include	"cglbdec.h"
+
+typedef struct dump {
+} DUMP;
+char *dump_node_stack[MAX_DUMP_NODE_STACK];
+int dump_node_stack_depth;
+int dump_attribute_phase;
+
+#define dump_put printf
+void dump_startline() {
+	int i;
+	for (i=0;i<dump_node_stack_depth;i++)
+		dump_put("  ");
+}
+void dump_newnode(char *name) {
+	if (dump_attribute_phase)
+		dump_put(">\n");
+	dump_startline();
+	dump_put("<%s",name);
+	dump_node_stack[dump_node_stack_depth++] = name;
+	dump_attribute_phase = 1;
+}
+void dump_addstr(char *name,char *v) {
+	assert(dump_attribute_phase);
+	dump_put(" %s='%s'",name,v);
+}
+void dump_addint(char *name,int v) {
+	char b[100];
+	sprintf(b,"%d",v);
+	dump_addstr(name,b);
+}
+void dump_addreg(char *name,int v) {
+	assert(dump_attribute_phase);
+	if (v>=RESULT && v<RESULT+8)
+		dump_put(" %s='d%d'",name,v-RESULT);
+	else if (v>=PRESULT && v<PRESULT+8)
+		dump_put(" %s='a%d'",name,v-PRESULT);
+	else if (v==FRAMEPTR)
+		dump_put(" %s='fp'",name);
+	else
+		ierr(DUMP,3);
+}
+void dump_endnode() {
+	dump_node_stack_depth--;
+	if (dump_attribute_phase)
+		dump_put(" />\n");
+	else
+		dump_startline(), dump_put("</%s>",dump_node_stack[dump_node_stack_depth]);
+	dump_attribute_phase = 0;
+}
+
+void dump_genstmt(struct snode *stmt) {
+	while (stmt != 0) {
+		switch (stmt->type) {
+			case st_compound:
+				dump_genstmt(stmt->s1);
+				break;
+			case st_label:
+				dump_newnode("st_label");
+				dump_addint("id",stmt->v2.i);
+				dump_endnode();
+				dump_genstmt(stmt->s1);
+				break;
+			case st_goto:
+				dump_newnode("st_goto");
+				dump_addint("id",stmt->v2.i);
+				dump_endnode();
+				break;
+			case st_break:
+				dump_newnode("st_break");
+				dump_endnode();
+				break;
+			case st_continue:
+				dump_newnode("st_continue");
+				dump_endnode();
+				break;
+			case st_expr:
+				dump_newnode("st_expr");
+				dump_expr(stmt->exp);
+				dump_endnode();
+				break;
+			case st_return:
+				if (!stmt->exp || ret_type->type==bt_void) {
+					dump_newnode("st_return");
+					dump_endnode();
+					break;
+				}
+				switch (ret_type->type) {
+					case bt_struct:
+					case bt_union:
+#ifdef BCDFLT
+					case bt_float:
+#ifdef DOUBLE
+					case bt_double:
+#endif
+#endif
+#ifdef SHORT_STRUCT_PASSING
+						if (ret_type->size<=4) {
+							if (stmt->exp->nodetype!=en_ref)
+								ierr(DUMP,1);
+							dump_newnode("st_return");
+							dump_newnode("expr");
+							dump_addreg("target",mk_reg(RESULT));
+							dump_newnode("e_deref");
+							dump_addint("esize",ret_type->size);
+							dump_expr(stmt->exp->v.p[0]);
+							dump_endnode();
+							dump_endnode();
+							dump_endnode();
+							break;
+						}
+#endif
+						assert(0);
+						dump_newnode("st_return");
+						dump_newnode("expr");
+						dump_addstr("target","__tmp_structreturn");
+						dump_expr(stmt->exp);
+						dump_newnode("");
+						dump_newnode("");
+						break;
+#ifndef BCDFLT
+					case bt_float:
+#ifdef DOUBLE
+					case bt_double:
+#endif
+#endif
+					case bt_char: case bt_uchar:
+					case bt_short: case bt_ushort:
+					case bt_long: case bt_ulong:
+					case bt_pointer:
+						dump_newnode("st_return");
+						dump_newnode("expr");
+						dump_addreg("target",ret_type->type==bt_pointer?mk_reg(PRESULT):mk_reg(RESULT));
+						dump_expr(stmt->exp);
+						dump_endnode();
+						dump_endnode();
+						break;
+					default:
+						ierr(DUMP,1);
+				}
+				break;
+			case st_if:
+				dump_newnode("st_if");
+				dump_newnode("condition");
+				dump_expr(stmt->exp);
+				dump_endnode();
+				dump_newnode("true");
+				dump_genstmt(stmt->s1);
+				dump_endnode();
+				dump_newnode("false");
+				dump_genstmt(stmt->v1.s);
+				dump_endnode();
+				dump_endnode();
+				break;
+			case st_asm:
+				dump_newnode("st_asm");
+				dump_newnode("TODO");
+				//dump_asm((struct ocode *)stmt->v1.i);
+				dump_endnode();
+				dump_endnode();
+				break;
+			case st_while:
+				dump_newnode("st_while");
+				if (stmt->exp) {
+					dump_newnode("condition");
+					dump_expr(stmt->exp);
+					dump_endnode();
+				}
+				dump_newnode("body");
+				dump_genstmt(stmt->s1);
+				dump_newnode("st_labelcontinue");
+				dump_endnode();
+				dump_endnode();
+				dump_endnode();
+				break;
+			case st_do:
+				dump_newnode(stmt->exp ? "st_do" : "st_while");
+				dump_newnode("body");
+				dump_genstmt(stmt->s1);
+				dump_endnode();
+				if (stmt->exp) {
+					dump_newnode("condition");
+					dump_expr(stmt->exp);
+					dump_endnode();
+				}
+				dump_endnode();
+				break;
+			case st_for:
+				if (stmt->exp) {
+					dump_newnode("st_expr");
+					dump_expr(stmt->exp);
+					dump_endnode();
+				}
+				dump_newnode("st_while");
+				dump_newnode("condition");
+				dump_expr(stmt->v1.e);
+				dump_endnode();
+				dump_newnode("body");
+				dump_genstmt(stmt->s1);
+				if (stmt->v2.e) {
+					dump_newnode("st_expr");
+					dump_expr(stmt->v2.e);
+					dump_endnode();
+				}
+				dump_endnode();
+				dump_endnode();
+				break;
+			case st_switch:
+			default:
+				ierr(DUMP,2);
+		}
+		stmt = stmt->next;
+	}
+}
+
+void dump_genfunc(struct snode *stmt) {
+	opt1(stmt);
+	dump_newnode("function");
+	dump_newnode("returns");
+	dump_type(ret_type);
+	dump_endnode();
+	dump_newnode("code");
+	dump_genstmt(stmt);
+	dump_genreturn(NIL_SNODE);
+	dump_endnode();
+	dump_endnode();
+}

+ 98 - 0
gtc/src/vcg.c

@@ -0,0 +1,98 @@
+#ifdef VCG
+#ifdef PC
+#define MAXINT 0x7FFFFFFF
+#endif
+#ifndef __HAVE_STACK_IMAGE
+#define __HAVE_STACK_IMAGE
+typedef struct _stackimg {
+	int next_data,next_addr;
+#ifndef INFINITE_REGISTERS
+	int reg_alloc_ptr,reg_stack_ptr;
+	char dreg_in_use[MAX_DATA+1];
+	char areg_in_use[MAX_ADDR+1];
+	struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1];
+	int act_scratch;
+#endif
+} STACK_IMAGE;
+#endif
+STACK_IMAGE vcg_img[VCG_MAX+1];
+int vcg_nxl[VCG_MAX+1];
+int vcg_aborted[VCG_MAX+1];
+int vcg_init() {
+	if (--vcg_lvl<0) {
+		vcg_lvl++;
+		return 0;
+	}
+//	tmp_use();
+	usestack(&vcg_img[vcg_lvl]);
+	vcg_peep_head[vcg_lvl]=0;
+	vcg_aborted[vcg_lvl]=0;
+	vcg_nxl[vcg_lvl]=nextlabel;
+	g_code(op_label,0,0,0);
+	return 1;
+//	vcg_on++;
+//	vcg_cost[vcg_lvl]=0;
+}
+int en_dir_cost(struct enode *ep) {
+	switch (ep->nodetype) {
+		case en_icon:
+			return (ep->v.i>=-32768 && ep->v.i<32767)?1:2;
+		case en_labcon:
+		case en_nacon:
+			return 1;
+		case en_add:
+		case en_sub:
+			return max(en_dir_cost(ep->v.p[0]),en_dir_cost(ep->v.p[1]));
+	}
+}
+int cost_tab[] = {
+	0,0,0,0,0,1,1,1,-MAXINT-1,2,1,1,1,1,2,0,0
+};
+int vcg_cost() {
+	int cost=0;
+	if (!vcg_aborted[vcg_lvl]) {
+		struct ocode *ip;
+		opt3();
+		ip = peep_head;
+		while (ip != 0) {
+	#define am_cost(x) (x?(x->mode==am_direct?en_dir_cost(x->offset):cost_tab[x->mode]):0)
+			cost++;
+			switch (ip->opcode) {
+			case op_label:
+			case op_even:
+				cost--;
+				break;
+			case op_moveq:
+			case op_addq: case op_subq:
+			case op_lsl: case op_lsr: case op_asl: case op_asr:
+			case op_rol: case op_ror: case op_roxl: case op_roxr:
+			case op_trap:
+				cost+=am_cost(ip->oper2);
+				break;
+			case op_bxx:
+				/* what should we do here? */
+				break;
+			case op_dbxx:
+				cost++;
+				break;
+			default:
+				cost+=am_cost(ip->oper1)+am_cost(ip->oper2);
+				break;
+			}
+			if (cost<0) cost+=(-MAXINT-1)+((ip->length+1)>>1);
+			ip = ip->fwd;
+		}
+	//	vcg_on--;
+	//	tmp_free();
+	} else cost=12345;
+	return cost;
+}
+int vcg_done() {
+	freestack(&vcg_img[vcg_lvl]);
+	nextlabel=vcg_nxl[vcg_lvl];
+	int cost=vcg_cost();
+	vcg_lvl++;
+	return cost;
+}
+#endif
+// vim:ts=4:sw=4

+ 8 - 0
gtc/src/version.h

@@ -0,0 +1,8 @@
+#ifndef VERSION_H_
+#define VERSION_H_
+
+#define GTC_MAJOR 0
+#define GTC_MINOR 902
+#define GTC_VERSION "0.90.2"
+
+#endif

+ 24 - 0
h/Makefile

@@ -0,0 +1,24 @@
+BIN=../bin
+STRIP = perl script/strip.pl
+TXT89 = $(BIN)/txt89t
+
+all: src/*.h
+	$(RM) *.89t
+	$(RM) processed/*.89t
+	$(RM) -r stripped
+	mkdir stripped
+	sh -c 'for f in src/*.h; do $(STRIP) "$$f" > "stripped/$${f#src/}"; done'
+	$(TXT89) --compact -f gtchdr stripped/*.h
+	mv *.89t processed
+	$(RM) -r stripped
+	touch all
+
+clean:
+distclean: clean
+scratchclean: distclean
+	$(RM) processed/*.89t all
+
+include ../config.mk
+install: all
+	mkdir -p $(prefix)/share/gtc/include
+	install -m 644 src/*.h $(prefix)/share/gtc/include

+ 0 - 0
h/all


+ 1 - 0
h/legacy/README

@@ -0,0 +1 @@
+These files are deprecated, but I'm leaving them here for reference purposes.

+ 67 - 0
h/legacy/ezgen

@@ -0,0 +1,67 @@
+ #include "inclgen"
+ #include "genle"
+ #ifdef RESOURCE
+ FILE *resf=0;
+ #ifdef RES_TYPE
+ RES_TYPE *data=0;
+ #else
+ void *data=0;
+ #endif
+ #endif
+ DSCREEN *scr1=0,*scr2=0,*sc=0;
+ #ifdef DISP_SCR
+ DSCREEN *sd=0;
+ #endif
+ 
+ int curscr=0;
+ void gl_main();
+ void gl_upd() {
+  if (!curscr) {
+   gl_set_dscreen_int(
+ #ifdef DISP_SCR
+    sd=
+ #endif
+    scr1);
+   gl_set_dscreen_function(sc=scr2);
+  } else {
+   gl_set_dscreen_int(
+ #ifdef DISP_SCR
+    sd=
+ #endif
+    scr2);
+   gl_set_dscreen_function(sc=scr1);
+  }
+  curscr=~curscr;
+ }
+ int gl_load() {
+  int hd;
+  gl_init();
+  gl_init_dscreen(&scr1, &hd);
+  if (!hd) goto nohd;
+  gl_push_hd(hd);
+  gl_init_dscreen(&scr2, &hd);
+  if (!hd) goto nohd;
+  gl_push_hd(hd);
+  gl_upd();
+ #ifdef RESOURCE
+  resf=fopen(RESOURCE,"rb");
+  if (!resf) goto nohd;
+  (void *)data=*(void **)resf;
+ #ifdef GFX_RES
+  gl_set_spr_xy(0,0);
+  gl_set_spr_tile(data);
+ #endif
+ #endif
+  return 1;
+ nohd:
+  return 0;
+ }
+ void _main() {
+  if (gl_load()) gl_main();
+ #ifdef RESOURCE
+  if (resf) fclose(resf);
+ #endif
+  gl_wait_no_key();
+  gl_free_hd();
+  gl_quit();
+ }

+ 42 - 0
h/legacy/ezgensc

@@ -0,0 +1,42 @@
+ #include "inclgen"
+ #include "genle"
+ #include "sccomm"
+ #include "scliba"
+ #ifdef RESOURCE
+ FILE *resf;
+ #endif
+ 
+ void gl_main();
+ int gl_load() {
+  GLB
+  int hd;
+  gl_init();
+  gl_init_dscreen(&g scr1, &hd);
+  if (!hd) goto nohd;
+  gl_push_hd(hd);
+  gl_init_dscreen(&g scr2, &hd);
+  if (!hd) goto nohd;
+  gl_push_hd(hd);
+  gl_upd();
+ #ifdef RESOURCE
+  resf=fopen(RESOURCE,"rb");
+  if (!resf) goto nohd;
+  (void *)g data=*(void **)resf;
+ #ifdef GFX_RES
+  gl_set_spr_xy(0,0);
+  gl_set_spr_tile(g data);
+ #endif
+ #endif
+  return 1;
+ nohd:
+  return 0;
+ }
+ void _main() {
+  if (gl_load()) gl_main();
+ #ifdef RESOURCE
+  if (resf) fclose(resf);
+ #endif
+  gl_wait_no_key();
+  gl_free_hd();
+  gl_quit();
+ }

+ 1 - 0
h/legacy/genle

@@ -0,0 +1 @@
+#include <gen.h>

+ 4 - 0
h/legacy/inclgen

@@ -0,0 +1,4 @@
+#define USE_KERNEL
+#include <tigcclib.h>
+#define X 160
+#define Y 100

+ 1 - 0
h/legacy/include

@@ -0,0 +1 @@
+#include <tigcclib.h>

+ 340 - 0
h/processed/COPYING

@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

BIN
h/processed/assert.89t


BIN
h/processed/compat.89t


BIN
h/processed/default.89t


BIN
h/processed/doors.89t


BIN
h/processed/extgraph.89t


BIN
h/processed/gen.89t


BIN
h/processed/nostub.89t


BIN
h/processed/patch.89t


BIN
h/processed/std.89t


BIN
h/processed/tigcclib.89t


BIN
h/processed/ttunpack.89t


BIN
h/processed/xupak.89t


+ 31 - 0
h/script/strip.pl

@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+my $multicomment=0;
+
+while (<>) {
+	chomp;
+	if (!$multicomment) {
+		s|//.*$| |g;
+		s|/\*.*?\*/| |g;
+		if (m|/\*|) {
+			s|/\*.*$| |g;
+			$multicomment=1;
+		}
+	} elsif (m|\*/|) {
+		s|^.*?\*/| |g;
+		$multicomment=0;
+	} else {
+		$_='';
+	}
+	s|^\s+||g;
+	s|\s+$||g;
+	s|\s+| |g;
+	s|^(\#define \w+) |\1\t|g;
+	s|(\W) (.)|\1\2|g;
+	s|(.) (\W)|\1\2|g;
+	s:(?<!\w)0x([A-Fa-f0-9]{1,5})(?!(\#|\d)):hex($1):ge;
+	while (s:(?<!\w)(\d+)\*(\d+)(?!(\#|\d)):$1*$2:ge) {}
+	s|\t| |g;
+	$_.="\n" if $_;
+	print;
+}

Some files were not shown because too many files changed in this diff