Import VBCC source snapshot (29/04/2022)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..28dca08
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,309 @@
+
+# used to create vbcc, vc and ucpp
+CC = gcc -std=c9x -g -DHAVE_AOS4 #-fsanitize=address #-DHAVE_ECPP -DHAVE_MISRA 
+LDFLAGS = -lm
+
+# native version; used to create dtgen
+NCC = $(CC)
+NLDFLAGS = $(LDFLAGS)
+
+all: bin/vc bin/vprof bin/vbcc$(TARGET) #bin/vcpp
+
+vbccs: bin/vbccs$(TARGET)
+
+bin/vc: frontend/vc.c
+	$(CC) frontend/vc.c -o bin/vc $(LDFLAGS)
+
+bin/vprof: vprof/vprof.c
+	$(CC) vprof/vprof.c -o bin/vprof $(LDFLAGS)
+
+doc/vbcc.pdf:
+	texi2dvi --pdf doc/vbcc.texi
+	rm -f vbcc.cp vbcc.fn vbcc.vr vbcc.tp vbcc.ky vbcc.pg vbcc.toc \
+	      vbcc.aux vbcc.log
+
+doc/vbcc.html:
+	(cd doc;texi2html -split=chapter -nosec_nav -frames vbcc.texi)
+	sed -e s/vbcc_13/vbcc_1/ <doc/vbcc_frame.html >doc/vbcc.html
+
+vcppobjs = vcpp/cpp.o vcpp/eval.o vcpp/getopt.o vcpp/hideset.o vcpp/include.o \
+	   vcpp/lex.o vcpp/macro.o vcpp/nlist.o vcpp/tokens.o vcpp/unix.o
+
+_vbcc.tar.gz:
+	-(cd ..;tar zcvf vbcc.tar.gz --exclude=*/dt.c --exclude=*/dt.h vbcc/Makefile vbcc/bin/.dummy vbcc/*.[ch] vbcc/datatypes/*.[ch] vbcc/doc/*.texi vbcc/frontend/vc.c vbcc/machines/*/*.[ch] vbcc/machines/*/machine.dt vbcc/machines/*/schedule.[ch] vbcc/machines/*/compress.[ch] vbcc/ucpp/*.[ch] vbcc/ucpp/README vbcc/vprof/vprof.c vbcc/vsc/vsc.[ch] vbcc/vcpr/vcpr.[ch])
+
+bin/osekrm: osekrm.c
+	$(CC) osekrm.c -o bin/osekrm
+
+dist: bin/osekrm
+	mv supp.h t1
+	mv supp.c t2
+	mv main.c t3
+	mv machines/ppc/machine.c t4
+	mv declaration.c t5
+	mv flow.c t6
+	mv ic.c t7
+	mv parse_expr.c t8
+	mv statements.c t9
+	mv rd.c t10
+	mv type_expr.c t11
+	bin/osekrm <t1 >supp.h
+	bin/osekrm <t2 >supp.c
+	bin/osekrm <t3 >main.c
+	bin/osekrm <t4 >machines/ppc/machine.c
+	bin/osekrm <t5 >declaration.c
+	bin/osekrm <t6 >flow.c
+	bin/osekrm <t7 >ic.c
+	bin/osekrm <t8 >parse_expr.c
+	bin/osekrm <t9 >statements.c
+	bin/osekrm <t10 >rd.c
+	bin/osekrm <t11 >type_expr.c
+	make _vbcc.tar.gz
+	mv t1 supp.h
+	mv t2 supp.c
+	mv t3 main.c
+	mv t4 machines/ppc/machine.c
+	mv t5 declaration.c
+	mv t6 flow.c
+	mv t7 ic.c
+	mv t8 parse_expr.c
+	mv t9 statements.c
+	mv t10 rd.c
+	mv t11 type_expr.c	
+
+bin/vcpp: $(vcppobjs)
+	$(CC) $(LDFLAGS) $(vcppobjs) -o bin/vcpp
+
+vcpp/cpp.o: vcpp/cpp.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/cpp.c -o vcpp/cpp.o
+
+vcpp/eval.o: vcpp/eval.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/eval.c -o vcpp/eval.o
+
+vcpp/getopt.o: vcpp/getopt.c
+	$(CC) -c -Ivcpp vcpp/getopt.c -o vcpp/getopt.o
+
+vcpp/hideset.o: vcpp/hideset.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/hideset.c -o vcpp/hideset.o
+
+vcpp/include.o: vcpp/include.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/include.c -o vcpp/include.o
+
+vcpp/lex.o: vcpp/lex.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/lex.c -o vcpp/lex.o
+
+vcpp/macro.o: vcpp/macro.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/macro.c -o vcpp/macro.o
+
+vcpp/nlist.o: vcpp/nlist.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/nlist.c -o vcpp/nlist.o
+
+vcpp/tokens.o: vcpp/tokens.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/tokens.c -o vcpp/tokens.o
+
+vcpp/unix.o: vcpp/unix.c vcpp/cpp.h
+	$(CC) -c -Ivcpp vcpp/unix.c -o vcpp/unix.o
+
+TRGDIR = machines/$(TARGET)
+
+bobjects = $(TRGDIR)/main.o $(TRGDIR)/vars.o $(TRGDIR)/declaration.o \
+	   $(TRGDIR)/parse_expr.o $(TRGDIR)/type_expr.o $(TRGDIR)/ic.o \
+	   $(TRGDIR)/machine.o $(TRGDIR)/statements.o \
+	   $(TRGDIR)/supp.o $(TRGDIR)/dt.o \
+           $(TRGDIR)/assert.o $(TRGDIR)/cpp.o $(TRGDIR)/hash.o \
+           $(TRGDIR)/lexer.o $(TRGDIR)/macro.o $(TRGDIR)/mem.o \
+           $(TRGDIR)/eval.o
+#           $(TRGDIR)/AdjList.o $(TRGDIR)/DUChain.o \
+#           $(TRGDIR)/ICodeInsertion.o $(TRGDIR)/NodeList.o \
+#           $(TRGDIR)/RAllocMain.o $(TRGDIR)/Web.o
+
+fobjects = $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+	   $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+	   $(TRGDIR)/alias.o $(TRGDIR)/range.o $(bobjects)
+
+sobjects = $(TRGDIR)/opts.o $(TRGDIR)/regss.o $(bobjects)
+
+tasm	 = $(TRGDIR)/supp.o $(TRGDIR)/tasm.o $(TRGDIR)/dt.o \
+	   $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+	   $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+	   $(TRGDIR)/alias.o $(TRGDIR)/machine.o
+
+mbasic	 = $(TRGDIR)/supp.o $(TRGDIR)/mbasic.o $(TRGDIR)/dt.o \
+	   $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+	   $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+	   $(TRGDIR)/alias.o $(TRGDIR)/machine.o
+
+minicomp	 = $(TRGDIR)/supp.o $(TRGDIR)/minicompg.tab.o $(TRGDIR)/minicomp.o $(TRGDIR)/dt.o \
+	   $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+	   $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+	   $(TRGDIR)/alias.o $(TRGDIR)/machine.o
+
+vscobjects = $(TRGDIR)/vsc.o $(TRGDIR)/schedule.o
+
+vcprobjects = $(TRGDIR)/vcpr.o $(TRGDIR)/compress.o
+
+bin/vbcc$(TARGET): $(fobjects)
+	$(CC) $(LDFLAGS) $(fobjects) -o bin/vbcc$(TARGET)
+
+bin/vbccs$(TARGET): $(sobjects)
+	$(CC) $(LDFLAGS) $(sobjects) -o bin/vbccs$(TARGET)
+
+bin/vsc$(TARGET): $(vscobjects)
+	$(CC) $(LDFLAGS) $(vscobjects) -o bin/vsc$(TARGET)
+
+bin/vcpr$(TARGET): $(vcprobjects)
+	$(CC) $(LDFLAGS) $(vcprobjects) -o bin/vcpr$(TARGET)
+
+bin/tasm$(TARGET): $(tasm)
+	$(CC) $(LDFLAGS) $(tasm) -o bin/tasm$(TARGET)
+
+bin/mbasic$(TARGET): $(mbasic)
+	$(CC) $(LDFLAGS) $(mbasic) -o bin/mbasic$(TARGET)
+
+bin/minicomp$(TARGET): $(minicomp)
+	$(CC) $(LDFLAGS) $(minicomp) -o bin/minicomp$(TARGET)
+
+bin/dtgen: datatypes/dtgen.c datatypes/datatypes.h datatypes/dtconv.h
+	$(NCC) datatypes/dtgen.c -o bin/dtgen -Idatatypes $(NLDFLAGS)
+
+$(TRGDIR)/dt.h: bin/dtgen $(TRGDIR)/machine.dt
+	bin/dtgen $(TRGDIR)/machine.dt $(TRGDIR)/dt.h $(TRGDIR)/dt.c
+
+$(TRGDIR)/dt.c: bin/dtgen $(TRGDIR)/machine.dt
+	bin/dtgen $(TRGDIR)/machine.dt $(TRGDIR)/dt.h $(TRGDIR)/dt.c
+
+$(TRGDIR)/dt.o: $(TRGDIR)/dt.h $(TRGDIR)/dt.c
+	$(CC) -c $(TRGDIR)/dt.c -o $(TRGDIR)/dt.o -I$(TRGDIR) -Idatatypes
+
+$(TRGDIR)/tasm.o: tasm.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c tasm.c -o $(TRGDIR)/tasm.o -I$(TRGDIR)
+
+$(TRGDIR)/mbasic.o: mbasic.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c mbasic.c -o $(TRGDIR)/mbasic.o -I$(TRGDIR)
+
+$(TRGDIR)/minicomp.o: minicomp.c minicomp.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c minicomp.c -o $(TRGDIR)/minicomp.o -I$(TRGDIR)
+
+$(TRGDIR)/minicompg.tab.o: minicompg.y minicomplexer.c minicomp.h supp.h
+	bison minicompg.y
+	$(CC) -c minicompg.tab.c -o $(TRGDIR)/minicompg.tab.o -I$(TRGDIR)
+
+$(TRGDIR)/supp.o: supp.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c supp.c -o $(TRGDIR)/supp.o -I$(TRGDIR)
+
+$(TRGDIR)/main.o: main.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c main.c -o $(TRGDIR)/main.o -I$(TRGDIR)
+
+$(TRGDIR)/vars.o: vars.c vbc.h supp.h $(TRGDIR)/machine.h errors.h $(TRGDIR)/dt.h
+	$(CC) -c vars.c -o $(TRGDIR)/vars.o -I$(TRGDIR)
+
+$(TRGDIR)/declaration.o: declaration.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c declaration.c -o $(TRGDIR)/declaration.o -I$(TRGDIR)
+
+$(TRGDIR)/parse_expr.o: parse_expr.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c parse_expr.c -o $(TRGDIR)/parse_expr.o -I$(TRGDIR)
+
+$(TRGDIR)/type_expr.o: type_expr.c vbc.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c type_expr.c -o $(TRGDIR)/type_expr.o -I$(TRGDIR)
+
+$(TRGDIR)/ic.o: ic.c vbc.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c ic.c -o $(TRGDIR)/ic.o -I$(TRGDIR)
+
+$(TRGDIR)/statements.o: statements.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c statements.c -o $(TRGDIR)/statements.o -I$(TRGDIR)
+
+$(TRGDIR)/opt.o: opt.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c opt.c -o $(TRGDIR)/opt.o -I$(TRGDIR)
+
+$(TRGDIR)/av.o: av.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c av.c -o $(TRGDIR)/av.o -I$(TRGDIR)
+
+$(TRGDIR)/rd.o: rd.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c rd.c -o $(TRGDIR)/rd.o -I$(TRGDIR)
+
+$(TRGDIR)/regs.o: regs.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c regs.c -o $(TRGDIR)/regs.o -I$(TRGDIR)
+
+$(TRGDIR)/flow.o: flow.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c flow.c -o $(TRGDIR)/flow.o -I$(TRGDIR)
+
+$(TRGDIR)/cse.o: cse.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c cse.c -o $(TRGDIR)/cse.o -I$(TRGDIR)
+
+$(TRGDIR)/cp.o: cp.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c cp.c -o $(TRGDIR)/cp.o -I$(TRGDIR)
+
+$(TRGDIR)/loop.o: loop.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c loop.c -o $(TRGDIR)/loop.o -I$(TRGDIR)
+
+$(TRGDIR)/alias.o: alias.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c alias.c -o $(TRGDIR)/alias.o -I$(TRGDIR)
+
+$(TRGDIR)/range.o: range.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c range.c -o $(TRGDIR)/range.o -I$(TRGDIR)
+
+$(TRGDIR)/preproc.o: preproc.c vbpp.h supp.h vbc.h $(TRGDIR)/dt.h
+	$(CC) -c preproc.c -o $(TRGDIR)/preproc.o -I$(TRGDIR)
+
+$(TRGDIR)/assert.o: ucpp/assert.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/assert.c -o $(TRGDIR)/assert.o -I$(TRGDIR)
+
+$(TRGDIR)/cpp.o: ucpp/cpp.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/cpp.c -o $(TRGDIR)/cpp.o -I$(TRGDIR)
+
+$(TRGDIR)/hash.o: ucpp/hash.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/hash.c -o $(TRGDIR)/hash.o -I$(TRGDIR)
+
+$(TRGDIR)/lexer.o: ucpp/lexer.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/lexer.c -o $(TRGDIR)/lexer.o -I$(TRGDIR)
+
+$(TRGDIR)/macro.o: ucpp/macro.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/macro.c -o $(TRGDIR)/macro.o -I$(TRGDIR)
+
+$(TRGDIR)/mem.o: ucpp/mem.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/mem.c -o $(TRGDIR)/mem.o -I$(TRGDIR)
+
+$(TRGDIR)/eval.o: ucpp/eval.c ucpp/cpp.h ucpp/mem.h ucpp/tune.h $(TRGDIR)/dt.h
+	$(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/eval.c -o $(TRGDIR)/eval.o -I$(TRGDIR)
+
+$(TRGDIR)/machine.o: $(TRGDIR)/machine.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h dwarf2.c
+	$(CC) -c $(TRGDIR)/machine.c -o $(TRGDIR)/machine.o -I$(TRGDIR) -I.
+
+$(TRGDIR)/opts.o: opt.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c -DNO_OPTIMIZER opt.c -o $(TRGDIR)/opts.o -I$(TRGDIR)
+
+$(TRGDIR)/regss.o: regs.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c -DNO_OPTIMIZER regs.c -o $(TRGDIR)/regss.o -I$(TRGDIR)
+
+$(TRGDIR)/vsc.o: vsc/vsc.h vsc/vsc.c $(TRGDIR)/schedule.h
+	$(CC) -c vsc/vsc.c -o $(TRGDIR)/vsc.o -I$(TRGDIR)
+
+$(TRGDIR)/schedule.o: vsc/vsc.h $(TRGDIR)/schedule.h $(TRGDIR)/schedule.c
+	$(CC) -c $(TRGDIR)/schedule.c -o $(TRGDIR)/schedule.o -I$(TRGDIR) -Ivsc
+
+$(TRGDIR)/vcpr.o: vcpr/vcpr.h vcpr/vcpr.c
+	$(CC) -c vcpr/vcpr.c -o $(TRGDIR)/vcpr.o -I$(TRGDIR)
+
+$(TRGDIR)/compress.o: vcpr/vcpr.h $(TRGDIR)/compress.c
+	$(CC) -c $(TRGDIR)/compress.c -o $(TRGDIR)/compress.o -I$(TRGDIR) -Ivcpr
+
+
+
+# Graph coloring register allocator by Alex
+$(TRGDIR)/AdjList.o: GCRegAlloc/AdjList.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c GCRegAlloc/AdjList.c -o $(TRGDIR)/AdjList.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/DUChain.o: GCRegAlloc/DUChain.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c GCRegAlloc/DUChain.c -o $(TRGDIR)/DUChain.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/ICodeInsertion.o: GCRegAlloc/ICodeInsertion.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c GCRegAlloc/ICodeInsertion.c -o $(TRGDIR)/ICodeInsertion.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/NodeList.o: GCRegAlloc/NodeList.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c GCRegAlloc/NodeList.c -o $(TRGDIR)/NodeList.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/RAllocMain.o: GCRegAlloc/RAllocMain.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c GCRegAlloc/RAllocMain.c -o $(TRGDIR)/RAllocMain.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/Web.o: GCRegAlloc/Web.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+	$(CC) -c GCRegAlloc/Web.c -o $(TRGDIR)/Web.o -IGCRegAlloc -I$(TRGDIR)
diff --git a/alias.c b/alias.c
new file mode 100644
index 0000000..f0a942e
--- /dev/null
+++ b/alias.c
@@ -0,0 +1,822 @@
+/*  $VER: vbcc (alias.c) $Revision: 1.6 $  */
+/*  Listen benutzter/veraenderter Variablen und Behandlung von Decknamen.   */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+static bvtype **gpt;
+
+static unsigned long ptsize;
+
+#define is_restrict(i) ((i)<=vcount-rcount&&(vilist[i]->vtyp->flags&RESTRICT))
+
+/* sets points-to-info for var i to undefined */
+void undef_pt(bvtype **pt,int i)
+{
+  if(i<0||i>=vcount) ierror(0);
+  if(pt[i]) ptsize-=vsize;
+  free(pt[i]);
+  pt[i]=0;
+  if(i<rcount){
+    i+=vcount-rcount;
+    if(pt[i]) ptsize-=vsize;
+    free(pt[i]);
+    pt[i]=0;
+  }
+}
+
+/* walks through a clist and sets the corresponding bit in bv
+   for every variable whose address is contained in the clist */
+void add_clist_refs(bvtype *bv,type *t,const_list *cl)
+{
+  /*FIXME: bei Aufrufen auch auf locale, nicht USEDASDEST|USEDASADDR */
+  int i;zmax sz;
+  if(ISARRAY(t->flags)){
+    for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;sz=zmadd(sz,l2zm(1L)),cl=cl->next){
+      if(!cl->other){ierror(0);return;}
+      add_clist_refs(bv,t->next,cl->other);
+    }
+    return;
+  }
+  if(ISUNION(t->flags)){
+    add_clist_refs(bv,(*t->exact->sl)[0].styp,cl);
+    return;
+  }
+  if(ISSTRUCT(t->flags)){
+    type *st;
+    for(i=0;i<t->exact->count&&cl;i++){
+      if(!cl->other){ierror(0);return;}
+      st=(*t->exact->sl)[i].styp;
+      if(!(*t->exact->sl)[i].identifier) ierror(0);
+      if((*t->exact->sl)[i].identifier[0]){
+        add_clist_refs(bv,st,cl->other);
+        cl=cl->next;
+      }
+    }
+    return;
+  }
+  if(cl->tree&&(cl->tree->o.flags&VARADR)){
+    /* careful: variable might not have a valid index if it is not
+       used within the function optimized */
+    i=cl->tree->o.v->index;
+    if(i>=0&&i<vcount-rcount&&vilist[i]==cl->tree->o.v){
+      /*printf("add %s\n",vilist[i]->identifier);*/
+      BSET(bv,i);
+    }
+  }
+}
+
+/* copies points-to-info for one var to another */
+void copy_pt(bvtype **pt,int to,int from)
+{
+  if(to<0||to>=vcount) ierror(0);
+  if(from<0||from>=vcount) ierror(0);
+  if(!pt[from]){
+    if(from>=vcount-rcount&&pt[from-(vcount-rcount)]){
+      /* if dref check, whether from only points to initialized const */
+      int i;bvtype *new;
+      for(i=0;i<vcount;i++){
+	if(BTST(pt[from-(vcount-rcount)],i)){
+	  Var *v=vilist[i];
+	  if(!is_const(v->vtyp)||!v->clist||(v->storage_class!=STATIC&&v->storage_class!=EXTERN))
+	    break;
+	}
+      }
+      if(i==vcount){
+	/* yes, take the points-to-info from clist */
+	if(!pt[to]||to+vcount-rcount==from){
+	  new=mymalloc(vsize);
+	  ptsize+=vsize;
+	}else
+	  new=pt[to];
+	memset(new,0,vsize);
+	for(i=0;i<vcount;i++){
+	  if(BTST(pt[from-(vcount-rcount)],i))
+	    add_clist_refs(new,vilist[i]->vtyp,vilist[i]->clist);
+	}
+	if(to+vcount-rcount==from){
+	  ptsize-=vsize;
+	  free(pt[to]);
+	}
+	pt[to]=new;
+	return;
+      }
+    }
+    undef_pt(pt,to);
+  }else{
+    if(!pt[to]){
+      pt[to]=mymalloc(vsize);
+      ptsize+=vsize;
+    }
+    memcpy(pt[to],pt[from],vsize);
+  }
+}
+
+/* set var i points only to j in points-to-info */
+void set_pt(bvtype **pt,int i,int j)
+{
+  if(i<0||i>=vcount) ierror(0);
+  if(j<0||j>=vcount) ierror(0);
+  if(!pt[i]){
+    pt[i]=mymalloc(vsize);
+    ptsize+=vsize;
+  }
+  memset(pt[i],0,vsize);
+  BSET(pt[i],j);
+}
+
+void print_single_pt(bvtype *pt)
+{
+  int j;
+  if(pt){
+    for(j=0;j<vcount;j++){
+      if(BTST(pt,j))
+	printf("  %s<%s>(%p)\n",(j>=vcount-rcount)?"*":"",vilist[j]->identifier,(void*)vilist[j]);
+    }
+  }else{
+    printf("  (undefined)\n");
+  }
+}
+
+void print_pt(bvtype **pt)
+{
+  int i,j;
+  if(!pt) return;
+  printf("points-to:\n");
+  for(i=0;i<vcount;i++){
+    printf("%s<%s>(%p):\n",(i>=vcount-rcount)?"*":"",vilist[i]->identifier,(void*)vilist[i]);
+    print_single_pt(pt[i]);
+  }
+}
+
+/* creates new points-to-info; every var set to undefined */
+bvtype **new_pt(void)
+{
+  bvtype **pt;
+  int i;
+  pt=mymalloc(vcount*sizeof(*pt));
+  ptsize+=vcount*sizeof(*pt);
+  for(i=0;i<vcount;i++){
+    if(i<rcount&&(vilist[i]->vtyp->flags&RESTRICT)){
+      pt[i]=mymalloc(vsize);
+      ptsize+=vsize;
+      memset(pt[i],0,vsize);
+      BSET(pt[i],i+vcount-rcount);
+    }else
+      pt[i]=0;
+  }
+  return pt;
+}
+
+void free_pt(bvtype **pt)
+{
+  int i;
+  if(pt){
+    for(i=0;i<vcount;i++){
+      if(pt[i]) ptsize-=vsize;
+      free(pt[i]);
+    }
+    ptsize-=vcount*sizeof(*pt);
+    free(pt);
+  }
+}
+
+/* set points-to-info of *v to union of points-to of all vars in the
+   points-to-info of v */
+void dref_pt(bvtype **pt,int i)
+{
+  int j,d;
+  if(i<0||i>=rcount) ierror(0);
+  d=i+vcount-rcount;
+  if(!pt[i]){
+    undef_pt(pt,d);
+    return;
+  }
+  if(!pt[d]){
+    pt[d]=mymalloc(vsize);
+    ptsize+=vsize;
+  }
+  memset(pt[d],0,vsize);
+  for(j=0;j<vcount;j++){
+    if(BTST(pt[i],j)){
+      Var *v=vilist[j];
+      if(v->clist&&is_const(v->vtyp)&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+	add_clist_refs(pt[d],v->vtyp,v->clist);
+      }else if(!pt[j]){
+	undef_pt(pt,d);
+	return;
+      }else
+	bvunite(pt[d],pt[j],vsize);
+    }
+  }
+}
+
+void trans_pt(bvtype **pt,IC *p)
+{
+  int i,j,newset=-1,sv,cp;
+  if((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q1,&p->z,ztyp(p)))
+    return;
+  if((p->z.flags&VAR)&&ISSCALAR(p->z.v->vtyp->flags)){
+    i=p->z.v->index;
+    if(i<0||i>=vcount) ierror(0);
+    if(p->z.flags&DREFOBJ){
+      if(i>=rcount) ierror(0);
+      i+=vcount-rcount;
+    }
+    if(!is_restrict(i)){
+      if(p->code==ASSIGN){
+	newset=i;sv=-1;cp=-1;
+	if(p->q1.flags&VARADR){
+	  sv=p->q1.v->index;
+	  set_pt(pt,i,p->q1.v->index);
+	}else if(p->q1.flags&VAR){
+	  j=p->q1.v->index;
+	  if(j<0||j>=vcount) ierror(0);
+	  if(p->q1.flags&DREFOBJ){
+	    if(j>=rcount) ierror(0);
+	    j+=vcount-rcount;
+	  }
+	  cp=j;
+	  copy_pt(pt,i,j);
+	}else{
+	  if(!pt[i]){
+	    pt[i]=mymalloc(vsize);
+	    ptsize+=vsize;
+	  }
+	  memset(pt[i],0,vsize);
+	}
+      }  
+      if(p->code==ADDRESS){
+	newset=i;sv=p->q1.v->index;cp=-1;
+	set_pt(pt,i,p->q1.v->index);
+      }
+      if((p->code==ADDI2P||p->code==SUBIFP)&&(p->q1.flags&VAR)){
+	newset=i;sv=-1;cp=-1;
+	if(p->q1.flags&VARADR){
+	  sv=p->q1.v->index;
+	  set_pt(pt,i,p->q1.v->index);
+	}else{
+	  j=p->q1.v->index;
+	  if(j<0||j>=vcount) ierror(0);
+	  if(p->q1.flags&DREFOBJ){
+	    if(j>=rcount) ierror(0);
+	    j+=vcount-rcount;
+	  }
+	  cp=j;
+	  copy_pt(pt,i,j);
+	}
+      }
+    }
+  }
+  if(newset>=0&&newset<rcount){
+    if(newset<0) ierror(0);
+    dref_pt(pt,newset);
+  }
+  for(i=0;i<p->change_cnt;i++){
+    j=p->change_list[i].v->index;
+    if(j<0||j>=vcount) ierror(0);
+    if(p->change_list[i].flags&DREFOBJ){
+      if(j>=rcount) ierror(0);
+      j+=vcount-rcount;
+    }
+    if(j!=newset&&!is_restrict(j)){
+      if(newset>=0&&pt[j]){
+	if(sv>=0){
+	  if(sv>=vcount) ierror(0);
+	  BSET(pt[j],sv);
+	}
+	if(cp>=0&&pt[cp]){
+	  if(cp<0||cp>=vcount) ierror(0);
+	  bvunite(pt[j],pt[cp],vsize);
+	}
+      }else
+	undef_pt(pt,j);
+    }
+  }
+}
+
+bvtype **clone_pt(bvtype **pt)
+{
+  int i;
+  bvtype **new;
+  if(!pt)
+    return new_pt();
+  new=mymalloc(vcount*sizeof(*new));
+  ptsize+=vcount*sizeof(*new);
+  for(i=0;i<vcount;i++){
+    if(pt[i]){
+      new[i]=mymalloc(vsize);
+      ptsize+=vsize;
+      memcpy(new[i],pt[i],vsize);
+    }else
+      new[i]=0;
+  }
+  return new;
+}
+
+/* tests if two points-to-infos are identical */
+int equal_pt(bvtype **pt1,bvtype **pt2)
+{
+  int i;
+  if(!pt1&&!pt2) 
+    return 1;
+  if(!pt1||!pt2)
+    return 0;
+  for(i=0;i<vcount;i++){
+    if(!pt1[i]&&!pt2[i])
+      continue;
+    if(!pt1[i]||!pt2[i])
+      return 0;
+    if(memcmp(pt1[i],pt2[i],vsize))
+      return 0;
+  }
+  return 1;
+}
+#if 0
+void calc_pt(flowgraph *fg)
+{
+  flowgraph *g;
+  flowlist *in;
+  IC *p;
+  bvtype **pt,**ppt;
+  int i,all_preds,changed;
+
+  changed=1;
+  while(changed){
+    if(DEBUG&1024) printf("calc_pt pass\n");
+    changed=0;
+    for(g=fg;g;g=g->normalout){
+      /* do all predecessors already have points-to-info? */
+      all_preds=1;
+      for(in=g->in;in;in=in->next){
+	if(!in->graph->pt){
+	  all_preds=0;
+	  break;
+	}
+      }
+      if(all_preds&&g->in){
+	/* calc union of all predecessors */
+	pt=clone_pt(g->in->graph->pt);
+	for(in=g->in->next;in;in=in->next){
+	  ppt=in->graph->pt;
+	  for(i=0;i<vcount;i++){
+	    if(pt[i]){
+	      if(!ppt[i])
+		undef_pt(pt,i);
+	      else
+		bvunite(pt[i],ppt[i],vsize);
+	    }
+	  }
+	}
+      }else
+	pt=new_pt();
+      for(p=g->start;p;p=p->next){
+	trans_pt(pt,p);
+	if(p==g->end)
+	  break;
+      }
+      if(pt==g->pt) ierror(0);
+      if(!changed){
+	if(!equal_pt(pt,g->pt)){
+	  changed=1;
+	  free_pt(g->pt);
+	  g->pt=pt;
+	}else{
+	  free_pt(pt);
+	}
+      }else{
+	free_pt(g->pt);
+	g->pt=pt;
+      }
+    }
+  }
+}
+#endif
+int p_typ(Var *v)
+/*  Liefert den Typ, auf den Variable zeigen kann. Falls nicht eindeutig    */
+/*  wird CHAR zurueckgegeben, da ein char * auf alles zeigen kann.          */
+{
+    type *t=v->vtyp;int f;
+    /*  Kein Zeiger? Dann moeglicherweise Struktur, die verschiedene Zeiger */
+    /*  enthalten koennte. Koennte man evtl. noch genauer pruefen.          */
+    if(!ISPOINTER(t->flags)||!t->next||(v->flags&DNOTTYPESAFE)) return CHAR;
+    f=t->next->flags&NQ;
+    if(f==VOID) f=CHAR;
+    return f;
+}
+
+/* propagates information if a variable whose address may have been taken
+   is modified */
+static void propagate_pointers(bvtype *set,Var *v,int t,int i)
+{
+  int j,t2;
+  if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+    if(noaliasopt){
+      bvunite(set,av_drefs,vsize);
+    }else{
+      for(j=0;j<rcount;j++){
+	t2=p_typ(vilist[j]);
+	if(t==t2||t2==CHAR||!ISSCALAR(t)||!ISSCALAR(t2)){
+	  if(!gpt||!gpt[j]||(i>=0&&BTST(gpt[j],i)))
+	    BSET(set,j+vcount-rcount);
+	}	    
+      }
+    }
+  }
+}
+void alias_propagate(bvtype *set,int i,int t,int wr)
+{
+  int j,t2;
+  Var *v;
+  if(i<0||i>=vcount) ierror(0);
+  t&=NQ;
+  BSET(set,i);
+  if(wr&&i<rcount) BSET(set,i+vcount-rcount);
+  if(i>=vcount-rcount){
+    /* DREFOBJ */
+    if(noaliasopt||t==CHAR||!ISSCALAR(t)){
+      bvunite(set,av_drefs,vsize);
+      bvunite(set,av_address,vsize);
+      bvunite(set,av_globals,vsize);
+    }else{
+      for(j=0;j<vcount-rcount;j++){
+	v=vilist[j];
+	if(!gpt||!gpt[i-(vcount-rcount)]||BTST(gpt[i-(vcount-rcount)],j)){
+	  v=vilist[j];
+	  if(!v) ierror(0);
+	  if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+	    type *tp=v->vtyp;
+	    if(!v->vtyp) ierror(0);
+	    do{
+	      t2=tp->flags&NQ;
+	      tp=tp->next;
+	    }while(ISARRAY(t2));
+	    if(t==t2||!ISSCALAR(t2)){
+	      BSET(set,j);
+	      if(wr&&j<rcount) {BSET(set,j+vcount-rcount);continue;}
+	    }
+	  }
+	}
+	if(j<rcount){
+	  if(i<(vcount-rcount)) ierror(0);
+	  if(!gpt||
+	     (!gpt[i-(vcount-rcount)]&&!is_restrict(j))||
+	     (!gpt[j]&&!is_restrict(i-(vcount-rcount)))||
+	     (gpt[j]&&gpt[i-(vcount-rcount)]&&bvdointersect(gpt[i-(vcount-rcount)],gpt[j],vsize))){
+	    t2=p_typ(v);
+	    if(t==t2||t2==CHAR||!ISSCALAR(t2))
+	      BSET(set,j+vcount-rcount);
+	  }
+	}
+      }
+    }
+  }else{
+    v=vilist[i];
+    propagate_pointers(set,v,t,i);
+  }
+}
+
+void ic_changes(IC *p,bvtype *result)
+/*  Initialisiert den Bitvektor result mit allen Variablen, die durch das   */
+/*  IC p geaendert werden koennten.                                         */
+{
+    int i,j,t,t2;Var *v;
+    memset(result,0,vsize);
+    t=(ztyp(p)&NQ);
+    if(p->z.flags&VAR){
+        v=p->z.v;
+        i=v->index;
+        /*  Hilfsvariable, die waehrend diesem cse-Durchlauf eingefuehrt    */
+        /*  wurde.                                                          */
+        if(i<0) return;
+	if(i>=vcount) ierror(0);
+        if(p->z.flags&DREFOBJ){
+	  if(i>=rcount) ierror(0);
+	  alias_propagate(result,i+vcount-rcount,t,1);
+	}else{
+	  alias_propagate(result,i,t,1);
+	  if(i<rcount) BSET(result,i+vcount-rcount);
+	}
+    }
+    if(p->code==CALL){
+      function_info *fi;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(fi=p->q1.v->fi)&&(fi->flags&ALL_MODS)&&!(disable&65536)){
+	/*  we can get the set from the function_info */
+	for(i=0;i<fi->change_cnt;i++){
+	  if(v=fi->change_list[i].v){
+	    if(v->inr==inr&&v->index>=0){
+	      if(v->index>=vcount) ierror(0);
+	      alias_propagate(result,v->index,v->vtyp->flags&NQ,1);
+	    }else
+	      propagate_pointers(result,v,v->vtyp->flags&NQ,-1);
+	  }else{
+	    for(j=0;j<vcount-rcount;j++){
+	      v=vilist[j];
+	      if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+		t=v->vtyp->flags&NQ;
+		if(t==(fi->change_list[i].flags&NQ)||!ISSCALAR(t)){
+		  BSET(result,j);
+		  if(j<rcount) BSET(result,j+vcount-rcount);
+		}
+	      }
+	      if(j<rcount){
+		t=p_typ(vilist[j]);
+		if(t==CHAR||!ISSCALAR(t)||t==fi->change_list[i].flags)
+		  BSET(result,j+vcount-rcount);
+	      }
+	    }
+	  }
+	}
+      }else{
+	bvunite(result,av_drefs,vsize);
+	bvunite(result,av_address,vsize);
+	bvunite(result,av_globals,vsize);
+	bvunite(result,av_statics,vsize);
+      }
+    }
+    if((p->z.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      bvunite(result,av_drefs,vsize);
+    }
+}
+void ic_uses(IC *p,bvtype *result)
+/*  Initialisiert den Bitvektor result mit allen Variablen, die durch das   */
+/*  IC p benutzt werden koennten.                                           */
+{
+    int i,j,t,t2,c;Var *v;type *tp;
+    memset(result,0,vsize);
+    c=p->code;
+    if(c!=ADDRESS){
+        if((p->q1.flags&(VAR|VARADR))==VAR&&c!=ADDRESS&&(c!=CALL||(p->q1.flags&DREFOBJ))){
+            v=p->q1.v;
+            i=v->index;
+	    if(i<0||i>=vcount) ierror(0);
+	    t=q1typ(p);
+	    if(p->q1.flags&DREFOBJ){
+	      if(i>=rcount) ierror(0);
+	      alias_propagate(result,i+vcount-rcount,t,0);
+	    }
+	    alias_propagate(result,i,t,0);
+        }
+        if((p->q2.flags&(VAR|VARADR))==VAR){
+            v=p->q2.v;
+            i=v->index;
+	    if(i<0||i>=vcount) ierror(0);
+	    t=q2typ(p);
+	    if(p->q2.flags&DREFOBJ){
+	      if(i>=rcount) ierror(0);
+	      alias_propagate(result,i+vcount-rcount,t,0);
+	    }
+	    alias_propagate(result,i,t,0);
+        }
+    }
+    if((p->z.flags&(VAR|VARADR|DREFOBJ))==(VAR|DREFOBJ)){
+        v=p->z.v;
+        i=v->index;
+        if(i>=vcount) {pric2(stdout,p);ierror(0);}
+	t=(ztyp(p)&NQ);
+	alias_propagate(result,i,t,0);
+    }
+    if(p->code==CALL){
+      function_info *fi;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(fi=p->q1.v->fi)&&(fi->flags&ALL_USES)&&!(disable&65536)){
+	/*  we can get the set from the function_info */
+	for(i=0;i<fi->use_cnt;i++){
+	  if(v=fi->use_list[i].v){
+	    if(v->inr==inr&&v->index>=0)
+	      alias_propagate(result,v->index,v->vtyp->flags&NQ,0);
+	    else
+	      propagate_pointers(result,v,v->vtyp->flags&NQ,-1);
+	  }else{
+	    for(j=0;j<vcount-rcount;j++){
+	      v=vilist[j];
+	      if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+		t=v->vtyp->flags&NQ;
+		if(t==(fi->use_list[i].flags&NQ)||!ISSCALAR(t))
+		  BSET(result,j);
+	      }
+	      if(j<rcount){
+		t=p_typ(vilist[j]);
+		if(t==CHAR||!ISSCALAR(t)||t==fi->use_list[i].flags)
+		  BSET(result,j+vcount-rcount);
+	      }
+	    }
+	  }
+	}
+      }else{
+	bvunite(result,av_drefs,vsize);
+	bvunite(result,av_address,vsize);
+	bvunite(result,av_globals,vsize);
+	bvunite(result,av_statics,vsize);
+      }
+    }
+    if((p->q1.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      bvunite(result,av_drefs,vsize);
+    }
+    if((p->q2.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      bvunite(result,av_drefs,vsize);
+    }
+}
+void free_alias(flowgraph *fg)
+/*  Gibt alle use/change-Listen der ICs im Flussgraphen frei.               */
+{
+    IC *p;flowgraph *g;
+    if(DEBUG&1024) printf("freeing alias info\n");
+    for(g=fg;g;g=g->normalout){
+        for(p=g->start;p;p=p->next){
+            if(p->code==LABEL&&(p->use_cnt>0||p->change_cnt>0)) ierror(0);
+            if(p->use_cnt>0) {free(p->use_list);p->use_cnt=0;}
+            if(p->change_cnt>0) {free(p->change_list);p->change_cnt=0;}
+            if(p==g->end) break;
+        }
+    }
+    have_alias=0;
+}
+void create_alias(flowgraph *fg)
+/*  Initialisiert jedes IC mit einer Liste aller Variablen, die dadurch     */
+/*  benutzt und veraendert werden koennten. Z.Z. wird bis auf Typ-basierte  */
+/*  Optimierungen der worst-case angenommen.                                */
+{
+  bvtype *vars=mymalloc(vsize);
+  IC *p;flowgraph *g;
+  flowlist *in;
+  bvtype **ppt;
+  int i,cnt,all_preds,changed;
+  unsigned long heapsize;
+  if(DEBUG&1024) printf("creating alias info\n");
+
+  ptsize=0;
+  
+  changed=1;
+  while(changed){
+    if(DEBUG&1024) printf("create_alias pass\n");
+    changed=0;
+    if(have_alias)
+      free_alias(fg);
+    heapsize=0;
+    for(g=fg;g;g=g->normalout){
+      if((optflags&1024)&&!noaliasopt){
+	/* do all predecessors already have points-to-info? */
+	all_preds=1;
+	for(in=g->in;in;in=in->next){
+	  if(!in->graph->pt){
+	    all_preds=0;
+	    break;
+	  }
+	}
+	if(/*all_preds&&*/g->in){
+	  /* calc union of all predecessors */
+	  gpt=clone_pt(g->in->graph->pt);
+	  for(in=g->in->next;in;in=in->next){
+	    ppt=in->graph->pt;
+	    if(!ppt)
+	      continue;
+	    for(i=0;i<vcount;i++){
+	      if(gpt[i]){
+		if(!ppt[i])
+		  undef_pt(gpt,i);
+		else
+		  bvunite(gpt[i],ppt[i],vsize);
+	      }
+	    }
+	  }
+	}else
+	  gpt=new_pt();                 
+      }else{
+	gpt=0;
+      }
+      for(p=g->start;p;p=p->next){
+	int da; /* always consider a direct write, even if variable is const-qualified */
+	ic_uses(p,vars);
+	for(i=0,cnt=0;i<vcount;i++)
+	  if(BTST(vars,i)) cnt++;
+	p->use_cnt=cnt;
+	if(cnt==0){
+	  p->use_list=0;
+	}else{
+	  p->use_list=mymalloc(cnt*VLS);
+	  heapsize+=cnt*VLS;
+	  for(cnt=0,i=0;i<vcount;i++){
+	    if(BTST(vars,i)){
+	      p->use_list[cnt].v=vilist[i];
+	      if(i>=vcount-rcount) p->use_list[cnt].flags=DREFOBJ;
+	      else         p->use_list[cnt].flags=0;
+	      cnt++;
+	    }
+	  }
+	}
+	ic_changes(p,vars);
+	if((p->z.flags&(VAR|DREFOBJ))==VAR)
+	  da=p->z.v->index;
+	else
+	  da=0;
+	for(i=0,cnt=0;i<vcount;i++)
+	  if(BTST(vars,i)&&(i>=vcount-rcount||i==da||!is_const(vilist[i]->vtyp))) cnt++;
+	p->change_cnt=cnt;
+	if(cnt==0){
+	  p->change_list=0;
+	}else{
+	  p->change_list=mymalloc(cnt*VLS);
+	  heapsize+=cnt*VLS;
+	  for(cnt=0,i=0;i<vcount;i++){
+	    if(BTST(vars,i)&&(i>=vcount-rcount||i==da||!is_const(vilist[i]->vtyp))){
+	      p->change_list[cnt].v=vilist[i];
+	      if(i>=vcount-rcount) p->change_list[cnt].flags=DREFOBJ;
+	      else         p->change_list[cnt].flags=0;
+	      cnt++;
+	    }
+	  }
+	}
+
+	if(p->code==CALL){
+	  if((p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+	    int i=p->q1.v->index;
+	    if(i<0||i>=vcount) ierror(0);
+	    if(gpt&&gpt[i]){
+	      int j,cnt;
+	      for(cnt=0,j=0;j<vcount-rcount;j++){
+		if(BTST(gpt[i],j)&&ISFUNC(vilist[j]->vtyp->flags))
+		  cnt++;
+	      }
+	      if(cnt){
+		if(p->call_cnt) free(p->call_list);
+		p->call_cnt=cnt;
+		p->call_list=mymalloc(sizeof(*p->call_list)*cnt);
+		for(cnt=0,j=0;j<vcount-rcount;j++){
+		  if(BTST(gpt[i],j)&&ISFUNC(vilist[j]->vtyp->flags)){
+		    p->call_list[cnt].v=vilist[j];
+		    p->call_list[cnt].flags=0;
+		    cnt++;
+		  }
+		}
+		if(cnt==1&&all_preds){
+		  if(DEBUG&1024) {printf("replacing indirect call by single target:\n");pric2(stdout,p);}
+		  p->q1.flags=VAR;
+		  p->q1.val.vmax=l2zm(0L);
+		  p->q1.v=p->call_list[0].v;
+		}
+	      }
+	    }
+	  }	  
+	}
+
+	if((optflags&1024)&&!noaliasopt)
+	  trans_pt(gpt,p);
+	if(p==g->end) break;
+      }
+      if((optflags&1024)&&!noaliasopt){
+	if(!changed){
+	  if(!equal_pt(gpt,g->pt)){
+	    changed=1;
+	    free_pt(g->pt);
+	    g->pt=gpt;
+	  }else{
+	    free_pt(gpt);
+	  }
+	}else{
+	  free_pt(g->pt);
+	  g->pt=gpt;
+	}          
+      }           
+    }
+    if(DEBUG&16384) printf("create_alias heapsize=%lu\n",heapsize);
+    have_alias=1;
+  }
+  if(DEBUG&16384) printf("points-to heapsize=%lu\n",ptsize);
+  if((optflags&1024)&&!noaliasopt){
+    for(g=fg;g;g=g->normalout){
+      free_pt(g->pt);
+      g->pt=0;
+    }
+  }
+  free(vars);
+}
+#if 1
+void update_alias(Var *old,Var *new)
+/*  Aendert alle use/changes von (old) auf (new). Wird aufgerufen, wenn     */
+/*  copy-propagation eine Variable neu zu einem DREFOBJ macht.              */
+{
+    IC *p;int i;
+    if(DEBUG&1024) printf("update-alias\n");
+    for(p=first_ic;p;p=p->next){
+        for(i=0;i<p->use_cnt;i++){
+            if(p->use_list[i].v==old&&(p->use_list[i].flags&DREFOBJ)){
+                p->use_cnt++;
+                p->use_list=myrealloc(p->use_list,p->use_cnt*VLS);
+                p->use_list[p->use_cnt-1].v=new;
+                p->use_list[p->use_cnt-1].flags=DREFOBJ;
+                break;
+            }
+        }
+        for(i=0;i<p->change_cnt;i++){
+	  if(p->change_list[i].v==new||(p->change_list[i].v==old&&(p->change_list[i].flags&DREFOBJ))){
+                p->change_cnt++;
+                p->change_list=myrealloc(p->change_list,p->change_cnt*VLS);
+                p->change_list[p->change_cnt-1].v=new;
+                p->change_list[p->change_cnt-1].flags=DREFOBJ;
+                break;
+            }
+        }
+    }
+}
+#endif
diff --git a/av.c b/av.c
new file mode 100644
index 0000000..627fedd
--- /dev/null
+++ b/av.c
@@ -0,0 +1,557 @@
+/*  $VER: vbcc (av.c) $Revision: 1.9 $    */
+/*  aktive Variablen und Elimination unnoetiger Anweisungen */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+/*  fuer aktive Variablen   */
+Var **vilist;
+unsigned int vcount;    /*  0..vcount-rcount-1: vars, vcount-rcount..vcount: DREFOBJs */
+unsigned int rcount;
+size_t vsize;
+bvtype *av_globals,*av_address,*av_statics,*av_drefs;
+int report_dead_statements;
+
+void print_av(bvtype *bitvector)
+/*  druckt Variablen in einem Bitvektor */
+{
+    int i;
+    if(!bitvector) {printf("active variables not available\n");return;}
+    for(i=0;i<vcount-rcount;i++)
+        if(BTST(bitvector,i)) printf("%3d: %s,%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
+    for(i=vcount-rcount;i<vcount;i++)
+        if(BTST(bitvector,i)) printf("%3d: (%s),%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
+}
+
+static int clcnt;
+
+/* walks through a clist and numbers variables whose addresses are
+   contained; if pass==-1, index is set to -1, if pass==0, index is set,
+   otherwise vilist
+   clcnt is used as index-counter in pass 0 */
+void num_clist_refs(int pass,type *t,const_list *cl)
+{
+  /*FIXME: bei Aufrufen auch auf locale, nicht USEDASDEST|USEDASADDR */
+  int i;zmax sz;
+  if(ISARRAY(t->flags)){
+    for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;sz=zmadd(sz,l2zm(1L)),cl=cl->next){
+      if(!cl->other) 
+	return;
+      num_clist_refs(pass,t->next,cl->other);
+    }
+    return;
+  }
+  if(ISUNION(t->flags)){
+    num_clist_refs(pass,(*t->exact->sl)[0].styp,cl);
+    return;
+  }
+  if(ISSTRUCT(t->flags)&&!cl->tree){
+    type *st;
+    for(i=0;i<t->exact->count&&cl;i++){
+      st=(*t->exact->sl)[i].styp;
+      if(!(*t->exact->sl)[i].identifier) ierror(0);
+      if((*t->exact->sl)[i].identifier[0]){
+        if(cl->other)
+	  num_clist_refs(pass,st,cl->other);
+        cl=cl->next;
+      }
+    }
+    return;
+  }
+  if(cl->tree&&(cl->tree->o.flags&VARADR)){
+    Var *v=cl->tree->o.v;
+    if(pass==-1){
+      v->index=-1;
+    }else if(pass==0){
+      if(v->index<0) {v->index=clcnt++;v->inr=inr;}
+    }else{
+      if(v->index<0||v->index>=vcount-rcount)
+	ierror(0);
+      vilist[v->index]=v;
+    }
+  }
+}
+
+int inr;
+
+void num_vars(void)
+/*  Numeriert Variablen und erzeugt Indexliste  */
+{
+    unsigned int i,j,done;IC *p;Var *v,*a[4],*vp;
+    unsigned long heapsize=0;
+    if(DEBUG&1024) printf("numerating variables loop1\n");
+    inr++;
+    /*  alle Indizes auf -1 */
+    a[0]=vl0;
+    a[1]=vl1;
+    a[2]=vl2;
+    a[3]=vl3;
+#if 1
+    for(j=0;j<4;j++){
+        v=a[j];
+        while(v){
+            v->index=-1;
+            /*  Variablen von inline-Funktionen */
+            if(j==0&&v->fi&&v->fi->first_ic){
+                for(vp=v->fi->vars;vp;vp=vp->next) vp->index=-1;
+            }
+            v=v->next;
+        }
+    }
+    /* variables that may be referenced in inter-proc. dflow-info */
+    for(p=first_ic;p;p=p->next){
+      if(p->code==CALL&&(p->q1.flags&VAR)&&p->q1.v->fi){
+	function_info *fi=p->q1.v->fi;
+	if(fi->flags&ALL_USES){
+	  for(i=0;i<fi->use_cnt;i++){
+	    if(v=fi->use_list[i].v) fi->use_list[i].v->index=-1;
+	  }
+	}
+	if(fi->flags&ALL_MODS){
+	  for(i=0;i<fi->change_cnt;i++){
+	    if(v=fi->change_list[i].v) fi->change_list[i].v->index=-1;
+	  }
+	}
+      }
+      /* const-lists */
+      if((p->q1.flags&VAR))
+	if(p->q1.v->clist&&is_const(p->q1.v->vtyp)) num_clist_refs(-1,p->q1.v->vtyp,p->q1.v->clist);
+      if((p->q2.flags&VAR))
+	if(p->q2.v->clist&&is_const(p->q2.v->vtyp)) num_clist_refs(-1,p->q2.v->vtyp,p->q2.v->clist);
+      if((p->z.flags&VAR))
+	if(p->z.v->clist&&is_const(p->z.v->vtyp)) num_clist_refs(-1,p->z.v->vtyp,p->z.v->clist);
+    }
+#endif
+    /* Do we need this? */
+    for(p=first_ic;p;p=p->next){
+      if(p->q1.flags&VAR) {p->q1.v->index=-1;p->q1.v->flags&=~USEDASADR;}
+      if(p->q2.flags&VAR) {p->q2.v->index=-1;p->q2.v->flags&=~USEDASADR;}
+      if(p->z.flags&VAR) {p->z.v->index=-1;p->z.v->flags&=~USEDASADR;}
+    }
+    /*  erst alle Variablen, die als DREFOBJ benutzt werden */
+    if(DEBUG&1024) printf("numerating variables loop2\n");
+    i=0;
+    do{
+      done=1;
+      if(DEBUG&1024) printf("pass\n");
+      for(p=first_ic;p;p=p->next){
+        if(p->code<LABEL||p->code>BRA){
+	  int c=p->code;
+	  /* mark variables ad USEDASADR */
+	  if(c==ADDRESS) p->q1.v->flags|=USEDASADR;
+	  if(p->q1.flags&VARADR) p->q1.v->flags|=USEDASADR;
+	  if(p->q2.flags&VARADR) p->q2.v->flags|=USEDASADR;
+	  if(p->z.flags&VARADR) p->z.v->flags|=USEDASADR;
+	  j=(q1typ(p)&NQ);
+	  if((p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+	    v=p->q1.v;
+	    if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
+	    if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
+	  }
+	  j=(q2typ(p)&NQ);
+	  if((p->q2.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+	    v=p->q2.v;
+	    if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
+	    if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
+	  }
+	  j=(ztyp(p)&NQ);
+	  if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+	    v=p->z.v;
+	    if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
+	    if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
+	  }
+	  /* mark copies from DREFs also as DREFs (necessary?) (check z for !DREFOBJ?) */
+	  if((c==ASSIGN||c==ADDI2P||c==SUBIFP)&&(p->q1.flags&VAR)&&p->q1.v->index>=0&&(p->z.flags&VAR)&&p->z.v->index<0){
+	    if(!(p->z.flags&VAR)) ierror(0);
+	    p->z.v->index=i++;p->z.v->inr=inr;done=0;
+	  }
+	  /* mark copies to DREFs as DREFs (because of copy-propagation */
+	  /* and post-op reordering */
+	  if((c==ASSIGN||c==ADDI2P||c==SUBIFP)&&(p->z.flags&VAR)&&p->z.v->index>=0&&(p->q1.flags&VAR)&&p->q1.v->index<0){
+	    p->q1.v->index=i++;p->q1.v->inr=inr;done=0;
+	  }	  
+        }
+      }
+    }while(!done);
+    if(DEBUG&1024) printf("numerating variables loop3\n");
+    rcount=i;    /*  Anzahl der DREFOBJ-Variablen    */
+    /*  jetzt den Rest  */
+    for(p=first_ic;p;p=p->next){
+        int c=p->code;
+        if(1/*p->code<LABEL||p->code>BRA*/){
+            if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+	      j=(q1typ(p)&NQ);
+	      v=p->q1.v;
+	      if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
+	      if(v->index<0) {v->index=i++;v->inr=inr;}
+            }
+            if((p->q2.flags&(VAR|DREFOBJ))==VAR){
+	      j=(q2typ(p)&NQ);
+	      v=p->q2.v;
+	      if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
+	      if(v->index<0) {v->index=i++;v->inr=inr;}
+            }
+            if((p->z.flags&(VAR|DREFOBJ))==VAR){
+	      j=(ztyp(p)&NQ);
+	      v=p->z.v;
+	      if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
+	      if(v->index<0) {v->index=i++;v->inr=inr;}
+            }
+        }
+	/* const-lists */
+	if((p->q1.flags&VAR))
+	  if(p->q1.v->clist&&is_const(p->q1.v->vtyp)) {clcnt=i;num_clist_refs(0,p->q1.v->vtyp,p->q1.v->clist);i=clcnt;}
+	if((p->q2.flags&VAR))
+	  if(p->q2.v->clist&&is_const(p->q2.v->vtyp)) {clcnt=i;num_clist_refs(0,p->q2.v->vtyp,p->q2.v->clist);i=clcnt;}
+	if((p->z.flags&VAR))
+	  if(p->z.v->clist&&is_const(p->z.v->vtyp)) {clcnt=i;num_clist_refs(0,p->z.v->vtyp,p->z.v->clist);i=clcnt;}
+    }
+    if(DEBUG&1024) printf("numerating variables loop4\n");
+    vcount=i+rcount; /*  alle benutzten Variablen+Anzahl der DREFOBJs    */
+    vilist=mymalloc(vcount*sizeof(Var *));
+    heapsize+=vcount*sizeof(Var *);
+#if 0
+    for(j=0;j<4;j++){
+        int i;
+        v=a[j];
+        while(v){
+            i=v->index;
+/*            printf("%s has index %d\n",v->identifier,i);*/
+            if(i>=0){
+                if(i>=vcount-rcount) ierror(0);
+                vilist[i]=v;
+                if(i<rcount) vilist[i+vcount-rcount]=v;
+            }
+            /*  Variablen von inline-Funktionen */
+            if(j==0&&v->fi&&v->fi->first_ic){
+                for(vp=v->fi->vars;vp;vp=vp->next){
+                    i=vp->index;
+                    if(i>=0){
+                        if(i>=vcount-rcount) ierror(0);
+                        vilist[i]=vp;
+                        if(i<rcount) vilist[i+vcount-rcount]=vp;
+                    }
+                }
+            }
+            v=v->next;
+        }
+    }
+#endif
+
+    for(p=first_ic;p;p=p->next){
+      Var *v;
+      if(p->q1.flags&VAR){
+	i=p->q1.v->index;
+	vilist[i]=v=p->q1.v;
+	if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
+      }
+      if(p->q2.flags&VAR){
+	i=p->q2.v->index;
+	vilist[i]=v=p->q2.v;
+	if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
+
+      }
+      if(p->z.flags&VAR){
+	i=p->z.v->index;
+	vilist[i]=v=p->z.v;
+	if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
+      }
+    }
+    for(i=0;i<rcount;i++)
+      vilist[i+vcount-rcount]=vilist[i];
+
+    /*vsize=(vcount+CHAR_BIT-1)/CHAR_BIT;*/
+    vsize=BVSIZE(vcount);
+    if(DEBUG&(16384|1024)) printf("%lu variables (%lu DREFOBJs), vsize=%lu\n",(unsigned long)vcount,(unsigned long)rcount,(unsigned long)vsize);
+
+    av_drefs=mymalloc(vsize);
+    memset(av_drefs,0,vsize);
+    /*  alle DREFOBJs   */
+    for(i=vcount-rcount;i<vcount;i++) BSET(av_drefs,i);
+
+    /*  av_globals enthaelt alle globalen Variablen und av_address      */
+    /*  zusaetzlich noch alle Variablen, deren Adressen genommen wurden */
+    av_globals=mymalloc(vsize);
+    memset(av_globals,0,vsize);
+    av_statics=mymalloc(vsize);
+    memset(av_statics,0,vsize);
+    av_address=mymalloc(vsize);
+    memcpy(av_address,av_globals,vsize);
+    heapsize+=4*vsize;
+    for(i=0;i<vcount-rcount;i++){
+        if(vilist[i]->nesting==0||vilist[i]->storage_class==EXTERN) BSET(av_globals,i);
+        if(vilist[i]->flags&USEDASADR) BSET(av_address,i);
+        if(vilist[i]->storage_class==STATIC) BSET(av_statics,i);
+        if(i<rcount){
+/*            if(!ISPOINTER(vilist[i]->vtyp->flags)){ printf("%s(%ld)\n",vilist[i]->identifier,zm2l(vilist[i]->offset));ierror(0);}*/
+            BSET(av_address,i+vcount-rcount);
+            BSET(av_globals,i+vcount-rcount);
+        }
+    }
+    if(DEBUG&16384) printf("num_vars heapsize=%lu\n",heapsize);
+}
+void print_vi(void)
+/*  Druckt vilist und testet Konsistenz */
+{
+    int i;
+    printf("\nprint_vi()\n");
+    for(i=0;i<vcount;i++){
+        if(!vilist[i]||(i<rcount&&vilist[i]->index!=i)) ierror(0);
+        printf("%3d: %s\n",i,vilist[i]->identifier);
+    }
+}
+void av_change(IC *p,bvtype *use,bvtype *def)
+/*  Berechnet die Aenderungen, die sich durch IC p an use und def ergeben.  */
+{
+    int i,j,n=-1;
+    int g1,g2;
+
+    /*  Wenn eine Quelle==Ziel, dann wird dadurch kein neuer use erzeugt,   */
+    /*  um z.B. unbenutzte Induktionsvariablen in Schleifen zu eliminieren. */
+    g1=compare_objs(&p->q1,&p->z,p->typf);
+    g2=compare_objs(&p->q2,&p->z,p->typf);
+    if(!g1&&(p->q1.flags&(VAR|DREFOBJ))==VAR) n=p->q1.v->index;
+    if(!g2&&(p->q2.flags&(VAR|DREFOBJ))==VAR) n=p->q2.v->index;
+
+    for(j=0;j<p->use_cnt;j++){
+        i=p->use_list[j].v->index;
+        if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
+        if(i>=vcount) continue;
+        if(i!=n&&!BTST(def,i)) BSET(use,i);
+    }
+
+    /*  Ein Wert wird nicht zerstoert, wenn es kein elementarer Typ ist und */
+    /*  die Groesse kleiner als die Variable (steht in alle solchen ICs in  */
+    /*  q2.val.max.                                                         */
+    if((p->z.flags&(VAR|DREFOBJ))==VAR&&(ISSCALAR(p->z.v->vtyp->flags)||p->z.v->vtyp->flags==0||zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp)))){
+        i=p->z.v->index;
+        if(i>=vcount) ierror(0);
+        if(g1&&g2&&!BTST(use,i)) BSET(def,i);
+        /*  Wenn p geaendert wird, wird auch *p geaendert   */
+        if(i<rcount&&!BTST(def,i+vcount-rcount)) BSET(use,i+vcount-rcount);
+    }
+    if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&g1&&g2&&!(p->z.v->flags&DNOTTYPESAFE)){
+        i=p->z.v->index+vcount-rcount;
+        if(i>=vcount) ierror(0);
+        if(!BTST(use,i)) BSET(def,i);
+    }
+}
+void active_vars(flowgraph *fg)
+/*  analysiert aktive Variablen im Flussgraphen, nomain==0, wenn zu     */
+/*  optimierende Funktion main() ist                                    */
+{
+    IC *p;
+    int changed,pass;flowgraph *g;
+    unsigned long heapsize=0;
+
+    if(DEBUG&1024){printf("analysing active variables\n");/*scanf("%d",&i);*/}
+    tmp=mymalloc(vsize);
+    heapsize+=vsize;
+    /*  av_gen und av_kill fuer jeden Basic Block berechnen */
+    if(DEBUG&1024){printf("active_vars(): loop1\n");/*scanf("%d",&i);*/}
+    g=fg;
+    while(g){
+        g->av_gen=mymalloc(vsize);
+        memset(g->av_gen,0,vsize);
+        g->av_kill=mymalloc(vsize);
+        memset(g->av_kill,0,vsize);
+        g->av_in=mymalloc(vsize);
+        memset(g->av_in,0,vsize);
+        g->av_out=mymalloc(vsize);
+        memset(g->av_out,0,vsize);
+	heapsize+=4*vsize;
+        for(p=g->start;p;p=p->next){
+            av_change(p,g->av_gen,g->av_kill);
+            if(p==g->end) break;
+        }
+        g=g->normalout;
+    }
+
+    /*  av_in und av_out fuer alle Bloecke berechnen    */
+    if(DEBUG&1024){printf("active_vars(): loop2\npass: ");/*scanf("%d",&i);*/}
+    pass=0;
+    do{
+        if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+        changed=0;
+        g=fg;
+        while(g){
+            /* out(B)=U in(C) ueber alle Nachfolger C von B */
+            memset(g->av_out,0,vsize);  /*  noetig? */
+            if(g->branchout) bvunite(g->av_out,g->branchout->av_in,vsize);
+            if((!g->end||g->end->code!=BRA)&&g->normalout) bvunite(g->av_out,g->normalout->av_in,vsize);
+            /*  Am Ende muessen alle globalen Variablen bekannt sein    */
+            if(!g->normalout){
+                bvunite(g->av_out,av_globals,vsize);
+                /*if(!nocall)*/ bvunite(g->av_out,av_statics,vsize);
+            }
+            /* in(B)=use(B)U(out(B)-def(B)) */
+            memcpy(tmp,g->av_out,vsize);
+            bvdiff(tmp,g->av_kill,vsize);
+            bvunite(tmp,g->av_gen,vsize);
+
+            if(!bvcmp(tmp,g->av_in,vsize)){changed=1;memcpy(g->av_in,tmp,vsize);}
+            g=g->normalout;
+        }
+    }while(changed);
+    if(DEBUG&1024) printf("\n");
+    free(tmp);
+    if(DEBUG&16384) printf("av heapsize=%lu\n",heapsize);
+}
+void av_update(IC *p,bvtype *isused)
+{
+  int i,j;
+  if((p->z.flags&(VKONST|VAR))==VAR){
+    i=p->z.v->index;
+    if(p->z.flags&DREFOBJ) i+=vcount-rcount;    
+    if(i<0||i>=vcount){
+      printf("i=%d\n",i);pric2(stdout,p); ierror(0);
+    }
+    if(p->z.flags&DREFOBJ){
+      if(!(p->z.v->flags&DNOTTYPESAFE))
+	BCLR(isused,i);
+    }else{
+      if(ISSCALAR(p->z.v->vtyp->flags)||(p->code==ASSIGN&&zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp))))
+	BCLR(isused,i);
+    }
+    /*  bei Zuweisung an p wird *p aktiv    */
+    if(i<rcount) BSET(isused,i+vcount-rcount);
+  }
+  for(j=0;j<p->use_cnt;j++){
+    i=p->use_list[j].v->index;
+    if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
+    if(i<0||i>=vcount) continue;
+    BSET(isused,i);
+  }  
+}
+/* tests, if IC p uses or modifies var v */
+static int var_conflicts(Var *v,IC *p)
+{
+  int i;
+  for(i=0;i<p->use_cnt;i++)
+    if(p->use_list[i].v==v&&!(p->use_list[i].flags&DREFOBJ)) 
+      return 1;
+  for(i=0;i<p->change_cnt;i++)
+    if(p->change_list[i].v==v&&!(p->change_list[i].flags&DREFOBJ)) 
+      return 1;
+  return 0;
+}
+int dead_assignments(flowgraph *fg)
+/*  Findet Zuweisungen, die unnoetig sind, da die Variable nie mehr     */
+/*  benutzt werden kann.                                                */
+{
+    int changed=0;IC *p;bvtype *isused;
+    int i,j;
+    if(DEBUG&1024) printf("searching for dead assignments\n");
+    isused=mymalloc(vsize);
+    while(fg){
+      memcpy(isused,fg->av_out,vsize);
+      p=fg->end;
+      while(p){
+	if(p->z.flags&VAR){
+	  i=p->z.v->index;
+	  if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+	  if(!BTST(isused,i)&&!is_volatile_ic(p)&&!(disable&1)){
+	    if(DEBUG&1024){printf("dead assignment deleted:\n");pric2(stdout,p);}
+	    if(*p->z.v->identifier&&p->code!=ASSIGN){ err_ic=p;error(170,i>=vcount-rcount?"*":"",p->z.v->identifier);err_ic=0;}
+	    /*if(p->code!=GETRETURN)*/ changed=1;
+	    if(p==fg->start){remove_IC_fg(fg,p);break;}
+	    p=p->prev;remove_IC_fg(fg,p->next);
+	    continue;
+	  }
+	}
+	if(p->code!=SETRETURN&&p->code!=TEST&&p->code!=COMPARE&&(p->q1.flags&VAR)&&!BTST(isused,p->q1.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
+          IC *m,*a;int f=p->q1.flags,dt=p->q1.dtyp;
+	  p->q1.flags&=~DREFOBJ;
+	  a=p->prev;if(a) m=a->prev; else m=0;
+	  if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q1,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
+	    if(DEBUG&1024){
+	      printf("reorder post-op(q1):\n");
+	      pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
+	    }
+	    p->q1=a->q1;
+	    m->next=p;p->prev=m;
+	    if(p->next) p->next->prev=a;
+	    a->next=p->next;
+	    a->prev=p;p->next=a;
+	    if(fg->end==p) fg->end=a;
+	    if(p==last_ic) last_ic=a;
+	    remove_IC_fg(fg,m);
+	    av_update(a,isused);
+	    p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
+	    memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
+	    p->use_cnt+=a->use_cnt;
+	    changed=1;
+	    if((f&DREFOBJ)&&p->q1.v->index>=rcount)
+	      ierror(0);
+	  }
+	  p->q1.flags=f;
+	  p->q1.dtyp=dt;
+	}
+	if(p->code!=TEST&&p->code!=COMPARE&&(p->q2.flags&VAR)&&!BTST(isused,p->q2.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
+          IC *m,*a;int f=p->q2.flags,dt=p->q2.dtyp;
+	  p->q2.flags&=~DREFOBJ;
+	  a=p->prev;if(a) m=a->prev; else m=0;
+	  if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q2,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
+	    if(DEBUG&1024){
+	      printf("reorder post-op(q2):\n");
+	      pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
+	    }
+	    p->q2=a->q1;
+	    m->next=p;p->prev=m;
+	    if(p->next) p->next->prev=a;
+	    a->next=p->next;
+	    a->prev=p;p->next=a;
+	    if(fg->end==p) fg->end=a;
+	    if(p==last_ic) last_ic=a;
+	    remove_IC_fg(fg,m);
+	    av_update(a,isused);
+	    p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
+	    memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
+	    p->use_cnt+=a->use_cnt;
+	    changed=1;
+	    if((f&DREFOBJ)&&p->q2.v->index>=rcount)
+	      ierror(0);
+	  }
+	  p->q2.flags=f;
+	  p->q2.dtyp=dt;
+	}
+	if(p->code!=TEST&&p->code!=COMPARE&&(p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&!BTST(isused,p->z.v->index)){
+          IC *m,*a;int f=p->z.flags,dt=p->z.dtyp;
+	  p->z.flags&=~DREFOBJ;
+	  a=p->prev;if(a) m=a->prev; else m=0;
+	  if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->z,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
+	    if(DEBUG&1024){
+	      printf("reorder post-op(z):\n");
+	      pric2(stdout,m);pric2(stdout,a);pric2(stdout,p);
+	      printf("--");
+	    }
+	    p->z=a->q1;
+	    m->next=p;p->prev=m;
+	    if(p->next) p->next->prev=a;
+	    a->next=p->next;
+	    a->prev=p;p->next=a;
+	    if(fg->end==p) fg->end=a;
+	    if(p==last_ic) last_ic=a;
+	    remove_IC_fg(fg,m);
+	    av_update(a,isused);
+	    p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
+	    memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
+	    p->use_cnt+=a->use_cnt;
+	    changed=1;
+	    if((f&DREFOBJ)&&p->z.v->index>=rcount)
+	      ierror(0);
+	  }
+	  p->z.flags=f;
+	  p->z.dtyp=dt;
+	}
+	av_update(p,isused);
+	if(p==fg->start) break;
+	p=p->prev;
+      }
+      fg=fg->normalout;
+    }
+    free(isused);
+    return(changed);
+}
+
diff --git a/bin/.dummy b/bin/.dummy
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/bin/.dummy
diff --git a/bug.c b/bug.c
new file mode 100755
index 0000000..975ff3d
--- /dev/null
+++ b/bug.c
@@ -0,0 +1,130 @@
+/*  $VER: vbcc (loop.c) V0.8     */
+/*  schleifenorientierte Optimierungen  */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+#define MOVE_IC 1
+#define MOVE_COMP 2
+
+/*  Liste, in die ICs eingetragen werden, die aus Schleifen */
+/*  gezogen werden sollen.                                  */
+struct movlist{
+  struct movlist *next;
+  struct IC *IC;
+  struct flowgraph *target_fg;
+  int flags;
+};
+
+struct movlist *first_mov,*last_mov;
+
+int report_weird_code,report_suspicious_loops;
+
+/*  Bitvektoren fuer schleifeninvariante ICs    */
+bvtype *invariant,*inloop,*moved,*moved_completely;
+bvtype *fg_tmp;
+bvtype *not_movable;
+size_t bsize;
+
+
+/*  Liste, in die ICs fuer strength-reduction eingetragen   */
+/*  werden.                                                 */
+struct srlist{
+  struct srlist *next;
+  struct IC *ind_var;
+  struct IC *IC;
+  struct flowgraph *target_fg;
+  /*  Hilfsvariable, falls eine aequivalente Operation schon reduziert    */
+  /*  wurde.                                                              */
+  struct Var *hv;
+};
+
+struct srlist *first_sr,*last_sr;
+
+/*  Liste, in die Daten fuer loop-unrolling eingetragen werden. */
+struct urlist{
+  int flags;
+  long total,unroll;
+  struct IC *cmp,*branch,*ind;
+  struct flowgraph *start,*head;
+  struct urlist *next;
+} *first_ur;
+
+#define UNROLL_COMPLETELY 1
+#define UNROLL_MODULO 2
+#define UNROLL_INVARIANT 4
+#define UNROLL_REVERSE 8
+#define IND_ONLY_COUNTS 16
+#define MULTIPLE_EXITS 32
+
+/*  Hier werden Induktionsvariablen vermerkt    */
+struct IC **ind_vars;
+
+static struct flowgraph *first_fg;
+
+
+void calc_movable(struct flowgraph *start,struct flowgraph *end)
+/*  Berechnet, welche Definitionen nicht aus der Schleife start-end     */
+/*  verschoben werden duerfen. Eine Def. p von z darf nur verschoben    */
+/*  werden, wenn keine andere Def. von p existiert und alle             */
+/*  Verwendungen von z nur von p erreicht werden.                       */
+/*  Benutzt rd_defs.                                                    */
+{
+  struct flowgraph *g;struct IC *p;
+  int i,j,k,d;
+  bvtype *changed_vars;
+  if(DEBUG&1024) printf("calculating not_movable for blocks %d to %d\n",start->index,end->index);
+  if(0/*!(optflags&1024)*/){
+    memset(not_movable,UCHAR_MAX,dsize);
+    return;
+  }
+  memset(not_movable,0,dsize);
+  changed_vars=mymalloc(vsize);
+  memset(changed_vars,0,vsize);
+  for(i=0;i<vcount-rcount;i++){
+    if(vilist[i]->vtyp->flags&VOLATILE) BSET(changed_vars,i);
+    if(i<rcount){
+      if(!vilist[i]->vtyp->next||(vilist[i]->vtyp->next->flags&VOLATILE)) BSET(changed_vars,i+vcount-rcount);
+    }
+  }
+  for(g=start;g;g=g->normalout){
+    if(!g->rd_in) ierror(0);
+    memcpy(rd_defs,g->rd_in,dsize);
+    for(p=g->start;p;p=p->next){
+      for(j=0;j<p->change_cnt;j++){
+	i=p->change_list[j].v->index;
+	if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+	if(i>=vcount) continue;
+	if(BTST(changed_vars,i)||(q1typ(p)&VOLATILE)||(q2typ(p)&VOLATILE)||(ztyp(p)&VOLATILE)){
+	  bvunite(not_movable,var_defs[i],dsize);
+	}else{
+	  BSET(changed_vars,i);
+	}
+      }
+      for(k=0;k<p->use_cnt;k++){
+	i=p->use_list[k].v->index;
+	if(p->use_list[k].flags&DREFOBJ) i+=vcount-rcount;
+	if(i>=vcount) continue;
+	for(d=-1,j=1;j<=dcount;j++){
+	  if(BTST(rd_defs,j)&&BTST(var_defs[i],j)){
+	    if(d>=0){  /*  mehr als eine Def.  */
+	      bvunite(not_movable,var_defs[i],dsize);
+	      d=-1;break;
+	    }else d=j;
+	  }
+	  if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))){
+	    bvunite(not_movable,var_defs[i],dsize);
+	    d=-1;break;
+	  }
+	}
+      }
+      /*  Das hier, um rd_defs zu aktualisieren.  */
+      rd_change(p);
+      if(p==g->end) break;
+    }
+    if(g==end) break;
+  }
+  free(changed_vars);
+}
+
diff --git a/cp.c b/cp.c
new file mode 100644
index 0000000..8e21ef2
--- /dev/null
+++ b/cp.c
@@ -0,0 +1,357 @@
+/*  $VER: vbcc (cp.c) $Revision: 1.5 $     */
+/*  verfuegbare Kopien und copy propagation */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+/*  fuer verfuegbare Kopien */
+unsigned int ccount;
+size_t csize;
+IC **clist;
+
+/*  alle Assignments, globaler oder Adr. fuer propagation etc.         */
+bvtype *cp_globals,*cp_address,*cp_statics,*cp_drefs,*cp_act,*cp_dest;
+/*  alle Kopieranweisungen, die eine best. Variable als Quelle haben    */
+bvtype **copies;
+
+static bvtype *cp_matrix;
+
+void available_copies(flowgraph *fg)
+/*  berechnet die verfuegbaren Kopien fuer jeden Block      */
+{
+    flowgraph *g;IC *p;bvtype *tmp;
+    int changed,pass,i,j;
+    unsigned heapsize=0;
+    /*  cp_gen und cp_kill fuer jeden Block berechnen   */
+    if(DEBUG&1024) printf("analysing available copies\n");
+    tmp=mymalloc(csize);
+    heapsize+=csize;
+    for(g=fg;g;g=g->normalout){
+        g->cp_in=mymalloc(csize);
+        memset(g->cp_in,0,csize);
+        g->cp_out=mymalloc(csize);
+        memset(g->cp_out,0,csize);
+        g->cp_gen=mymalloc(csize);
+        memset(g->cp_gen,0,csize);
+        g->cp_kill=mymalloc(csize);
+        memset(g->cp_kill,0,csize);
+	heapsize+=4*csize;
+        for(p=g->end;p;p=p->prev){
+            memset(tmp,0,csize);
+            for(j=0;j<p->change_cnt;j++){
+                i=p->change_list[j].v->index;
+                if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+                if(i>=vcount) continue;
+                bvunite(tmp,copies[i],csize);
+            }
+            i=p->copyindex;
+            if(i>=0&&!BTST(g->cp_kill,i)) BSET(g->cp_gen,i);
+            bvdiff(tmp,g->cp_gen,csize);
+            bvunite(g->cp_kill,tmp,csize);
+
+            if(p==g->start) break;
+        }
+        if(g==fg){
+            memset(g->cp_in,0,csize);
+            memcpy(g->cp_out,g->cp_gen,csize);
+        }else{
+            memset(g->cp_out,UCHAR_MAX,csize);
+            bvdiff(g->cp_out,g->cp_kill,csize);
+        }
+    }
+    /*  cp_in und cp_out fuer jeden Block berechnen */
+    /*  out(b)=U-gen(B) vorinitialisiert und        */
+    /*  in(B0)=0, out(B0)=gen(B0)                   */
+    if(DEBUG&1024) {printf("pass:");pass=0;}
+    do{
+        if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+        changed=0;
+        g=fg->normalout;    /*  in B0 aendert sich nichts   */
+        while(g){
+            flowlist *lp;
+            /*  in(B)=Schnitt out(P) mit P Vorgaenger von B */
+            lp=g->in;
+            i=0;    /*  Flag fuer ersten Vorgaenger */
+            while(lp){
+                if(!lp->graph) ierror(0);
+                if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+                    if(i){
+                        bvintersect(g->cp_in,lp->graph->cp_out,csize);
+                    }else{
+                        memcpy(g->cp_in,lp->graph->cp_out,csize);i=1;
+                    }
+                }
+                lp=lp->next;
+            }
+            /*  out(b)=gen(B) U (in(B)-kill(B)  */
+            memcpy(tmp,g->cp_in,csize);
+            bvdiff(tmp,g->cp_kill,csize);
+            bvunite(tmp,g->cp_gen,csize);
+            if(!bvcmp(tmp,g->cp_out,csize)){changed=1;memcpy(g->cp_out,tmp,csize);}
+            g=g->normalout;
+        }
+    }while(changed);
+    if(DEBUG&1024) printf("\n");
+    if(DEBUG&16384) printf("available copies heapsize=%lu\n",(unsigned long)heapsize);
+    free(tmp);
+}
+
+int compare_cp(const void *a1,const void *a2)
+/*  Stub fuer compare_objs, damit als Vergleichsfunktion fuer qsort geht */
+{
+    IC *p1,*p2;int i1,i2;
+    p1=*((IC **)a1);p2=*((IC **)a2);
+    if(!p1||!p2) ierror(0);
+    i1=p1->typf; i2=p2->typf;
+    if(i1<i2) return -1;
+    if(i1>i2) return 1;
+    i1=compare_objs(&p1->q1,&p2->q1,p1->typf);
+    if(i1) return i1;
+    i1=compare_objs(&p1->z,&p2->z,p1->typf);
+    return i1;
+}
+
+void num_copies(void)
+/*  numeriert alle einfachen Kopieranweisungen  */
+{
+    IC *p;Var *v;int i,n,c;
+    bvtype *bp;
+    unsigned long heapsize=0;
+    if(DEBUG&1024) printf("numerating copies loop1\n");
+    ccount=0;
+    for(p=first_ic;p;p=p->next){
+        if(p->code==ASSIGN&&(p->q1.flags&(VAR/*|VARADR*/))==VAR&&(p->z.flags&VAR)) p->copyindex=ccount++;
+            else            p->copyindex=-1;
+    }
+    /*csize=(ccount+CHAR_BIT-1)/CHAR_BIT;*/
+    csize=BVSIZE(ccount);
+    if(DEBUG&(16384|1024)) printf("ccount=%lu, csize=%lu\n",(unsigned long)ccount,(unsigned long)csize);
+    clist=mymalloc(ccount*sizeof(IC *));
+    heapsize+=ccount*sizeof(IC *);
+    cp_globals=mymalloc(csize);
+    memset(cp_globals,0,csize);
+    cp_statics=mymalloc(csize);
+    memset(cp_statics,0,csize);
+    cp_address=mymalloc(csize);
+    memset(cp_address,0,csize);
+    cp_drefs=mymalloc(csize);
+    memset(cp_drefs,0,csize);
+    heapsize+=4*csize;
+    copies=mymalloc(vcount*sizeof(bvtype *));
+    heapsize+=vcount*sizeof(bvtype *);
+    if(DEBUG&1024){ printf("num_copies loop2\n");}
+    for(p=first_ic;p;p=p->next){
+        if(p->copyindex>=0){
+            clist[p->copyindex]=p;
+        }
+    }
+    if(DEBUG&1024){ printf("sorting copies\n");}
+    if(ccount>1) vqsort(clist,ccount,sizeof(IC *),compare_cp);
+    if(DEBUG&1024){ printf("renumbering copies\nnum_copies loop3\n");}
+    if(ccount>0){   /*  Aufpassen, da ccount unsigned!  */
+        for(c=0;c<ccount-1;c++){
+            if(!compare_cp(&clist[c],&clist[c+1]))
+                clist[c+1]->copyindex=clist[c]->copyindex;
+        }
+    }
+    if(DEBUG&1024) printf("re-sorting copies\n");
+    /*  wieder in die richtige Reihenfolge bringen  */
+    for(p=first_ic;p;p=p->next)
+        if(p->copyindex>=0) clist[p->copyindex]=p;
+
+    cp_matrix=bp=mymalloc(vcount*csize);
+    heapsize+=vcount*csize;
+    memset(cp_matrix,0,vcount*csize);
+
+    for(i=0;i<vcount;i++){
+      copies[i]=bp;
+      bp+=csize/sizeof(bvtype);
+    }
+
+    if(DEBUG&1024) printf("numerating copies loop4\n");
+    for(p=first_ic;p;p=p->next){
+        i=p->copyindex;
+        if(i>=0){
+/*            clist[i]=p;*/
+            v=p->z.v;
+            n=v->index;
+            if(p->z.flags&DREFOBJ) n+=vcount-rcount;
+            if(n<0||n>=vcount)
+	      ierror(0);
+            BSET(copies[n],i);
+            if(v->nesting==0||v->storage_class==EXTERN) BSET(cp_globals,i);
+            if(p->z.flags&DREFOBJ) BSET(cp_drefs,i);
+            if(v->storage_class==STATIC) BSET(cp_statics,i);
+            if(v->flags&USEDASADR) BSET(cp_address,i);
+            v=p->q1.v;
+            n=v->index;
+            if(p->q1.flags&DREFOBJ) n+=vcount-rcount;
+            if(n<0||n>=vcount){pric2(stdout,p);printf("n=%d\n",n); ierror(0);}
+            BSET(copies[n],i);
+            if(v->nesting==0||v->storage_class==EXTERN) BSET(cp_globals,i);
+            if(p->q1.flags&DREFOBJ) BSET(cp_drefs,i);
+            if(v->storage_class==STATIC) BSET(cp_statics,i);
+            if(v->flags&USEDASADR) BSET(cp_address,i);
+
+        }
+    }
+    if(DEBUG&2048){
+        printf("copy instructions:\n");
+        for(i=0;i<ccount;i++){
+            printf("%3d: ",i);pric2(stdout,clist[i]);
+            /*if(clist[i]->copyindex!=i) ierror(0);*/
+        }
+    }
+    if(DEBUG&16384) printf("num_cp heapsize=%lu\n",heapsize);
+}
+void print_cp(bvtype *cp)
+{
+    int i;
+    if(!cp) {printf("available copies not available\n");return;}
+    for(i=0;i<ccount;i++)
+        if(BTST(cp,i)){printf("%3d: ",i);pric2(stdout,clist[i]);}
+}
+int cprop(obj *o,int target,zmax size)
+/*  ersetzt gegebenenfalls  Kopien, noch aendern, so dass Pointer in DREFOBJS ersetzt werden wie bei target */
+{
+  IC *p,*f=0;int i;Var *old;
+  old=o->v;
+  i=old->index;
+  if(!target&&(o->flags&DREFOBJ)) i+=vcount-rcount;
+  if(i<0||i>=vcount) ierror(0);
+  memcpy(tmp,cp_act,csize);
+  bvintersect(tmp,copies[i],csize);
+  /*  waehrend diesem Durchlauf geaenderte Kopieranweisungen lieber nicht */
+  /*  beachten                                                            */
+  bvdiff(tmp,cp_dest,csize);
+  for(i=0;i<ccount;i++){
+    if(BTST(tmp,i)){
+      p=clist[i];
+      if(p->z.v==o->v
+	 &&(zmeqto(size,l2zm(0L))||zmeqto(size,p->q2.val.vmax))
+	 &&p->q1.v!=o->v&&zmeqto(p->z.val.vmax,o->val.vmax)
+	 &&(ISSCALAR(o->v->vtyp->flags)||(p->typf&NQ)==(o->v->vtyp->flags&NQ))
+	 &&!must_convert(p->typf,o->v->vtyp->flags,0)
+	 &&!is_volatile_ic(p)
+	 ){
+	if(((o->flags&DREFOBJ)&&!(p->q1.flags&DREFOBJ))||!(p->q1.flags&DREFOBJ)&&(!static_cse||!((p->q1.flags&(VAR|VARADR))==VAR)||(p->q1.v->storage_class!=EXTERN&&p->q1.v->storage_class!=STATIC))){
+	  int mdtyp;
+	  if(DEBUG&1024){ printf("can replace <%s> by copy:\n",o->v->identifier);pric2(stdout,clist[i]);}
+	  p->q1.flags&=~SCRATCH;
+	  mdtyp=o->dtyp;
+          /* Maybe it would be more precise to recalculate all (D)NOTTYPESAFE
+             info afterwards */
+          if(o->v->flags&NOTTYPESAFE){
+            if((p->q1.flags&(VAR|VARADR))==VAR)
+              p->q1.v->flags|=NOTTYPESAFE;
+          }
+          if(o->v->flags&DNOTTYPESAFE){
+            if((p->q1.flags&(VAR|VARADR))==VAR)
+              p->q1.v->flags|=DNOTTYPESAFE;
+          }
+	  *o=p->q1;
+	  if(target){
+	    o->flags|=DREFOBJ;
+	    o->dtyp=mdtyp;
+	    if((o->flags&(VARADR|DREFOBJ))==(VARADR|DREFOBJ))
+	      o->flags&=~(VARADR|DREFOBJ);
+	    update_alias(old,o->v);
+	    /*  Wenn eine Variable, dadurch zu einer DREF-Variable  */
+	    /*  wird, muss num_vars spaeter erneut gemacht werden   */
+	    if(o->v->index>=rcount){
+	      ierror(0);
+#if 0
+	      update_alias(old,o->v);
+	      return 2;
+#endif
+	    }
+	  }
+	  return 1;
+	}
+      }
+    }
+  }
+  return 0;
+}
+int copy_propagation(flowgraph *fg,int global)
+/*  gibt Kopien weiter  */
+{
+    flowgraph *g; obj old;int or;
+    IC *p;Var *v;int i,changed,r,j;
+    if(DEBUG&1024) printf("searching copies\n");
+    cp_act=mymalloc(csize);
+    cp_dest=mymalloc(csize);
+    memset(cp_dest,0,csize);
+    tmp=mymalloc(csize);
+    g=fg;changed=0;
+    while(g){
+        if(!global) memset(cp_act,0,csize); else memcpy(cp_act,g->cp_in,csize);
+        p=g->start;
+        while(p){
+            zmax size;
+            if(p->code==ASSIGN||p->code==PUSH) size=p->q2.val.vmax;
+                else size=l2zm(0L);
+/*            print_cp(cp_act); pric2(stdout,p);*/
+            r=0;
+            if(p->code!=ADDRESS&&p->code!=NOP){
+                if((p->q1.flags&(VAR|VARADR))==VAR){
+                    r|=cprop(&p->q1,0,size);
+                    if(p->q1.flags&DREFOBJ) r|=cprop(&p->q1,1,0);
+                }
+                if((p->q2.flags&(VAR|VARADR))==VAR){
+                /*  passt auf, dass USEQ2ASZ nicht verletzt wird, ist dabei */
+                /*  aber nicht sehr effizient (evtl. koennte kommutiert     */
+                /*  werden, o.ae.)                                          */
+                    if(!USEQ2ASZ){ old=p->q2;or=r;}
+                    r|=cprop(&p->q2,0,size);
+                    if(p->q2.flags&DREFOBJ) r|=cprop(&p->q2,1,0);
+                    if(!USEQ2ASZ&&!compare_objs(&p->q2,&p->z,p->typf)){
+                        if(DEBUG&1024) printf("copy propagation taken back, because of USEQ2ASZ\n");
+                        p->q2=old;
+                        r=or;
+                    }
+                }
+                if((p->z.flags&(VAR|VARADR|DREFOBJ))==(VAR|DREFOBJ)){
+                /*  passt auf, dass USEQ2ASZ nicht verletzt wird, ist dabei */
+                /*  aber nicht sehr effizient (evtl. koennte kommutiert     */
+                /*  werden, o.ae.                                           */
+                    if(!USEQ2ASZ){ old=p->z;or=r;}
+                    r|=cprop(&p->z,1,0);
+                    if(!USEQ2ASZ&&!compare_objs(&p->q2,&p->z,p->typf)){
+                        if(DEBUG&1024) printf("copy propagation taken back, because of USEQ2ASZ\n");
+                        p->z=old;
+                        r=or;
+                    }
+                }
+            }
+            if(r&&p->copyindex>=0) BSET(cp_dest,p->copyindex);
+            changed|=r;
+
+            for(j=0;j<p->change_cnt;j++){
+                i=p->change_list[j].v->index;
+                if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+                if(i>=vcount) continue;
+                bvdiff(cp_act,copies[i],csize);
+            }
+            if(p->copyindex>=0) BSET(cp_act,p->copyindex);
+
+            if(p==g->end) break;
+            p=p->next;
+        }
+        g=g->normalout;
+    }
+    free(cp_act);
+    free(cp_dest);
+    free(tmp);
+    free(clist);
+    free(cp_globals);
+    free(cp_statics);
+    free(cp_address);
+    free(cp_drefs);
+    free(cp_matrix);
+    free(copies);
+    gchanged|=changed;
+    return changed;
+}
+
diff --git a/cse.c b/cse.c
new file mode 100644
index 0000000..e180d3d
--- /dev/null
+++ b/cse.c
@@ -0,0 +1,411 @@
+/*  $VER: vbcc (cse.c) $Revision: 1.11 $    */
+/*  verfuegbare Ausdruecke und common subexpression elimination */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+/*  fuer verfuegbare Ausdruecke */
+IC **elist;
+unsigned int ecount;
+size_t esize;
+bvtype *ae_globals,*ae_statics,*ae_address,*ae_drefs;
+bvtype **ae_kills;
+
+static bvtype *cse_matrix;
+
+void available_expressions(flowgraph *fg)
+/*  berechnet die verfuegbaren Ausdruecke fuer jeden Block      */
+{
+    flowgraph *g;IC *p;bvtype *tmp;
+    int changed,pass,i,j;
+    unsigned long heapsize=0;
+    /*  ae_gen und ae_kill fuer jeden Block berechnen   */
+    if(DEBUG&1024) printf("analysing available expressions\n");
+    tmp=mymalloc(esize);
+    heapsize+=esize;
+    g=fg;
+    while(g){
+        g->ae_in=mymalloc(esize);
+        memset(g->ae_in,0,esize);
+        g->ae_out=mymalloc(esize);
+        memset(g->ae_out,0,esize);
+        g->ae_gen=mymalloc(esize);
+        memset(g->ae_gen,0,esize);
+        g->ae_kill=mymalloc(esize);
+        memset(g->ae_kill,0,esize);
+	heapsize+=4*esize;
+        p=g->end;
+        while(p){
+            memset(tmp,0,esize);
+            for(j=0;j<p->change_cnt;j++){
+                i=p->change_list[j].v->index;
+                if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+                if(i>=vcount) continue;
+                bvunite(tmp,ae_kills[i],esize);
+            }
+            bvdiff(tmp,g->ae_gen,esize);
+            bvunite(g->ae_kill,tmp,esize);
+            i=p->expindex;
+            if(i>=0&&!BTST(g->ae_kill,i)) BSET(g->ae_gen,i);
+
+            if(p==g->start) break;
+            p=p->prev;
+        }
+        if(g==fg){
+            memset(g->ae_in,0,esize);
+            memcpy(g->ae_out,g->ae_gen,esize);
+        }else{
+            memset(g->ae_out,UCHAR_MAX,esize);
+            bvdiff(g->ae_out,g->ae_kill,esize);
+        }
+        g=g->normalout;
+    }
+
+    /*  ae_in und ae_out fuer jeden Block berechnen */
+    /*  out(b)=U-gen(B) vorinitialisiert und        */
+    /*  in(B0)=0, out(B0)=gen(B0)                   */
+    if(DEBUG&1024) {printf("pass:");pass=0;}
+    do{
+        if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+        changed=0;
+        g=fg->normalout;    /*  in B0 aendert sich nichts   */
+        while(g){
+            flowlist *lp;
+            /*  in(B)=Schnitt out(P) mit P Vorgaenger von B */
+            lp=g->in;
+            i=0;    /*  Flag fuer ersten Vorgaenger */
+            while(lp){
+                if(!lp->graph) ierror(0);
+                if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+                    if(i){
+                        bvintersect(g->ae_in,lp->graph->ae_out,esize);
+                    }else{
+                        memcpy(g->ae_in,lp->graph->ae_out,esize);i=1;
+                    }
+                }
+                lp=lp->next;
+            }
+            /*  out(b)=gen(B) U (in(B)-kill(B)  */
+            memcpy(tmp,g->ae_in,esize);
+            bvdiff(tmp,g->ae_kill,esize);
+            bvunite(tmp,g->ae_gen,esize);
+            if(!bvcmp(tmp,g->ae_out,esize)){changed=1;memcpy(g->ae_out,tmp,esize);}
+            g=g->normalout;
+        }
+    }while(changed);
+    if(DEBUG&1024) printf("\n");
+    if(DEBUG&16384) printf("available expressions heapsize=%lu\n",heapsize);
+    free(tmp);
+}
+
+int compare_objs(obj *o1,obj *o2,int t)
+/*  Vergleicht die beiden Objekte; liefert 0, wenn sie gleich sind, sonst   */
+/*  1 oder -1, um eine Ordnung darauf zu definieren                         */
+{
+    int i1,i2;
+    i1=o1->flags&~SCRATCH;i2=o2->flags&~SCRATCH;
+    if(i1<i2) return -1;
+    if(i1>i2) return 1;
+    if(i1&DREFOBJ){
+      if(o1->dtyp<o2->dtyp) return -1;
+      if(o1->dtyp>o2->dtyp) return 1;
+    }
+    if(i1&KONST) return(compare_const(&o1->val,&o2->val,t));
+    if(i1&VAR){
+        i1=o1->v->index; i2=o2->v->index;
+        if(i1<i2) return -1;
+        if(i1>i2) return 1;
+	if(!zmeqto(o1->val.vmax,o2->val.vmax)){
+	  if(zmleq(o1->val.vmax,o2->val.vmax))
+	    return -1;
+	  else
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+int compare_exp(const void *a1,const void *a2)
+/*  Stub fuer compare_objs, damit als Vergleichsfunktion fuer qsort geht */
+{
+    IC *p1,*p2;int i1,i2;
+    p1=*((IC **)a1);p2=*((IC **)a2);
+    if(!p1||!p2) ierror(0);
+    i1=p1->code; i2=p2->code;
+    if(i1<i2) return -1;
+    if(i1>i2) return 1;
+    i1=p1->typf&(NU|VOLATILE|SIGNED_CHARACTER); i2=p2->typf&(NU|VOLATILE|SIGNED_CHARACTER);
+    if(i1<i2) return -1;
+    if(i1>i2) return 1;
+    i1=compare_objs(&p1->q1,&p2->q1,q1typ(p1));
+    if(i1) return i1;
+    i1=compare_objs(&p1->q2,&p2->q2,q2typ(p1));
+    return i1;
+}
+
+void print_ae(bvtype *exp)
+{
+    int i;
+    if(!exp){ printf("available expressions not available\n"); return;}
+    for(i=0;i<ecount;i++)
+        if(BTST(exp,i))
+            {printf("%3d,%3d: ",elist[i]->expindex,i);pric2(stdout,elist[i]);}
+}
+void num_exp(void)
+/*  numeriert die Ausdruecke so, dass gleiche Ausdruecke die gleiche    */
+/*  nummer erhalten                                                     */
+{
+    IC *p;int c,i;
+    bvtype *bp;
+    unsigned long heapsize=0;
+    if(DEBUG&1024) printf("numerating expressions\n");
+    ecount=0;
+    if(DEBUG&1024){ printf("num_exp loop1\n");}
+    for(p=first_ic;p;p=p->next){
+        c=p->code;
+        if(p->z.flags&&p->q1.flags&&(c!=ASSIGN||(p->q1.flags&DREFOBJ)||(static_cse&&(p->q1.flags&(VAR|VARADR))==VAR&&ISSCALAR(p->q1.v->vtyp->flags)&&(p->q1.v->storage_class==EXTERN||p->q1.v->storage_class==STATIC)))&&c!=MOVETOREG&&c!=MOVEFROMREG){
+            p->expindex=ecount++;
+            if(c==ADD||c==MULT||(c>=OR&&c<=AND)){
+                if(p->q2.flags&&compare_objs(&p->q1,&p->q2,p->typf)<0&&(USEQ2ASZ||compare_objs(&p->q1,&p->z,p->typf))){
+                    obj o;
+                    o=p->q1;p->q1=p->q2;p->q2=o;
+                }
+            }
+        }else p->expindex=-1;
+    }
+    elist=mymalloc(ecount*sizeof(IC *));
+    heapsize+=ecount*sizeof(IC *);
+    if(DEBUG&1024){ printf("num_exp loop2\n");}
+    for(p=first_ic;p;p=p->next){
+        if(p->expindex>=0){
+            elist[p->expindex]=p;
+        }
+    }
+    /*esize=(ecount+CHAR_BIT-1)/CHAR_BIT;*/
+    esize=BVSIZE(ecount);
+    if(DEBUG&(16384|1024)){ printf("%lu expressions, esize=%lu\nsorting expressions\n",(unsigned long)ecount,(unsigned long)esize);}
+    if(ecount>1) vqsort(elist,ecount,sizeof(IC *),compare_exp);
+    if(DEBUG&1024){ printf("renumbering expressions\nnum_exp loop3\n");}
+    if(ecount>0){   /*  Aufpassen, da ecount unsigned!  */
+        for(c=0;c<ecount-1;c++){
+            if(!compare_exp(&elist[c],&elist[c+1]))
+                elist[c+1]->expindex=elist[c]->expindex;
+        }
+    }
+    if(DEBUG&1024) printf("re-sorting expressions\n");
+    /*  wieder in die richtige Reihenfolge bringen  */
+    for(p=first_ic;p;p=p->next)
+        if(p->expindex>=0) elist[p->expindex]=p;
+    ae_globals=mymalloc(esize);
+    memset(ae_globals,0,esize);
+    ae_statics=mymalloc(esize);
+    memset(ae_statics,0,esize);
+    ae_address=mymalloc(esize);
+    memset(ae_address,0,esize);
+    ae_drefs=mymalloc(esize);
+    memset(ae_drefs,0,esize);
+    heapsize+=esize;
+    if(DEBUG&1024){ printf("num_exp loop4\n");}
+    ae_kills=mymalloc(vcount*sizeof(bvtype *));
+    heapsize+=vcount*sizeof(bvtype *);
+    cse_matrix=bp=mymalloc(vcount*esize);
+    heapsize+=vcount*esize;
+    memset(bp,0,vcount*esize);
+    for(c=0;c<vcount;c++){
+        ae_kills[c]=bp;
+	bp+=esize/sizeof(bvtype);
+    }
+    if(DEBUG&1024){ printf("num_exp loop5\n");}
+    for(c=0;c<ecount;c++){
+        Var *v;
+/*        if(c<ecount-1&&elist[c]==elist[c+1]) continue;*/  /*  gleiche ueberspringen   */
+        p=elist[c];
+        if(p->code==ADDRESS) continue;
+        if((p->q1.flags&(VAR|VARADR))==VAR){
+            v=p->q1.v;
+            i=v->index;
+            BSET(ae_kills[i],c);
+            if(p->q1.flags&DREFOBJ){ BSET(ae_kills[i+vcount-rcount],c);BSET(ae_drefs,c);}
+            if(v->nesting==0||v->storage_class==EXTERN) BSET(ae_globals,c);
+            if(v->storage_class==STATIC) BSET(ae_statics,c);
+            if(v->flags&USEDASADR) BSET(ae_address,c);
+        }
+        if((p->q2.flags&(VAR|VARADR))==VAR){
+            v=p->q2.v;
+            i=v->index;
+            BSET(ae_kills[i],c);
+            if(p->q2.flags&DREFOBJ){ BSET(ae_kills[i+vcount-rcount],c);BSET(ae_drefs,c);}
+            if(v->nesting==0||v->storage_class==EXTERN) BSET(ae_globals,c);
+            if(v->storage_class==STATIC) BSET(ae_statics,c);
+            if(v->flags&USEDASADR) BSET(ae_address,c);
+        }
+    }
+    if(DEBUG&16384) printf("num_exp heapsize=%lu\n",heapsize);
+}
+void cse_replace(flowgraph *g,IC *p,IC *o,Var *v)
+/*  ersetzt die cse bei o zu p mit Variable v   */
+{
+    IC *n;
+    /*  Kopieranweisung erzeugen    */
+    if(DEBUG&1024) printf("cse_replace\n");
+    n=new_IC();
+    n->line=o->line;
+    n->file=o->file;
+    n->code=ASSIGN;
+    n->typf=p->typf;
+    n->expindex=n->defindex=-1;    
+    n->q2.flags=0;
+    n->q2.val.vmax=szof(v->vtyp);
+    n->q1.flags=VAR;
+    n->q1.v=v;
+    n->q1.val.vmax=l2zm(0L);
+    n->z=o->z;
+
+    /*  Die Kopieranweisung benutzt hoechstens, was die urspruengliche  */
+    /*  Operation benutzt hat+die Hilfsvariable und aendert nur, was    */
+    /*  die urspruengliche vorher geaendert hat.                        */
+    if(have_alias){
+        n->use_cnt=o->use_cnt+1;
+        n->use_list=mymalloc(n->use_cnt*VLS);
+        n->use_list[0].v=v;
+        n->use_list[0].flags=0;
+        memcpy(&n->use_list[1],o->use_list,o->use_cnt*VLS);
+        n->change_cnt=o->change_cnt;
+        n->change_list=o->change_list;
+    }
+    /*  evtl. FLussgraph korrigieren    */
+    if(g->end==o) g->end=n;
+    /*  einfuegen   */
+    insert_IC(o,n);
+    /*  Operation auf Hilfsvariable umlenken    */
+    o->z=n->q1;
+    /*  Operation aendert nun nur Hilfsvariable.   */
+    if(have_alias){
+        /*  Liste nicht freigeben, da sie umgebogen wird.   */
+        o->change_cnt=1;
+        o->change_list=mymalloc(VLS);
+        o->change_list[0].v=v;
+        o->change_list[0].flags=0;
+    }	 
+}
+void cse_search(flowgraph *g,IC *p,IC *o,Var *v,int global,bvtype *bmk)
+/*  sucht die Quelle(n) fuer common subexpression und ersetzt sie   */
+/*  bmk ist Buffer, um zu merken, welche Bloecke schon besucht sind */
+{
+    flowlist *lp;
+    /*  Letzte Berechnung des Ausdrucks suchen, beginnend bei o */
+    /*  bei global kann o auch 0 sein!                          */
+/*    if(DEBUG&1024) printf("cse_search\n");*/
+    if(global){
+        if(BTST(bmk,g->index)) return;
+    }
+    while(o&&o->expindex!=p->expindex){
+        if(o==g->start) break;
+        o=o->prev;
+    }
+    if(!o&&!global) ierror(0);
+    if(o&&o->expindex==p->expindex){
+        if(!(o->z.flags&VAR)||o->z.v!=v)
+            cse_replace(g,p,o,v);
+        return;
+    }
+    if(!global) ierror(0);
+    /*  Block als besucht markieren, wenn er durchsucht wurde. Der  */
+    /*  erste Block bei globaler Suche muss beachtet werden und     */
+    /*  Endlosschleifen vermieden werden.                           */
+    if(o||!g->end) BSET(bmk,g->index);
+    lp=g->in;
+    while(lp){
+        if(!lp->graph) ierror(0);
+        if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+            cse_search(lp->graph,p,lp->graph->end,v,global,bmk);
+        }
+        lp=lp->next;
+    }
+}
+
+int cse(flowgraph *fg,int global)
+/*  common-subexpression-elimination; wenn global==0 werden nur einzelne    */
+/*  Bloecke betrachtet                                                      */
+{
+    flowgraph *g;IC *p,*o;int changed,i,j;
+    bvtype *ae,*done;Var *v;type *new;
+    if(DEBUG&1024) printf("common-subexpression-elimination\n");
+    changed=0;
+    ae=mymalloc(esize);
+    if(global){
+      done=mymalloc(esize);
+      memset(done,0,esize);
+    }else
+      done=0;
+    for(g=fg;g;g=g->normalout){
+        if(!global) memset(ae,0,esize); else memcpy(ae,g->ae_in,esize);
+        p=g->start;
+        while(p){
+            i=p->expindex;
+	    /* TODO: correctly handle KONST|DREFOBJ in change_list and enable KONST|DREFOBJ */
+            if(i>=0&&!is_volatile_ic(p)&&(p->q1.flags&(KONST|DREFOBJ))!=(KONST|DREFOBJ)&&(p->q2.flags&(KONST|DREFOBJ))!=(KONST|DREFOBJ)){
+	      if(!global||!BTST(done,i)){
+	        int t=ztyp(p);
+                if(i>=ecount) ierror(0);
+		if(p->code==ASSIGN&&!zmeqto(p->q2.val.vmax,sizetab[t&NQ])) t=ARRAY; /* no memcpy ICs */
+                if(BTST(ae,i)&&ISSCALAR(t)&&!(elist[i]->flags&EFF_IC)){
+                    if(DEBUG&1024){ printf("can eliminate common subexpression:\n");pric2(stdout,p);}
+                    /*  Hilfsvariable erzeugen  */
+                    new=new_typ();
+		    new->flags=t;
+                    if(p->code==COMPARE||p->code==TEST) new->flags=0;
+                    if(ISPOINTER(new->flags)){
+                        new->next=new_typ();
+                        new->next->flags=VOID;
+                    }
+                    v=add_tmp_var(new);
+                    v->index=-1;
+                    /*  Operation durch assign Hilfsvariable ersetzen   */
+                    p->code=ASSIGN;
+                    p->typf=new->flags;
+                    p->q1.flags=VAR;
+                    p->q1.v=v;
+                    p->q1.val.vmax=l2zm(0L);
+                    p->q2.flags=0;
+                    p->q2.val.vmax=szof(new);
+                    if(global){
+                        bvtype *bmk;size_t bsize;
+                        /*bsize=(basic_blocks+CHAR_BIT)/CHAR_BIT;*/
+			bsize=BVSIZE(basic_blocks+1);
+                        bmk=mymalloc(bsize);
+                        memset(bmk,0,bsize);
+                        cse_search(g,p,0,v,global,bmk);
+                        free(bmk);
+			BSET(done,i);
+                    }else
+		      cse_search(g,p,p->prev,v,global,0);
+                    changed=1;
+                    gchanged|=1;
+                }else BSET(ae,i);
+	      }
+            }
+            for(j=0;j<p->change_cnt;j++){
+                i=p->change_list[j].v->index;
+                if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+                if(i>=vcount) continue;
+                bvdiff(ae,ae_kills[i],esize);
+            }
+            if(p==g->end) break;
+            p=p->next;
+        }
+    }
+
+    free(done);
+    free(ae);
+    free(cse_matrix);
+    free(ae_kills);
+    free(ae_globals);
+    free(ae_statics);
+    free(ae_address);
+    free(ae_drefs);
+    free(elist);
+
+    return changed;
+}
diff --git a/datatypes/datatypes.h b/datatypes/datatypes.h
new file mode 100755
index 0000000..75cf5a3
--- /dev/null
+++ b/datatypes/datatypes.h
@@ -0,0 +1,36 @@
+/* elementary data types currently known to vbcc */
+
+/* unsigned 8bit byte */
+"S8BU", "standard unsigned 8bit byte",
+
+/* signed 8bit byte */
+"S8BS", "standard 2-complement 8bit byte", 
+
+/* typical unsigned integers, big-endian */
+"S16BUBE", "standard 8bit-byte-based unsigned 16bit word, big-endian",
+"S32BUBE", "standard 8bit-byte-based unsigned 32bit word, big-endian",
+"S64BUBE", "standard 8bit-byte-based unsigned 64bit byte, big-endian",
+
+/* typical unsigned integers, little-endian */
+"S16BULE", "standard 8bit-byte-based unsigned 16bit word, little-endian",
+"S32BULE", "standard 8bit-byte-based unsigned 32bit word, little-endian",
+"S64BULE", "standard 8bit-byte-based unsigned 64bit byte, little-endian",
+
+/* typical signed integers, big-endian */
+"S16BSBE", "standard 8bit-byte-based 2-complement 16bit word, big-endian",
+"S32BSBE", "standard 8bit-byte-based 2-complement 32bit word, big-endian",
+"S64BSBE", "standard 8bit-byte-based 2-complement 64bit word, big-endian",
+
+/* typical signed integers, little-endian */
+"S16BSLE", "standard 8bit-byte-based 2-complement 16bit word, little-endian",
+"S32BSLE", "standard 8bit-byte-based 2-complement 32bit word, little-endian",
+"S64BSLE", "standard 8bit-byte-based 2-complement 64bit word, little-endian",
+
+/* typical IEEE-floats, big-endian */
+"S32BIEEEBE", "standard 8bit-byte-based 32bit IEEE floating-point, big-endian",
+"S64BIEEEBE", "standard 8bit-byte-based 64bit IEEE floating-point, big-endian",
+
+/* typical IEEE-floats, little-endian */
+"S32BIEEELE", "standard 8bit-byte-based 32bit IEEE floating-point, little-endian",
+"S64BIEEELE", "standard 8bit-byte-based 64bit IEEE floating-point, little-endian",
+
diff --git a/datatypes/dtconv.h b/datatypes/dtconv.h
new file mode 100755
index 0000000..7fe6cd8
--- /dev/null
+++ b/datatypes/dtconv.h
@@ -0,0 +1,20 @@
+"S16BSBE","S16BSLE","dtswap16f.c","dtswap16t.c",2,
+"S16BUBE","S16BULE","dtswap16f.c","dtswap16t.c",2,
+"S32BSBE","S32BSLE","dtswap32f.c","dtswap32t.c",4,
+"S32BUBE","S32BULE","dtswap32f.c","dtswap32t.c",4,
+"S64BSBE","S64BSLE","dtswap64f.c","dtswap64t.c",8,
+"S64BUBE","S64BULE","dtswap64f.c","dtswap64t.c",8,
+"S32BIEEEBE","S32BIEEELE","dtswap32f.c","dtswap32t.c",4,
+"S64BIEEEBE","S64BIEEELE","dtswap64f.c","dtswap64t.c",8,
+"S16BSLE","S16BSBE","dtswap16f.c","dtswap16t.c",2,
+"S16BULE","S16BUBE","dtswap16f.c","dtswap16t.c",2,
+"S32BSLE","S32BSBE","dtswap32f.c","dtswap32t.c",4,
+"S32BULE","S32BUBE","dtswap32f.c","dtswap32t.c",4,
+"S64BSLE","S64BSBE","dtswap64f.c","dtswap64t.c",8,
+"S64BULE","S64BUBE","dtswap64f.c","dtswap64t.c",8,
+"S32BIEEELE","S32BIEEEBE","dtswap32f.c","dtswap32t.c",4,
+"S64BIEEELE","S64BIEEEBE","dtswap64f.c","dtswap64t.c",8,
+
+#include "dtwidths.h"
+
+
diff --git a/datatypes/dtf.c b/datatypes/dtf.c
new file mode 100644
index 0000000..be36f46
--- /dev/null
+++ b/datatypes/dtf.c
@@ -0,0 +1,11 @@
+from)
+{
+  DTTTYPE to=0;
+  int i,j=0;
+  for(i=sizeof(from.a)-1;i>=0;i--)
+    to=(to<<8)|(from.a[i]&255);
+
+  to<<=(sizeof(to)*8)-BITSIZE;
+  to>>=(sizeof(to)*8)-BITSIZE;
+  return to;
+}
diff --git a/datatypes/dtgen.c b/datatypes/dtgen.c
new file mode 100755
index 0000000..513d20c
--- /dev/null
+++ b/datatypes/dtgen.c
@@ -0,0 +1,397 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#ifndef __STDC_VERSION__
+#ifdef __GNUC__
+#define __STDC_VERSION__ 199901L
+#endif
+#endif
+
+struct dtlist {char *spec,*descr;} dts[]={
+#include "datatypes.h"
+};
+
+struct dtconvlist {char *from,*to,*filef,*filet;int size;} cnvs[]={
+#include "dtconv.h"
+};
+
+int dtcnt=sizeof(dts)/sizeof(dts[0]);
+int cnvcnt=sizeof(cnvs)/sizeof(cnvs[0]);
+
+signed char *have;
+
+#define CHAR 1
+#define UCHAR 2
+#define SHORT 3 
+#define USHORT 4
+#define INT 5
+#define UINT 6
+#define LONG 7
+#define ULONG 8
+#define LLONG 9
+#define ULLONG 10
+#define FLOAT 11
+#define DOUBLE 12
+#define LDOUBLE 13
+#define POINTER 14
+
+#define TYPECNT POINTER
+
+char *typen[TYPECNT+1]={"error","char","uchar","short","ushort","int","uint",
+		        "long","ulong","llong","ullong","float","double","ldouble",
+			"pointer"};
+char *ftypen[TYPECNT+1]={"error","char","unsigned char","short","unsigned short",
+                                 "int","unsigned int","long","unsigned long",
+			         "long long","unsigned long long",
+                                 "float","double","long double",
+			         "char *"};
+
+int dt[TYPECNT+1],cnv[TYPECNT+1];
+char *nt[TYPECNT+1];
+FILE *fin,*cout,*hout;
+int crosscompiler;
+
+void *mymalloc(size_t size)
+{
+  void *p=malloc(size);
+  if(!p){
+    printf("Out of memory!\n");
+    exit(EXIT_FAILURE);
+  }
+  return p;
+}
+
+#define TESTTYPE(type,VALA,VALB) \
+    if(sizeof(type)*CHAR_BIT==bits){\
+      type tst=VALA;\
+      if(islittle&&*((unsigned char *)&tst)==VALB)\
+        return yn?"y":#type;\
+      if(isbig&&*(((unsigned char *)(&tst+1))-1)==VALB)\
+	return yn?"y":#type;\
+    }\
+
+
+char *yndefault(char *spec,int yn)
+{
+  int isieee=0,isunsigned=0,issigned,islittle=0,isbig=0,bits=0;
+  char *none;
+  if(yn) none="n"; else none="";
+  if(*spec++!='S') return none;
+  while(isdigit(*(unsigned char *)spec))
+    bits=bits*10+*spec++-'0';
+  if(*spec++!='B') return none;
+  if(!strncmp(spec,"IEEE",4))
+    {isieee=1;spec+=4;}
+  else if(*spec=='U')
+    {isunsigned=1;spec++;}
+  else if(*spec=='S')
+    {issigned=1;spec++;}
+  else
+    return none;
+  if(spec[0]=='B'&&spec[1]=='E')
+    {isbig=1;spec++;}
+  else if(spec[0]=='L'&&spec[1]=='E')
+    {islittle=1;spec++;}
+  else
+    islittle=isbig=1;
+  if(isieee){
+    TESTTYPE(float,1.0,0);
+    TESTTYPE(double,1.0,0);
+    TESTTYPE(long double,1.0,0);
+    return none;
+  }
+  if(isunsigned){
+    TESTTYPE(unsigned char,123,123);
+    TESTTYPE(unsigned short,123,123);
+    TESTTYPE(unsigned int,123,123);
+    TESTTYPE(unsigned long,123,123);
+#if __STDC_VERSION__==199901L
+    TESTTYPE(unsigned long long,123,123);
+#endif
+    return none;
+  }
+  if(issigned){
+    TESTTYPE(signed char,123,123);
+    TESTTYPE(signed short,123,123);
+    TESTTYPE(signed int,123,123);
+    TESTTYPE(signed long,123,123);
+#if __STDC_VERSION__==199901L
+    TESTTYPE(signed long long,123,123);
+#endif
+    return none;
+  }
+  return none;
+}
+
+    
+int askyn(char *def)
+{
+  char in[8];
+  do{
+    printf("Type y or n [%s]: ",def);
+    fflush(stdout);
+    fgets(in,sizeof(in),stdin);
+    if(*in=='\n') strcpy(in,def);
+  }while(*in!='y'&&*in!='n');
+  return *in=='y';
+}
+
+char *asktype(char *def)
+{
+  char *in=mymalloc(128);
+  printf("Enter that type[%s]: ",def);
+  fflush(stdout);
+  fgets(in,127,stdin);
+  if(in[strlen(in)-1]=='\n') in[strlen(in)-1]=0;
+  if(!*in) strcpy(in,def);
+  return in;
+}
+
+int tst(int type,char *spec)
+{
+  int i,j;
+  for(i=0;i<dtcnt;i++){
+    if(strstr(spec,dts[i].spec)){ 
+      if(have[i]==-2) continue;
+      if(have[i]>=0){
+/* 	printf("auto: %s == %s\n",dts[i].spec,nt[have[i]]); */
+	dt[type]=i;
+	nt[type]=nt[have[i]];
+	cnv[type]=-1;
+	return 1;
+      }else{
+	printf("Does your system/compiler support a type implemented as\n%s?\n",dts[i].descr);
+	if(askyn(yndefault(dts[i].spec,1))){
+	  dt[type]=i;
+	  nt[type]=asktype(yndefault(dts[i].spec,0));
+	  have[i]=type;
+	  cnv[type]=-1;
+	  return 1;
+	}else{
+	  have[i]=-2;
+	}
+      }
+    }
+  }
+  for(j=0;j<cnvcnt;j++){
+    char *s=0;
+    if(strstr(spec,cnvs[j].from)) s=cnvs[j].to;
+/*     if(strstr(spec,cnvs[j].to)) s=cnvs[j].from; */
+    if(s){
+      for(i=0;i<dtcnt;i++){
+	if(!strcmp(s,dts[i].spec)){
+	  if(have[i]==-2) continue;
+	  if(have[i]>=0){
+	    dt[type]=i;
+	    nt[type]=nt[have[i]];
+	    cnv[type]=j;
+	    return 2;
+	  }else{
+	    printf("Does your system/compiler support a type implemented as\n%s?\n",dts[i].descr);
+	    if(askyn(yndefault(dts[i].spec,1))){
+	      dt[type]=i;
+	      nt[type]=asktype(yndefault(dts[i].spec,0));
+	      have[i]=type;
+	      cnv[type]=j;
+	      return 2;
+	    }else{
+	      have[i]=-2;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  return 0;
+}
+    
+char *castfrom(int type)
+{
+  if(cnv[type]>=0){
+    char *s=mymalloc(16);
+    sprintf(s,"dtcnv%df",type);
+    return s;
+  }else{
+    return "";
+  }
+}
+char *castto(int type)
+{
+  if(cnv[type]>=0){
+    char *s=mymalloc(16);
+    sprintf(s,"dtcnv%dt",type);
+    return s;
+  }else{
+    return "";
+  }
+} 
+void gen_cast(char *name,int from,int to)
+{
+  fprintf(hout,"#define %s(x) %s((%s)%s(x))\n",name,castto(to),nt[to],castfrom(from));
+}
+void gen_2op(char *name,char *op,int type)
+{
+  fprintf(hout,"#define %s(a,b) %s(%s(a)%s%s(b))\n",name,castto(type),castfrom(type),op,castfrom(type));
+} 
+void gen_1op(char *name,char *op,int type)
+{
+  fprintf(hout,"#define %s(a) %s(%s%s(a))\n",name,castto(type),op,castfrom(type));
+} 
+void gen_cmp(char *name,char *op,int type)
+{
+  fprintf(hout,"#define %s(a,b) (%s(a)%s%s(b))\n",name,castfrom(type),op,castfrom(type));
+} 
+int main(int argc,char **argv)
+{
+  char type[128],spec[128];
+  int i,r;
+  if(argc!=4){ printf("Usage: dtgen <config-file> <output-file.h> <output-file.c>\n");exit(EXIT_FAILURE);}
+/*   printf("%d datatypes, %d conversions\n",dtcnt,cnvcnt); */
+  have=mymalloc(dtcnt*sizeof(*have));
+  memset(have,-1,sizeof(*have)*dtcnt);
+  fin=fopen(argv[1],"r");
+  if(!fin){ printf("Could not open <%s> for input!\n",argv[1]);exit(EXIT_FAILURE);}
+  hout=fopen(argv[2],"w");
+  if(!hout){ printf("Could not open <%s> for output!\n",argv[2]);exit(EXIT_FAILURE);}
+  cout=fopen(argv[3],"w");
+  if(!hout){ printf("Could not open <%s> for output!\n",argv[3]);exit(EXIT_FAILURE);}
+  printf("Are you building a cross-compiler?\n");
+  crosscompiler=askyn("y");
+  for(i=1;i<=TYPECNT;i++){
+    fgets(spec,127,fin);
+/*     printf("Specs for z%s:\n%s\n",typen[i],spec); */
+    if(!crosscompiler){
+      dt[i]=i;
+      nt[i]=ftypen[i];
+      have[i]=i;
+      cnv[i]=-1;
+    }else{
+      if(!tst(i,spec)){
+	printf("Problem! Your system does not seem to provide all of the data types\n"
+	       "this version of vbcc needs.\nWrite to vb@compilers.de!\n");
+	exit(EXIT_FAILURE);
+      }
+    }
+  }
+  fprintf(hout,"\n\n/* Machine generated file. DON'T TOUCH ME! */\n\n\n");
+  fprintf(cout,"\n\n/* Machine generated file. DON'T TOUCH ME! */\n\n\n");
+  fprintf(hout,"#ifndef DT_H\n");
+  fprintf(hout,"#define DT_H 1\n");
+  fprintf(cout,"#include \"dt.h\"\n\n");
+  for(i=1;i<=TYPECNT;i++){
+    if(cnv[i]>=0){
+      int bits;
+      sscanf(cnvs[cnv[i]].from,"S%dB",&bits);
+      fprintf(hout,"typedef struct {char a[%d];} dt%df;\n",cnvs[cnv[i]].size,i);
+      fprintf(hout,"typedef dt%df z%s;\n",i,typen[i]);
+      fprintf(hout,"typedef %s dt%dt;\n",nt[i],i);
+      fprintf(hout,"dt%dt dtcnv%df(dt%df);\n",i,i,i);
+      fprintf(hout,"dt%df dtcnv%dt(dt%dt);\n",i,i,i);
+      fprintf(cout,"#undef BITSIZE\n#define BITSIZE %d\n",bits);
+      fprintf(cout,"#undef DTTTYPE\n#define DTTTYPE dt%dt\n",i);
+      fprintf(cout,"#undef DTFTYPE\n#define DTFTYPE dt%df\n",i);
+      fprintf(cout,"dt%dt dtcnv%df(dt%df\n",i,i,i);
+      fprintf(cout,"#include \"%s\"\n",cnvs[cnv[i]].filef);
+      fprintf(cout,"dt%df dtcnv%dt(dt%dt\n",i,i,i);
+      fprintf(cout,"#include \"%s\"\n",cnvs[cnv[i]].filet);
+    }else{
+      fprintf(hout,"typedef %s z%s;\n",nt[i],typen[i]);
+    }
+  }
+
+  gen_cast("zc2zm",CHAR,LLONG);
+  gen_cast("zs2zm",SHORT,LLONG);
+  gen_cast("zi2zm",INT,LLONG);
+  gen_cast("zl2zm",LONG,LLONG);
+  gen_cast("zll2zm",LLONG,LLONG);
+  gen_cast("zm2zc",LLONG,CHAR);
+  gen_cast("zm2zs",LLONG,SHORT);
+  gen_cast("zm2zi",LLONG,INT);
+  gen_cast("zm2zl",LLONG,LONG);
+  gen_cast("zm2zll",LLONG,LLONG);
+
+  gen_cast("zuc2zum",UCHAR,ULLONG);
+  gen_cast("zus2zum",USHORT,ULLONG);
+  gen_cast("zui2zum",UINT,ULLONG);
+  gen_cast("zul2zum",ULONG,ULLONG);
+  gen_cast("zull2zum",ULLONG,ULLONG);
+  gen_cast("zum2zuc",ULLONG,UCHAR);
+  gen_cast("zum2zus",ULLONG,USHORT);
+  gen_cast("zum2zui",ULLONG,UINT);
+  gen_cast("zum2zul",ULLONG,ULONG);
+  gen_cast("zum2zull",ULLONG,ULLONG);
+
+  gen_cast("zum2zm",ULLONG,LLONG);
+  gen_cast("zm2zum",LLONG,ULLONG);
+  gen_cast("zf2zld",FLOAT,LDOUBLE);
+  gen_cast("zd2zld",DOUBLE,LDOUBLE);
+  gen_cast("zld2zf",LDOUBLE,FLOAT);
+  gen_cast("zld2zd",LDOUBLE,DOUBLE);
+  gen_cast("zld2zm",LDOUBLE,LLONG);
+  gen_cast("zm2zld",LLONG,LDOUBLE);
+  gen_cast("zld2zum",LDOUBLE,ULLONG);
+  gen_cast("zum2zld",ULLONG,LDOUBLE);
+  gen_cast("zp2zum",POINTER,ULLONG);
+  gen_cast("zum2zp",ULLONG,POINTER);
+ 
+  fprintf(hout,"#define l2zm(x) %s((%s)(x))\n",castto(LLONG),nt[LLONG]);
+  fprintf(hout,"#define ul2zum(x) %s((%s)(x))\n",castto(ULLONG),nt[ULLONG]);
+  fprintf(hout,"#define d2zld(x) %s((%s)(x))\n",castto(LDOUBLE),nt[LDOUBLE]);
+  fprintf(hout,"#define zm2l(x) ((long)%s(x))\n",castfrom(LLONG));
+  fprintf(hout,"#define zum2ul(x) ((unsigned long)%s(x))\n",castfrom(ULLONG));
+  fprintf(hout,"#define zld2d(x) ((double)%s(x))\n",castfrom(LDOUBLE));
+
+  gen_2op("zmadd","+",LLONG);
+  gen_2op("zumadd","+",ULLONG);
+  gen_2op("zldadd","+",LDOUBLE);
+  gen_2op("zmsub","-",LLONG);
+  gen_2op("zumsub","-",ULLONG);
+  gen_2op("zldsub","-",LDOUBLE);
+  gen_2op("zmmult","*",LLONG);
+  gen_2op("zummult","*",ULLONG);
+  gen_2op("zldmult","*",LDOUBLE);
+  gen_2op("zmdiv","/",LLONG);
+  gen_2op("zumdiv","/",ULLONG);
+  gen_2op("zlddiv","/",LDOUBLE);
+  gen_2op("zmmod","%",LLONG);
+  gen_2op("zummod","%",ULLONG);
+  gen_2op("zmlshift","<<",LLONG);
+  gen_2op("zumlshift","<<",ULLONG);
+  gen_2op("zmrshift",">>",LLONG);
+  gen_2op("zumrshift",">>",ULLONG);
+  gen_2op("zmand","&",LLONG);
+  gen_2op("zumand","&",ULLONG);
+  gen_2op("zmor","|",LLONG);
+  gen_2op("zumor","|",ULLONG);
+  gen_2op("zmxor","^",LLONG);
+  gen_2op("zumxor","^",ULLONG);
+  gen_2op("zmmod","%",LLONG);
+  gen_2op("zummod","%",ULLONG);
+
+  gen_1op("zmkompl","~",LLONG);
+  gen_1op("zumkompl","~",ULLONG);
+
+  gen_cmp("zmleq","<=",LLONG);
+  gen_cmp("zumleq","<=",ULLONG);
+  gen_cmp("zldleq","<=",LDOUBLE);
+  gen_cmp("zmeqto","==",LLONG);
+  gen_cmp("zumeqto","==",ULLONG);
+  gen_cmp("zldeqto","==",LDOUBLE);
+
+  fprintf(hout,"#endif\n");
+
+  fclose(fin);
+  fclose(hout);
+  fclose(cout);
+  free(have);  
+  return 0;
+}
+
+
+
+
+
+
diff --git a/datatypes/dtswap32f.c b/datatypes/dtswap32f.c
new file mode 100755
index 0000000..44e0640
--- /dev/null
+++ b/datatypes/dtswap32f.c
@@ -0,0 +1,13 @@
+from)
+{
+  DTTTYPE to;
+  unsigned char *fp=((unsigned char *)&from)+3,*tp=(unsigned char *)&to;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  return to;
+}
+
+  	
+
diff --git a/datatypes/dtswap32t.c b/datatypes/dtswap32t.c
new file mode 100755
index 0000000..38f2637
--- /dev/null
+++ b/datatypes/dtswap32t.c
@@ -0,0 +1,13 @@
+from)
+{
+  DTFTYPE to;
+  unsigned char *fp=((unsigned char *)&from)+3,*tp=(unsigned char *)&to;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  return to;
+}
+
+  	
+
diff --git a/datatypes/dtswap64f.c b/datatypes/dtswap64f.c
new file mode 100755
index 0000000..c8cc74c
--- /dev/null
+++ b/datatypes/dtswap64f.c
@@ -0,0 +1,17 @@
+from)
+{
+  DTTTYPE to;
+  unsigned char *fp=((unsigned char *)&from)+7,*tp=(unsigned char *)&to;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  return to;
+}
+
+  	
+
diff --git a/datatypes/dtswap64t.c b/datatypes/dtswap64t.c
new file mode 100755
index 0000000..fd1d0a3
--- /dev/null
+++ b/datatypes/dtswap64t.c
@@ -0,0 +1,17 @@
+from)
+{
+  DTFTYPE to;
+  unsigned char *fp=((unsigned char *)&from)+7,*tp=(unsigned char *)&to;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  *tp++=*fp--;
+  return to;
+}
+
+  	
+
diff --git a/datatypes/dtt.c b/datatypes/dtt.c
new file mode 100644
index 0000000..57b2de5
--- /dev/null
+++ b/datatypes/dtt.c
@@ -0,0 +1,11 @@
+from)
+{
+ DTFTYPE to;
+ int i;
+ from&=(((DTTTYPE)1)<<BITSIZE)-1;
+ for(i=0;i<sizeof(to.a);i++){
+   to.a[i]=from&255;
+   from>>=8;
+ }
+ return to;
+}
diff --git a/datatypes/dtwidths.h b/datatypes/dtwidths.h
new file mode 100644
index 0000000..384c745
--- /dev/null
+++ b/datatypes/dtwidths.h
@@ -0,0 +1,240 @@
+"S1BU","S8BULE","dtf.c","dtt.c",1,
+"S1BU","S8BUBE","dtf.c","dtt.c",1,
+"S1BS","S8BSLE","dtf.c","dtt.c",1,
+"S1BS","S8BSBE","dtf.c","dtt.c",1,
+"S2BU","S8BULE","dtf.c","dtt.c",1,
+"S2BU","S8BUBE","dtf.c","dtt.c",1,
+"S2BS","S8BSLE","dtf.c","dtt.c",1,
+"S2BS","S8BSBE","dtf.c","dtt.c",1,
+"S3BU","S8BULE","dtf.c","dtt.c",1,
+"S3BU","S8BUBE","dtf.c","dtt.c",1,
+"S3BS","S8BSLE","dtf.c","dtt.c",1,
+"S3BS","S8BSBE","dtf.c","dtt.c",1,
+"S4BU","S8BULE","dtf.c","dtt.c",1,
+"S4BU","S8BUBE","dtf.c","dtt.c",1,
+"S4BS","S8BSLE","dtf.c","dtt.c",1,
+"S4BS","S8BSBE","dtf.c","dtt.c",1,
+"S5BU","S8BULE","dtf.c","dtt.c",1,
+"S5BU","S8BUBE","dtf.c","dtt.c",1,
+"S5BS","S8BSLE","dtf.c","dtt.c",1,
+"S5BS","S8BSBE","dtf.c","dtt.c",1,
+"S6BU","S8BULE","dtf.c","dtt.c",1,
+"S6BU","S8BUBE","dtf.c","dtt.c",1,
+"S6BS","S8BSLE","dtf.c","dtt.c",1,
+"S6BS","S8BSBE","dtf.c","dtt.c",1,
+"S7BU","S8BULE","dtf.c","dtt.c",1,
+"S7BU","S8BUBE","dtf.c","dtt.c",1,
+"S7BS","S8BSLE","dtf.c","dtt.c",1,
+"S7BS","S8BSBE","dtf.c","dtt.c",1,
+"S9BU","S16BULE","dtf.c","dtt.c",2,
+"S9BU","S16BUBE","dtf.c","dtt.c",2,
+"S9BS","S16BSLE","dtf.c","dtt.c",2,
+"S9BS","S16BSBE","dtf.c","dtt.c",2,
+"S10BU","S16BULE","dtf.c","dtt.c",2,
+"S10BU","S16BUBE","dtf.c","dtt.c",2,
+"S10BS","S16BSLE","dtf.c","dtt.c",2,
+"S10BS","S16BSBE","dtf.c","dtt.c",2,
+"S11BU","S16BULE","dtf.c","dtt.c",2,
+"S11BU","S16BUBE","dtf.c","dtt.c",2,
+"S11BS","S16BSLE","dtf.c","dtt.c",2,
+"S11BS","S16BSBE","dtf.c","dtt.c",2,
+"S12BU","S16BULE","dtf.c","dtt.c",2,
+"S12BU","S16BUBE","dtf.c","dtt.c",2,
+"S12BS","S16BSLE","dtf.c","dtt.c",2,
+"S12BS","S16BSBE","dtf.c","dtt.c",2,
+"S13BU","S16BULE","dtf.c","dtt.c",2,
+"S13BU","S16BUBE","dtf.c","dtt.c",2,
+"S13BS","S16BSLE","dtf.c","dtt.c",2,
+"S13BS","S16BSBE","dtf.c","dtt.c",2,
+"S14BU","S16BULE","dtf.c","dtt.c",2,
+"S14BU","S16BUBE","dtf.c","dtt.c",2,
+"S14BS","S16BSLE","dtf.c","dtt.c",2,
+"S14BS","S16BSBE","dtf.c","dtt.c",2,
+"S15BU","S16BULE","dtf.c","dtt.c",2,
+"S15BU","S16BUBE","dtf.c","dtt.c",2,
+"S15BS","S16BSLE","dtf.c","dtt.c",2,
+"S15BS","S16BSBE","dtf.c","dtt.c",2,
+"S17BU","S32BULE","dtf.c","dtt.c",3,
+"S17BU","S32BUBE","dtf.c","dtt.c",3,
+"S17BS","S32BSLE","dtf.c","dtt.c",3,
+"S17BS","S32BSBE","dtf.c","dtt.c",3,
+"S18BU","S32BULE","dtf.c","dtt.c",3,
+"S18BU","S32BUBE","dtf.c","dtt.c",3,
+"S18BS","S32BSLE","dtf.c","dtt.c",3,
+"S18BS","S32BSBE","dtf.c","dtt.c",3,
+"S19BU","S32BULE","dtf.c","dtt.c",3,
+"S19BU","S32BUBE","dtf.c","dtt.c",3,
+"S19BS","S32BSLE","dtf.c","dtt.c",3,
+"S19BS","S32BSBE","dtf.c","dtt.c",3,
+"S20BU","S32BULE","dtf.c","dtt.c",3,
+"S20BU","S32BUBE","dtf.c","dtt.c",3,
+"S20BS","S32BSLE","dtf.c","dtt.c",3,
+"S20BS","S32BSBE","dtf.c","dtt.c",3,
+"S21BU","S32BULE","dtf.c","dtt.c",3,
+"S21BU","S32BUBE","dtf.c","dtt.c",3,
+"S21BS","S32BSLE","dtf.c","dtt.c",3,
+"S21BS","S32BSBE","dtf.c","dtt.c",3,
+"S22BU","S32BULE","dtf.c","dtt.c",3,
+"S22BU","S32BUBE","dtf.c","dtt.c",3,
+"S22BS","S32BSLE","dtf.c","dtt.c",3,
+"S22BS","S32BSBE","dtf.c","dtt.c",3,
+"S23BU","S32BULE","dtf.c","dtt.c",3,
+"S23BU","S32BUBE","dtf.c","dtt.c",3,
+"S23BS","S32BSLE","dtf.c","dtt.c",3,
+"S23BS","S32BSBE","dtf.c","dtt.c",3,
+"S24BU","S32BULE","dtf.c","dtt.c",3,
+"S24BU","S32BUBE","dtf.c","dtt.c",3,
+"S24BS","S32BSLE","dtf.c","dtt.c",3,
+"S24BS","S32BSBE","dtf.c","dtt.c",3,
+"S25BU","S32BULE","dtf.c","dtt.c",4,
+"S25BU","S32BUBE","dtf.c","dtt.c",4,
+"S25BS","S32BSLE","dtf.c","dtt.c",4,
+"S25BS","S32BSBE","dtf.c","dtt.c",4,
+"S26BU","S32BULE","dtf.c","dtt.c",4,
+"S26BU","S32BUBE","dtf.c","dtt.c",4,
+"S26BS","S32BSLE","dtf.c","dtt.c",4,
+"S26BS","S32BSBE","dtf.c","dtt.c",4,
+"S27BU","S32BULE","dtf.c","dtt.c",4,
+"S27BU","S32BUBE","dtf.c","dtt.c",4,
+"S27BS","S32BSLE","dtf.c","dtt.c",4,
+"S27BS","S32BSBE","dtf.c","dtt.c",4,
+"S28BU","S32BULE","dtf.c","dtt.c",4,
+"S28BU","S32BUBE","dtf.c","dtt.c",4,
+"S28BS","S32BSLE","dtf.c","dtt.c",4,
+"S28BS","S32BSBE","dtf.c","dtt.c",4,
+"S29BU","S32BULE","dtf.c","dtt.c",4,
+"S29BU","S32BUBE","dtf.c","dtt.c",4,
+"S29BS","S32BSLE","dtf.c","dtt.c",4,
+"S29BS","S32BSBE","dtf.c","dtt.c",4,
+"S30BU","S32BULE","dtf.c","dtt.c",4,
+"S30BU","S32BUBE","dtf.c","dtt.c",4,
+"S30BS","S32BSLE","dtf.c","dtt.c",4,
+"S30BS","S32BSBE","dtf.c","dtt.c",4,
+"S31BU","S32BULE","dtf.c","dtt.c",4,
+"S31BU","S32BUBE","dtf.c","dtt.c",4,
+"S31BS","S32BSLE","dtf.c","dtt.c",4,
+"S31BS","S32BSBE","dtf.c","dtt.c",4,
+"S33BU","S64BULE","dtf.c","dtt.c",5,
+"S33BU","S64BUBE","dtf.c","dtt.c",5,
+"S33BS","S64BSLE","dtf.c","dtt.c",5,
+"S33BS","S64BSBE","dtf.c","dtt.c",5,
+"S34BU","S64BULE","dtf.c","dtt.c",5,
+"S34BU","S64BUBE","dtf.c","dtt.c",5,
+"S34BS","S64BSLE","dtf.c","dtt.c",5,
+"S34BS","S64BSBE","dtf.c","dtt.c",5,
+"S35BU","S64BULE","dtf.c","dtt.c",5,
+"S35BU","S64BUBE","dtf.c","dtt.c",5,
+"S35BS","S64BSLE","dtf.c","dtt.c",5,
+"S35BS","S64BSBE","dtf.c","dtt.c",5,
+"S36BU","S64BULE","dtf.c","dtt.c",5,
+"S36BU","S64BUBE","dtf.c","dtt.c",5,
+"S36BS","S64BSLE","dtf.c","dtt.c",5,
+"S36BS","S64BSBE","dtf.c","dtt.c",5,
+"S37BU","S64BULE","dtf.c","dtt.c",5,
+"S37BU","S64BUBE","dtf.c","dtt.c",5,
+"S37BS","S64BSLE","dtf.c","dtt.c",5,
+"S37BS","S64BSBE","dtf.c","dtt.c",5,
+"S38BU","S64BULE","dtf.c","dtt.c",5,
+"S38BU","S64BUBE","dtf.c","dtt.c",5,
+"S38BS","S64BSLE","dtf.c","dtt.c",5,
+"S38BS","S64BSBE","dtf.c","dtt.c",5,
+"S39BU","S64BULE","dtf.c","dtt.c",5,
+"S39BU","S64BUBE","dtf.c","dtt.c",5,
+"S39BS","S64BSLE","dtf.c","dtt.c",5,
+"S39BS","S64BSBE","dtf.c","dtt.c",5,
+"S40BU","S64BULE","dtf.c","dtt.c",5,
+"S40BU","S64BUBE","dtf.c","dtt.c",5,
+"S40BS","S64BSLE","dtf.c","dtt.c",5,
+"S40BS","S64BSBE","dtf.c","dtt.c",5,
+"S41BU","S64BULE","dtf.c","dtt.c",6,
+"S41BU","S64BUBE","dtf.c","dtt.c",6,
+"S41BS","S64BSLE","dtf.c","dtt.c",6,
+"S41BS","S64BSBE","dtf.c","dtt.c",6,
+"S42BU","S64BULE","dtf.c","dtt.c",6,
+"S42BU","S64BUBE","dtf.c","dtt.c",6,
+"S42BS","S64BSLE","dtf.c","dtt.c",6,
+"S42BS","S64BSBE","dtf.c","dtt.c",6,
+"S43BU","S64BULE","dtf.c","dtt.c",6,
+"S43BU","S64BUBE","dtf.c","dtt.c",6,
+"S43BS","S64BSLE","dtf.c","dtt.c",6,
+"S43BS","S64BSBE","dtf.c","dtt.c",6,
+"S44BU","S64BULE","dtf.c","dtt.c",6,
+"S44BU","S64BUBE","dtf.c","dtt.c",6,
+"S44BS","S64BSLE","dtf.c","dtt.c",6,
+"S44BS","S64BSBE","dtf.c","dtt.c",6,
+"S45BU","S64BULE","dtf.c","dtt.c",6,
+"S45BU","S64BUBE","dtf.c","dtt.c",6,
+"S45BS","S64BSLE","dtf.c","dtt.c",6,
+"S45BS","S64BSBE","dtf.c","dtt.c",6,
+"S46BU","S64BULE","dtf.c","dtt.c",6,
+"S46BU","S64BUBE","dtf.c","dtt.c",6,
+"S46BS","S64BSLE","dtf.c","dtt.c",6,
+"S46BS","S64BSBE","dtf.c","dtt.c",6,
+"S47BU","S64BULE","dtf.c","dtt.c",6,
+"S47BU","S64BUBE","dtf.c","dtt.c",6,
+"S47BS","S64BSLE","dtf.c","dtt.c",6,
+"S47BS","S64BSBE","dtf.c","dtt.c",6,
+"S48BU","S64BULE","dtf.c","dtt.c",6,
+"S48BU","S64BUBE","dtf.c","dtt.c",6,
+"S48BS","S64BSLE","dtf.c","dtt.c",6,
+"S48BS","S64BSBE","dtf.c","dtt.c",6,
+"S49BU","S64BULE","dtf.c","dtt.c",7,
+"S49BU","S64BUBE","dtf.c","dtt.c",7,
+"S49BS","S64BSLE","dtf.c","dtt.c",7,
+"S49BS","S64BSBE","dtf.c","dtt.c",7,
+"S50BU","S64BULE","dtf.c","dtt.c",7,
+"S50BU","S64BUBE","dtf.c","dtt.c",7,
+"S50BS","S64BSLE","dtf.c","dtt.c",7,
+"S50BS","S64BSBE","dtf.c","dtt.c",7,
+"S51BU","S64BULE","dtf.c","dtt.c",7,
+"S51BU","S64BUBE","dtf.c","dtt.c",7,
+"S51BS","S64BSLE","dtf.c","dtt.c",7,
+"S51BS","S64BSBE","dtf.c","dtt.c",7,
+"S52BU","S64BULE","dtf.c","dtt.c",7,
+"S52BU","S64BUBE","dtf.c","dtt.c",7,
+"S52BS","S64BSLE","dtf.c","dtt.c",7,
+"S52BS","S64BSBE","dtf.c","dtt.c",7,
+"S53BU","S64BULE","dtf.c","dtt.c",7,
+"S53BU","S64BUBE","dtf.c","dtt.c",7,
+"S53BS","S64BSLE","dtf.c","dtt.c",7,
+"S53BS","S64BSBE","dtf.c","dtt.c",7,
+"S54BU","S64BULE","dtf.c","dtt.c",7,
+"S54BU","S64BUBE","dtf.c","dtt.c",7,
+"S54BS","S64BSLE","dtf.c","dtt.c",7,
+"S54BS","S64BSBE","dtf.c","dtt.c",7,
+"S55BU","S64BULE","dtf.c","dtt.c",7,
+"S55BU","S64BUBE","dtf.c","dtt.c",7,
+"S55BS","S64BSLE","dtf.c","dtt.c",7,
+"S55BS","S64BSBE","dtf.c","dtt.c",7,
+"S56BU","S64BULE","dtf.c","dtt.c",7,
+"S56BU","S64BUBE","dtf.c","dtt.c",7,
+"S56BS","S64BSLE","dtf.c","dtt.c",7,
+"S56BS","S64BSBE","dtf.c","dtt.c",7,
+"S57BU","S64BULE","dtf.c","dtt.c",8,
+"S57BU","S64BUBE","dtf.c","dtt.c",8,
+"S57BS","S64BSLE","dtf.c","dtt.c",8,
+"S57BS","S64BSBE","dtf.c","dtt.c",8,
+"S58BU","S64BULE","dtf.c","dtt.c",8,
+"S58BU","S64BUBE","dtf.c","dtt.c",8,
+"S58BS","S64BSLE","dtf.c","dtt.c",8,
+"S58BS","S64BSBE","dtf.c","dtt.c",8,
+"S59BU","S64BULE","dtf.c","dtt.c",8,
+"S59BU","S64BUBE","dtf.c","dtt.c",8,
+"S59BS","S64BSLE","dtf.c","dtt.c",8,
+"S59BS","S64BSBE","dtf.c","dtt.c",8,
+"S60BU","S64BULE","dtf.c","dtt.c",8,
+"S60BU","S64BUBE","dtf.c","dtt.c",8,
+"S60BS","S64BSLE","dtf.c","dtt.c",8,
+"S60BS","S64BSBE","dtf.c","dtt.c",8,
+"S61BU","S64BULE","dtf.c","dtt.c",8,
+"S61BU","S64BUBE","dtf.c","dtt.c",8,
+"S61BS","S64BSLE","dtf.c","dtt.c",8,
+"S61BS","S64BSBE","dtf.c","dtt.c",8,
+"S62BU","S64BULE","dtf.c","dtt.c",8,
+"S62BU","S64BUBE","dtf.c","dtt.c",8,
+"S62BS","S64BSLE","dtf.c","dtt.c",8,
+"S62BS","S64BSBE","dtf.c","dtt.c",8,
+"S63BU","S64BULE","dtf.c","dtt.c",8,
+"S63BU","S64BUBE","dtf.c","dtt.c",8,
+"S63BS","S64BSLE","dtf.c","dtt.c",8,
+"S63BS","S64BSBE","dtf.c","dtt.c",8,
diff --git a/declaration.c b/declaration.c
new file mode 100644
index 0000000..942bed7
--- /dev/null
+++ b/declaration.c
@@ -0,0 +1,4781 @@
+/*  $VER: vbcc (declaration.c) $Revision: 1.90 $    */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "vbcc_cpp.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+#define PLAIN_STORAGE_CLASS 7
+#define PARAMETER 8
+#define OLDSTYLE 16
+
+void dynamic_init(Var *v,type *t,const_list *cl,zmax of,int noconst);
+int test_assignment(type *,np);
+int return_sc,return_reg,has_return,return_inline;
+char *return_vattr;
+static int did_return_label;
+#ifdef HAVE_TARGET_ATTRIBUTES
+unsigned long return_tattr;
+#endif
+zumax return_mask;
+zmax init_dyn_sz,init_const_sz;
+int init_dyn_cnt,init_const_cnt;
+
+void init_sl(struct_list *sl);
+
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+extern np gen_libcall(char *,np,type *,np,type *);
+extern int float_used;
+extern void optimize(long,Var *);
+
+extern type uct;
+
+void needs(char *s)
+{
+  Var *v;
+  if(!(v=find_ext_var(s))||!strcmp(v->identifier,s)){
+    Var *needs=add_var(s,clone_typ(&uct),EXTERN,0);
+    needs->flags|=(USEDASSOURCE|REFERENCED|NEEDS);
+  }		
+}
+
+static void clear_main_ret(void)
+{
+  if(c99&&!strcmp(cur_func,"main")&&return_typ&&ISSCALAR(return_typ->flags)){
+    /* in c99, main returns 0 if it falls from back */
+    IC *new=new_IC();
+    new->code=SETRETURN;
+    new->q1.val.vmax=l2zm(0L);
+    eval_const(&new->q1.val,MAXINT);
+    insert_const(&new->q1.val,return_typ->flags&NU);
+    new->q1.flags=KONST;
+    new->typf=return_typ->flags;
+    new->q2.val.vmax=szof(return_typ);
+    new->q2.flags=new->z.flags=0;
+    new->z.reg=freturn(return_typ);
+    add_IC(new);
+  }
+}
+
+static char *get_string(void)
+/* Liest Stringkonstante und liefert Wert als String (malloced) */
+{
+  np tree;int l;char *p;
+  const_list *cl;
+  killsp();
+  if(ctok->type!=T_STRING) {error(74);return 0;}
+  tree=string_expression();
+  if(!tree||tree->flags!=STRING){
+    error(229);
+    return 0;
+  }
+  cl=tree->cl;l=0;
+  while(cl){
+    l++;
+    cl=cl->next;
+  }
+  p=mymalloc(l);
+  cl=tree->cl;l=0;
+  while(cl){
+    p[l]=CHARBACK(zm2l(zc2zm(cl->other->val.vchar)));
+    l++;
+    cl=cl->next;
+  }
+  if(tree) free_expression(tree);
+  killsp();
+  return p;
+}
+
+/* checks whether string is a valid vector type */
+/* returns the dimension */
+static int check_vect(char *s,char *base)
+{
+  int i=strlen(base),dim;
+  if(strncmp(s,base,i)) return 0;
+  dim=s[i];
+  if(dim=='2'||dim=='3'||dim=='4'||dim=='8'){
+    if(s[i+1]==0)
+      return dim-'0';
+    else
+      return 0;
+  }
+  if(s[i]=='1'&&s[i+1]=='6'&&s[i+2]==0)
+    return 16;
+  return 0;
+}
+
+int settyp(int typnew, int typold)
+/* Unterroutine fuer declaration_specifiers().              */
+{
+  if(DEBUG&2) printf("settyp: new=%d old=%d\n",typnew,typold);
+  if(typold==LONG&&typnew==FLOAT){ error(203); return DOUBLE;}
+  if(typold==LONG&&typnew==DOUBLE) return LDOUBLE;
+  if(c99&&typold==LONG&&typnew==LONG) return LLONG;
+  if(typold==INT&&(typnew==SHORT||typnew==LONG)) return typnew;
+  if(typold!=0&&typnew!=INT){error(47);return(typnew);}
+  if(typold==0&&typnew==INT) return(INT);
+  if(typold==0) return(typnew);
+  if(typold==SHORT||typold==LONG||typold==LLONG) return(typold);
+  error(48);
+  return(typnew);
+}
+
+#define dsc if(storage_class) error(49); if(typ||type_qualifiers) error(50)
+#define XSIGNED 16384
+
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+
+type *declaration_specifiers(void)
+/* Erzeugt neuen Typ und gibt Zeiger darauf zurueck,      */
+/* parst z.B. unsigned int, bla etc.               */
+{
+  int typ=0,type_qualifiers=0,notdone,storage_class,hard_reg,have_inline;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+  char *imerk,sident[MAXI],sbuff[MAXI],*attr=0,*vattr=0;
+  zumax mask=ul2zum(0UL);
+  type *new=new_typ(),*t,*ts;
+  struct_declaration *ssd;
+  struct_list (*sl)[];
+  size_t slsz;
+  Var *v;
+  int dim;
+#ifdef HAVE_TARGET_ATTRIBUTES
+  unsigned long tattr=0;
+#endif
+  storage_class=hard_reg=have_inline=0;
+  do{
+    killsp();notdone=0;
+    if(ctok->type==NAME){
+      if(!strcmp("struct",ctok->name)||!strcmp("union",ctok->name)||(ecpp&&!strcmp("class",ctok->name))){
+        if(!strcmp("struct",ctok->name)) notdone=STRUCT;
+        if(!strcmp("union",ctok->name)) {
+          notdone=UNION;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+        next_token();
+        killsp();
+        if(ctok->type!=LBRA){
+          cpbez(sident,1);
+          next_token();
+          killsp();
+          ssd=find_struct(sident,0);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+          if(ssd&&ctok->type==LBRA&&find_struct(sident,nesting)&&ssd->count>0) error(13,sident);
+          if(!ssd||((ctok->type==LBRA||ctok->type==SEMIC)&&!find_struct(sident,nesting))){
+            typ=settyp(notdone,typ);
+            ssd=mymalloc(sizeof(*ssd));
+            ssd->count=0;
+            new->exact=ssd=add_sd(ssd,notdone);
+            if(!ecpp)add_struct_identifier(sident,ssd);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+          }else{
+            new->exact=ssd;
+            typ=settyp(new->flags=notdone,typ);
+          }
+        }else{
+          *sident=0;
+          typ=settyp(notdone,typ);
+          ssd=mymalloc(sizeof(*ssd));
+          ssd->count=0;
+          new->exact=ssd=add_sd(ssd,notdone);
+        }
+        if(ssd->typ!=notdone) error(230,sident);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif        
+        if(ctok->type==LBRA){
+          int bfoffset,bfsize,flex_array=0,cbfo=0;
+	  int scount;
+          zmax off=l2zm(0L);
+          next_token();
+          killsp();
+          slsz=SLSIZE;
+          imerk=ident;
+            sl=mymalloc(slsz*sizeof(struct_list));
+            ssd->count=0;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+	  scount=ssd->count;
+          ts=declaration_specifiers();
+          while(ctok->type!=RBRA&&ts){
+            if(flex_array) error(231);
+            ident=sbuff;
+            t=declarator(clone_typ(ts));
+            killsp();
+            bfsize=bfoffset=-1;
+            if(ctok->type==T_COLON){
+              np tree;
+              if((ts->flags&NQ)!=INT) {
+                error(51);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+              }
+              next_token();killsp();tree=assignment_expression();
+
+              if(type_expression(tree,0)){
+                int tsize;
+                if(tree->flags!=CEXPR) error(52);
+                if(!ISINT(tree->ntyp->flags)) error(52);
+                eval_const(&tree->val,tree->ntyp->flags);
+                bfsize=(int)zm2l(vmax);
+                tsize=(int)zm2l(zmmult(sizetab[t->flags&NQ],char_bit));
+                if(bfsize<0||bfsize>tsize||(bfsize==0&&*ident)){
+                  error(332);bfsize=1;
+                }
+                if(bfsize+cbfo>tsize){
+                  bfoffset=cbfo=0;
+                }else{
+                  bfoffset=cbfo;
+                }
+                if(bfsize!=0)
+                  cbfo+=bfsize;
+                else
+                  cbfo=0;
+              }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+              if(tree) free_expression(tree);
+            }else{
+              if(!ecpp&&*ident==0) error(53);
+              cbfo=0;
+            }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+            if(type_uncomplete(t)){
+              if(!c99||notdone!=STRUCT||flex_array||(t->flags&NQ)!=ARRAY||type_uncomplete(t->next)){
+                error(14,sbuff);
+                freetyp(t);
+                break;
+              }else{
+                flex_array=1;
+              }
+            }
+	    if(ISARRAY(t->flags)&&t->dsize){
+	      error(352,sbuff);
+	    }
+            if(ISFUNC(t->flags)){
+              if(!ecpp){
+                error(15,sbuff);
+              }
+            }
+            if(*ident!=0){
+              int i=scount;
+              while(--i>=0)
+                if(!strcmp((*sl)[i].identifier,ident))
+                  error(16,ident);
+            }
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+	    (*sl)[scount].bfoffset=bfoffset;
+            (*sl)[scount].bfsize=bfsize;
+            (*sl)[scount].styp=t;
+            if(!ecpp) (*sl)[scount].identifier=add_identifier(ident,strlen(ident));
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+            if(pack_align>0&&pack_align<falign(t))
+              (*sl)[scount].align=pack_align;
+            else
+              (*sl)[scount].align=falign(t);
+            {
+              zmax m,al=(*sl)[scount].align;
+              zmax sz=szof(t);
+              m=off;
+              if((zmeqto(al,l2zm(0L))||zmeqto(sz,l2zm(0L)))&&!flex_array){
+                if (!ecpp){
+                  error(316,ident);
+                }
+              }else{
+                off=zmmult(zmdiv(zmadd(off,zmsub(al,l2zm(1L))),al),al);
+                if(!zmeqto(m,off)) error(306,ident);
+                if(!flex_array){
+                  m=zmmult(zmdiv(zmadd(off,zmsub(sz,l2zm(1L))),sz),sz);
+                  if(!zmeqto(m,off)) error(307,ident);
+                  off=zmadd(off,sz);
+                }
+              }
+            }
+            scount++;
+            if(scount>=slsz-1){
+              slsz+=SLSIZE;
+              sl=myrealloc(sl,slsz*sizeof(struct_list));
+            }
+            killsp();
+            if(ctok->type==COMMA) {next_token();killsp();continue;}
+            if(ctok->type!=SEMIC) error(54); else next_token();
+            killsp();
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+            if(ctok->type!=RBRA){
+              if(ts) freetyp(ts);
+              ts=declaration_specifiers();killsp();
+            }
+          }
+          if(ts) freetyp(ts);
+	  ssd->count=scount;
+          if(ssd->count==0) error(55);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+          ident=imerk;
+					add_sl(ssd,sl);
+					free(sl);
+          if(ctok->type!=RBRA) error(56); else next_token();
+          new->flags=notdone|type_qualifiers;
+        }
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+        notdone=1;
+      }else if(!strcmp("enum",ctok->name)){
+        /*  enumerations; die Namen werden leider noch ignoriert    */
+        next_token();killsp();notdone=1;
+        if(ctok->type!=LBRA){cpbez(buff,1);next_token();killsp();}
+        if(ctok->type==LBRA){
+          /* mode: 0=start 1=first was not init 2=first was init 3=more init */
+          zmax val; Var *v; type *t;int mode=0;
+          val=l2zm(0L);
+          next_token();killsp();
+          while(ctok->type!=RBRA){
+            cpbez(sident,1);next_token();killsp();
+            if(*sident==0) {error(56);break;}
+            t=new_typ();
+            t->flags=CONST|INT;
+            if(find_var(sident,nesting)) error(17,sident);
+            v=add_var(sident,t,AUTO,0); /*  AUTO hier klug? */
+            if(ctok->type==ASGN){
+              if(mode==2) mode=3;
+              if(mode==0) mode=2;
+#ifdef HAVE_MISRA                                /* MISRA Rule 9.3 checking */
+/* removed */
+#endif
+              next_token();killsp();
+              v->clist=initialization(v->vtyp,0,0,0,0,0);
+              val=zi2zm(v->clist->val.vint);killsp();
+            }else{
+              if(mode==0) mode=1;
+#ifdef HAVE_MISRA                                /* MISRA Rule 9.3 checking */
+/* removed */
+#endif
+              v->clist=mymalloc(CLS);
+              v->clist->val.vint=zm2zi(val);
+              v->clist->next=v->clist->other=0;
+              v->clist->tree=0;
+	      v->clist->idx=l2zm(0L);
+            }
+            vmax=l2zm(1L);val=zmadd(val,vmax);
+            v->vtyp->flags=CONST|ENUM;
+            if(ctok->type!=RBRA&&ctok->type!=COMMA) {error(56);break;}
+            if(ctok->type==COMMA) next_token();
+            killsp();
+            if(ctok->type==RBRA) {next_token(); break;}
+          }
+        }
+        killsp();
+        typ=settyp(INT,typ);
+      }else if(!strcmp("__readsmem",ctok->name)||!strcmp("__writesmem",ctok->name)){
+        enum {READS,WRITES} op;
+        char *imerk,tbuf[MAXI];
+        type *tmp;
+        if(!strcmp("__readsmem",ctok->name))
+          op=READS;
+        else
+          op=WRITES;
+        next_token();killsp();
+        if(ctok->type==LPAR) next_token(); else error(151);
+        imerk=ident;ident=tbuf;
+        tmp=declarator(declaration_specifiers());
+        ident=imerk;
+        if(tmp){
+          if(vattr)
+            vattr=myrealloc(vattr,strlen(vattr)+25);
+          else{
+            vattr=mymalloc(25);
+            vattr[0]=0;
+          }
+          sprintf(vattr+strlen(vattr),";%s(%d)",op==READS?"readmem":"writemem",tmp->flags);
+        }
+        killsp();
+        if(ctok->type==RPAR) next_token(); else error(59);
+        killsp();
+        notdone=1;
+      }else if(!strcmp("void",ctok->name)){
+        next_token();
+        typ=settyp(VOID,typ);notdone=1;
+      }else if(!strcmp("char",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+        next_token();
+        typ=settyp(CHAR,typ);
+	notdone=1;
+	if(default_unsigned&&!(type_qualifiers&XSIGNED))
+	  type_qualifiers|=UNSIGNED;
+      }else if(!strcmp("short",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        next_token();
+        typ=settyp(SHORT,typ);notdone=1;
+      }else if(!strcmp("int",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        next_token();
+        typ=settyp(INT,typ);notdone=1;
+      }else if(!strcmp("long",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        next_token();
+        typ=settyp(LONG,typ);notdone=1;
+      }else if(!strcmp("float",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        next_token();
+        typ=settyp(FLOAT,typ);notdone=1;
+      }else if(!strcmp("double",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        next_token();
+        typ=settyp(DOUBLE,typ);notdone=1;
+      }else if(!strcmp("const",ctok->name)){
+        next_token();
+        if(type_qualifiers&CONST) error(58);
+        type_qualifiers|=CONST;notdone=1;
+      }else if(!strcmp("volatile",ctok->name)){
+        next_token();
+        if(type_qualifiers&VOLATILE) error(58);
+        type_qualifiers|=VOLATILE;notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"bool"))){
+	next_token();
+	typ=settyp(VECBOOL+dim-1,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"char"))){
+	next_token();
+	typ=settyp(VECCHAR+dim-1,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"uchar"))){
+	next_token();
+	typ=settyp((VECCHAR+dim-1)|UNSIGNED,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"short"))){
+	next_token();
+	typ=settyp(VECSHORT+dim-1,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"ushort"))){
+	next_token();
+	typ=settyp((VECSHORT+dim-1)|UNSIGNED,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"int"))){
+	next_token();
+	typ=settyp(VECINT+dim-1,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"uint"))){
+	next_token();
+	typ=settyp((VECINT+dim-1)|UNSIGNED,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"long"))){
+	next_token();
+	typ=settyp(VECLONG+dim-1,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"ulong"))){
+	next_token();
+	typ=settyp((VECLONG+dim-1)|UNSIGNED,typ);
+	notdone=1;
+      }else if(opencl&&(dim=check_vect(ctok->name,"float"))){
+	next_token();
+	typ=settyp(VECFLOAT+dim-1,typ);
+	notdone=1;
+#if 0
+      }else if(c99&&!strcmp("restrict",ctok->name)){
+        next_token();
+        if(type_qualifiers&RESTRICT) error(58);
+        type_qualifiers|=RESTRICT;notdone=1;
+#endif
+      }else if(!strcmp("unsigned",ctok->name)){
+        next_token();
+        if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
+        notdone=1;type_qualifiers|=UNSIGNED;
+      }else if(!strcmp("signed",ctok->name)){
+        next_token();
+        if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
+        notdone=1;type_qualifiers|=XSIGNED;
+      }else if(!strcmp("auto",ctok->name)){
+        next_token();
+        dsc;storage_class=AUTO;notdone=1;
+      }else if(!strcmp("register",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        next_token();
+        dsc;storage_class=REGISTER;notdone=1;
+      }else if(!strcmp("static",ctok->name)){
+        next_token();
+        dsc;storage_class=STATIC;notdone=1;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+      }else if(!strcmp("extern",ctok->name)){
+        next_token();
+        dsc;storage_class=EXTERN;notdone=1;
+      }else if(!strcmp("typedef",ctok->name)){
+        next_token();
+        dsc;storage_class=TYPEDEF;notdone=1;
+      }else if(c99&&!strcmp("inline",ctok->name)){
+        next_token();
+        have_inline=1;notdone=1;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+			}else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__reg",ctok->name)){
+        char *d;
+        next_token();killsp(); 
+        if(ctok->type==LPAR) next_token(); else error(151);
+        killsp();
+        if(d=get_string()){
+          for(hard_reg=1;hard_reg<=MAXR;hard_reg++){
+            if(!strcmp(d,regnames[hard_reg])) break;
+          }
+          if(hard_reg>MAXR){ hard_reg=0;error(220,d);}
+          notdone=1;
+          free(d);
+        }
+        killsp();
+        if(ctok->type==RPAR) next_token(); else error(59);
+        killsp();
+      }else if(!strcmp("__mask",ctok->name)){
+	np tree;
+	next_token();killsp();
+        if(ctok->type==LPAR) next_token(); else error(151);
+	tree=expression();
+	if(tree&&type_expression(tree,0)){
+	  if(tree->flags==CEXPR&&ISINT(tree->ntyp->flags)){
+	    eval_const(&tree->val,tree->ntyp->flags);
+	    mask=vumax;
+	  }else
+	    error(18);
+	  free_expression(tree);
+	}else
+	  error(18);
+        killsp();
+        if(ctok->type==RPAR) next_token(); else error(59);
+        killsp();
+	notdone=1;
+      }else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__attr",ctok->name)){
+        char *d;
+        next_token();killsp(); 
+        if(ctok->type==LPAR) next_token(); else error(151);
+        killsp();
+        if(d=get_string()){
+          if(!attr){
+            attr=d;
+          }else{
+            attr=myrealloc(attr,strlen(attr)+strlen(d)+2);
+            strcat(attr,";");
+            strcat(attr,d);
+            free(d);
+          }
+          notdone=1;
+        }
+        killsp();
+        if(ctok->type==RPAR) next_token(); else error(59);
+        killsp();
+      }else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__vattr",ctok->name)){
+        char *d;
+        next_token();killsp();
+        if(ctok->type==LPAR) next_token(); else error(151);
+        killsp();
+        if(d=get_string()){
+          if(!vattr){
+            vattr=d;
+          }else{
+            vattr=myrealloc(vattr,strlen(vattr)+strlen(d)+2);
+            strcat(vattr,";");
+            strcat(vattr,d);
+            free(d);
+          }
+          notdone=1;
+        }
+        killsp();
+        if(ctok->type==RPAR) next_token(); else error(59);
+        killsp();
+      }else{
+#ifdef HAVE_TARGET_ATTRIBUTES
+        int i;
+        for(i=0;g_attr_name[i];i++){
+          if(!strcmp(g_attr_name[i],ctok->name)){
+            if(tattr&(1L<<i)) error(227,ctok->name);
+            tattr|=(1L<<i);
+            next_token();
+            notdone=1;break;
+          }
+        }
+#endif
+        if(!notdone&&typ==0&&!(type_qualifiers&(XSIGNED|UNSIGNED))){
+          v=find_var(ctok->name,0);
+          if(v&&v->storage_class==TYPEDEF){
+            free(new);
+            new=clone_typ(v->vtyp);
+            typ=settyp(new->flags,typ);
+            notdone=1;
+            next_token();
+          }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+        }
+      }
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(DEBUG&2) printf("typ:%d\n",typ);
+  }while(notdone);
+  killsp();
+  return_sc=storage_class;
+  return_reg=hard_reg;
+  return_vattr=vattr;
+  return_mask=mask;
+  return_inline=have_inline;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_TARGET_ATTRIBUTES
+  return_tattr=tattr;
+#endif
+  if(typ==0){
+    if(storage_class==0&&type_qualifiers==0&&!hard_reg){
+      free(new);
+      return 0;
+    }
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    typ=INT;
+  }
+  if(type_qualifiers&(XSIGNED|UNSIGNED))
+    if(!ISINT(typ))
+      error(58);
+  new->flags=typ|type_qualifiers;
+  new->attr=attr;
+  return new;
+}
+
+type *declarator(type *a)
+/* Erzeugt einen neuen Typ, auf Basis des Typs a.           */
+/* a wird hiermit verkettet.                                */
+{
+  type *t;
+  killsp();*ident=0;
+  t=direct_declarator(pointer(a));
+  if(!a)
+    {if(t) freetyp(t);return 0;}
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+#ifdef HAVE_EXT_TYPES
+  conv_typ(t);
+#endif  
+  return t;
+}
+type *pointer(type *a)
+/* Unterroutine fuer declarator(), behandelt Zeiger auf Typ.   */
+{
+  type *t;char *attr;int notdone;
+  if(!a) return(0);
+  killsp();
+  while(ctok->type==STAR){
+    next_token();
+    t=new_typ();
+    t->flags=POINTER_TYPE(a);
+    t->next=a;
+    attr=0;
+    a=t;
+    do{
+      killsp();
+      notdone=0;
+      if(ctok->type==NAME&&!strcmp("const",ctok->name)){
+	a->flags|=CONST;
+	notdone=1;
+	next_token();
+      }else if(ctok->type==NAME&&!strcmp("volatile",ctok->name)){
+	a->flags|=VOLATILE;
+	notdone=1;
+	next_token();
+      }else if(c99&&ctok->type==NAME&&!strcmp("restrict",ctok->name)){
+	a->flags|=RESTRICT;
+	notdone=1;
+	next_token();
+      }else if(ctok->type==NAME&&!strcmp("__attr",ctok->name)){
+	char *d;
+	next_token();
+	killsp();
+	if(ctok->type==LPAR) next_token(); else error(151);
+	killsp();
+	if(d=get_string()){
+	  if(!attr){
+	    attr=d;
+	  }else{
+	    attr=myrealloc(attr,strlen(attr)+strlen(d)+2);
+	    strcat(attr,";");
+	    strcat(attr,d);
+	    free(d);
+	  }
+	  notdone=1;
+	}
+	killsp();
+	if(ctok->type==RPAR) next_token(); else error(59);
+	killsp();
+      }
+    }while(notdone);
+    a->attr=attr;
+  }
+  return a;
+}
+type *direct_declarator(type *a)
+/*  Unterroutine zu declarator()                    */
+/*  behandelt [],(funkt),(dekl).                     */
+{
+  type *rek=0,*merk,*p,*t=0,*first,*last=0;
+  struct_declaration *fsd;
+  struct_list (*sl)[];
+  size_t slsz;char *imerk;
+  char fbuff[MAXI];
+  killsp();
+  if(ctok->type!=NAME&&ctok->type!=LPAR&&ctok->type!=LBRK)
+    return a;
+  if(ctok->type==NAME){
+    cpbez(ident,1);
+    next_token();
+    if(!a) return(0);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  }
+  else if(ctok->type==LPAR&&a){
+    /* Rekursion */
+    token mtok;
+    copy_token(&mtok,ctok);
+    next_token(); killsp();
+    if(ctok->type!=RPAR&&*ident==0&&!declaration(0)){
+      merk=a;
+      rek=declarator(a);
+      if(ctok->type!=RPAR) error(59); else next_token();
+    }else
+
+      push_token(&mtok);
+    free(mtok.name);
+  }
+  if(!a)return(0);
+  killsp();
+  while(ctok->type==LBRK||ctok->type==LPAR){
+    if(ctok->type==LBRK){
+      next_token();
+      killsp();
+      p=new_typ();
+      p->flags=ARRAY;
+      p->next=0;
+      if(ctok->type==RBRK){
+        p->size=l2zm(0L);
+      }else{
+        np tree;
+        tree=expression();
+        if(!type_expression(tree,0)){
+          /*                    error("incorrect constant expression");*/
+        }else{
+          if(tree->sidefx&&!c99) error(60);
+          if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){
+	    if(!c99||!ALLOCVLA_INLINEASM)
+	      error(19);
+	    else{
+	      type *st;IC *new;
+	      st=new_typ();
+	      st->flags=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG);
+	      p->dsize=add_tmp_var(st);
+	      gen_IC(tree,0,0);
+	      convert(tree,st->flags);
+	      new=new_IC();
+	      new->code=ASSIGN;
+	      new->typf=st->flags;
+	      new->q1=tree->o;
+	      new->z.flags=VAR;
+	      new->z.v=p->dsize;
+	      new->z.val.vmax=l2zm(0L);
+	      new->q2.val.vmax=szof(st);
+	      add_IC(new);
+	    }
+          }else{
+            eval_constn(tree);
+            p->size=vmax;
+            if(zmleq(p->size,l2zm(0L))) {error(61);p->size=l2zm(1L);}
+          }
+        }
+        free_expression(tree);
+      }
+      if(ctok->type!=RBRK) error(62); else next_token();
+      if(last){
+        last->next=p;
+        last=p;
+      }else{
+        first=last=p;
+      }
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(ctok->type==LPAR){
+      int komma,firstparm,oldstyle=0;
+#if 0 /*#ifdef HAVE_REGPARMS*/
+      treg_handle reg_handle=empty_reg_handle;
+      type rpointer={0};
+      if(!ffreturn(a)&&(a->flags&NQ)!=VOID){
+	rpointer.flags=POINTER_TYPE(a);
+        rpointer.next=a;
+        reg_parm(&reg_handle,&rpointer,0,a); /*TODO: a might be incomplete */
+      }
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+      next_token();
+      killsp();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      fsd=mymalloc(sizeof(*fsd));
+      slsz=SLSIZE;
+      sl=mymalloc(sizeof(struct_list)*slsz);
+      fsd->count=0;
+      imerk=ident;komma=0;
+      enter_block();
+      firstparm=1;
+      while(ctok->type!=RPAR&&ctok->type!=MDOTS){
+        int hard_reg;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+	if(!firstparm&&!komma) error(57);
+	komma=firstparm=0;
+        ident=fbuff;*fbuff=0;
+        t=declaration_specifiers();
+        hard_reg=return_reg;
+        t=declarator(t);
+        if(!t){
+          oldstyle=1;
+          if(*ident==0) {error(20);freetyp(t);continue;}
+        }
+        if(fsd->count){
+          if((t&&!(*sl)[fsd->count-1].styp)||
+             (!t&&(*sl)[fsd->count-1].styp))
+            error(63);
+        }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+        if(!return_sc) return_sc=AUTO;
+        if(return_sc!=AUTO&&return_sc!=REGISTER)
+          {error(21);return_sc=AUTO;}
+        (*sl)[fsd->count].styp=t;
+        (*sl)[fsd->count].storage_class=return_sc;
+	{
+	  int m=nesting;
+	  nesting=0;
+	  (*sl)[fsd->count].identifier=add_identifier(ident,strlen(ident));
+	  nesting=m;
+	}
+        if(t){
+          if(((*sl)[fsd->count].styp->flags&NQ)==VOID&&fsd->count!=0)
+            error(22);
+          /*  Arrays in Zeiger umwandeln  */
+          if(ISARRAY((*sl)[fsd->count].styp->flags))
+            (*sl)[fsd->count].styp->flags=POINTER_TYPE((*sl)[fsd->count].styp->next);
+	  /*  Funktionen in Zeiger auf Funktionen umwandeln   */
+	  if(ISFUNC((*sl)[fsd->count].styp->flags)){
+	    type *new;
+	    new=new_typ();
+	    new->next=(*sl)[fsd->count].styp;
+	    new->flags=POINTER_TYPE(new->next);
+	    (*sl)[fsd->count].styp=new;
+	  }
+	}
+        if(hard_reg&&regok(hard_reg,t->flags,-1)<=0) error(217,regnames[hard_reg]);
+#if 0 /*#ifdef HAVE_REGPARMS*/
+        if(t) (*sl)[fsd->count].reg=reg_parm(&reg_handle,t,0,a); /*TODO: a might be incomplete */
+        if(hard_reg) (*sl)[fsd->count].reg=hard_reg;
+#else
+        (*sl)[fsd->count].reg=hard_reg;
+#endif
+        fsd->count++;
+        if(fsd->count>=slsz-2){     /*  eins Reserve fuer VOID  */
+          slsz+=SLSIZE;
+          sl=myrealloc(sl,slsz*sizeof(struct_list));
+        }
+        killsp(); /* Hier Syntaxpruefung strenger machen */
+        if(ctok->type==COMMA) {next_token();komma=1; killsp();}
+      }
+      ident=imerk;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      if(ctok->type!=MDOTS||!komma){
+        int ecpp_addvoid=0;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+        if(ecpp_addvoid||(!ecpp&&fsd->count>0&&(!(*sl)[fsd->count-1].styp||((*sl)[fsd->count-1].styp->flags&NQ)!=VOID))){
+          (*sl)[fsd->count].styp=new_typ();
+          (*sl)[fsd->count].styp->flags=VOID;
+          (*sl)[fsd->count].styp->next=0;
+          (*sl)[fsd->count].reg=0;
+          (*sl)[fsd->count].identifier=empty;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+          fsd->count++;
+        }
+        if(ecpp&&ctok->type==MDOTS){next_token();killsp();}
+      }else if(komma){
+        next_token();komma=0;
+        if(oldstyle) error(221);
+      }
+      p=new_typ();
+      p->flags=FUNKT;
+      {
+        int m=nesting;
+        nesting=0;
+        p->exact=add_sd(fsd,FUNKT);
+        add_sl(fsd,sl);
+        free(sl);
+        nesting=m;
+      }
+#ifdef HAVE_REGPARMS
+      {
+	treg_handle reg_handle=empty_reg_handle;
+	int i,r;
+
+	p->next=a;
+
+	if(!ffreturn(a)&&(a->flags&NQ)!=VOID){
+	  type rpointer={0};
+
+	  rpointer.flags=POINTER_TYPE(a);
+	  rpointer.next=a;
+	  reg_parm(&reg_handle,&rpointer,0,p);
+	}
+
+	for(i=0;i<p->exact->count;i++){
+	  if((*p->exact->sl)[i].styp)
+	    r=reg_parm(&reg_handle,(*p->exact->sl)[i].styp,0,p);
+	  else
+	    r=0;
+	  if((*p->exact->sl)[i].reg==0) (*p->exact->sl)[i].reg=r;
+	}
+      }
+#endif
+      killsp();
+      if(komma) error(59);
+      if(ctok->type!=RPAR) error(59); else next_token();
+      killsp();
+      if(ctok->type==COMMA||ctok->type==SEMIC||ctok->type==RPAR||ctok->type==ASGN)
+	leave_block();
+      if(last){
+        last->next=p;
+        last=p;
+      }else{
+        first=last=p;
+      }
+    }
+    killsp();
+  }
+  if(last){last->next=a;last=a;a=first;}
+  if(rek!=0&&rek!=merk){
+    /* Zweite Liste anhaengen */
+    p=rek;
+    while(p->next!=merk) p=p->next;
+    if(p) p->next=a; else ierror(0);
+    return rek;
+  }
+  return a;
+}
+int declaration(int offset)
+/*  Testet, ob eine Typangabe kommt. Wenn offset!=0 ist,    */
+/*  muss s auf '(' zeigen und es wird getestet, ob nach der */
+/*  Klammer eine Typangabe kommt.                           */
+/*  In jedem Fall zeigt s danach wieder auf dieselbe Stelle */
+/*  im Source.                                              */
+{
+  Var *v;token mtok;
+  int fl=0;
+  if(offset){
+    copy_token(&mtok,ctok);
+    next_token();
+    killsp();
+  }
+  if(ctok->type==NAME){
+    if(!strcmp("auto",ctok->name)) fl=1;
+    else if(!strcmp("char",ctok->name)) fl=1;
+    else if(!strcmp("const",ctok->name)) fl=1;
+    else if(!strcmp("double",ctok->name)) fl=1;
+    else if(!strcmp("enum",ctok->name)) fl=1;
+    else if(!strcmp("extern",ctok->name)) fl=1;
+    else if(!strcmp("float",ctok->name)) fl=1;
+    else if(!strcmp("int",ctok->name)) fl=1;
+    else if(!strcmp("long",ctok->name)) fl=1;
+    else if(!strcmp("register",ctok->name)) fl=1;
+    else if(c99&&!strcmp("restrict",ctok->name)) fl=1;
+    else if(!strcmp("short",ctok->name)) fl=1;
+    else if(!strcmp("signed",ctok->name)) fl=1;
+    else if(!strcmp("static",ctok->name)) fl=1;
+    else if(!strcmp("struct",ctok->name)) fl=1;
+    else if(!strcmp("typedef",ctok->name)) fl=1;
+    else if(!strcmp("union",ctok->name)) fl=1;
+    else if(!strcmp("unsigned",ctok->name)) fl=1;
+    else if(!strcmp("void",ctok->name)) fl=1;
+    else if(!strcmp("volatile",ctok->name)) fl=1;
+    else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__reg",ctok->name)) fl=1;
+    else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__attr",ctok->name)) fl=1;
+    else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__vattr",ctok->name)) fl=1;
+    else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__mask",ctok->name)) fl=1;
+    else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__readsmem",ctok->name)) fl=1;
+    else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__writesmem",ctok->name)) fl=1;
+    else{
+      v=find_var(ctok->name,0);
+      if(v&&v->storage_class==TYPEDEF) fl=1;
+    }
+  }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  if(offset){
+    push_token(&mtok);
+    free(mtok.name);
+  }
+  return fl;
+}
+void init_sl(struct_list *sl){
+  if(!sl){ierror(0);return;}
+  sl->identifier=0;
+  sl->styp=0;
+  sl->align=0;
+  sl->bfoffset=-1;
+  sl->bfsize=-1;
+  sl->reg=0;
+  sl->storage_class=0;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+}
+void add_sl(struct_declaration *sd,struct_list (*sl)[])
+/*  Fuegt ein struct_list-Array in eine struct_declaration ein.     */
+/*  Das Array muss mind. sd->count Elements haben und wird kopiert. */
+{
+  size_t sz=sizeof(struct_list)*sd->count;
+  sd->sl=mymalloc(sz);
+  memcpy(sd->sl,sl,sz);
+}
+struct_declaration *add_sd(struct_declaration *new,int typ)
+/*  Fuegt eine Declaration in Liste ein.     */
+{
+  new->next=0;
+  new->label=0;
+  new->typ=typ;
+  new->identifier=0;
+  new->tunit=last_tunit;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  if(first_sd[nesting]==0){
+    first_sd[nesting]=last_sd[nesting]=new;
+  }else{
+    last_sd[nesting]->next=new;
+    last_sd[nesting]=new;
+  }
+  return new;
+}
+void free_sd(struct_declaration *p)
+/*  Gibt eine struct_declaration-List inkl. struct_lists und    */
+/*  allen Typen jeder struct_list frei, nicht aber identifier.  */
+{
+  int i;struct_declaration *merk;
+  while(p){
+    merk=p->next;
+    if(p->sl){
+      for(i=0;i<p->count;i++){
+	if((*p->sl)[i].styp) freetyp((*p->sl)[i].styp);
+      }
+      if(p->count>0) free(p->sl);
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+    free(p);
+    p=merk;
+  }
+}
+char *add_identifier(char *identifier,int length)
+/*  Kopiert identifier an sicheren Ort, der spaeter zentral     */
+/*  freigegeben werden kann.                                    */
+/*  Sollte noch einbauen, dass ueberprueft wird, ob schon       */
+/*  vorhanden und dann nicht zweimal speichern.                 */
+{
+  identifier_list *new;
+  if((*identifier==0&&length==0)||identifier==empty) return(empty);
+  new=mymalloc(sizeof(identifier_list));
+  new->identifier=mymalloc(length+1);
+  memcpy(new->identifier,identifier,length+1);
+  new->next=0;new->length=length;
+  if(last_ilist[nesting]){
+    last_ilist[nesting]->next=new;
+    last_ilist[nesting]=new;
+  }else{
+    last_ilist[nesting]=first_ilist[nesting]=new;
+  }
+  return(new->identifier);
+}
+void free_ilist(identifier_list *p)
+/*  Gibt eine verkettete identifier_liste und saemtliche darin  */
+/*  gespeicherten Identifier frei.                              */
+{
+  identifier_list *merk;
+  while(p){
+    merk=p->next;
+    if(p->identifier) free(p->identifier);
+    free(p);
+    p=merk;
+  }
+}
+int type_uncomplete(type *p)
+/*  Testet, ob Typ unvollstaendig ist. Momentan gelten nur      */
+/*  unvollstaendige Strukturen und Arrays von solchen als       */
+/*  unvollstaendig, aber keine Zeiger oder Funktionen darauf.   */
+{
+  struct_declaration *sd;
+  if(!p){ierror(0);return(0);}
+  if(ISSTRUCT(p->flags)||ISUNION(p->flags))
+    if(p->exact->count<=0) return 1;
+  if(ISARRAY(p->flags)){
+    if(!p->dsize&&zmleq(p->size,l2zm(0L))) return 1;
+if(!p->next) ierror(0);
+    if(type_uncomplete(p->next)) return 1;
+  }
+  return 0;
+}
+void add_struct_identifier(char *identifier,struct_declaration *sd)
+/*  Erzeugt neuen struct_identifier, fuegt ihn in Liste an und  */
+/*  vervollstaendigt unvollstaendige Typen dieser Struktur.     */
+{
+  struct_identifier *new;
+/*    type *t;*/
+  if(DEBUG&1) printf("add_si %s (nesting=%d)->%p\n",identifier,nesting,(void *)sd);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  new=mymalloc(sizeof(struct_identifier));
+  new->identifier=add_identifier(identifier,strlen(identifier));
+  new->sd=sd;
+  new->next=0; 
+  if(first_si[nesting]==0){
+    first_si[nesting]=new;last_si[nesting]=new;
+  }else{
+    last_si[nesting]->next=new;last_si[nesting]=new;
+  }
+  sd->identifier=new->identifier;
+}
+void free_si(struct_identifier *p)
+/*  Gibt eine struct_identifier-Liste frei, aber nicht die      */
+/*  identifiers und struct_declarations.                        */
+{
+  struct_identifier *merk;
+  while(p){
+    merk=p->next;
+    p->sd->identifier="<prototype-only>";
+    free(p);
+    p=merk;
+  }
+}
+struct_declaration *find_struct(char *identifier,int endnesting)
+
+/*  Sucht angegebene Strukturdefinition und liefert             */
+/*  entsprechende struct_declaration.                           */
+{
+  struct_identifier *si; int i,l;
+  if(misracheck) l=strlen(identifier);
+  for(i=nesting;i>=endnesting;i--){
+    si=first_si[i];
+    while(si){
+      if(!strcmp(si->identifier,identifier)){
+        if(DEBUG&1) printf("found tag <%s> at nesting %d->%p\n",identifier,i,(void *)si->sd);
+        return(si->sd);
+      }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+	si=si->next;
+	}
+  }
+  if(DEBUG&1) printf("didn't find tag <%s>\n",identifier);
+  return(0);
+}
+
+/* generate code to create a variable-lenght-array */
+static void create_allocvl(Var *v)
+{
+  np tree,ds;
+  IC *new;Var *fv;
+
+  /* check if we got a frame-pointer */
+  if(FPVLA_REG&&!regsa[FPVLA_REG]){
+    if(regused[FPVLA_REG])
+      ierror(0);
+    else
+      regsa[FPVLA_REG]=regscratch[FPVLA_REG]=regused[FPVLA_REG]=1;
+  }
+
+  /* if this is the first vla in this block, save old sp */
+  if(!block_vla[nesting]){
+    /* declare function - may be done by the backend, if necessary */
+    if(!(fv=find_ext_var("__oldvlasp"))){
+      type *t;
+      static type voidt={VOID};
+      struct_declaration *sd=mymalloc(sizeof(*sd));
+      t=new_typ();
+      t->flags=FUNKT;
+
+      t->next=new_typ();
+      t->next->flags=POINTER_TYPE(&voidt);
+      t->next->next=clone_typ(&voidt);
+      sd->count=0;
+      t->exact=add_sd(sd,FUNKT);
+      fv=add_var("__oldvlasp",t,EXTERN,0);
+      fv->fi=new_fi();
+      fv->fi->flags|=(ALL_USES|ALL_MODS);
+      fv->fi->inline_asm=mystrdup(OLDSPVLA_INLINEASM);
+    } 
+    block_vla[nesting]=add_tmp_var(clone_typ(fv->vtyp->next));
+    tree=gen_libcall("__oldvlasp",0,0,0,0);
+    new=new_IC();
+    new->code=ASSIGN;
+    new->z.flags=VAR;
+    new->z.v=block_vla[nesting];
+    new->z.val.vmax=l2zm(0L);
+    new->q1=tree->o;
+    new->q2.flags=0;
+    new->typf=block_vla[nesting]->vtyp->flags;
+    new->q2.val.vmax=sizetab[new->typf];
+    add_IC(new);
+    free_expression(tree);
+  }
+
+  /* make room on the stack */
+  ds=new_node();
+  ds->flags=IDENTIFIER;
+  ds->identifier=empty;
+  ds->dsize=vlength_szof(v->vtyp);
+  ds->val.vmax=l2zm(0L);
+  ds->ntyp=clone_typ(ds->dsize->vtyp);
+  ds->o.flags=VAR;
+  ds->o.v=ds->dsize;
+  ds->o.val.vmax=l2zm(0L);
+  ds->left=ds->right=0;
+
+  if(!find_ext_var("__allocvla")){
+    /* declare function */
+    struct_declaration *sd=mymalloc(sizeof(*sd));
+    type *t=new_typ();
+    sd->count=1;
+    sd->sl=mymalloc(sizeof(struct_list));
+    (*sd->sl)[0].storage_class=AUTO;
+    (*sd->sl)[0].styp=clone_typ(ds->dsize->vtyp);
+    (*sd->sl)[0].reg=ALLOCVLA_REG;
+    t->flags=FUNKT;
+    t->exact=add_sd(sd,FUNKT);
+    t->next=new_typ();
+    t->next->flags=POINTER_TYPE(v->vtyp);
+    t->next->next=new_typ();
+    t->next->next->flags=v->vtyp->flags;
+    fv=add_var("__allocvla",t,EXTERN,0);
+    fv->fi=new_fi();
+    fv->fi->flags|=(ALL_USES|ALL_MODS);
+    fv->fi->inline_asm=mystrdup(ALLOCVLA_INLINEASM);
+  }
+
+  if(!type_expression(ds,0)) ierror(0);
+  tree=gen_libcall("__allocvla",ds,0,0,0);
+  new=new_IC();
+  new->code=ASSIGN;
+  new->z.flags=VAR;
+  new->z.v=v;
+  new->z.val.vmax=l2zm(0L);
+  new->q1=tree->o;
+  new->q2.flags=0;
+  new->typf=POINTER_TYPE(v->vtyp);
+  new->q2.val.vmax=sizetab[new->typf];
+  add_IC(new);
+  free_expression(tree);
+  vlas=1;
+}
+
+/* reset sp to remove variable-length-arrays */
+void freevl(void)
+{
+  np tree,ds;
+  Var *fv;
+  dontdelete=1; /* never remove them, otherwise, fix_vla_jump get confused */
+  if(!find_ext_var("__resetvlasp")){
+    struct_declaration *sd=mymalloc(sizeof(*sd));
+    type *t=new_typ();
+    sd->count=1;
+    sd->sl=mymalloc(sizeof(struct_list));
+    (*sd->sl)[0].storage_class=AUTO;
+    (*sd->sl)[0].styp=clone_typ(block_vla[nesting]->vtyp);
+    (*sd->sl)[0].reg=FREEVLA_REG;
+    t->flags=FUNKT;
+    t->exact=add_sd(sd,FUNKT);
+    t->next=new_typ();
+    t->next->flags=VOID;
+    fv=add_var("__resetvlasp",t,EXTERN,0);
+    fv->fi=new_fi();
+    fv->fi->flags|=(ALL_USES|ALL_MODS);
+    fv->fi->inline_asm=mystrdup(FREEVLA_INLINEASM);
+  }
+  if(nesting==1){
+    clear_main_ret();
+    gen_label(return_label);
+    did_return_label=1;
+  }
+  ds=new_node();
+  ds->flags=IDENTIFIER;
+  ds->identifier=empty;
+  ds->dsize=block_vla[nesting];
+  ds->val.vmax=l2zm(0L);
+  ds->ntyp=clone_typ(ds->dsize->vtyp);
+  ds->left=ds->right=0;
+  ds->o.flags=VAR;
+  ds->o.v=ds->dsize;
+  ds->o.val.vmax=l2zm(0L);
+  if(!type_expression(ds,0)) ierror(0);
+  tree=gen_libcall("__resetvlasp",ds,0,0,0);
+  free_expression(tree);
+  dontdelete=0;
+}  
+
+void clearvl(void)
+{
+  llist *p,*n;
+  vlaadjust_list *vl,*vn;
+  /* look for stack-adjusts that have to be removed */
+  vl=vlaadjusts[nesting];
+  while(vl){
+    int ln;
+    IC *ic=vl->branch;
+    if(ic){
+      ln=ic->typf;
+      if(ic->code!=BRA) ierror(0);
+      p=vladeflabels[nesting];
+      while(p){
+	if(p->label==ln) break;
+	p=p->next;
+      }
+      if(!p){
+	ic=ic->prev;
+	while(ic!=vl->first->prev){
+	  if(!ic) ierror(0);
+	  ic->code=NOP;
+	  ic->q1.flags=ic->q2.flags=ic->z.flags=0;
+	  ic=ic->prev;
+	}
+      }
+    }
+    vn=vl->next;
+    free(vl);
+    vl=vn;
+  }
+  freevl();
+  block_vla[nesting]=0;
+  p=vladeflabels[nesting];
+  while(p){
+    n=p->next;
+    free(p);
+    p=n;
+  }
+  p=vlajmplabels[nesting];
+  while(p){
+    n=p->next;
+    free(p);
+    p=n;
+  }
+  vladeflabels[nesting]=vlajmplabels[nesting]=0;
+  vlaadjusts[nesting]=0;
+}
+
+/* Handle a stack of stored sp variables when traversing an IC list; */
+void vla_nesting(IC *p,Var **vn,int *nest)
+{
+  if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__oldvlasp")){
+    IC *p2=p->next;
+    while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
+    if(!p2||p2->code!=GETRETURN||(p2->z.flags&(VAR|DREFOBJ))!=VAR) ierror(0);
+    /*printf("found save sp to %p\n",p2->z.v);*/
+    vn[*nest]=p2->z.v;
+    (*nest)++;
+    vn[*nest]=0;
+    if(*nest>=MAXN) ierror(0);
+    return;
+  }
+  if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__resetvlasp")){ 
+    /*printf("found reset\n");*/
+    if(*nest<=0) ierror(0);
+    (*nest)--;
+    return;
+  }
+}
+
+static int return_vla_nest;
+static Var *return_last_vlasp;
+
+/* Find the stack pointer that is needed when jumping to label lab */
+Var *vla_find_sp(int lab)
+{
+  IC *p;int nest=0;
+  static Var *vn[MAXN];
+  for(p=first_ic;p;p=p->next){
+    if(p->code==LABEL&&p->typf==lab){
+      return_vla_nest=nest;
+      return_last_vlasp=vn[nest];
+      if(nest<=0)
+	return 0;
+      else
+	return vn[nest-1];
+    }
+    vla_nesting(p,vn,&nest);
+  }
+  ierror(0);
+}
+
+void vla_jump_fix(void)
+{
+  IC *p;int nest=0;
+  static Var *vn[MAXN],*savedsp;
+  if(DEBUG&1) printf("searching for vla-jump-fixes\n");
+  for(p=first_ic;p;p=p->next){
+    /*pric2(stdout,p);*/
+    if(p->code>=BEQ&&p->code<=BRA){
+      /*printf("jump found\n");*/
+      p->savedsp=0;
+      if(1/*nest>0*/){
+	/*printf("is in vla context!\n");*/
+	savedsp=vla_find_sp(p->typf);
+	if(return_vla_nest>nest||(nest>0&&return_vla_nest==nest&&savedsp!=vn[nest-1])){
+	  err_ic=p;
+	  error(351);
+	}else if(nest==0||savedsp==vn[nest-1]){
+	  /*printf("jump within the same context\n");*/
+	}else{
+	  if(vn[nest]){
+	    if(DEBUG&1) printf("have to set sp to %p\n",return_last_vlasp);
+	    p->savedsp=return_last_vlasp;
+	  }else{
+	    int ndiff=nest-return_vla_nest-1;
+	    IC *p2;
+	    /*printf("have to search oldsp ndiff=%d\n",ndiff);*/
+	    for(p2=p->prev;p2;p2=p2->prev){
+	      if(p2->code==CALL&&(p2->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p2->q1.v->identifier,"__oldvlasp")){
+		if(ndiff==0){
+		  /*printf("found savesp\n");*/
+		  p2=p2->next;
+		  while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
+		  if(!p2||p2->code!=GETRETURN) ierror(0);
+		  if((p2->z.flags&(VAR|DREFOBJ))!=VAR) ierror(0);
+		  /*printf("found oldsp %p\n",p2->z.v);*/
+		  p->savedsp=p2->z.v;
+		  break;
+		}
+		ndiff--;
+	      }
+	      if(p2->code==CALL&&(p2->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p2->q1.v->identifier,"__resetvlasp")){
+		ndiff++;
+	      }
+	    }
+	    if(!p2) ierror(0);
+	  }
+	}
+      }else{
+	/*printf("not in vla context\n");*/
+      }
+    }
+    vla_nesting(p,vn,&nest);
+  }
+  for(p=first_ic;p;p=p->next){
+    if(p->code>=BEQ&&p->code<=BRA){  
+      if(p->savedsp){
+	IC *merkfic,*merklic,*newcode,*m,*new,*setr=0;
+	np ds,tree;
+	if(DEBUG&1) printf("generating sp-adjust\n");
+        merkfic=first_ic;merklic=last_ic;
+	first_ic=0;last_ic=0;
+	ds=new_node();
+	ds->flags=IDENTIFIER;
+	ds->identifier=empty;
+	ds->dsize=p->savedsp;
+	ds->val.vmax=l2zm(0L);
+	ds->ntyp=clone_typ(ds->dsize->vtyp);
+	ds->left=ds->right=0;
+	ds->o.flags=VAR;
+	ds->o.v=ds->dsize;
+	ds->o.val.vmax=l2zm(0L);
+	if(!type_expression(ds,0)) ierror(0);
+	tree=gen_libcall("__resetvlasp",ds,0,0,0);
+	free_expression(tree);
+	newcode=first_ic;
+	first_ic=merkfic;last_ic=merklic;
+	if(p->code==BRA){
+	  /* check if the branch was preceded by a SETRETURN */
+	  IC *p2=p->prev;
+	  while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG))
+	    p2=p2->prev;
+	  if(p2->code==SETRETURN&&p2->z.reg)
+	    setr=p2;
+	}else{
+	  new=new_IC();
+	  new->typf=++label;
+	  if(p->code==BEQ) new->code=BRA;
+	  else if(p->code==BNE) new->code=BEQ;
+	  else if(p->code==BLT) new->code=BGE;
+	  else if(p->code==BGT) new->code=BLE;
+	  else if(p->code==BLE) new->code=BGT;
+	  else if(p->code==BGE) new->code=BLT;
+	  insert_IC(p->prev,new);
+	}
+	while(newcode){
+	  m=newcode->next;
+	  insert_IC(p->prev,newcode);
+	  newcode=m;
+	}
+	if(p->code!=BRA){
+	  p->code=BRA;
+	  new=new_IC();
+	  new->code=LABEL;
+	  new->typf=label;
+	  insert_IC(p,new);
+	}
+	if(setr){
+	  /* save the return value to save it from being overwritten */
+	  /* could be optimized further */
+	  Var *v;
+	  if(ISSCALAR(setr->typf)){
+	    static type t={0};
+	    t.flags=setr->typf;
+	    v=add_tmp_var(clone_typ(&t));
+	  }else ierror(0);
+	  new=new_IC();
+	  *new=*setr;
+	  new->q1.flags=VAR;
+	  new->q1.v=v;
+	  new->q1.val.vmax=l2zm(0L);
+	  setr->z=new->q1;
+	  setr->code=ASSIGN;
+	  insert_IC(p->prev,new);
+	}
+      }
+    }
+  }
+}  
+  
+
+Var *add_tmp_var(type *t)
+{
+  t->flags&=NU;
+  return add_var(empty,t,AUTO,0);
+}
+Var *add_var(char *identifier, type *t, int storage_class,const_list *clist)
+/*  Fuegt eine Variable mit Typ in die var_list ein.            */
+/*  In der storage_class werden die Flags PARAMETER und evtl.   */
+/*  OLDSTYLE und REGPARM erkannt.                               */
+{
+  Var *new;int f;
+  struct_declaration *sd;
+  static zmax paroffset;
+  zmax al;
+  /*if(*identifier==0) return;*/ /* sollte woanders bemaekelt werden */
+  if(DEBUG&2) printf("add_var(): %s\n",identifier);
+#ifdef HAVE_TARGET_VARHOOK_PRE
+  add_var_hook_pre(identifier,t,storage_class,clist);
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  if(ISFUNC(t->flags&NQ)&&(ISARRAY(t->next->flags)||ISFUNC(t->next->flags)))
+    error(25);
+  new=mymalloc(sizeof(Var));
+  if(!*identifier&&identifier!=empty) ierror(0);
+  new->clist=clist;
+  new->vtyp=t;
+  new->storage_class=storage_class&PLAIN_STORAGE_CLASS;
+  new->reg=0;
+  new->vattr=0;
+  new->next=0;
+  new->flags=0;
+  new->inr=0;
+  new->fi=0;
+  new->nesting=nesting;
+  new->filename=filename;
+  new->line=line;
+  new->dfilename=0;
+  new->dline=0;
+  new->description=0;
+  new->tunit=last_tunit;
+  new->inline_copy=0;
+  new->index=-1;
+#ifdef HAVE_TARGET_ATTRIBUTES
+  new->tattr=0;
+#endif
+  /*    if((storage_class&PLAIN_STORAGE_CLASS)==STATIC||(storage_class&PLAIN_STORAGE_CLASS)==EXTERN) new->flags=USEDASSOURCE|USEDASDEST;*/
+  if(DEBUG&2) printf("storage_class=%d\n",storage_class);
+  if(storage_class&PARAMETER) new->flags|=USEDASDEST;
+  if(storage_class&REGPARM){
+    new->flags|=REGPARM;
+    if(!(storage_class&DBLPUSH)){
+      if((storage_class&OLDSTYLE)&&(t->flags&NQ)==FLOAT)
+	new->flags|=CONVPARAMETER;
+      storage_class&=~PARAMETER;
+    }
+  }
+  if(DEBUG&2) printf("storage_class=%d\n",storage_class);
+  if(DEBUG&2) printf("max_offset=%ld\n",zm2l(max_offset));
+  if(is_vlength(t)&&storage_class!=AUTO&&storage_class!=REGISTER)
+    error(315);
+  if((storage_class&PLAIN_STORAGE_CLASS)==REGISTER) new->priority=registerpri; else new->priority=0;
+  if(/*nesting==0&&*/new->storage_class==EXTERN){
+    int m=nesting;
+    nesting=0;
+    new->identifier=add_identifier(identifier,strlen(identifier));
+    nesting=m;
+    if(last_ext){
+      last_ext->next=new;
+      last_ext=new;
+    }else{
+      first_ext=last_ext=new;
+      vl0=first_ext;
+    }
+    if(hash_ext) add_hashentry(hash_ext,new->identifier,new);
+  }else{
+    new->identifier=add_identifier(identifier,strlen(identifier));
+    if(last_var[nesting]){
+      new->offset=zmadd(last_var[nesting]->offset,szof(last_var[nesting]->vtyp));
+      last_var[nesting]->next=new;
+      last_var[nesting]=new;
+    }else{
+      new->offset=l2zm(0L);
+      paroffset=l2zm(0L);;
+      first_var[nesting]=last_var[nesting]=new;
+      if(nesting==0) vl1=new;
+      if(nesting==1) vl2=new;
+    }
+  }
+  f=t->flags&NQ;
+  if((storage_class&PLAIN_STORAGE_CLASS)==AUTO||(storage_class&PLAIN_STORAGE_CLASS)==REGISTER){
+    if(DEBUG&2) printf("auto\n");
+    al=falign(t);
+    if((c_flags_val[0].l&2)&&nesting==1&&!(storage_class&PARAMETER)){
+      new->offset=max_offset;
+    }else{
+      if(storage_class&PARAMETER){
+        new->offset=paroffset;
+	if(align_arguments)
+	  new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(al,l2zm(1L))),al),al);
+      }else{
+        new->offset=local_offset[nesting];
+	new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(al,l2zm(1L))),al),al);
+      }
+    }
+    if(storage_class&PARAMETER){
+      new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+      if(ISINT(f)&&f<INT&&!short_push){
+        /*  Integer-Erweiterungen fuer alle Funktionsparameter  */
+        paroffset=zmadd(new->offset,sizetab[INT]);
+      }else{
+        if(f==FLOAT&&(storage_class&OLDSTYLE)){
+          /*  Bei alten Funktionen werden FLOAT als DOUBLE uebergeben */
+          new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(align[DOUBLE],l2zm(1L))),align[DOUBLE]),align[DOUBLE]);
+          paroffset=zmadd(new->offset,sizetab[DOUBLE]);
+        }else{
+          paroffset=zmadd(new->offset,szof(new->vtyp));
+        }
+      }
+    }else{
+      local_offset[nesting]=zmadd(new->offset,szof(new->vtyp));
+    }
+    if(!(storage_class&PARAMETER))
+      if(zmleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
+    if(DEBUG&2) printf("max_offset=%ld\n",zm2l(max_offset));
+  }
+  if((storage_class&PLAIN_STORAGE_CLASS)==STATIC) new->offset=l2zm((long)++label);
+  if(storage_class&PARAMETER){
+
+    if(DEBUG&2) printf("parameter\n");
+
+    if(ISINT(f)&&f<INT&&!zmleq(sizetab[INT],sizetab[f])){
+      if(BIGENDIAN){
+        new->offset=zmadd(new->offset,zmsub(sizetab[INT],sizetab[f]));
+      }else{
+        if(!LITTLEENDIAN)
+          ierror(0);
+      }
+    }
+    if((storage_class&OLDSTYLE)&&f==FLOAT){
+      /*  Bei alten Funktionen werden DOUBLE nach FLOAT konvertiert   */
+      if(!(storage_class&REGPARM)){
+#if HAVE_LIBCALLS
+	static type dt={DOUBLE},ft={FLOAT};
+	static node n,nn;
+	IC *conv=new_IC();
+	n.flags=REINTERPRET;
+	n.left=&nn;
+	n.ntyp=&dt;
+	nn.flags=IDENTIFIER;
+	nn.identifier=identifier;
+	nn.ntyp=&ft;
+	nn.o.flags=VAR|DONTREGISTERIZE;
+	nn.o.v=new;
+	nn.o.val.vmax=l2zm(0L);
+	n.o=nn.o;
+	convert(&n,FLOAT);
+	
+
+	conv->code=ASSIGN;
+	conv->typf=FLOAT;
+	conv->q1=n.o;
+	conv->z.v=new;
+	conv->z.flags=VAR;
+	conv->z.val.vmax=l2zm(0L);
+	conv->q2.val.vmax=sizetab[FLOAT];
+	conv->z.v=new;
+	add_IC(conv);	
+#else
+	IC *conv=new_IC();
+	conv->code=CONVERT;
+	conv->typf=FLOAT;
+	conv->typf2=DOUBLE;
+	conv->q1.flags=VAR|DONTREGISTERIZE;
+	conv->z.flags=VAR;
+	conv->q2.flags=0;
+	conv->q1.v=conv->z.v=new;
+	conv->q1.val.vmax=conv->z.val.vmax=l2zm(0);
+	add_IC(conv);
+#endif
+      }
+      new->flags|=CONVPARAMETER;
+    }
+    new->offset=zmsub(l2zm(0L),zmadd(maxalign,new->offset));
+  }
+  if((storage_class&PLAIN_STORAGE_CLASS)==EXTERN){
+    if(!strcmp("fprintf",identifier)) new->flags|=PRINTFLIKE;
+    if(!strcmp("printf",identifier))  new->flags|=PRINTFLIKE;
+    if(!strcmp("sprintf",identifier)) new->flags|=PRINTFLIKE;
+    if(!strcmp("fscanf",identifier))  new->flags|=SCANFLIKE;
+    if(!strcmp("scanf",identifier))   new->flags|=SCANFLIKE;
+    if(!strcmp("sscanf",identifier))  new->flags|=SCANFLIKE;
+  }
+  if(is_vlength(new->vtyp))
+    create_allocvl(new);
+#ifdef HAVE_TARGET_VARHOOK_POST
+  add_var_hook_post(new);
+#endif
+  return(new);
+}
+void free_var(Var *p)
+/*  Gibt Variablenliste inkl. Typ, aber ohne Identifier frei.   */
+{
+  Var *merk;
+  while(p){
+    if(!*p->identifier&&p->identifier!=empty) ierror(0);
+    free(p->description);
+    free(p->vattr);
+    merk=p->next;
+    if(!(p->flags&USEDASADR)&&(p->storage_class==AUTO||p->storage_class==REGISTER)){
+      if(*p->identifier&&!(p->flags&USEDASDEST)&&ISSCALAR(p->vtyp->flags)) error(64,p->identifier);
+      if(*p->identifier&&!(p->flags&USEDASSOURCE)&&ISSCALAR(p->vtyp->flags)) error(65,p->identifier);
+    }
+    if(DEBUG&2) printf("free_var %s, pri=%d\n",p->identifier,p->priority);
+    if(p->vtyp) freetyp(p->vtyp);
+    if(p->clist) free_clist(p->clist);
+    if(p->fi){
+      if(DEBUG&2) printf("free_fi of function %s\n",p->identifier);
+      free_fi(p->fi);
+      if(DEBUG&2) printf("end free_fi of function %s\n",p->identifier);
+    }
+    free(p);
+    p=merk;
+  }
+}
+Var *find_ext_var(char *identifier)
+{
+  Var *v;int l;
+  if(misracheck) l=strlen(identifier);
+  if(hash_ext) return find_name(hash_ext,identifier);
+  for(v=first_ext;v;v=v->next){
+    if(!strcmp(v->identifier,identifier)) return v;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+  }
+  return 0;
+}
+Var *find_var(char *identifier,int endnesting)
+/*  Sucht Variable mit Bezeichner und liefert Zeiger zurueck    */
+/*  es werden nur Variablen der Bloecke endnesting-nesting      */
+/*  durchsucht.                                                 */
+{
+  int i,l;Var *v;
+  if(identifier==0||*identifier==0) return 0;
+  if(misracheck) l=strlen(identifier);
+  for(i=nesting;i>=endnesting;i--){
+    for(v=first_var[i];v;v=v->next){
+      if(!strcmp(v->identifier,identifier))
+	return v;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    }
+  }
+  if(endnesting==0){
+    v=find_ext_var(identifier);
+    if(v&&!(v->flags&NOTINTU))
+      return v;
+    else
+      return 0;
+  }else
+    return 0;
+}
+
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+
+
+
+int check_zero_initialisation(const_list* cl, int typ) 
+{
+  
+  if (cl->next) return 0;
+  if (cl->tree) return 0;
+  if (cl->other)  {
+    return check_zero_initialisation(cl->other,typ);
+  } else {
+    eval_const(&cl->val,typ);
+    if ( (zmeqto(vmax,l2zm(0L))) && (zumeqto(vumax,ul2zum(0UL))) && (zldeqto(vldouble,d2zld(0.0))) ) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* decide whether a initialization shall be performed only be generated code
+   or if a table copy should be used first */
+int use_only_dyn_init(zmax sz,zmax dyn_sz,zmax const_sz,int dyn_cnt,int const_cnt)
+{
+  if(zmleq(sz,l2zm(clist_copy_stack)))
+    return 1;
+  if(zmeqto(dyn_sz,l2zm(0L)))
+    return 0;
+  if(!zmleq(zmdiv(sz,dyn_sz),l2zm(2L)))
+    return 0;
+  else
+    return 1;
+}
+
+void init_local_compound(Var *v)
+{
+  if(v->storage_class==AUTO||v->storage_class==REGISTER){
+    IC *new;
+    /*  Initialisierung von auto-Variablen  */
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=v->vtyp->flags;
+    new->q2.flags=0;
+    new->q2.val.vmax=szof(v->vtyp);
+    new->z.flags=VAR;
+    new->z.v=v;
+    new->z.val.vmax=l2zm(0L);
+    if(v->clist->tree){
+      /*  einzelner Ausdruck  */
+      gen_IC(v->clist->tree,0,0);
+      convert(v->clist->tree,v->vtyp->flags&NU);
+      new->q1=v->clist->tree->o;
+      add_IC(new);
+      /*                        v->clist=0;*/
+    }else{
+      /*  Array etc.  */
+      Var *nv;
+      if(!ISSCALAR(v->vtyp->flags)&&!use_only_dyn_init(szof(v->vtyp),init_dyn_sz,init_const_sz,init_dyn_cnt,init_const_cnt)){
+	nv=add_var(empty,clone_typ(v->vtyp),STATIC,v->clist);
+	nv->flags|=DEFINED;
+	nv->dfilename=filename;
+	nv->dline=line;
+	nv->vtyp->flags|=CONST;
+	/*                        v->clist=0;*/
+	new->q1.flags=VAR;
+	new->q1.v=nv;
+	new->q1.val.vmax=l2zm(0L);
+
+	add_IC(new);
+	
+	dynamic_init(v,v->vtyp,v->clist,0,1);
+      }else{
+	dynamic_init(v,v->vtyp,v->clist,0,0);
+      }
+    }   
+  }
+}
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+void var_declaration(void)
+/*  Bearbeitet eine Variablendeklaration und erzeugt alle       */
+/*  noetigen Strukturen.                                        */
+{
+  type *ts,*t,*old=0,*om=0;char *imerk,vident[MAXI];
+  int mdef=0,makeint=0,notdone,storage_class,msc,extern_flag,isfunc,
+    had_decl,hard_reg,mhr,diffunit=0,inline_flag;
+  Var *v;
+  char *vattr;
+  zumax mask;
+  int base_type;
+#ifdef HAVE_TARGET_ATTRIBUTES
+  unsigned long tattr;
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  ts=declaration_specifiers();notdone=1;
+
+  storage_class=return_sc;hard_reg=return_reg;vattr=return_vattr;mask=return_mask;
+  inline_flag=return_inline;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+  if(for_decl&&storage_class!=0&&storage_class!=AUTO&&storage_class!=REGISTER){
+    error(299);
+    storage_class=AUTO;
+  }
+
+#ifdef HAVE_TARGET_ATTRIBUTES
+  tattr=return_tattr;
+#endif
+  if(storage_class==EXTERN) extern_flag=1; else extern_flag=0;
+  killsp();
+  if(ctok->type==SEMIC){
+    if(!ts) error(0);
+    if(storage_class||(!ISSTRUCT(ts->flags)&&!ISUNION(ts->flags)&&(ts->flags&NQ)!=INT))
+      error(36);
+    freetyp(ts);
+    next_token();killsp();
+    return;
+  }
+  if(nesting==0&&(storage_class==AUTO||storage_class==REGISTER))
+    {error(66);storage_class=EXTERN;}
+  if(!ts){
+    if(nesting<=1){
+      ts=new_typ();
+      ts->flags=INT;ts->next=0;
+      makeint=1;
+      if(!storage_class) storage_class=EXTERN;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      error(67);
+    }else{
+      error(365);
+    }
+  }
+  if(storage_class==0){
+    if(nesting==0) 
+      storage_class=EXTERN;
+    else
+      storage_class=AUTO;
+  }
+  msc=storage_class;mhr=hard_reg;
+  while(notdone){
+    int oldnesting=nesting;
+    imerk=ident;ident=vident;*vident=0;  /* merken von ident hier vermutlich */
+    storage_class=msc;hard_reg=mhr;
+    if(old) {freetyp(old);old=0;}
+    t=declarator(clone_typ(ts));
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_EXT_TYPES
+    conv_typ(t);
+#endif
+    if(!ISFUNC(t->flags)){
+        isfunc=0;
+        if(inline_flag) error(301);
+    }else{
+        isfunc=1;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        if(storage_class!=STATIC&&storage_class!=TYPEDEF) storage_class=EXTERN;
+    }
+    ident=imerk;                    /* nicht unbedingt noetig ?         */
+    if(!*vident){
+      free(ts);free(t);
+      error(36);return;
+    }
+    v=find_var(vident,oldnesting);
+    if(!v&&/*oldnesting==0&&*/storage_class==EXTERN&&cross_module&&(v=find_ext_var(vident))){
+      v->flags&=~NOTINTU;
+      diffunit=1;
+      /*FIXME: check auf doppelte Def. */
+    }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(v){
+      had_decl=1;
+      if(storage_class==TYPEDEF){
+        error(226,v->identifier);
+      }else{
+        if(nesting>0&&(v->flags&DEFINED)&&!extern_flag&&!isfunc){
+          error(27,vident);
+        }else{
+          if(t&&v->vtyp&&!compatible_types(v->vtyp,t,NU|CONST|VOLATILE)){
+	    if(ISFUNC(t->flags)&&!ISFUNC(v->vtyp->flags))
+	      error(361,vident);
+	    else
+	      error(68,vident);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+          }
+          if((storage_class!=v->storage_class&&!extern_flag)||hard_reg!=v->reg)
+            error(28,v->identifier);
+          if(!isfunc&&!extern_flag) v->flags|=TENTATIVE;
+        }
+#ifdef HAVE_TARGET_ATTRIBUTES
+        {
+          int i;
+          for(i=0;g_attr_name[i];i++){
+            if((v->tattr&(1L<<i))!=(tattr&(1L<<i))) error(228,vident,g_attr_name[i]);
+          }
+          v->tattr=tattr;
+        }
+#endif
+        if(vattr){
+	  if(!v->vattr||!strstr(v->vattr,vattr)){
+	    error(370,v->identifier,vattr,v->vattr?v->vattr:empty);
+	    add_attr(&v->vattr,vattr);
+	  }
+          if(ISFUNC(v->vtyp->flags)) fi_from_attr(v);
+        }
+        if(!isfunc){
+          if(!ISARRAY(t->flags)||!zmeqto(t->size,l2zm(0L))){
+            free(v->vtyp);
+            v->vtyp=t;
+          }
+        }else{
+          om=v->vtyp;
+          if(t->exact->count>0){
+            old=v->vtyp;v->vtyp=t;
+          }
+        }
+      }
+#ifdef HAVE_TARGET_VARHOOK_POST
+      add_attr_haddecl=v;
+      add_var_hook_post(v);
+      add_attr_haddecl=0;
+#endif
+      
+    }else{
+      had_decl=0;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      if(isfunc&&ctok->type!=COMMA&&ctok->type!=SEMIC&&ctok->type!=RPAR&&ctok->type!=ASGN&&nesting>0) nesting--;
+      if(!zumeqto(mask,ul2zum(0UL))){
+	sprintf(vident+strlen(vident),".%lu",zum2ul(mask));
+      }
+      v=add_var(vident,t,storage_class,0);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+      v->reg=hard_reg;
+      if(vattr)
+	add_attr(&v->vattr,vattr);
+      if(ISFUNC(v->vtyp->flags))
+        fi_from_attr(v);
+#ifdef HAVE_TARGET_ATTRIBUTES
+      v->tattr=tattr;
+#endif
+      if(isfunc&&ctok->type!=COMMA&&ctok->type!=SEMIC&&ctok->type!=RPAR&&ctok->type!=ASGN&&nesting>=0) nesting++;
+      if(!v) ierror(0);
+      else{
+        if(!isfunc&&!extern_flag){
+          v->flags|=TENTATIVE;
+          if(nesting>0){
+            v->flags|=DEFINED;
+            v->dfilename=filename;
+            v->dline=line;
+          }
+        }
+      }
+      om=0;
+    }
+    if(isfunc&&inline_flag){
+      v->flags|=INLINEFUNC;
+      if(extern_flag) v->flags|=INLINEEXT;
+    }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(disallow_statics&&v->storage_class==STATIC&&*v->identifier&&!is_const(v->vtyp))
+      error(302,v->identifier);
+    killsp();
+    /*  Inline-Assembler-Code in Funktionsdeklarationen */
+    if(ctok->type==ASGN&&ISFUNC(v->vtyp->flags)&&(header_cnt>0||!(c_flags[7]&USEDFLAG))){
+      np tree;
+      next_token();killsp();
+      if(v->fi){free(v->fi->inline_asm);v->fi->inline_asm=0;}
+      if(!v->fi) v->fi=new_fi();
+      v->fi->inline_asm=get_string();
+      /*STRBACK(v->fi->inline_asm);*/
+      mdef=1;
+    }else{
+      /*if(v->fi){free(v->fi->inline_asm);v->fi->inline_asm=0;}*/
+    }
+    /*  Initialisierung von Variablen bei Deklaration   */
+    if(ctok->type==ASGN){
+
+      next_token();killsp();
+      if(!had_decl&&v->nesting==0&&v->storage_class==EXTERN&&strcmp("main",v->identifier))
+        error(168,v->identifier);
+      if(v->flags&DEFINED){
+        if(nesting==0) error(30,v->identifier);
+      }else{
+        v->flags|=DEFINED;
+        v->dfilename=filename;
+        v->dline=line;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+      }
+      if(v->storage_class==TYPEDEF) error(114,v->identifier);
+      if(extern_flag){
+        if(nesting==0)
+          error(118,v->identifier);
+        else
+          error(207,v->identifier);
+        if(v->storage_class!=EXTERN){ error(77);v->storage_class=EXTERN;}
+      }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+      init_dyn_sz=l2zm(0L);
+      init_dyn_cnt=0;
+      init_const_sz=l2zm(0L);
+      init_const_cnt=0;
+      v->clist=initialization(v->vtyp,v->storage_class==AUTO||v->storage_class==REGISTER,0,0,0,0);
+                /* MISRA Rule 9.2 violation checking and error reporting */
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+      if(v->clist){
+        if(ISARRAY(v->vtyp->flags)&&zmeqto(v->vtyp->size,l2zm(0L))){
+          const_list *p=v->clist;
+          while(p){v->vtyp->size=zmadd(p->idx,l2zm(1L));p=p->next;}
+          if(v->storage_class==AUTO||v->storage_class==REGISTER){
+            local_offset[nesting]=zmadd(local_offset[nesting],szof(v->vtyp));
+            if(zmleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
+          }
+        }
+        if(v->storage_class==AUTO||v->storage_class==REGISTER){
+
+	  init_local_compound(v);
+
+        }else if(c_flags[19]&USEDFLAG){
+          /*  Ohne Optimierung gleich erzeugen; das ist noch  */
+          /*  etwas von der genauen Implementierung der Liste */
+          /*  der Variablen abhaengig.                        */
+          Var *merk=v->next;
+          v->next=0;
+          gen_vars(v);
+          v->next=merk;
+          v->clist=0;
+        }
+      }
+    }else{
+      if((v->flags&DEFINED)&&type_uncomplete(v->vtyp)) error(202,v->identifier);
+      if((v->vtyp->flags&CONST)&&(v->storage_class==AUTO||v->storage_class==REGISTER))
+        error(119,v->identifier);
+    }
+    if(ctok->type==COMMA) {next_token();killsp();mdef=1;} else notdone=0;
+  }
+  freetyp(ts);
+
+  if(ISFUNC(t->flags)&&v->reg)
+    t->next->reg=v->reg;
+
+  if(!mdef&&t&&(t->flags&NQ)==FUNKT&&ctok->type!=SEMIC){
+    /*  Funktionsdefinition*/
+    int i,oldstyle=0;
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_REGPARMS
+    treg_handle reg_handle;
+#endif
+    if(DEBUG&1) printf("Funktionsdefinition! %s %p\n",v->identifier,(void *)v);
+    {
+      int i;
+      for(i=1;i<=MAXR;i++) {regs[i]=regused[i]=regsa[i];regsbuf[i]=0;}
+    }
+    cur_func=v->identifier;
+    cur_funcv=v;
+    if(only_inline==2) only_inline=0;
+    if(nesting<1) enter_block();
+    if(nesting>1) error(32);
+    if(v->flags&DEFINED){
+      if(!inline_flag||!cross_module){
+                                error(33,v->identifier);
+      }else{
+        if(v->fi->first_ic){
+          free_IC(v->fi->first_ic);
+          v->fi->first_ic=0;
+        }
+      }
+    }else{
+      v->flags|=DEFINED;
+      v->dfilename=filename;
+      v->dline=line;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    }
+    if(storage_class!=EXTERN&&storage_class!=STATIC) error(34);
+    if(extern_flag&&!inline_flag) error(120);
+    if(storage_class==EXTERN&&!strcmp(v->identifier,"main")&&(!t->next||t->next->flags!=INT)) error(121);
+    if(!had_decl&&v->nesting==0&&v->storage_class==EXTERN&&strcmp("main",v->identifier))
+      error(168,v->identifier);
+    while(!ecpp&&ctok->type!=LBRA){
+      /*  alter Stil  */
+      type *nt=declaration_specifiers();notdone=1;oldstyle=OLDSTYLE;
+      if(!ts) {error(35);}
+      while(notdone){
+        int found=0;
+        imerk=ident;ident=vident;*vident=0;
+        ts=declarator(clone_typ(nt));
+        ident=imerk;
+        if(!ts) {error(36);}
+        else{
+          for(i=0;i<t->exact->count;i++){
+            if(!strcmp((*t->exact->sl)[i].identifier,vident)){
+              found=1;
+              if((*t->exact->sl)[i].styp){
+                error(69,vident);
+                freetyp((*t->exact->sl)[i].styp);
+              }
+              /*  typ[] in *typ   */
+              if(ISARRAY(ts->flags)) ts->flags=POINTER_TYPE(ts);
+              /*  typ() in *typ() */
+              if(ISFUNC(ts->flags)){
+                type *new=new_typ();
+                new->flags=POINTER_TYPE(ts);
+                new->next=ts;
+                ts=new;
+              }
+              if(!return_sc) return_sc=AUTO;
+              if(return_sc!=AUTO&&return_sc!=REGISTER)
+                {error(122);return_sc=AUTO;}
+              (*t->exact->sl)[i].storage_class=return_sc;
+              (*t->exact->sl)[i].reg=return_reg;
+              if(return_reg) error(219);
+              (*t->exact->sl)[i].styp=ts;
+            }
+          }
+        }
+        if(!found) {error(37,vident);}
+        killsp();
+        if(ctok->type==COMMA) {next_token();killsp();} else notdone=0;
+      }
+      if(nt) freetyp(nt);
+      if(ctok->type==SEMIC){
+        next_token();killsp();
+      }else{
+        error(54);
+        while(ctok->type!=LBRA&&ctok->type!=SEMIC){next_token();killsp();}
+      }
+    }
+    if(!ecpp&&t->exact->count==0){
+      struct_list sl[1];
+      if(DEBUG&1) printf("prototype converted to (void)\n");
+      t->exact->count=1;
+      sl[0].identifier=empty;
+      sl[0].storage_class=AUTO;
+      sl[0].styp=new_typ();
+      sl[0].styp->flags=VOID;
+      sl[0].styp->next=0;
+      sl[0].reg=0;
+      nesting--;
+      add_sl(t->exact,&sl);
+      nesting++;
+    }
+    if(om&&om->exact&&!compare_sd(om->exact,t->exact)) {
+      error(123);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    }
+    nocode=0;currentpri=1;
+    /*        enter_block();*/
+    local_offset[1]=l2zm(0L);
+    return_var=0;
+    if(!v->vtyp) ierror(0);
+#ifdef HAVE_REGPARMS
+    reg_handle=empty_reg_handle;
+#endif
+    if(v->vtyp->next->flags==VOID){
+      return_typ=0;
+    }else{
+      return_typ=v->vtyp->next;
+      if(!ffreturn(return_typ)&&(return_typ->flags&NQ)!=VOID){
+        /*  Parameter fuer die Rueckgabe von Werten, die nicht in einem */
+        /*  Register sind.                                              */
+        type *rt=new_typ();int reg;
+        rt->flags=POINTER_TYPE(return_typ);rt->next=return_typ;
+#ifdef HAVE_REGPARMS
+        reg=reg_parm(&reg_handle,rt,0,v->vtyp);
+        if(!reg){
+	  return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|oldstyle,0);
+	}else{
+	  return_var=add_var(empty,clone_typ(rt),reg<0?(AUTO|PARAMETER|REGPARM|DBLPUSH|oldstyle):(AUTO|PARAMETER|REGPARM|oldstyle),0);
+	  return_var->reg=reg;
+	}
+#else
+        return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|oldstyle,0);
+#endif
+        return_var->flags|=DEFINED;
+        return_var->dfilename=filename;
+        return_var->dline=line;
+        free(rt);
+      }
+    }
+    first_ic=last_ic=0;ic_count=0;max_offset=l2zm(0L);
+    if(!zmleq(local_offset[1],Z0)) max_offset=local_offset[1];
+    for(i=0;i<t->exact->count;i++){
+      /* TODO: missing pointer for struct return */
+#ifdef HAVE_REGPARMS
+      int didrp=0;
+      if((*t->exact->sl)[i].styp){
+        int tr;
+        tr=reg_parm(&reg_handle,(*t->exact->sl)[i].styp,0,t);
+        didrp=1;
+        if(!(*t->exact->sl)[i].reg) (*t->exact->sl)[i].reg=tr;
+      }
+#endif
+      if(!(*t->exact->sl)[i].styp&&*(*t->exact->sl)[i].identifier){
+        type *nt;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+        nt=new_typ();
+        nt->flags=INT;
+        (*t->exact->sl)[i].styp=nt;
+        (*t->exact->sl)[i].storage_class=AUTO;
+        (*t->exact->sl)[i].reg=0;
+        error(124);
+      }
+      if(*(*t->exact->sl)[i].identifier){
+        Var *tmp;int sc,tr;
+        sc=((*t->exact->sl)[i].storage_class|PARAMETER|oldstyle);
+#ifdef HAVE_REGPARMS
+        if(!didrp){
+          if(!t->exact->sl) ierror(0);
+          if(!(*t->exact->sl)[i].styp) ierror(0);
+          tr=reg_parm(&reg_handle,(*t->exact->sl)[i].styp,0,t);
+          if(!(*t->exact->sl)[i].reg) (*t->exact->sl)[i].reg=tr;
+        }
+#endif
+        if((*t->exact->sl)[i].reg>0) sc|=REGPARM;
+        if((*t->exact->sl)[i].reg<0) sc|=(REGPARM|DBLPUSH);
+        tmp=add_var((*t->exact->sl)[i].identifier,clone_typ((*t->exact->sl)[i].styp),sc,0);
+        tmp->reg=(*t->exact->sl)[i].reg;
+        tmp->flags|=DEFINED;
+        tmp->dfilename=filename;
+        tmp->dline=line;
+        if(oldstyle){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+          freetyp((*t->exact->sl)[i].styp);
+          (*t->exact->sl)[i].styp=0; /*  Prototype entfernen */
+        }
+      }
+    }
+    if(oldstyle) t->exact->count=0; /*  Prototype entfernen */
+    /*        local_offset[1]=l2zm(0L);*/
+    return_label=++label;
+    function_calls=0;float_used=0;has_return=0;goto_used=0;vlas=0;
+    did_return_label=0;
+    for(i=1;i<=MAXR;i++) simple_scratch[i]=0;
+    if(v->storage_class==EXTERN&&(v->flags&INLINEFUNC))
+      disallow_statics=1;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+
+    if(c99){
+      /* c99 predefined __func__ */
+      type *ft=new_typ();
+      Var *fnc;
+
+      /* create type */
+      ft->flags=ARRAY;
+      ft->size=l2zm((long)strlen(cur_func)+1);
+      ft->next=new_typ();
+      ft->next->flags=CONST|CHAR;
+
+      /* use string_expression() to create const_list */
+      fnc=add_var("__func__",ft,STATIC,cl_from_string(cur_func,cur_func+strlen(cur_func)));
+      fnc->flags|=DEFINED;
+    }
+
+    /* Generate intermediate code for function */
+    compound_statement();
+
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    cur_funcv=0;
+    disallow_statics=0;
+    if(block_vla[nesting]) clearvl();
+    if((v->vtyp->next->flags&NQ)!=VOID&&!has_return){
+      if(strcmp(v->identifier,"main")) error(173,v->identifier);
+      else error(174,v->identifier);
+    }
+#if 0
+    {int i;
+    for(i=1;i<=MAXR;i++) if(regs[i]!=regsa[i]) {printf("Register %s:\n",regnames[i]);ierror(0);}
+    }
+#endif
+    if(!did_return_label){
+      clear_main_ret();
+      gen_label(return_label);
+    }
+    /* backpatch code for jumps out of vla-scope if necessary */
+    if(vlas)
+      vla_jump_fix();
+    if(cross_module){
+      if(!v->fi) v->fi=new_fi();
+      v->fi->statics=first_var[0];
+    }else if(first_ic&&errors==0){
+      if((c_flags[2]&USEDFLAG)&&ic1){fprintf(ic1,"function %s\n",v->identifier); pric(ic1,first_ic);}
+      vl1=first_var[0];
+      vl2=first_var[1];
+      vl3=merk_varf;
+      optimize(optflags,v);
+      if((c_flags[3]&USEDFLAG)&&ic2){fprintf(ic2,"function %s\n",v->identifier); pric(ic2,first_ic);}
+      if(out&&!only_inline&&!(c_flags[5]&USEDFLAG)){
+        memset(regs_modified,0,RSIZE);
+        gen_code(out,first_ic,v,max_offset);
+        static_stack_check(v);
+        v->flags|=GENERATED;
+#ifdef HAVE_REGS_MODIFIED
+        if(!v->fi) v->fi=new_fi();
+        if(v->fi->flags&ALL_REGS)
+        {
+          int i;
+          for(i=1;i<=MAXR;i++){
+            if(reg_pair(i,&rp)){
+              if(BTST(regs_modified,i)){
+                BSET(regs_modified,rp.r1);
+                BSET(regs_modified,rp.r2);
+              }else{
+                if(BTST(regs_modified,rp.r1)||BTST(regs_modified,rp.r2))
+                  BSET(regs_modified,i);
+              }
+            }
+          }
+          memcpy(v->fi->regs_modified,regs_modified,RSIZE);
+          v->fi->flags|=ALL_REGS;
+        }
+#endif
+      }
+      /*if(DEBUG&8192){fprintf(ic2,"function %s, after gen_code\n",v->identifier); pric(ic2,first_ic);}*/
+      free_IC(first_ic);
+      first_ic=last_ic=0;
+    }
+    if(cross_module){
+      if(!v->fi) v->fi=new_fi();
+      v->fi->first_ic=first_ic;
+      v->fi->last_ic=last_ic;
+      first_ic=last_ic=0;
+    }
+    if(v->fi&&v->fi->first_ic){
+      Var *vp;
+      if(DEBUG&1) printf("leave block %d (inline-version)\n",nesting);
+      if(block_vla[nesting]) clearvl();
+      if(nesting!=1) ierror(0);
+      if(merk_varl) merk_varl->next=first_var[nesting]; else merk_varf=first_var[nesting];
+      if(last_var[nesting]) merk_varl=last_var[nesting];
+      if(merk_sil) merk_sil->next=first_si[nesting]; else merk_sif=first_si[nesting];
+      if(last_si[nesting]) merk_sil=last_si[nesting];
+      if(merk_sdl) merk_sdl->next=first_sd[nesting]; else merk_sdf=first_sd[nesting];
+      if(last_sd[nesting]) merk_sdl=last_sd[nesting];
+      if(merk_ilistl) merk_ilistl->next=first_ilist[nesting]; else merk_ilistf=first_ilist[nesting];
+      if(last_ilist[nesting]) merk_ilistl=last_ilist[nesting];
+      
+      if(merk_varf&&!only_inline&&!cross_module) gen_vars(merk_varf);
+      if(first_llist) free_llist(first_llist);
+      first_llist=0;
+      if(first_clist) free_clist(first_clist);
+      first_clist=0;
+      if(merk_sif) free_si(merk_sif);
+      /*  struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden,     */
+      /*  dass struct-declarations in Prototypen frei werden und dann eine        */
+      /*  spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird.      */
+      /*  Nicht sehr schoen - wenn moeglich noch mal aendern.                     */
+      /*            if(merk_sdf) free_sd(merk_sdf);*/
+      /*  hier noch was ueberlegen    */
+      /*            if(merk_ilistf) free_ilist(merk_ilistf);*/
+      nesting--;
+      v->fi->vars=merk_varf;
+      /*            v->fi->vars=first_var[1];*/
+      /*  keine echten Parameter=>keine negativen Offsets */
+      /*            vp=first_var[1];*/
+      if(!cross_module){
+        vp=merk_varf;
+        while(vp){
+          if(vp->storage_class==AUTO||vp->storage_class==REGISTER){
+            /*if(DEBUG&1024) printf("handling variable %s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);*/
+            if(!zmleq(l2zm(0L),vp->offset)){
+              vp->offset=l2zm(0L);
+              if(DEBUG&1024) printf("converted parameter <%s>(%ld) for inlining\n",vp->identifier,(long)zm2l(vp->offset));
+            }else vp->offset=l2zm(4L);  /*  Dummy, da recalc_offsets?   */
+          }
+          vp=vp->next;
+        }
+      }
+    }else{
+      leave_block();
+    }
+    if(only_inline==2) only_inline=0;
+    cur_func="oops, I forgot it";
+  }else{
+    if(makeint) error(125);
+    if(ctok->type==SEMIC) next_token(); else error(54);
+    if(ISFUNC(t->flags)&&t->exact){
+      struct_declaration *sd=t->exact;int i,f;
+      for(f=0,i=0;i<sd->count;i++)
+        if(!(*sd->sl)[i].styp){error(126);f=1;}
+      if(f){
+        for(i=0;i<sd->count;i++) if((*sd->sl)[i].styp) freetyp((*sd->sl)[i].styp);
+        sd->count=0;
+      }
+    }
+  }
+  if(old) freetyp(old);
+}
+int compatible_types(type *a,type *b,int qual)
+/*  Vergleicht, ob Typ beider Typen gleich ist, const/volatile      */
+/*  werden laut ANSI nicht beruecksichtigt.                         */
+{
+  struct_declaration *sd;
+  int af=a->flags&qual,bf=b->flags&qual;
+  if(af!=bf) return(0);
+  af&=NQ;bf&=NQ;
+  if(ISFUNC(af)){
+    if(a->exact->count&&!compare_sd(a->exact,b->exact)) return(0);
+  }
+  if(ISSTRUCT(af)||ISUNION(af)){
+    if(cross_module&&a->exact->tunit!=b->exact->tunit) return 1;
+    if(a->exact!=b->exact) return(0);
+  }
+  if(ISARRAY(af)){
+    if(!zmeqto(a->size,l2zm(0L))&&!zmeqto(b->size,l2zm(0L))&&!zmeqto(a->size,b->size)) return(0);
+  }
+  if(a->next==0&&b->next!=0) return(0);
+  if(a->next!=0&&b->next==0) return(0);
+  if(a->next==0&&b->next==0) return(1);
+  if(qual!=NQ) qual=(NU|CONST|VOLATILE);
+  return(compatible_types(a->next,b->next,qual));
+}
+int compare_sd(struct_declaration *a,struct_declaration *b)
+/*  Vergleicht, ob zwei struct_declarations identisch sind          */
+/*  Wird nur nur fuer Prototypen benutzt, leere Liste immer gleich. */
+{
+  int i;
+  if(!a->count||!b->count) return(1);
+  if(a->count!=b->count) return(0);
+  for(i=0;i<a->count;i++){
+    if((*a->sl)[i].styp&&(*b->sl)[i].styp&&!compatible_types((*a->sl)[i].styp,(*b->sl)[i].styp,NU)) return(0);
+    if((*a->sl)[i].reg!=(*b->sl)[i].reg) {error(368);return 0;}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+  }
+  return(1);
+}
+void free_clist(const_list *p)
+/*  Gibt clist frei.                                        */
+{
+  const_list *merk;
+  return;
+  while(p){
+    merk=p->next;
+    if(p->other) free_clist(p->other);
+    if(p->tree) free_expression(p->tree);
+    free(p);
+    p=merk;
+  }
+}
+void gen_clist(FILE *,type *,const_list *);
+
+void gen_vars(Var *v)
+/*  Generiert Variablen.                                    */
+{
+  int mode,al,first_pass=1;Var *p;
+  if(errors!=0||(c_flags[5]&USEDFLAG)) return;
+  if(optsize)
+    al=zm2l(maxalign);
+  else
+    al=0;
+  for(;al>=0;al--){
+    for(mode=0;mode<3;mode++){
+      int i,flag;
+      for(p=v;p;p=p->next){
+	if(p->flags&NEEDS) continue;
+        if(optsize&&zm2l(falign(p->vtyp))!=al)
+          continue;
+        if(cross_module&&!(p->flags&REFERENCED)) continue;
+        if(DEBUG&2) printf("gen_var(): %s\n",p->identifier);
+        if(p->storage_class==STATIC||p->storage_class==EXTERN){
+          if(!(p->flags&GENERATED)){
+            if(p->storage_class==EXTERN&&!(p->flags&(USEDASSOURCE|USEDASDEST))&&!(p->flags&(TENTATIVE|DEFINED))) continue;
+	    if(p->storage_class==STATIC&&p->nesting>0&&!(p->flags&(USEDASSOURCE|USEDASDEST))) continue;
+            /*  erst konstante initialisierte Daten */
+            if(mode==0){
+              if(!p->clist) continue;
+              if(!(p->vtyp->flags&(CONST|STRINGCONST))){
+                type *t=p->vtyp;int f=0;
+                do{
+                  if(t->flags&(CONST|STRINGCONST)) break;
+                  if(!ISARRAY(t->flags)){f=1;break;}
+                  t=t->next;
+                }while(1);
+                if(f) continue;
+              }
+            }
+            /*  dann initiolisierte */
+            if(mode==1&&!p->clist) continue;
+            /*  und dann der Rest   */
+         
+	    if(mode==2&&p->clist) continue;
+   
+            if(!(p->flags&(TENTATIVE|DEFINED))){
+              if(!((p->vtyp->flags&NQ)==FUNKT)||!p->fi||!p->fi->inline_asm){
+		if(mask_opt){
+		  if((p->flags&PRINTFLIKE)&&!strstr(p->identifier,".")) needs("vfprintf");
+		  if((p->flags&SCANFLIKE)&&!strstr(p->identifier,".")) needs("vfscanf");
+		}
+                gen_var_head(out,p);
+	      }
+              if(p->storage_class==STATIC&&(!p->fi||!p->fi->inline_asm)) error(127,p->identifier);
+              continue;
+            }else{
+              /*gen_align(out,falign(p->vtyp));*/
+            }
+            if(!((p->vtyp->flags&NQ)==FUNKT)||!p->fi||!p->fi->inline_asm){
+	      if(mask_opt){
+		if((p->flags&PRINTFLIKE)&&!strstr(p->identifier,".")) needs("vfprintf");
+		if((p->flags&SCANFLIKE)&&!strstr(p->identifier,".")) needs("vfscanf");
+	      }
+              gen_var_head(out,p);
+	    }
+            if(!p->clist){
+              if(type_uncomplete(p->vtyp)) error(202,p->identifier);
+              gen_ds(out,szof(p->vtyp),p->vtyp);
+            }else{
+              gen_clist(out,p->vtyp,p->clist);
+            }
+            p->flags|=GENERATED;
+          }else if(p->flags&INLINEEXT){
+            /* a function was declared extern inline and defined;
+               we have to create external linkage */
+            int m=p->flags;
+            /* pretend, it was only declared, but not defined and remove
+               INLINEEXT */
+            p->flags&=~(DEFINED|INLINEEXT);
+            gen_var_head(out,p);
+            p->flags|=DEFINED;
+          }
+        }
+      }
+      first_pass=0;
+    }
+  }
+  if(mask_opt){
+    for(p=v;p;p=p->next)
+      if(p->flags&NEEDS) gen_var_head(out,p);
+  }
+}
+
+/* creates code that dynamically initializes a variable */
+void dynamic_init(Var *v,type *t,const_list *cl,zmax of,int noconst)
+{
+  int f=t->flags;
+  if(ISARRAY(f)){
+    zmax i;
+    for(i=l2zm(0L);!zmleq(t->size,i);i=zmadd(i,l2zm(1L))){
+      if(cl&&zmeqto(cl->idx,i)){
+	dynamic_init(v,t->next,cl->other,of,noconst);
+	cl=cl->next;
+      }else{
+	dynamic_init(v,t->next,0,of,noconst);
+      }
+      of=zmadd(of,szof(t->next));
+    }
+  }else if(ISUNION(f)&&(!cl||!cl->tree)){
+    dynamic_init(v,(*t->exact->sl)[cl?zm2l(cl->idx):0].styp,cl?cl->other:0,of,noconst);
+  }else if(ISSTRUCT(f)&&(!cl||!cl->tree)){
+    zmax al;int fl;type *st;
+    int bfo,i;
+    for(i=0;i<t->exact->count&&cl;i++){
+      if(!cl->other){
+	if(errors==0)
+	  ierror(0);
+	return;
+      }
+      st=(*t->exact->sl)[i].styp;
+      al=(*t->exact->sl)[i].align;
+      if(!(*t->exact->sl)[i].identifier) ierror(0);
+      bfo=(*t->exact->sl)[i].bfoffset;
+      if(!zmeqto(zmmod(of,al),l2zm(0L))){
+        of=zmadd(of,zmsub(al,zmmod(of,al)));
+      }
+      if(bfo>=0){
+	int bfs=(*t->exact->sl)[i].bfsize;
+	static obj dest = {0};
+	  
+	dest.flags=VAR;
+	dest.v=v;
+	dest.val.vmax=of;
+
+	if(bfo==0){
+	  /* first clear entire bitfield */
+	  IC *new=new_IC();
+	  new->code=ASSIGN;
+	  new->z=dest;
+	  new->typf=st->flags;
+	  new->q2.val.vmax=sizetab[st->flags&NQ];
+	  new->q1.flags=KONST;
+	  new->q1.val.vmax=l2zm(0L);
+	  eval_const(&new->q1.val,MAXINT);
+	  insert_const(&new->q1.val,st->flags&NU);
+	  add_IC(new);
+	}
+
+	/* bitfield */
+	if(!zmeqto(cl->idx,l2zm(i))||!cl->other){
+	  /* nothing to do, initialized before */
+	}else if(cl->other->tree){
+	  obj dummy;
+	  gen_IC(cl->other->tree,0,0);
+	  convert(cl->other->tree,st->flags);
+	  insert_bitfield(&dest,&cl->other->tree->o,&cl->other->tree->o,bfs,bfo,st->flags,1);
+	  cl=cl->next;
+	}else{
+	  static obj val = {0};
+	  val.flags=KONST;
+	  val.val=cl->other->val;
+	  insert_bitfield(&dest,&val,&val,bfs,bfo,st->flags,1);
+	  cl=cl->next;
+	}
+	if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
+	  of=zmadd(of,szof(st));
+	}
+      }else{
+	if(zmeqto(l2zm((long)i),cl->idx)){
+	  dynamic_init(v,st,cl->other,of,noconst);
+	  cl=cl->next;
+	}else
+	  dynamic_init(v,st,0,of,noconst);
+        of=zmadd(of,szof(st));
+      }
+    }
+    for(;i<t->exact->count;i++){
+      st=(*t->exact->sl)[i].styp;
+      al=(*t->exact->sl)[i].align;
+      bfo=(*t->exact->sl)[i].bfoffset;
+      if(bfo>0) continue;
+      if(!zmeqto(zmmod(of,al),l2zm(0L))){
+        of=zmadd(of,zmsub(al,zmmod(of,al)));
+      }
+      dynamic_init(v,st,0,of,noconst);
+      of=zmadd(of,szof(st));
+    }
+  }else{
+    IC *new;
+    if(noconst&&(!cl||!cl->tree))
+      return;
+    new=new_IC();
+    new->code=ASSIGN;
+    new->z.flags=VAR;
+    new->z.v=v;
+    new->z.val.vmax=of;
+    new->typf=t->flags;
+    new->q2.val.vmax=szof(t);
+    if(!cl){
+      new->q1.flags=KONST;
+      gval.vmax=l2zm(0L);
+      eval_const(&gval,MAXINT);
+      insert_const(&new->q1.val,t->flags&NU);
+    }else if(cl->tree){
+      gen_IC(cl->tree,0,0);
+      if(ISSCALAR(t->flags))
+	convert(cl->tree,t->flags);
+      new->q1=cl->tree->o;
+    }else{
+      new->q1.flags=KONST;
+      new->q1.val=cl->val;
+    }
+    add_IC(new);
+  }
+}
+
+
+void gen_clist(FILE *f,type *t,const_list *cl)
+/*  Generiert dc fuer const_list.                           */
+{
+  int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL);
+
+#if 0
+  for(i=0;i<(int)szof(t);i++){
+    zuchar c;int s;
+    s=get_clist_byte(t,cl,i,&c);
+    printf("%03d: 0x%02x (%d)\n",i,(int)c,s);
+  }
+#endif
+
+
+  if(ISARRAY(t->flags)){
+    for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;cl=cl->next){
+      if(!cl->other){ierror(0);return;}
+      if(!zmeqto(sz,cl->idx))
+	gen_ds(f,zmmult(zmsub(cl->idx,sz),szof(t->next)),t->next);
+
+      gen_clist(f,t->next,cl->other);
+      sz=zmadd(cl->idx,l2zm(1L));
+    }
+    if(!zmleq(t->size,sz)) gen_ds(f,zmmult(zmsub(t->size,sz),szof(t->next)),t->next);
+    return;
+  }
+  if(ISUNION(t->flags)){
+    int i=zm2l(cl->idx);
+    if(cl&&cl->tree){
+      /* union initialized by another union */
+      gen_ds(f,szof(t),t);
+    }else{
+      gen_clist(f,(*t->exact->sl)[i].styp,cl->other);
+      sz=zmsub(szof(t),szof((*t->exact->sl)[i].styp));
+      if(!zmeqto(sz,l2zm(0L))) gen_ds(f,sz,0);
+    }
+    return;
+  }
+  if(ISSTRUCT(t->flags)){
+    zmax al;int fl;type *st;
+    sz=l2zm(0L);
+    if(cl&&cl->tree){
+      /* initialized by another */
+      gen_ds(f,szof(t),t);
+      sz=zmadd(sz,szof(t));
+    }else{
+      for(i=0;i<t->exact->count&&cl;i++){
+	if(!cl->other){ierror(0);return;}
+	st=(*t->exact->sl)[i].styp;
+	al=(*t->exact->sl)[i].align;
+	if(!(*t->exact->sl)[i].identifier) ierror(0);
+	bfo=(*t->exact->sl)[i].bfoffset;
+	if(!zmeqto(zmmod(sz,al),l2zm(0L))){
+	  gen_ds(f,zmsub(al,zmmod(sz,al)),0);
+	  sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
+	}
+	if(bfo>=0){
+	  /* bitfield */
+	  if((*t->exact->sl)[i].identifier[0]){
+	    bfs=(*t->exact->sl)[i].bfsize;
+	    if(zmeqto(l2zm((long)i),cl->idx)){
+	      eval_const(&cl->other->val,st->flags);
+	      cl=cl->next;
+	    }else{
+	      vumax=ul2zum(0UL);
+	    }
+	    vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL)));
+	    bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags))));
+	  }          
+	  if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
+	    /* last bitfield in integer */
+	    const_list bfcl;
+	    gval.vumax=bfval;
+	    eval_const(&gval,UNSIGNED|MAXINT);
+	    insert_const(&bfcl.val,st->flags&NU);
+	    bfcl.tree=0;
+	    gen_dc(f,st->flags&NU,&bfcl);
+	    bfval=ul2zum(0L);
+	    sz=zmadd(sz,szof(st));
+	  }
+	}else{
+	  if(zmeqto(l2zm((long)i),cl->idx)){
+	    gen_clist(f,st,cl->other);
+	    cl=cl->next;
+	  }else
+	    gen_ds(f,szof(st),st);
+	  sz=zmadd(sz,szof(st));
+	}
+      }
+      for(;i<t->exact->count;i++){
+	st=(*t->exact->sl)[i].styp;
+	al=(*t->exact->sl)[i].align;
+	bfo=(*t->exact->sl)[i].bfoffset;
+	if(bfo>0) continue;
+	if(!zmeqto(zmmod(sz,al),l2zm(0L))){
+	  gen_ds(f,zmsub(al,zmmod(sz,al)),0);
+	  sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
+	}
+	gen_ds(f,szof((*t->exact->sl)[i].styp),(*t->exact->sl)[i].styp);
+	sz=zmadd(sz,szof(st));
+      }
+    }
+    al=falign(t);
+    if(!zmeqto(zmmod(sz,al),l2zm(0L)))
+      gen_ds(f,zmsub(al,zmmod(sz,al)),0);
+    return;
+  }
+
+  if(cl->tree) cl->tree->o.am=0;
+
+  if(zmeqto(cl->idx,l2zm(-1L)))
+    gen_ds(f,szof(t),t);
+  else
+    gen_dc(f,t->flags&NU,cl);
+}
+
+/* finds the correct place in a const list to insert new initializer */
+const_list *insert_cl(const_list *old,zmax idx)
+{
+  const_list *p,*cl=0;
+  if(old&&zmleq(old->idx,idx)){
+    p=old;
+    do{
+      if(zmeqto(p->idx,idx)){
+	/* found existing entry */
+	cl=p;
+	break;
+      }
+      if(!p->next||!zmleq(p->next->idx,idx))
+	break;
+      p=p->next;
+    }while(p);
+  }else
+    p=0;
+  /* we need a new entry */
+  if(!cl){
+    cl=mymalloc(CLS);
+    cl->tree=0;
+    cl->other=0;
+    cl->idx=idx;
+    if(p){
+      cl->next=p->next;
+      p->next=cl;
+    }else
+      cl->next=old;
+  }
+  return cl;
+}
+
+const_list *designator(type *t,const_list *cl)
+{
+  int f=t->flags&NQ;
+  np tree;
+  if(!c99) return 0;
+  if(ISARRAY(f)&&ctok->type==LBRK){
+    next_token();
+    killsp();
+    tree=expression();
+    if(ctok->type!=RBRK)
+      error(62);
+    else
+      {next_token();killsp();}
+    if(!type_expression(tree,0)){
+      /*                    error("incorrect constant expression");*/
+    }else{
+      if(tree->sidefx) error(60);
+      if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){
+	error(19);
+      }else{
+	/* check index for valid range */
+	eval_constn(tree);
+	if(!zmleq(l2zm(0L),vmax)) {error(354);vmax=l2zm(0L);}
+	if(!zmeqto(t->size,l2zm(0L))&&zmleq(t->size,vmax)) {error(354);vmax=l2zm(0L);}
+
+	cl=insert_cl(cl,vmax);
+
+	return cl;
+      }
+    }
+  }else if((ISSTRUCT(f)||ISUNION(f))&&ctok->type==DOT){
+    next_token();
+    killsp();
+    if(ctok->type!=NAME){
+      error(53);
+    }else{
+      int i,n=-1;
+      for(i=0;i<t->exact->count;i++)
+	if(!strcmp((*t->exact->sl)[i].identifier,ctok->name)) n=i;
+      if(n<0){
+	error(23,ctok->name);
+	return 0;
+      }
+      next_token();
+      killsp();
+
+      if(!ISUNION(f)||!cl)
+	cl=insert_cl(cl,l2zm((long)n));
+
+      return cl;
+    }
+  }
+  return 0;
+}
+
+/* declare a builtin function with up to two scalar arguments */
+Var *declare_builtin(char *name,int ztyp,int q1typ,int q1reg,int q2typ,int q2reg,int nosidefx,char *asm)
+{
+  struct_declaration *sd;
+  type *t;
+  Var *v;
+  int args;
+  if(!(v=find_ext_var(name))){
+    sd=mymalloc(sizeof(*sd));
+    if(q1typ==0) args=1;
+    else if(q2typ!=0) args=3;
+    else args=2;
+    sd->sl=mymalloc(args*sizeof(struct_list));
+    memset(sd->sl,0,args*sizeof(struct_list));
+    sd->count=args;
+    if(q1typ){
+      (*sd->sl)[0].styp=new_typ();
+      (*sd->sl)[0].styp->flags=q1typ;
+      (*sd->sl)[0].reg=q1reg;
+    }
+    if(q2typ){
+      (*sd->sl)[1].styp=new_typ();
+      (*sd->sl)[1].styp->flags=q2typ;
+      (*sd->sl)[1].reg=q2reg;
+    }
+    (*sd->sl)[args-1].styp=new_typ();
+    (*sd->sl)[args-1].styp->flags=VOID;
+    (*sd->sl)[args-1].reg=0;
+    t=new_typ();
+    t->flags=FUNKT;
+    t->exact=add_sd(sd,FUNKT);
+    t->next=new_typ();
+    t->next->flags=ztyp;
+    v=add_var(name,t,EXTERN,0);
+    v->flags|=BUILTIN;
+    if(asm||nosidefx){
+      v->fi=new_fi();
+      if(asm) v->fi->inline_asm=asm;
+      if(nosidefx){
+	v->fi->call_cnt=v->fi->use_cnt=v->fi->change_cnt=0;
+	v->fi->flags=ALL_CALLS|ALL_USES|ALL_MODS|ALWAYS_RETURNS|NOSIDEFX;
+      }
+    }
+  }
+  return v;
+}
+
+
+const_list *initialization(type *t,int noconst,int level,int desi,struct_declaration *fstruct,const_list *first)
+/*  Traegt eine Initialisierung in eine const_list ein.         */
+{
+  const_list *cl,**prev;
+  np tree,tree2;
+  int bracket,desi_follows=0;
+  zmax i;
+  token mtok;
+  
+  int f=t->flags&NQ;
+  if(ISFUNC(f)){error(42);return(0);}
+  if(ctok->type==LBRA){next_token();killsp();bracket=1;} else bracket=0;
+  if(ISARRAY(f)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    if(t->dsize){
+      error(358);
+    }else if(zmeqto(t->size,l2zm(0L))&&level!=0){
+      error(359);
+    }else if(ctok->type==T_STRING&&t->next&&(t->next->flags&NQ)==CHAR){
+      killsp();
+      tree=string_expression();
+      first=tree->cl;
+      free_expression(tree);
+    }else{
+      const_list *last=first;
+      if(level==0&&!bracket) error(157);
+      for(i=l2zm(0L);desi_follows||((zmeqto(t->size,l2zm(0L))||!zmleq(t->size,i)||ctok->type==LBRK)&&ctok->type!=RBRA);i=zmadd(i,l2zm(1L))){
+        if(!zmleq(i,0)){
+          if(ctok->type==COMMA){next_token();killsp();} else break;
+          if(ctok->type==RBRA) break;
+        }
+	/* check for first designated initializer */
+	cl=designator(t,first);
+	if(!cl){
+	  /* no designator */
+	  cl=insert_cl(last,i);
+	  cl->other=initialization(t->next,c99?noconst:0,level+1,0,fstruct,cl->other);
+	  if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
+	    first=cl->other;
+	    first->other=0;
+	    break;
+	  }
+	}else{
+	  /* designator: store current object and handle remaining designators */
+	  i=cl->idx;
+	  if(ctok->type!=ASGN){
+	    if(ctok->type!=LBRK&&ctok->type!=DOT)
+	      error(355);
+	  }else{
+	    cl->other=0;
+	    next_token();killsp();
+	  }
+	  cl->other=initialization(t->next,c99?noconst:0,level+1,1,fstruct,cl->other);
+	}
+	if(cl->next==first) first=cl;
+	last=cl;
+        killsp();
+	if(desi&&!bracket)
+	  break;
+	desi_follows=0;
+	if(ctok->type==COMMA){
+	  copy_token(&mtok,ctok);
+	  next_token();killsp();
+	  if(ctok->type==LBRK)
+	    desi_follows=1;
+	  push_token(&mtok);
+	}
+      }
+
+      if(bracket&&zmeqto(i,l2zm(0L))) error(360);
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    }
+  }else if(ISSTRUCT(f)&&(bracket||!noconst||c99)){
+    if(t->exact->count<=0)
+      {error(43);return(0);}
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+    prev=0;
+    if(level==0&&!bracket&&!c99) error(157);
+    for(i=l2zm(0L);desi_follows||(!zmleq(t->exact->count,i)&&ctok->type!=RBRA);i=zmadd(i,l2zm(1L))){
+      if(!desi_follows&&(*t->exact->sl)[zm2l(i)].identifier[0]==0) continue; /* unnamed bitfield */
+      if(!zmleq(i,0)){
+        if(ctok->type==COMMA){next_token();killsp();} else break;
+        if(ctok->type==RBRA) break;
+      }
+      cl=designator(t,first);
+
+      if(!cl){
+	cl=insert_cl(first,l2zm((long)i));
+	cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,0,!fstruct&&!bracket&&zmeqto(i,l2zm(0L))?t->exact:fstruct,cl->other);
+	if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
+	  if(fstruct){
+	    first=cl->other;
+	    first->other=0;
+	  }else{
+	    *cl=*cl->other;
+	    cl->idx=l2zm(-1L);
+	    cl->other=0;
+	    first=cl;
+	  }
+	  break;
+	}
+      }else{
+	i=zm2l(cl->idx);
+	if(ctok->type!=ASGN){
+	  if(ctok->type!=LBRK&&ctok->type!=DOT)
+	    error(355);
+	}else{
+	  next_token();killsp();
+	  cl->other=0;
+	}
+	cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,1,fstruct,cl->other);
+      }
+      if(cl->next==first) first=cl;
+      if(desi&&!bracket)
+	break;
+      desi_follows=0;
+      if(ctok->type==COMMA){
+	copy_token(&mtok,ctok);
+	next_token();killsp();
+	if(ctok->type==DOT)
+	  desi_follows=1;
+	push_token(&mtok);
+      }
+    }
+
+    if(bracket&&zmeqto(i,l2zm(0L))) error(360);
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+  }else if(ISUNION(f)&&(c99||bracket||!noconst)){
+    if(t->exact->count<=0)
+      {error(44);return(0);}
+
+    if(level==0&&!bracket&&!c99) error(157);
+    desi_follows=1;
+    while(desi_follows){
+      cl=designator(t,first);
+
+      if(!cl){
+	cl=insert_cl(first,l2zm((long)0));
+	cl->other=initialization((*t->exact->sl)[0].styp,c99?noconst:0,level+1,0,!fstruct&&!bracket?t->exact:fstruct,cl->other);
+	if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
+	  if(fstruct){
+	    first=cl->other;
+	    first->other=0;
+	  }else{
+	    *cl=*cl->other;
+	    cl->other=0;
+	    cl->idx=l2zm(-1L);
+	    first=cl;
+	  }
+	  break;
+	}
+      }else{
+	i=zm2l(cl->idx);
+	if(ctok->type!=ASGN){
+	  if(ctok->type!=LBRK&&ctok->type!=DOT)
+	    error(355);
+	}else{
+	  next_token();killsp();
+	  cl->other=0;
+	}
+	cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,1,fstruct,cl->other);
+      }
+      first=cl;
+      if(desi&&!bracket)
+	break;
+      desi_follows=0;
+      if(ctok->type==COMMA){
+	copy_token(&mtok,ctok);
+	next_token();killsp();
+	if(ctok->type==DOT)
+	  desi_follows=1;
+	else
+	  push_token(&mtok);
+      }
+    }
+  }else{
+    int oldconst=const_expr;
+    tree2=tree=assignment_expression();
+
+    if(!tree){error(45);return(0);}
+    if(!noconst) const_expr=1;
+    if(!type_expression(tree,t)){free_expression(tree); const_expr=oldconst;return 0;}
+    const_expr=oldconst;
+
+    tree=makepointer(tree);
+
+    /* check for complete assignment in dynamic initialization */
+    if(noconst&&(ISSTRUCT(tree->ntyp->flags)||ISUNION(tree->ntyp->flags))&&fstruct==tree->ntyp->exact){
+      first=mymalloc(CLS);
+      first->tree=tree;
+      first->next=first->other=0;
+      first->idx=l2zm(-2L);
+      return first;
+    }
+
+    if(!test_assignment(t,tree)){free_expression(tree); return 0;}
+    if(!noconst){
+      /*  nur Konstanten erlaubt (bei Arrays/Strukturen etc. oder static) */
+      if(tree->flags!=CEXPR){
+        /*while(tree->flags==CAST) tree=tree->left;*/
+        if(!tree->sidefx/*tree->flags==ADDRESS||tree->flags==ADDRESSS||tree->flags==ADDRESSA*/){
+          const_expr=1;
+          gen_IC(tree,0,0);
+          const_expr=oldconst;
+          if(!(tree->o.flags&VARADR)){
+            /*  hier fehlen noch viele Pruefungen   */
+            free_expression(tree);error(46);
+            return(0);
+          }
+          tree->o.v->flags|=USEDASADR;
+          first=mymalloc(CLS);
+          first->next=first->other=0;
+          first->tree=tree;
+	  first->idx=l2zm(0L);
+          killsp();
+        }else{
+          free_expression(tree);error(46);
+          return(0);
+        }
+      }else{
+        first=mymalloc(CLS);
+	first->idx=l2zm(0L);
+        first->next=first->other=0;
+        first->tree=0;
+        eval_constn(tree);
+        tree->ntyp->flags=t->flags;
+        insert_constn(tree);
+        first->val=tree->val;
+        free_expression(tree2);
+        killsp();
+      }
+    }else{
+      /*  auch anderes erlaubt    */
+      first=mymalloc(CLS);
+      first->next=first->other=0;
+      first->tree=tree;
+      killsp();
+      if(!tree->sidefx){
+	if(tree->flags==CEXPR){
+	  eval_constn(tree);
+	  tree->ntyp->flags=t->flags;
+	  insert_constn(tree);
+	  first->val=tree->val;
+	  first->tree=0;
+	  first->idx=l2zm(0L);
+	  init_const_sz=zmadd(init_const_sz,szof(tree->ntyp));
+	  init_const_cnt++;
+	  free_expression(tree2);
+	}else{
+	  first->idx=l2zm(-1L);
+	  init_dyn_sz=zmadd(init_dyn_sz,szof(tree->ntyp));
+	  init_dyn_cnt++;
+	}
+      }else{
+	first->idx=l2zm(-1L);
+	init_dyn_sz=zmadd(init_dyn_sz,szof(tree->ntyp));
+	init_dyn_cnt++;
+      }
+    }
+  }
+  if(bracket){
+    if(ctok->type==COMMA){next_token();killsp();}
+    if(ctok->type==RBRA){next_token();killsp();} else error(128);
+  }
+  return(first);
+}
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
diff --git a/doc/errors.texi b/doc/errors.texi
new file mode 100644
index 0000000..798b39b
--- /dev/null
+++ b/doc/errors.texi
@@ -0,0 +1,1399 @@
+  @item "declaration expected" (Fatal, Error, ANSI-violation)
+
+        Something is pretty wrong with the source.
+
+
+  @item "only one input file allowed" (Fatal)
+
+        vbcc accepts only a single filename to compile. You can use a
+        frontend to compile multiple files or perhaps you mistyped an
+        option.
+
+
+  @item "Flag <%s> specified more than once" ()
+
+        You specified a command line option that should be specified only
+        once more than once. Maybe you have this option in your config-file
+        and used it in the command line, too?
+        The first occurrence will override the latter ones.
+
+
+  @item "Flag <%s> needs string" (Fatal)
+
+        This option hast to be specified with a string parameter, e.g.
+        -flag=foobar
+
+
+  @item "Flag <%s> needs value" (Fatal)
+
+        This option hast to be specified with an integer parameter, e.g.
+        -flag=1234
+
+
+  @item "Unknown Flag <%s>" (Fatal)
+
+        This option is not recognized by vbcc. Perhaps you mistyped it, used
+        the wrong case or specified an option of the frontend to vbcc?
+
+
+  @item "No input file" (Fatal)
+
+        You did not specify an input file. Your source file should not start
+        with a '-' and if you use a frontend make sure it has the proper
+        suffix.
+
+
+  @item "Could not open <%s> for input" (Fatal)
+
+        A file could not be opened.
+
+
+  @item "need a struct or union to get a member" (Error, ANSI-violation)
+
+        The source contains something like a.b where a is not a structure
+        or union.
+
+
+  @item "too many (%d) nested blocks" (Fatal, Error)
+
+        vbcc only allows a maximum number of nested blocks
+        (compund-statements). You can increase this number by changing
+        the line #define MAXN <something> in vbc.h and recompiling vbcc.
+
+
+ @item "left block 0" (Error, ANSI-violation)
+
+        This error should not occur.
+
+
+ @item "incomplete struct <%s>" (Error, ANSI-violation)
+
+        You tried to get a member of an incomplete structure/union.
+        You defined struct x y; somewhere without defining struct x@{...@}.
+
+
+ @item "out of memory" (Fatal, Error)
+
+        Guess what.
+
+
+ @item "redeclaration of struct <%s>" (Error, ANSI-violation)
+
+        You may not redeclare a struct/union in the same block.
+
+
+ @item "incomplete type (%s) in struct" (Error, ANSI-violation)
+
+        Every member in a struct/union declaration must be complete.
+        Perhaps you only wanted a pointer to that type and forgot the '*'?
+
+
+ @item "function (%s) in struct/union" (Error, ANSI-violation)
+
+        Functions cannot be members of structs/unions.
+
+
+ @item "redeclaration of struct/union member <%s>" (Error, ANSI-violation)
+
+        Two members of a struct/union have the same name.
+
+
+ @item "redeclaration of <%s>" (Error, ANSI-violation)
+
+        You used a name already in use in an enumeration.
+
+
+ @item "invalid constant expression" (Error, ANSI-violation)
+
+        ??? Nowhere to find...
+
+
+ @item "array dimension must be constant integer" (Error, ANSI-violation)
+
+        The dimensions of an array must be constants (real constants,
+        const int x=100; int y[x]; is not allowed) and integers
+        (int y[100.0]; is not allowed either).
+
+
+ @item "no declarator and no identifier in prototype" (Error, ANSI-violation)
+
+
+
+ @item "invalid storage-class in prototype" (Error, ANSI-violation)
+
+        Function parameters may only be auto or register.
+
+
+ @item "void not the only function argument" (Error, ANSI-violation)
+
+        You tried to declare a function that has an argument of type void
+        as well as other arguments.
+
+
+ @item "<%s> no member of struct/union" (Error, ANSI-violation)
+
+        The struct/union does not contain a member called like that.
+
+
+ @item "increment/decrement is only allowed for aithmetic and pointer types" (Error, ANSI-violation)
+
+
+
+ @item "functions may not return arrays or functions" (Error, ANSI-violation)
+
+
+
+ @item "only pointers to functions can be called" (Error, ANSI-violation)
+
+        You tried to call something that did not decay into a pointer to
+        a function.
+
+
+ @item "redefinition of var <%s>" (Error, ANSI-violation)
+
+
+
+ @item "redeclaration of var <%s> with new storage-class" (Error, ANSI-violation)
+
+
+
+ @item "first operand of conditional-expression must be arithmetic or pointer type" (Error, ANSI-violation)
+
+
+
+ @item "multiple definitions of var <%s>" (Error, ANSI-violation)
+
+        There have been multiple definitions of a global variable with
+        initialization.
+
+
+ @item "operands of : do not match" (Error, ANSI-violation)
+
+        In an expression of the form a ? b : c
+        - a and b must have the same type or
+        - a and b both must have arithmetic types or
+        - one of them must be a pointer and the other must be void * or 0
+
+
+ @item "function definition in inner block" (Error, ANSI-violation)
+
+        C does not allow nested functions.
+
+
+ @item "redefinition of function <%s>" (Error, ANSI-violation)
+
+        Defining two functions with the same name in one translation-unit
+        is no good idea.
+
+
+ @item "invalid storage-class for function" (Error, ANSI-violation)
+
+        Functions must not have storage-classes register or auto.
+
+
+ @item "declaration-specifiers expected" (Error, ANSI-violation)
+
+
+
+ @item "declarator expected" (Error, ANSI-violation)
+
+
+
+ @item "<%s> is no parameter" (Error, ANSI-violation)
+
+        In an old-style function definition you tried to declare a name as
+        parameter which was not in the identifier-list.
+
+
+ @item "assignment of different structs/unions" (Error, ANSI-violation)
+
+
+
+ @item "invalid types for assignment" (Error, ANSI-violation)
+
+        In an assignment-context (this includes passing arguments to
+        prototyped functions) the source and target must be one of the
+        following types:
+
+        - both are arithmetic types
+        - both are the same struct/union
+        - one of them is a pointer to void and the other one is any pointer
+        - the target is any pointer and the source is an integral
+          constant-expression with the value 0
+        - both are pointer to the same type (here the target may have
+          additional const/volatile qualifiers - not recursively, however)
+
+        Any other combinations should be illegal.
+
+
+ @item "only 0 can be compared against pointer" (Warning, ANSI-violation)
+
+        You may not compare a pointer against any other constant but a
+        0 (null pointer).
+
+
+ @item "pointers do not point to the same type" (Warning, ANSI-violation)
+
+        You tried to compare or assign pointers that point to different
+        types. E.g. the types they point to may have different attributes.
+
+
+ @item "function initialized" (Error, Fatal, ANSI-violation)
+
+        There was a '=' after a function declaration.
+
+
+ @item "initialization of incomplete struct" (Error, Fatal, ANSI-violation)
+
+        A structure is incomplete if the only its name, but not the
+        content is known. You cannot do much with such structures.
+
+
+ @item "initialization of incomplete union" (Error, Fatal, ANSI-violation)
+
+        A union is incomplete if the only its name, but not the
+        content is known. You cannot do much with such unions.
+
+
+ @item "empty initialization" (Error, ANSI-violation)
+
+        There was no valid expression after the '=' in a variable definition.
+
+
+ @item "initializer not a constant" (Error, ANSI-violation)
+
+        Static variables and compound types may only be initialized with
+        constants.
+        Variables with const qualifier are no valid constant-expressions
+        here.
+
+        Addresses of static variables are ok, but casting them may turn
+        them into non-constant-expressions.
+
+
+ @item "double type-specifier" (Warning, ANSI-violation)
+
+
+
+ @item "illegal type-specifier" (Warning, ANSI-violation)
+
+
+
+ @item "multiple storage-classes" (Warning, ANSI-violation)
+
+
+
+ @item "storage-class specifier should be first" (Warning, ANSI-violation)
+
+
+
+ @item "bitfields must be ints" (Warning, ANSI-violation)
+
+
+
+ @item "bitfield width must be constant integer" (Warning, ANSI-violation)
+
+
+
+ @item "struct/union member needs identifier" (Warning, ANSI-violation)
+
+
+
+ @item "; expected" (Warning, ANSI-violation)
+
+        Probably you forgot a ';' or there is a syntactic error in an
+        expression.
+
+
+ @item "struct/union has no members" (Warning, ANSI-violation)
+
+        You defined an empty struct or union.
+
+
+ @item "@} expected" (Warning, ANSI-violation)
+
+
+
+ @item ", expected" (Warning, ANSI-violation)
+
+
+
+ @item "invalid unsigned" (Warning, ANSI-violation)
+
+
+
+ @item ") expected" (Warning, ANSI-violation)
+
+
+
+ @item "array dimension has sidefx (will be ignored)" (Warning, ANSI-violation)
+
+
+
+ @item "array of size 0 (set to 1)" (Warning, ANSI-violation)
+
+        ANSI C does not allow arrays or any objects to have a size of 0.
+
+
+ @item "] expected" (Warning, ANSI-violation)
+
+
+
+ @item "mixed identifier- and parameter-type-list" (Warning, ANSI-violation)
+
+
+
+ @item "var <%s> was never assigned a value" (Warning)
+
+
+
+ @item "var <%s> was never used" (Warning)
+
+
+
+ @item "invalid storage-class" (Warning, ANSI-violation)
+
+
+
+ @item "type defaults to int" (Warning)
+
+
+
+ @item "redeclaration of var <%s> with new type" (Warning, ANSI-violation)
+
+
+
+ @item "redeclaration of parameter <%s>" (Warning, ANSI-violation)
+
+
+
+ @item ": expected" (Warning, ANSI-violation)
+
+
+
+ @item "illegal escape-sequence in string" (Warning, ANSI-violation)
+
+
+
+ @item "character constant contains multiple chars" (Warning)
+
+
+
+ @item "could not evaluate sizeof-expression" (Error, ANSI-violation)
+
+
+
+ @item "" expected (unterminated string)" (Error, ANSI-violation)
+
+
+
+ @item "something wrong with numeric constant" (Error, ANSI-violation)
+
+
+
+ @item "identifier expected" (Fatal, Error, ANSI-violation)
+
+
+
+ @item "definition does not match previous declaration" (Warning, ANSI-violation)
+
+
+
+ @item "integer added to illegal pointer" (Warning, ANSI-violation)
+
+
+
+ @item "offset equals size of object" (Warning)
+
+
+
+ @item "offset out of object" (Warning, ANSI-violation)
+
+
+
+ @item "only 0 should be cast to pointer" (Warning)
+
+
+
+ @item "unknown identifier <%s>" (Error, ANSI-violation)
+
+
+
+ @item "too few function arguments" (Warning, ANSI-violation)
+
+
+
+ @item "division by zero (result set to 0)" (Warning, ANSI-violation)
+
+
+
+ @item "assignment of different pointers" (Warning, ANSI-violation)
+
+
+
+ @item "lvalue required for assignment" (Error, ANSI-violation)
+
+
+
+ @item "assignment to constant type" (Error, ANSI-violation)
+
+
+
+ @item "assignment to incomplete type" (Error, ANSI-violation)
+
+
+
+ @item "operands for || and && have to be arithmetic or pointer" (Error, ANSI-violation)
+
+
+
+ @item "bitwise operations need integer operands" (Error, ANSI-violation)
+
+
+
+ @item "assignment discards const" (Warning, ANSI-violation)
+
+        You assigned something like (const type *) to (type *).
+
+
+ @item "relational expression needs arithmetic or pointer type" (Error, ANSI-violation)
+
+
+
+ @item "both operands of comparison must be pointers" (Error, ANSI-violation)
+
+        You wrote an expression like a == b where one operand was a pointer
+        while the other was not. Perhaps a function is not declared correctly
+        or you used NULL instead of 0?
+
+
+ @item "operand needs arithmetic type" (Error, ANSI-violation)
+
+
+
+ @item "pointer arithmetic with void * is not possible" (Error, ANSI-violation)
+
+        Adding/subtracting from a pointer to void is not possible.
+
+
+ @item "pointers can only be subtracted" (Error, ANSI-violation)
+
+        You cannot add, multiply etc. two pointers.
+
+
+ @item "invalid types for operation <%s>" (Error, ANSI-violation)
+
+
+
+ @item "invalid operand type" (Error, ANSI-violation)
+
+
+
+ @item "integer-pointer is not allowed" (Error, ANSI-violation)
+
+        You may not subtract a pointer from an integer.
+        Adding an integer or subtracting it from a pointer is ok.
+
+
+@item "assignment discards volatile" (Warning, ANSI-violation)
+
+        You assigned something like (volatile type *) to (type *).
+
+
+@item "<<, >> and % need integer operands" (Error, ANSI-violation)
+
+
+
+@item "casting from void is not allowed" (Error, ANSI-violation)
+
+        Casting something of type void to anything makes no sense.
+
+
+@item "integer too large to fit into pointer" (Error, ANSI-violation)
+
+        You tried to assign an integer to a pointer that is too small to
+        hold the integer.
+        Note that assignment of pointers<->integers is never portable.
+
+
+@item "only integers can be cast to pointers" (Error, ANSI-violation)
+
+
+
+@item "invalid cast" (Error, ANSI-violation)
+
+
+
+@item "pointer too large to fit into integer" (Error, ANSI-violation)
+
+        You tried to assign a pointer to an integer that is too small to
+        hold the pointer.
+        Note that assignment of pointers<->integers is never portable.
+
+
+@item "unary operator needs arithmetic type" (Error, ANSI-violation)
+
+
+
+@item "negation type must be arithmetic or pointer" (Error, ANSI-violation)
+
+
+
+@item "complement operator needs integer type" (Error, ANSI-violation)
+
+
+
+@item "pointer assignment with different qualifiers" (Warning, ANSI-violation)
+
+        You tried to assign a pointer to a pointer that points to a type
+        with different qualifiers (e.g. signed<->unsigned).
+
+
+@item "dereferenced object is no pointer" (Error, ANSI-violation)
+
+
+
+@item "dereferenced object is incomplete" (Error, ANSI-violation)
+
+        You tried to dereference a pointer to an incomplete object.
+        Either you had a pointer to an array of unknown size or a pointer
+        to a struct or union that was not (yet) defined.
+
+
+@item "only 0 should be assigned to pointer" (Warning, ANSI-violation)
+
+        You may not assign constants other than a null pointer to any
+        pointer.
+
+
+@item "typedef <%s> is initialized" (Warning, ANSI-violation)
+
+
+
+@item "lvalue required to take address" (Error, ANSI-violation)
+
+        You can only get the address of an object, but not of expressions
+        etc.
+
+
+@item "unknown var <%s>" (Error, ANSI-violation)
+
+
+
+@item "address of register variables not available" (Error, ANSI-violation)
+
+        If a variable is declared as 'register' its address may not be
+        taken (no matter if the variable actually gets assigned to a
+        register).
+
+
+@item "var <%s> initialized after 'extern'" (Warning)
+
+
+
+@item "const var <%s> not initialized" (Warning)
+
+        A constant variable was not initialized in its definition.
+        As there is no other legal way to assign a value to a constant
+        variable this is probable an error.
+
+
+@item "function definition after 'extern'" (Warning, ANSI-violation)
+
+
+
+@item "return type of main is not int" (Warning, ANSI-violation)
+
+        main() should be defined as
+
+            int main(int argc, char **argv)
+
+        Especially the return type of main must be 'int' - 'void' is
+        not allowed by ANSI C.
+
+
+@item "invalid storage-class for function parameter" (Warning, ANSI-violation)
+
+        Function parameters may only have 'auto' or 'register' as
+        storage-class. 'static' or 'extern' are not allowed.
+
+
+@item "formal parameters conflict with parameter-type-list" (Warning, ANSI-violation)
+
+
+
+@item "parameter type defaults to int" (Warning)
+
+        A function definition contains no explicit type specifier.
+        'int' will be assumed.
+
+
+@item "no declaration-specifier, used int" (Warning, ANSI-violation)
+
+        A variable was declared/defined without a type specified.
+        This is not allowed in ANSI C (apart from functions).
+
+
+@item "no declarator in prototype" (Warning, ANSI-violation)
+
+
+
+@item "static var <%s> never defined" (Warning)
+
+
+
+@item "@} expected" (Warning)
+
+
+
+@item "left operand of comma operator has no side-effects" (Warning)
+
+        In an expression of the form a,b a has no side-effects and is
+        therefore superfluous.
+
+
+@item "label empty" (Error, ANSI-violation)
+
+        There was a ':' without an identifier before it.
+
+
+@item "redefinition of label <%s>" (Error, ANSI-violation)
+
+        The label was defined more than once in the same function.
+        Consider that labels can not be hidden in inner blocks.
+
+
+@item "case without switch" (Error, ANSI-violation)
+
+        A case label was found outside of any switch-statements.
+
+
+@item "case-expression must be constant" (Error, ANSI-violation)
+
+        The expression after 'case' must be constant.
+
+
+@item "case-expression must be integer" (Error, ANSI-violation)
+
+        The expression after 'case' must be integer.
+
+
+@item "empty if-expression" (Error, ANSI-violation)
+
+        There was no valid expression after 'if'.
+
+
+@item "if-expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+        The expression after 'if' must be arithmetic (i.e. an integer
+        or floating point type) or a pointer.
+
+
+@item "empty switch-expression" (Error, ANSI-violation)
+
+        There was no valid expression after 'switch'.
+
+
+@item "switch-expression must be integer" (Error, ANSI-violation)
+
+        The expression after 'switch' must be an integer.
+
+
+@item "multiple default labels" (Error, ANSI-violation)
+
+        There was more than one default label in a switch-statement.
+
+
+@item "while-expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+        The expression after the 'while' must be arithmetic (i.e. an integer
+        or floating point type) or a pointer.
+
+
+@item "empty while-expression" (Error, ANSI-violation)
+
+        There was no valid expression after 'while'.
+
+
+@item "for-expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+        The expression inside the 'for' must be arithmetic (i.e. an integer
+        or floating point type) or a pointer.
+
+
+@item "do-while--expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+        The expression after the 'while' must be arithmetic (i.e. an integer
+        or floating point type) or a pointer.
+
+
+@item "goto without label" (Error, ANSI-violation)
+
+        'goto' must be followed by a label.
+
+
+@item "continue not within loop" (Error, ANSI-violation)
+
+        'continue' is only allowed inside of loops.
+        Perhaps there are unbalanced '@{' '@}'.
+
+
+@item "break not in matching construct" (Error, ANSI-violation)
+
+        'break' is only allowed inside of loops or switch-statements.
+        Perhaps there are unbalanced '@{' '@}'.
+
+
+@item "label <%s> was never defined" (Error, ANSI-violation)
+
+        There is a goto to a label that was never defined.
+
+
+@item "label <%s> was never used" (Warning)
+
+        You defined a label, but there is no goto that jumps to it.
+
+
+@item "register %s not ok" (Warning)
+
+        There was an internal error (i.e. a bug in the compiler)!
+        Please report the error to vb@@compilers.de. Thanks!
+
+
+@item "default not in switch" (Warning, ANSI-violation)
+
+        A default label that is not in any switch-statement was found.
+        Perhaps there are unbalanced '@{' '@}'.
+
+
+@item "( expected" (Warning, ANSI-violation)
+
+
+
+@item "loop eliminated" (Warning)
+
+        There was a loop that will never be executed (e.g. while(0)...)
+        and therefore the entire loop was eliminated.
+        I do not know any reason for such loops, so there is probably an
+        error.
+
+
+@item "statement has no effect" (Warning)
+
+        There is a statement that does not cause any side-effects (e.g.
+        assignments, function calls etc.) and is therefore superfluous.
+        E.g. you might have typed a==b; instead of a=b;
+
+
+@item "'while' expected" (Warning, ANSI-violation)
+
+        The 'while' in a do-while loop is missing.
+
+
+@item "function should not return a value" (Warning)
+
+        You specified an argument to return although the function is
+        void. Declare the function as non-void.
+
+
+@item "function should return a value" (Warning)
+
+        You did not specify an argument to return although the function
+        is not void. Declare the function as void or specify a return
+        value.
+
+
+@item "@{ expected" (Warning, ANSI-violation)
+
+
+
+@item "internal error %d in line %d of file %s !!" (Fatal, Error)
+
+        There was an internal error (i.e. a bug in the compiler)!
+        Please report the error to vb@@compilers.de. Thanks!
+
+
+@item "there is no message number %d" (Fatal)
+
+        You tried to activate or suppress a message that does not exist.
+
+
+@item "message number %d cannot be suppressed" (Fatal)
+
+        You cannot suppress a message that displays a real error,
+        ANSI-violation or another real problem.
+        Only 'harmless' warnings can be suppressed.
+
+
+@item "implicit declaration of function <%s>" (Warning)
+
+        A function was called before it was declared and therefore
+        implicitly declared as
+
+            int function();
+
+        This should be avoided in new programs.
+
+
+@item "function call without prototype in scope" (Warning)
+
+        When writing new programs it is probably sensible to use prototypes
+        for every function. If a function is called without a prototype in
+        scope this may cause incorrect type conversions and is usually an
+        error.
+
+
+@item "#pragma used" (Warning)
+
+        Usage of #pragma should be avoided in portable programs.
+
+
+@item "assignment in comparison context" (Warning)
+
+        The expression in an if-, for-, while- or do-while-statement
+        is an assignment, e.g.
+
+            if(i=0)...
+
+        This could an error, if you wanted if(i==0).
+        If you turned on this warning and want it to shut up for a
+        certain expression you can cast it to its type, e.g.
+
+            if((int)(i=0))...
+
+        Note that only assignments with '=' will be warned, not '+=' etc.
+
+
+@item "comparison redundant because operand is unsigned" (Warning)
+
+        A comparison with an unsigned variable is redundant, because
+        the result will always be constant, e.g.
+
+            unsigned int i;
+            if(i<0)...
+
+        This usually is a programming error and can be avoided in all cases.
+
+
+@item "cast to narrow type may cause loss of precision" (Warning)
+
+        A variable is cast to a type smaller than its original type, so
+        that some information may get lost.
+        However this warning will be displayed in lots of cases where
+        no problem can arise, e.g. (short)(a==b).
+
+
+@item "pointer cast may cause alignment problems" (Warning)
+
+        A pointer is cast to a pointer to a type with stricter alignment
+        requirements, i.e. the new pointer might be invalid if you do not
+        know what you are doing.
+        Those casts should be avoidable in all 'usual' cases.
+
+
+@item "no declaration of global variable <%s> before definition" (Warning)
+
+        It is usually good to declare all global variables (including
+        functions) in header files.
+
+
+@item "'extern' inside function" (Warning)
+
+        Declaration of external variables in inner blocks is usually
+        not a good idea.
+
+
+@item "dead assignment to <%s> eliminated" (Warning)
+
+        A variable is assigned a value that is never used or gets
+        overwritten before it is used. If this occurs in real code then
+        there is either an error or an unnecessary assignment.
+
+        This is detected only in optimizing compilation.
+
+
+@item "var <%s> is used before defined" (Warning)
+
+        The variable is used before it was assigned a value and therefore
+        is undefined. It cannot be detected if the code where it is used
+        can be reached, but if it is reached it will cause undefined
+        behaviour. So it is most probably an error either way (see 170).
+
+        However not all uninitialized usages can be found.
+
+        Also note that the compiler may choose convenient values for
+        uninitialized variables. Example:
+
+            int f(int a)
+            @{
+                int x;
+                if(a) x=0;
+                return(x);
+            @}
+
+        Here the optimizer may choose that x==0 if it is uninitialized and
+        then only generate a return(0);
+        It can also happen that you get different values if you read an
+        uninitialized variable twice although it was not assigned a value
+        in between.
+
+        This is only detected in optimizing compilation.
+
+
+@item "would need more than %ld optimizer passes for best results" (Warning)
+
+        The optimizer would probably be able to do some further
+        optimizations if you increased the number of allowed passes
+        with the -optpasses=n option.
+
+
+@item "function <%s> has no return statement" (Warning)
+
+        A non-void function has no return statement. Either this function
+        never returns (then better declare it as void) or it reaches
+        end of control which would be an error.
+
+        As main() cannot be declared as void you will not be warned if
+        main has no return statement. If you want a warning for main, too,
+        you can turn on warning 174.
+
+
+@item "function <main> has no return statement" (Warning)
+
+        The same like 173 for main, so you can turn it on/off separately.
+
+
+@item "this code is weird" (Warning)
+
+        The code has a very strange control flow. There is probably a
+        jump inside a loop or something similar and the optimizer will
+        not make any loop optimization and perhaps worse register
+        allocation on this construct.
+        There must be goto statements in the source.
+
+        This warning is only detected in optimizing compilation.
+
+
+@item "size of incomplete type not available" (Warning, ANSI-violation)
+
+        An incomplete type must not be the argument for sizeof.
+
+
+@item "line too long" (FATAL, Error, ANSI-violation, Preprocessor)
+
+
+
+@item "identifier must begin with a letter or underscore" (FATAL, Error, ANSI-violation, Preprocessor)
+
+
+
+@item "cannot redefine macro" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "missing ) after argumentlist" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "identifier expected" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "illegal character in identifier" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "missing operand before/after ##" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "no macro-argument after #-operator" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "macro redefinition not allowed" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "unexpected end of file (unterminated comment)" (FATAL, Error, Preprocessor)
+
+
+
+@item "too many nested includes" (FATAL, Error, Preprocessor)
+
+
+
+@item "#else without #if/#ifdef/#ifndef" (FATAL, Error, ANSI-violation, Preprocessor)
+
+
+
+@item "#else after #else" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "#endif without #if" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "cannot include file" (FATAL, Error, Preprocessor)
+
+
+
+@item "expected \" or < in #include-directive" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "unknown #-directive" (Warning, Preprocessor)
+
+
+
+@item "wrong number of macro arguments" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "macro argument expected" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "out of memory" (FATAL, Error, Preprocessor)
+
+
+
+@item "macro redefinition" (Warning, Preprocessor)
+
+
+
+@item "/* in comment" (Warning, Preprocessor)
+
+
+
+@item "cannot undefine macro" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "characters after #-directive ignored" (Warning, Preprocessor)
+
+
+
+@item "duplicate case labels" (Warning, ANSI-violation)
+
+        Each case-label in a switch-statement must have a distinct constant
+        value attached (after converting it to the type of the
+        switch-expression).
+
+
+@item "var <%s> is incomplete" (Warning, ANSI-violation)
+
+        An incomplete var was defined. probably you wrote something like:
+
+            int a[];
+
+
+@item "long float is no longer valid" (Warning, ANSI-violation)
+
+        'long float' was a synonym for double in K&R C, but this is no longer
+        allowed in ANSI C.
+
+
+@item "long double is not really supported by vbcc" (Warning)
+
+        vbcc does not know about long double yet and therefore will use it
+        simply as a synonym for double. This should not break any legal code,
+        but you will not get error messages if you e.g. assign a pointer to
+        double to a pointer to long double.
+
+
+@item "empty struct-declarations are not yet handled correct" (Warning)
+
+        obsolete
+
+
+@item "identifier too long (only %d characters are significant)" (Warning)
+
+
+
+@item "illegal initialization of var <%s>" (Warning, ANSI-violation)
+
+        Perhaps you tried to initialize a variable with external linkage
+        in an inner block.
+
+
+@item "suspicious loop" (Warning)
+
+        vbcc thinks a loop-condition looks suspicious. A possible example
+        could be for(i=0;i!=7;i+=2)
+
+
+@item "ansi/iso-mode turned on" (Warning)
+
+        You turned on the ANSI/ISO-conforming mode. This warning is always
+        displayed unless it is suppressed. So vbcc cannot be blamed to miss
+        a diagnostic for any constraint violation. :-)
+
+
+@item "division by zero (result set to 0)" (Warning, ANSI-violation)
+
+        Similar to warning 84.
+
+
+@item "constant out of range" (Warning, ANSI-violation)
+
+        An integral constant is too large to fit into an unsigned long.
+
+
+@item "constant is unsigned due to size" (Warning)
+
+        If an integral constant is so large that it cannot be represented
+        as long its type is promoted to unsigned long.
+
+
+@item "varargs function called without prototype in scope" (Warning)
+
+        A function which takes a variable number of arguments must not be
+        called without a prototype in scope. E.g. calling printf() without
+        #include <stdio.h> may cause this warning.
+
+
+@item "suspicious format string" (Warning)
+
+        The format-string of a printf-/scanflike function seems to be corrupt
+        or not matching the type of the arguments.
+
+
+@item "format string contains \'\\0\'" (Warning)
+
+        The format string for a printf-/scanflike function contains an
+        embedded '\0' character.
+
+
+@item "illegal use of keyword <%s>" (Warning, ANSI-violation)
+
+        The reserved keywords of C may not be used as identifier.
+
+
+@item "register <%s> used with wrong type" (Error)
+
+
+@item "register <%s> is not free" (Error)
+
+
+@item "'__reg' used in old-style function definition" (Warning)
+
+
+@item "unknown register \"%s\"" (Warning)
+
+
+@item "'...' only allowed with prototypes" (Warning, ANSI-violation)
+
+
+@item "Hey, do you really know the priority of '&&' vs. '||'?" (Warning)
+
+
+@item "be careful with priorities of <</>> vs. +/-" (Warning)
+
+
+@item "address of auto variable returned" (Warning)
+
+
+@item "void function returns a void expression" (Warning)
+
+
+@item "redeclaration of typedef <%s>" (Warning, ANSI-violation)
+
+
+@item "multiple specification of attribute \"%s\"" (Warning)
+
+
+@item "redeclaration of var \"%s\" with differing setting of attribute \"%s\"" (Warning)
+
+@item "string-constant expected" (Error)
+
+@item "tag \"%s\" used for wrong type" (Warning, ANSI-violation)
+
+@item "member after flexible array member" (Error, ANSI-violation)
+
+@item "illegal number" (Error, ANSI-violation)
+
+@item "void character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "spurious tail in octal character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "spurious tail in hexadecimal character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal escape sequence in character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid constant integer value" (Preprocessor, Error, ANSI-violation)
+
+@item "a right parenthesis was expected" (Preprocessor, Error, ANSI-violation)
+
+@item "a colon was expected" (Preprocessor, Error, ANSI-violation)
+
+@item "truncated constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue operator '%s' in constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid token in constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "trailing garbage in constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "void condition for a #if/#elif" (Preprocessor, Error, ANSI-violation)
+
+@item "void condition (after expansion) for a #if/#elif" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid '#include'" (Preprocessor, Error, ANSI-violation)
+
+@item "macro expansion did not produce a valid filename for #include" (Preprocessor, Error, ANSI-violation)
+
+@item "file '%s' not found" (Preprocessor, Error, ANSI-violation)
+
+@item "not a valid number for #line" (Preprocessor, Error, ANSI-violation)
+
+@item "not a valid filename for #line" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue '#'" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue #else" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue #elif" (Preprocessor, Error, ANSI-violation)
+
+@item "unmatched #endif" (Preprocessor, Error, ANSI-violation)
+
+@item "unknown cpp directive '#%s'" (Preprocessor, Error, ANSI-violation)
+
+@item "unterminated #if construction" (Preprocessor, Error, ANSI-violation)
+
+@item "could not flush output (disk full ?)" (Preprocessor, Error, ANSI-violation)
+
+@item "truncated token" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal character '%c'" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished string at end of line" (Preprocessor, Error, ANSI-violation)
+
+@item "missing macro name" (Preprocessor, Error, ANSI-violation)
+
+@item "trying to redefine the special macro %s" (Preprocessor, Error, ANSI-violation)
+
+@item "truncated macro definition" (Preprocessor, Error, ANSI-violation)
+
+@item "'...' must end the macro argument list" (Preprocessor, Error, ANSI-violation)
+
+@item "void macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "missing comma in macro argument list" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "duplicate macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "'__VA_ARGS__' is forbidden in macros with a fixed number of arguments" (Preprocessor, Error, ANSI-violation)
+
+@item "operator '##' may neither begin nor end a macro" (Preprocessor, Error, ANSI-violation)
+
+@item "operator '#' not followed by a macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "macro '%s' redefined unidentically" (Preprocessor, Error, ANSI-violation)
+
+@item "not enough arguments to macro" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished macro call" (Preprocessor, Error, ANSI-violation)
+
+@item "too many argument to macro" (Preprocessor, Error, ANSI-violation)
+
+@item "operator '##' produced the invalid token '%s%s'" (Preprocessor, Error, ANSI-violation)
+
+@item "quad sharp" (Preprocessor, Error, ANSI-violation)
+
+@item "void macro name" (Preprocessor, Error, ANSI-violation)
+
+@item "macro %s already defined" (Preprocessor, Error, ANSI-violation)
+
+@item "trying to undef special macro %s" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal macro name for #ifdef" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished #ifdef" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal macro name for #undef" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished #undef" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal macro name for #ifndef" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished #ifndef" (Preprocessor, Error, ANSI-violation)
+
+@item "reconstruction of <foo> in #include" (Preprocessor, Warning)
+
+@item "comment in the middle of a cpp directive" (Preprocessor, Warning)
+
+@item "null cpp directive" (Preprocessor, Warning)
+
+@item "rogue '#' in code compiled out" (Preprocessor, Warning)
+
+@item "rogue '#' dumped" (Preprocessor, Warning)
+
+@item "#error%s" (Preprocessor, ANSI-violation, Error)
+
+@item "trigraph ?""?%c encountered" (Preprocessor, Warning)
+
+@item "unterminated #if construction (depth %ld)" (Preprocessor, Error, ANSI-violation)
+
+@item "malformed identifier with UCN: '%s'" (Preprocessor, Warning, ANSI-violation)
+
+@item "truncated UTF-8 character" (Preprocessor, Warning, ANSI-violation)
+
+@item "identifier not followed by whitespace in #define" (Preprocessor, Warning, ANSI-violation)
+
+@item "assignment discards restrict" (Warning, ANSI-violation)
+
+@item "storage-class in declaration within for() converted to auto" (Warning, ANSI-violation)
+
+@item "corrupted special object" (ANSI-violation, Fatal)
+
+@item "<inline> only allowed in function declarations" (Error, ANSI-violation)
+
+@item "reference to static variable <%s> in inline function with external linkage" (Error, ANSI-violation)
+
+@item "underflow of pragma popwarn" (Error, ANSI-violation)
+
+@item "invalid argument to _Pragma" (Preprocessor, Error, ANSI-violation)
+
+@item "missing comma before '...'" (Preprocessor, Error, ANSI-violation)
+
+@item "padding bytes behind member <%s>" (Warning)
+
+@item "member <%s> does not have natural alignment" (Warning)
+
+@item "function <%s> exceeds %s limit" (Warning)
+
+@item "%s could not be calculated for function <%s>" (Warning)
+
+@item "offsetof applied to non-struct" (Error, ANSI-violation) 
+
+@item "trailing garbage in #ifdef" (Preprocessor, Warning, ANSI-violation)
+
+@item "too many arguments to macro" (Preprocessor, Warning, ANSI-violation)
+
+@item "truncated comment" (Preprocessor, Warning|ANSI-violation)
+
+@item "trailing garbage in preprocessing directive" (Preprocessor, Warning, ANSI-violation)
+
+@item "variable-length array must have auto storage-class" (Error, ANSI-violation)
+
+@item "member <%s> has type with zero alignment/size (probably void)" (Error, ANSI-violation, Fatal)
+
+@item "stack information for target <%s> unavailable" (Warning)
+
+@item "used registers information unavailable for target <%s>" (Warning)
+
+@item "computed %sstack usage %d but set to %d" (Warning)
+
+@item "unable to compute call targets" (Warning)
+
+@item "computed register usage differs from specified one" (Warning)
+
+@item "trailing garbage in #include" (Preprocessor, Warning ,ANSI-violation)
+
+@item "target-warning: %s" (Warning)
+
+@item "target-error: %s" (Error)
diff --git a/doc/interface.texi b/doc/interface.texi
new file mode 100644
index 0000000..5648833
--- /dev/null
+++ b/doc/interface.texi
@@ -0,0 +1,2830 @@
+
+@section Introduction
+
+This chapter is under construction!
+
+    
+
+This chapter describes some of the internals of @command{vbcc}
+ and tries to explain
+what has to be done to write a code generator for @command{vbcc}.
+However if someone wants to write one, I suggest to contact me first,
+so that it can be integrated into the source tree.
+
+You have to create a new directory for the new target named
+@file{machines/<target-name>} and write the files @file{machine.c}, 
+@file{machine.h}
+and @file{machine.dt}. The compiler for this target will be called
+@command{vbcc<target-name>} and can be built doing a
+@command{make TARGET=<target-name> bin/vbcc<target-name>}.
+
+From now on integer means any of @code{char, short, int, long, long long} or their
+unsigned couterparts. Arithmetic means integer or @code{float} or 
+@code{double} or @code{long double}.
+Elementary type means arithmetic or pointer.
+
+Note that this documentation may mention explicit values when introducing
+symbolic constants. This is due to copying and pasting from the source
+code. These values may not be up to date and in some cases can be overridden.
+Therefore do never use the absolute values but rather the symbolic
+representations.
+
+
+@section Building vbcc
+
+This section deals with the steps necessary to build the typical
+@command{vbcc} executables from the sources.
+
+@subsection Directory Structure
+
+    The vbcc-directory contains the following important files and
+    directories:
+@table @file
+@item    vbcc/
+The main directory containing the compiler sources.
+
+@item    vbcc/Makefile
+The Makefile used to build @command{vbcc}.
+
+@item    vbcc/frontend/
+Directory containing the source to @command{vc}, the compiler driver.
+
+@item    vbcc/machines/<target>/
+Directory for the @code{<target>} backend.
+
+@item    vbcc/machines/ucpp/
+Directory containing the builtin preprocessor.
+
+@item    vbcc/vsc/
+Directory containing source to @command{vsc}, the instruction scheduler.
+
+@item    vbcc/bin/
+Directory the executables will be placed in.
+@end table
+
+    All compiling is done from the main directory.
+    The frontend @command{vc}
+ is not target-dependend and therefore only one version
+    is created.
+
+    Every available target has at least one subdirectory with its name in
+    @file{vbcc/machines} and contains at least the files 
+@file{machine.h}, @file{machine.c} and
+    @file{machine.dt}. Target-specific object-files will also be stored in that
+    directory.
+
+    The executables will be placed in @file{vbcc/bin/}. The main compiler will
+    be called @command{vbcc<target>}.
+
+
+@subsection Adapting the Makefile
+
+    Before building anything you have to insert correct values for
+    @code{CC, NCC, LDFLAGS} and @code{NLDFLAGS} in the @file{Makefile}.
+
+@table @code
+    @item CC
+       Here you have to insert a command that invokes an ANSI C
+             compiler you want to use to build vbcc. It must support
+             @option{-D}, @option{-I}, @option{-c} and @option{-o}
+                 the same like e.g. @command{vc} or @command{gcc}.
+             Additional options should also be inserted here. E.g. if you
+             are compiling for the Amiga with @command{vbcc} you should add 
+                @option{-DAMIGA}.
+
+    @item LDFLAGS 
+         Here you have to add options which are necessary for linking.
+             E.g. some compilers need special libraries for floating-point.
+
+    @item NCC
+    @itemx NLDFLAGS
+    These are similar to @code{CC} and @code{LDFLAGS} but they must always
+    describe a native compiler, i.e. Programs compiled with @code{NCC/NLDFLAGS}
+    must be executable on the host system. This is needed because during
+    the build programs may have to be executed on the host.
+@end table
+
+    An example for the Amiga using @command{vbcc} would be:
+@example
+      CC = vc -DAMIGA -c99
+      LDFLAGS = -lmieee
+      NCC = $(CC)
+      NLDFLAGS = $(LDFLAGS)
+@end example
+
+    An example for a typical Unix-installation would be:
+@example
+      CC = cc
+      LDFLAGS = -lm
+      NCC = $(CC)
+      NLDFLAGS = $(LDFLAGS)
+@end example
+
+The following settings are probably necessary for Open/Free/Any BSD i386 systems:
+@example
+      CC = gcc -D_ANSI_SOURCE
+      LDFLAGS = -lm
+      NCC = $(CC)
+      NLDFLAGS = $(LDFLAGS)
+@end example
+
+
+@subsection Building vc
+
+Note to users of Open/Free/Any BSD i386 systems: You will probably have to use
+GNU make instead of BSD make, i.e. in the following examples replace "make"
+with "gmake".
+
+    Type:
+@example
+      make bin/vc
+@end example
+
+@subsection Building vsc
+
+    Type:
+@example
+      make TARGET=<target> bin/vsc<target>
+@end example
+    For example:
+@example
+      make TARGET=alpha bin/vscalpha
+@end example
+
+    Omit this step if there is no file @file{machines/<target>/schedule.c}.
+
+
+@subsection Building vbcc
+
+    Type:
+
+@example
+      make TARGET=<target> bin/vbcc<target>
+@end example
+For example:
+@example
+      make TARGET=alpha bin/vbccalpha
+@end example
+
+    During the build the program @command{dtgen} will be generated and executed on
+    the host-system. First it will ask you whether you are building a
+    cross-compiler.
+
+    Answer @code{y} only if you are building a cross-compiler (i.e. a compiler
+    which does not produce code for the same machine it it running on).
+
+    Note that it does _not_ matter if you are cross-building a compiler,
+    i.e. if you are running on system A and building a B->B compiler
+    by using an A->B compiler then you can answer @code{n}.
+
+    If you answered @code{y} you will be asked if your system/compiler offers
+    certain datatypes. This refers to the compiler you described with
+    CC in the Makefile.
+    E.g. if @code{CC} is an A->B cross-compiler you have to answer the questions
+    according to B.
+    To each question answer @code{y} or @code{n} depending if such a datatype is
+    available on that compiler. If you answered @code{y} you have to type in
+    the name of that type on the compiler (e.g. @code{signed int},
+    @code{unsigned char} etc.).
+    If there are not enough datatypes available to build @command{vbcc}
+    an error
+    message will be printed and the build aborts.
+
+
+@subsection Configuring
+
+    Consult the @command{vbcc}-documentation for information on
+    how to create the necessary config-files.
+
+
+@subsection Building Cross-Compilers
+
+    As there is often confusion when it comes to cross-building compilers
+    or building cross-compilers, here is what has to be done to cross-build
+    a B->C cross-compiler on system A with only a native A->A compiler
+    available.
+
+    This is done by first building an A->B compiler and then cross-building
+    the B->C compiler using the A->B compiler.
+
+    For the first step you use the A->A compiler for @code{CC} as well as
+        @code{NCC}.
+    Now you type:
+@example
+      make bin/vc
+      make TARGET=B bin/vscB   # omit if there is no machines/B/schedule.c
+      make TARGET=B bin/vbccB
+@end example
+
+    The questions about datatypes are answered according to A.
+    Then you should write a @file{vc.config} for the @code{vbccB}
+ cross-compiler.
+
+    Now create a second directory containing all the sources to @command{vbcc}
+ and
+    set @code{CC/LDFLAGS} to @command{vc} using the config-file for vbccB and
+        @code{NCC/NLDFLAGS}
+    to the A->A compiler. Type:
+@example
+      make bin/vc
+      make TARGET=C bin/vscC   # omit if there is no machines/C/schedule.c
+      make TARGET=C bin/vbccC
+@end example
+
+
+
+@section The Intermediate Code
+
+@command{vbcc} will generate intermediate code for every function and pass
+this code to the code generator which has to convert it into the desired output.
+
+In the future there may be a code generator generator which reads a machine
+description file and generates a code generator from that, but it is not
+clear whether this could simplify much without taking penalties in the
+generated code.
+Anyway, this would be a layer on top of the current interface to the code
+generator, so that the interface described in this document would still be
+valid and accessible.
+
+@subsection General Format
+
+The intermediate code is represented as a doubly linked list of quadruples
+(I am calling them ICs from now on) consisting mainly of an operator, two
+source operands and a target. They are represented like this:
+
+@example
+
+struct IC@{
+    struct IC *prev;
+    struct IC *next;
+    int code;
+    int typf;
+    int typf2;
+    [...]
+    struct obj q1;
+    struct obj q2;
+    struct obj z;
+    [...]
+    struct ext_ic ext;  /* optional */
+@};
+@end example
+
+The only members relevant to the code generator are
+@code{prev, next, code, typf, typf2, q1, q2, z} and (optionally) @code{ext_ic}.
+
+@code{prev} and @code{next} are pointers to the previous and next IC.
+The first IC has @code{prev==0} and the last one has @code{next==0}.
+
+@code{typf} and @code{typf2} are the type of the operands of this IC.
+In most ICs all operands have the same type and therefore only @code{typf}
+is used. However, some ICs have operands of different types (e.g.
+converting an operand to another type or adding an integer to a pointer).
+@code{typf2} is used in these cases.
+
+Macros are provided which yield the type of an operand.
+@code{q1typ(), q2typ()} and @code{ztyp()} return the type of the first source
+operand, the second source operand and the destination, respectively.
+They have to be passed a pointer to a valid IC as argument. The results are
+undefined if the IC does not contain the specified operand (e.g. @code{q2typ()}
+for an IC with only a single operand).
+
+The standard types which are defined by default are:
+
+@example
+    #define CHAR 
+    #define SHORT 
+    #define INT 
+    #define LONG 
+    #define LLONG
+    #define FLOAT 
+    #define DOUBLE 
+    #define LDOUBLE
+    #define VOID 
+    #define POINTER 
+    #define ARRAY 
+    #define STRUCT 
+    #define UNION 
+    #define ENUM          /*  not relevant for code generator     */
+    #define FUNKT 
+@end example
+
+    and can be additionally or'ed by
+
+@example
+    #define UNSIGNED
+    #define CONST
+    #define VOLATILE
+    #define UNCOMPLETE
+@end example
+
+    However, only @code{UNSIGNED} is of real importance for the code generator.
+    @code{typf&NQ} yields the type without any qualifiers, @code{typf&NU}
+    yields the type without any qualifiers but @code{UNSIGNED}.
+
+It is possible for backends to define additional types. @xref{exttypes}
+for documentation on how to extend the type system.
+
+@node operands
+@subsection Operands
+
+@code{q1, q2} and @code{z} are the source1 (quelle1 in German), source2 and
+target (ziel) operands, respectively.
+If a result has to be computed, it always will be stored in the object @code{z}
+and the objects @code{q1} and @code{q2} usually may not be destroyed during
+this operation (unless they are aliased with the destination).
+
+The objects are described by this structure:
+
+@example
+
+struct obj@{
+    int flags;
+    int reg;
+    int dtyp;
+    struct Var *v;
+    struct AddressingMode *am;
+    union atyps@{
+        zchar vchar;
+        zchar vuchar;
+        zshort vshort;
+        zushort vushort;
+        zint vint;
+        zuint vuint;
+        zlong vlong;
+        zulong vulong;
+        zllong vllong;
+        zullong vullong;
+        zmax vmax;
+        zumax vumax;
+        zfloat vfloat;
+        zdouble vdouble;
+        zldouble vldouble;
+    @} val;
+@};
+
+@end example
+
+@code{flags} specifies the kind of object. It can be a combination of
+
+@table @code
+
+@item #define KONST 1
+    The object is a constant. Its value is in the corresponding (to
+        @code{typf} or @code{typf2})
+    member of @code{val}.
+
+@item #define VAR 2
+    The object is a variable. The pointer to its @code{struct Var} is in 
+    @code{v}. @code{val.vlong} vontains an offset that has to be added to it.
+    Fur further details, @pxref{Variables}.
+
+@item #define DREFOBJ 32
+    The content of the location in memory the object points to is used.
+        @code{dtyp} contains the type of the pointer. In systems with
+        only one pointer type, this will always be @code{POINTER}.
+
+@item #define REG 64
+    The object is a register. @code{reg} contains its number.
+
+@item #define VARADR 128
+    The address of the object is to be used. Only together with static
+    variables (i.e. @code{storage_class == STATIC} or @code{EXTERN}).
+
+@end table
+
+The possible combinations of these flags should be:
+
+@itemize
+        @item @code{0} (no object)
+        @item @code{KONST}
+        @item @code{KONST|DREFOBJ}
+        @item @code{REG}
+        @item @code{VAR}
+        @item @code{VAR|REG}
+        @item @code{REG|DREFOBJ}
+        @item @code{KONST|DREFOBJ}
+        @item @code{VAR|DREFOBJ}
+        @item @code{VAR|REG|DREFOBJ}
+        @item @code{VAR|VARADR}
+@end itemize
+
+Also some other bits which are not relevant to the code generator may be set.
+
+Constants will usually be in @code{q2} if possible. One of the sources always
+is not constant and the target is always an lvalue.
+The types of the operands can be queried using the macros
+@code{q1typ(), q2typ()} and @code{ztyp()}.
+In most cases (i.e. when not explicitly stated) the type is an elementary type
+(i.e. arithmetic or pointer).
+
+@code{am} can be used to store information on special addressing modes.
+This has to be handled by the by the code generator. However @code{am} has to be 0
+or has to point to a @code{struct AddressingMode} that was allocated using @code{malloc()}
+when the code generator returns. @code{struct AddressingMode} has to be defined
+in @file{machine.h}.
+
+@code{val} stores either the value of the object if it is a constant or an
+offset if it is a variable.
+
+@code{code} specifies the operation. Fur further details @pxref{operations}.
+
+
+
+@node Variables
+@subsection Variables
+
+    A @code{struct Var} looks like:
+
+@example
+
+    struct Var@{
+        int storage_class;
+        [...]
+        char *identifier;
+        [...]
+        zmax offset;
+        struct Typ *vtyp;
+        [...]
+        char *vattr;
+        unsigned long tattr;   /* optional */
+    @};
+@end example
+
+
+    The relevant entries are:
+
+@table @code
+    @item identifier
+        The name of the variable. Usually only of interest for variables
+        with external-linkage.
+
+    @item storage_class
+        One of:
+        @example
+            #define AUTO 1
+            #define REGISTER 2
+            #define STATIC 3
+            #define EXTERN  4
+            #define TYPEDEF 5       /*  not relevant    */
+        @end example
+        The backend should use the macros @code{isauto(), isstatic()}
+        and @code{isextern()} to check which category a variable falls into.
+
+     @item offset
+        Contains an offset relative to the beginning of the variable's
+        storage. Used, for example, when accessing members of structures.
+
+     @item vtyp
+        The type of the variable (@pxref{compositetypes}).
+
+     @item vattr
+        A string with attributes used in the declaration of the variable.
+        @xref{targetattributes} for further details.
+
+     @item tattr
+        Flags used when declaring the variable.
+        @xref{targetattributes} for further details.
+@end table
+
+        If the variable is not assigned to a register (i.e. bit @code{REG}
+        is not set in the flags of the corresponding @code{struct obj}) then
+        the variable can be addressed in the following ways (with
+        examples of 68k-code):
+
+@table @code
+        @item isauto(storage_class) != 0
+            @code{offset} contains the offset inside the local-variables
+            section. The code generator must decide how it's going to handle
+            the activation record.
+            If @code{offset < 0} then the variable is a function argument on
+                the
+            stack. In this case the offset in the parameter-area is
+             @code{- (offset + maxalign)}.
+
+            The code generator may have to calculate the actual offset
+            to a stack- or frame-pointer from the value in @code{offset}.
+@example
+                offset + val.vlong(sp)
+@end example
+            Note that @code{storage_class == REGISTER} is equivalent to
+                @code{AUTO} - whether
+            the variable is actually assigned a register is specified by
+            the bit @code{REG} in the @code{flags} of the @code{struct obj}.
+
+        @item isextern(storage_class) != 0
+            The variable can be addressed through its name in @code{identifier}.
+@example
+                val.vlong + '_'identifier
+@end example
+
+        @item isstatic(storage_class) != 0
+            The variable can be addressed through a numbered label. The
+            label number is stored in @code{offset}.
+@example
+                val.vlong+'l'offset
+@end example
+@end table
+
+@node compositetypes
+@subsection Composite Types
+
+The C language offers types which are composed out of other types,
+e.g. structures or arrays. Therefore, a C type can be an arbitrarily
+complex structure. Usually the backend does not need to deal with
+those structures. The ICs contain only the simple type flags, e.g.
+@code{INT} or @code{STRUCT}, but not the members of a structure (instead
+the size is given).
+
+Most backends do not have to deal with complex types at all, but
+there are some ways to access them, if needed (for example, they may be
+needed when generating debug information). Therefore, this chapter
+describes the representation of such full types.
+
+Types are represented by the following structure:
+@example
+struct Typ @{
+  int flags;
+  struct Typ *next;
+  struct struct_declaration *exact;
+  zmax size;
+  char *attr;
+@};
+@end example
+
+@code{flags} is the simple type as it is generally used in the
+backend. The meaning of the other members depends on @code{flags}.
+@code{attr} is an attribute that can be added to the type using
+the sytax @code{__attr("...")} (which is parsed like a type-qualifier,
+e.g. @code{const}). If several attributes are specified
+for a type, the strings will be concatenated, separated by semi-colons.
+
+If the type is a pointer (@code{ISPOINTER(flags) != 0}), then @code{next}
+will point to the type the pointer points to.
+
+If the type is an array (@code{ISARRAY(flags) != 0}), then @code{size}
+contains the number of elements and @code{next} points to a type structure
+representing the type of each array element.
+
+If the type is a structure (@code{ISSTRUCT(flags) != 0}), a union
+(@code{ISUNION(flags) != 0}) or a function (@code{ISFUNC(flags) != 0}), 
+then @code{exact}
+is a pointer to a @code{struct_declaration} (which is also used to represent
+unions and function prototypes) that looks like this:
+@example
+struct struct_declaration @{
+  int count;
+  int label;
+  int typ;
+  ...
+  struct struct_list (*sl)[];
+  char *identifier;
+@};
+@end example
+
+@code{count} is the number of members, @code{label} can be used to store
+a label when generating debug information. @code{typ} is either @code{STRUCT},
+@code{UNION} or @code{FUNKT} to denote whether it applies to a structure,
+union or function-prototype.
+
+@code{identifier} is only available for struct- and union-tags.
+
+@code{sl} points to an array of @code{struct struct_list}s which contain
+information on each member/parameter:
+@example
+struct struct_list @{
+  char *identifier;
+  struct Typ *styp;
+  zmax align;
+  int bfoffset;
+  int bfsize;
+  int storage_class;
+  int reg;
+@};
+@end example
+
+@code{identifier} is the identifier of the member/parameter, if available.
+@code{styp} denotes the full type, @code{align} the alignment in bytes
+(only for struct/union), @code{bfoffset} and @code{bfsize} the size and
+offset of bitfield-members, @code{storage_class} the storage class of
+function parameters (may be @code{AUTO} or @code{REGISTER}) and @code{reg}
+denotes the register a parameter is passed in.
+
+Example: If @code{struct Typ *t} points to a structure-type, then the type
+of the second structure member can be accessed through
+@code{(*t->exact->sl)[1].styp}.
+
+A prototyped function will have a last argument of type @code{VOID} unless
+it is a function accepting a variable number of arguments. If a function
+was declared without a prototype it will have no parameters, a function
+declared with prototype accepting no arguments will have one parameter of
+type @code{VOID}.
+
+Also, in the case of a function type, the @code{next}-member of a
+@code{struct Typ} points to the return type of the function.
+
+
+@node operations
+@subsection Operations
+
+This section lists all the different operations allowed in the
+intermediate code passed to the backend. It lists the symbolic name
+of the @code{code} value (the value should not be used), a template
+of the operands and a description. The description sometimes
+contains internals (e.g. which types are stored in @code{typf} and
+which in @code{typf2}), but they should not be used. Access them using
+the macros provided (e.g. @code{q1typ,q2typ,ztyp}) whenever possible.
+
+
+@table @code
+@item #define ASSIGN 2
+
+    Copy @code{q1} to @code{z}. @code{q1->z}.
+
+    @code{q2.val.vmax} contains the size of the objects (this is
+    necessary if it is an array or a struct). It should be accessed
+    using the @code{opsize()}-macro.
+    @code{typf} does not have to be an elementary type!
+
+    The only case where @code{typf == ARRAY} should be in automatic initializations.
+
+    It is also possible that @code{(typf&NQ) == CHAR} but the size is != 1. This is
+    created for an inline memcpy/strcpy where the type is not known.
+
+@item #define OR 16
+@item #define XOR 17
+@itemx #define AND 18
+
+    Bitwise boolean operations. @code{q1,q2->z}.
+
+    All operands are integers.
+
+@item #define LSHIFT 25
+@itemx #define RSHIFT 26
+
+    Bit shifting. @code{q1,q2->z}.
+
+ @code{'q2'} is the number of shifts.
+    All operands are integers.
+
+@item #define ADD 27
+@item #define SUB 28
+@item #define MULT 29
+@itemx #define DIV 30
+
+    Standard arithmetic operations. @code{q1,q2->z}.
+
+    All operands are of arithmetic types (integers or floating point).
+
+@item #define MOD 31
+
+    Modulo (@code{%}). @code{q1,q2->z}.
+
+    All operands are integers.
+
+@item #define KOMPLEMENT 33
+
+    Bitwise complement. @code{q1->z}.
+
+    All operands are integers.
+
+@item #define MINUS 38
+
+    Unary minus. @code{q1->z}.
+
+    All operands are of arithmetic types (integers or floating point).
+
+@item #define ADDRESS 40
+
+    Get the address of an object. @code{q1->z}.
+
+    @code{z} is always a pointer and @code{q1} is always an auto variable.
+
+@item #define CALL 42
+
+    Call the function @code{q1}. @code{q1}.
+
+    @code{q2.val.vmax} contains the number of bytes pushed on the stack as
+    function arguments for this call (use the @code{pushedargsize()}-macro
+    to access this size). Those may have to be popped from the
+    stack after the function returns depending on the calling mechanism.
+
+    A @code{CALL} IC has a member @code{arg_cnt} which contains the number
+    of arguments to this function call. @code{arg_list[i]} (with @code{i}
+    in the range 0...@code{arg_cnt-1}) contains the pointer to the
+    IC passing the @code{i}-th argument.
+
+@item #define CONVERT 50
+
+    Convert one type to another. @code{q1->z}.
+
+    @code{z} is always of the type @code{typf}, @code{q1} of type @code{typf2}.
+
+    Conversions between floating point and pointers do not occur, neither 
+    do conversions to and from structs, unions, arrays or void.
+
+@item #define ALLOCREG 65
+
+    Allocate a register. @code{q1}.
+
+    From now on the register @code{q1.reg} is in use. No code has to be generated
+    for this, but it is probably useful to keep track of the registers
+    in use to know which registers are available for the code generator
+    at a certain time and which registers are trashed by the function.
+
+@item #define FREEREG 66
+
+    Release a register. @code{q1}.
+
+    From now on the register @code{q1.reg} is free.
+
+    Also it means that the value currently stored in @code{q1.reg} is not used any
+    more and provides a little bit of data flow information.
+    Note however, if a @code{FREEREG} follows a branch, the value of the register
+    may be used at the target of the branch.
+
+@item #define COMPARE 77
+
+    Compare and set condition codes. @code{q1,q2(->z)}.
+
+    Compare the operands and set the condition code, so that
+    @code{BEQ, BNE, BLT, BGE, BLE} or @code{BGT} works as desired.
+    If @code{z.flags == 0} (this is always the case unless the backend sets
+    @code{multiple_ccs} to 1 and @option{-no-multiple-ccs} is not used) 
+    the condition codes will be evaluated only by an IC immediately
+    following the @code{COMPARE}, i.e. the next instruction (except possible
+    @code{FREEREG}s) will be a conditional branch.
+
+    However, if a target supports several condition code registers and sets
+    the global variable @code{multiple_ccs} to 1, @command{vbcc} might use those registers
+    and perform certain optimizations. In this case @code{z} may be non-empty and the
+    condition codes have to be stored in @code{z}.
+
+    Note that even if @code{multiple_ccs} is set, a backend must nevertheless
+    be able to deal with @code{z == 0}.
+
+@item #define TEST 68
+
+    Test @code{q1} against 0 and set condition codes. @code{q1(->z)}
+
+    This is equivalent to @code{COMPARE q1,#0}
+    but only the condition code for @code{BEQ} and @code{BNE} has to be set.
+
+@item @code{#define LABEL 69}
+
+    Generate a label. @code{typf} specifies the number of the label.
+
+@item #define BEQ 70
+@item #define BNE 71
+@item #define BLT 72
+@item #define BGE 73
+@item #define BLE 74
+@itemx #define BGT 75
+
+    Branch on condition codes. (@code{q1}).
+
+    @code{typf} specifies the label where program execution shall continue, if the
+    condition code is true (otherwise continue with next statement).
+    The condition codes mean equal, not equal, less than, greater or equal,
+    less or equal and greater than.
+    If @code{q1} is empty (@code{q1.flags == 0}), the codes set by the last @code{COMPARE}
+    or @code{TEST} must be evaluated. Otherwise @code{q1} contains the condition codes.
+
+    On some machines the type of operands of a comparison (e.g unsigned or
+    signed) is encoded in the branch instructions rather than in the
+    comparison instructions. In this case the code generator has to keep
+    track of the type of the last comparison.
+
+    Similarly, in some architectures, the compare and the branch can be
+    combined.
+
+@item #define BRA 76
+
+    Branch always. @code{typf} specifies the label where program execution
+    continues.
+
+@item #define PUSH 78
+
+    Push @code{q1} on the stack (for argument passing). @code{q1}.
+
+    @code{q2.val.vmax} contains the size of the object (should be accessed
+    using the @code{opsize()}-macro), @code{z.val.vmax}
+    contains the size that has to be pushed (access it using the
+    @code{pushsize()}-macro). These sizes may differ due to
+    alignment issues.
+
+    @code{q1} does not have to
+    be an elementary type (see @code{ASSIGN}).
+    Also, @code{q1} can be empty. This is used for ABIs which require
+    stack-slots to be omitted.
+
+    Depending on @code{ORDERED_PUSH} the @code{PUSH} ICs are generated
+    starting with the first or the last arguments. The direction of
+    the stack-growth can be chosen by the backend. Note that this is only
+    used for function-arguments, they can be pushed in opposite direction
+    of the real stack.
+
+@item #define ADDI2P 81
+
+    Add an integer to a pointer. @code{q1,q2->z}.
+
+    @code{q1} and @code{z} are always pointers (of type @code{typf2}) and
+    @code{q2} is an integer of type @code{typf}.
+    @code{z} has to be @code{q1} increased by @code{q2} bytes.
+
+@item #define SUBIFP 82
+
+    Subtract an Integer from a pointer. @code{q1,q2->z}.
+
+    @code{q1} and @code{z} are always pointers (of type @code{typf2}) and
+    @code{q2} is an integer of type @code{typf}.
+    @code{z} has to be @code{q1} decreased by @code{q2} bytes.
+
+@item #define SUBPFP 83
+
+    Subtract a pointer from a pointer. @code{q1,q2->z}.
+
+    @code{q1} and @code{q2} are pointers (of type @code{typf2}) and
+    @code{z} is an integer of type @code{typf}.
+    @code{z} has to be @code{q1 - q2} in bytes.
+
+@item #define GETRETURN 93
+
+    Get the return value of the last function call. @code{->z}.
+
+    If the return value is in a register, its number will be @code{q1.reg}.
+    Otherwise @code{q1.reg} will be 0.
+    @code{GETRETURN} immediately follows a @code{CALL} IC (except possible
+    @code{FREEREG}s).
+
+@item #define SETRETURN 94
+
+    Set the return value of the current function. @code{q1}.
+
+    If the return value is passed in a register, the register number will be @code{z.reg}.
+    Otherwise @code{z.reg} will be 0.
+    @code{SETRETURN} is immediately followed by a function exit (i.e. it is the last
+    IC or followed by an unconditional branch to a label which is the last
+    IC - always ignoring possible @code{FREEREG}s).
+
+@item #define MOVEFROMREG 95
+
+    Move a register to memory. @code{q1->z}.
+
+    @code{q1} is always a register and @code{z} an array of size @code{regsize[q1.reg]}.
+
+@item #define MOVETOREG 96
+
+    Load a register from memory. @code{q1->z}.
+
+    @code{z} is always a register and @code{q1} an array of size @code{regsize[z.reg]}.
+
+@item #define NOP 97
+
+    Do nothing.
+
+@end table
+
+
+@section Type System
+
+@subsection Target Data Types
+
+As the compiler should be portable, we must not assume anything about
+the data types of the host system which is not guaranteed by
+ANSI/ISO C. Especially do not assume that the data types of the host
+system correspond to the ones of the target system.
+
+Therefore, @command{vbcc} will provide typedefs which can hold a data type
+of the target machine and (as there is no operator overloading in C)
+functions or macros to perform arithmetic on these types.
+
+The typedefs for the basic target's data types (they can be extended
+by additional types) are:
+
+@table @code
+    @item zchar
+           Type @code{char} on the target machine.
+    @item zuchar
+          Type @code{unsigned char} on the target machine.
+    @item zshort
+           Type @code{short} on the target machine.
+    @item zushort
+          Type @code{unsigned short} on the target machine.
+    @item zint
+           Type @code{int} on the target machine.
+    @item zuint
+          Type @code{unsigned int} on the target machine.
+    @item zlong
+           Type @code{long} on the target machine.
+    @item zulong
+          Type @code{unsigned long} on the target machine.
+    @item zllong
+           Type @code{long long} on the target machine.
+    @item zullong
+          Type @code{unsigned long long} on the target machine.
+    @item zmax
+          A type capable of storing (and correctly doing arithmetic on)
+          every signed integer type. Defaults to @code{zllong}.
+    @item zumax
+          A type capable of storing (and correctly doing arithmetic on)
+          every unsigned integer type. Defaults to @code{zullong}.
+    @item zfloat
+           Type @code{float} on the target machine.
+    @item zdouble
+           Type @code{double} on the target machine.
+    @item zldouble
+           Type @code{long double} on the target machine.
+    @item zpointer
+        A byte pointer on the target machine. Not really used.
+@end table
+
+These typedefs and arithmetic functions to work on them will be
+generated by the program @command{dtgen} when compiling @command{vbcc}.
+It will create the files @file{machines/$(TARGET)/dt.h} and @file{dt.c}.
+
+These files are generated from @file{machines/$(TARGET)/machine.dt}
+which must describe what representations the code generator needs.
+@command{dtgen} will then ask for available types on the host system and
+choose appropriate ones and/or install emulation functions, if available.
+
+In @file{machine.dt}, every data type representation gets a symbol (the ones which are
+already available can be looked up in @file{datatypes/datatypes.h} - new
+ones will be added when necessary).
+The first 14 lines must contain the representations for the
+following types:
+
+@enumerate
+       @item @code{signed char}
+       @item @code{unsigned char}
+       @item @code{signed short}
+       @item @code{unsigned short}
+       @item @code{signed int}
+       @item @code{unsigned int}
+       @item @code{signed long}
+       @item @code{unsigned long}
+       @item @code{signed long long}
+       @item @code{unsigned long long}
+       @item @code{float}
+       @item @code{double}
+       @item @code{long double}
+       @item @code{void *}
+@end enumerate
+
+If the code generator can use several representations, these can be
+added on the same line separated by spaces. E.g. the code generator
+for m68k does not care if the integers are stored big-endian or
+little-endian on the host system because it only accesses them through
+the provided arithmetic functions. It does, however, access floats
+and doubles through byte-pointers and therefore requires them to
+be stored in big-endian-format.
+
+@subsection Target Arithmetic
+
+Now you have a lot of functions/macros performing operations using the
+target machine's arithmetic. You can look them up in @file{dt.h/dt.c}.
+E.g. @code{zmadd()} takes two @code{zmax} and returns their sum as @code{zmadd}. @code{zumadd()} does
+the same with @code{zumax}, @code{zldadd()} with long doubles. No functions for smaller types
+are needed because you can calculate with the wider types and convert the
+results down if needed.
+
+Therefore, there are also conversion functions which convert between types of the
+target machine. E.g. @code{zm2zc} takes a @code{zmax} and returns the value
+converted to a @code{zchar}.
+Again, look at @file{dt.h/dt.c} to see which ones are there.
+
+A few functions for converting between target and host types are also
+there, e.g. @code{l2zm} takes a long and returns it converted to @code{zmax}.
+
+At last there are functions for comparing target data types. E.g.
+@code{zmleq(a,b)} returns true if @code{zlong a <= zlong b} and false otherwise.
+@code{zleqto(a,b)} returns true if @code{zlong a == zlong b} and false otherwise.
+
+
+
+@section @file{machine.h}
+
+This section describes the contents of the file @file{machine.h}.
+Note that
+some optional macros/declaration may be described someplace else in this
+manual.
+
+@table @code
+
+@item #include "dt.h"
+This should be the first statement in @file{machine.h}.
+
+@item struct AddressingMode @{ ... @};
+If machine-specific addressing modes (@pxref{addressingmodes}) are used,
+an appropriate structure can be specified here. Otherwise, just enter
+the following code:
+@example
+struct AddressingMode @{
+    int never_used;
+@};
+@end example
+
+@item #define MAXR <n>
+Insert the number of available registers.
+
+@item #define MAXGF <n>
+Insert the number of command line flags that can be used to
+configure the behaviour of the code generator. This must be at least one
+even if you do not use any flags.
+
+@item #define USEQ2ASZ <0/1>
+If this is set to zero, @command{vbcc} will not generate ICs with the
+target operand being the same as the 2nd source operand.
+This can sometimes simplify the code-generator, but usually
+the code is better if the code-generator allows it.
+
+@item #define MINADDI2P <type>
+Insert the smallest integer type
+that can be added to a pointer. Smaller types will be automatically converted
+to type @code{MINADDI2P} when they are to be added to a pointer.
+This may be subsumed by @code{shortcut()} in the future.
+
+@item #define MAXADDI2P <type>
+Insert the largest integer type
+that can be added to a pointer. Larger types will be automatically converted
+to type @code{MAXADDI2P} when they are to be added to a pointer.
+This may be subsumed by @code{shortcut()} in the future.
+
+@item #define BIGENDIAN <0/1>
+Insert 1 if integers are represented in big endian, i.e. the
+most significant byte is at the lowest memory address, the least significant
+byte at the highest.
+
+@item #define LITTLEENDIAN <0/1>
+Insert 1 if integers are represented in little endian, i.e.
+the least significant byte is at the lowest memory address, the most
+significant byte at the highest.
+
+@item #define SWITCHSUBS <0/1>
+Insert 1 if switch-statements should be compiled into a
+series of @code{SUB/TEST/BEQ} instructions rather than @code{COMPARE/BEQ}.
+This may be useful if the target has a more efficient @code{SUB}-instruction
+which sets condition codes (e.g. 68k).
+
+@item #define INLINEMEMCPY <n>
+Insert the largest size in bytes allowed for inline memcpy.
+In optimizing compilation, certain library memcpy/strcpy-calls
+with length known at compile-time will be inlined using an
+@code{ASSIGN} IC if the size is less or equal to @code{INLINEMEMCPY}.
+The type used for the @code{ASSIGN} IC will be @code{UNSIGNED|CHAR}.
+
+This may be replaced by a variable of type @code{zmax} in the future.
+
+@item #define ORDERED_PUSH <0/1>
+Insert 1 if @code{PUSH} ICs for function arguments shall
+be generated from left to right instead right to left.
+
+@item #define HAVE_REGPARMS 1
+Insert this line if the backend supports register parameters
+(@pxref{regparm}).
+
+@item #define HAVE_REGPAIRS 1
+Insert this line if the backend supports register pairs
+(@pxref{regpairs}).
+
+@item #define HAVE_INT_SIZET 1
+Insert this line if @code{size_t} shall be of type @code{unsigned int}
+rather than @code{unsigned long}.
+
+@item #define EMIT_BUF_LEN <n>
+Insert the maximum length of a line of code output.
+
+@item #define EMIT_BUF_DEPTH <n>
+Insert the number of output lines that should be buffered. This
+can be useful for peephole-optimizing the assembly output (see
+below).
+
+@item #define HAVE_TARGET_PEEPHOLE <0/1>
+Insert 1 if the backend provides an @code{asm_peephole()}
+function (@pxref{asmpeephole}).
+
+@item #define HAVE_TARGET_ATTRIBUTES 1
+Insert this line if the backend provides old target-specific
+variable-attributes (@pxref{targetattributes}).
+
+@item #define HAVE_TARGET_PRAGMAS 1
+Insert this line if the backend provides target-specific
+@code{#pragma}-directives (@pxref{targetpragmas}).
+
+@item #define HAVE_REGS_MODIFIED 1
+Insert this line if the backend supports inter-procedural
+register-allocation (@pxref{regsmodified}).
+
+@item #define HAVE_TARGET_RALLOC 1
+Insert this line if the backend supports context-sensitive
+register-allocation (@pxref{targetralloc}).
+
+@item #define HAVE_TARGET_EFF_IC 1
+Insert this line if the backend provides a @code{mark_eff_ics()}
+function (@pxref{markeffics}).
+
+@item #define HAVE_EXT_IC 1
+Insert this line if the backend provides a @code{struct ext_ic}
+(@pxref{extic}).
+
+@item #define HAVE_EXT_TYPES 1
+Insert this line if the backend supports additional types
+(@pxref{exttypes}).
+
+@item #define HAVE_TGT_PRINTVAL 1
+Insert this line if the backend provides an own @code{printval} function
+@pxref{tgtprintval}).
+
+@item #define JUMP_TABLE_DENSITY <float>
+@item #define JUMP_TABLE_LENGTH <int>
+These values controls the creation of jump-tables (@pxref{jumptables}).
+
+
+@item #define ALLOCVLA_REG <reg>
+@item #define ALLOCVLA_INLINEASM <inline-asm>
+@item #define FREEVLA_REG <reg>
+@item #define FREEVLA_INLINEASM <inline-asm>
+@item #define OLDSPVLA_INLINEASM <inline-asm>
+@item #define FPVLA_REG <reg>
+Necessary defines for C99 variable-length-arrays (@pxref{vlas}).
+
+@item #define HAVE_LIBCALLS 1
+Insert this line if the backend wants certain ICs to be replaced with
+calls to library functions (@pxref{libcalls}).
+
+@item #define AVOID_FLOAT_TO_UNSIGNED 1
+@item #define AVOID_UNSIGNED_TO_FLOAT 1
+Insert these lines to tell the frontend not to generate @code{CONVERT} ICs
+that convert between unsigned integers and floating point. In those cases,
+additional intermediate code will be generated that implements the
+conversion using only signed integers.
+
+@end table
+
+@section @file{machine.c}
+
+This is the main part of the code generator. The first statement
+should be @code{#include "supp.h"} which will include all necessary
+declarations.
+
+The following variables and functions must be provided by machine.c.
+
+@subsection Name and Copyright
+
+    The codegenerater must define a zero-terminated character array
+    @code{char cg_copyright[];} containing name and copyright-notice of
+    the code-generator.
+
+@subsection Command Line Options
+
+    You can use code generator specific commandline options.
+    The number of flags is specified as @code{MAXGF} in @file{machine.h}.
+    Insert the names for the flags as @code{char *g_flags_name[MAXGF]}.
+    If an option was specified @code{(g_flags[i]&USEDFLAG)} is not zero.
+    In @code{int g_flags[MAXGF]} you can choose how the options are to be
+    used:
+@table @code
+        @item 0
+                The option can only be specified. E.g. if
+                @code{g_flags_name[2]=="myflag"}, the commandline may contain
+                @option{-myflag} and @code{(g_flags[2]&USEDFLAG)!=0}.
+      @item VALFLAG
+   The option must be specified with an integer constant, e.g.
+                @option{-myflag=1234}. This value can be found in
+                @code{g_flags_val[2].l}.
+   @item  STRINGFLAG
+   The option must be specified with a string, e.g.
+                @option{-myflag=Hallo}. The pointer to the string can be found in
+                @code{g_flags_val[2].p}.
+@end table
+
+@subsection Data Types
+
+The following variables have to be initialized to describe the
+representation of the data types.
+
+@table @code
+@item MAX_TYPE
+ This macro contains the number of different types. In case of target-specific
+ extended types (@pxref{exttypes}) this is set by the backend, otherwise the
+ frontend will use a default.
+
+@item zmax char_bit;
+ The number of bits in a @code{char} on the target (usually 8).
+
+@item    zmax align[MAX_TYPE+1];
+ This array must contain the necessary alignments for every
+    type in bytes. Some of the entries in this array are not actually
+    used, but @code{align[type&NQ]} must yield the correct alignment for every type.
+    @code{align[CHAR]} must be 1.
+
+    The alignment of a structure depends not only on @code{sizetab[STRUCT]}
+    but also on the alignment of the members. The maximum of the alignments
+    of all members and @code{sizetab[STRUCT]} is the alignment of any
+    particular structure, i.e. @code{sizetab[STRUCT]} is only a minimum
+    alignment.
+
+    The same applies to unions and arrays.
+
+@item zmax maxalign;
+        This variable  must be set to an alignment in bytes that is used when
+    pushing arguments on the stack. (FIXME: describe stackalign)
+
+@item zmax sizetab[MAX_TYPE+1];
+ This array must contain the sizes of every type in bytes.
+
+@item zmax t_min[MAX_TYPE+1];
+  This array must contain the smallest representable number for every
+    signed integer type.
+
+@item zumax t_max[MAX_TYPE+1];
+  This array must contain the largest representable number for every
+    signed integer type.
+
+@item zumax tu_max[MAX_TYPE+1];
+  This array must contain the largest representable number for every
+    unsigned integer type.
+
+@end table
+
+    As @code{zmax} and @code{zumax} may be no elementary types on the host
+    machine, those arrays have to be initialized dynamically (in 
+    @code{init_cg()}). It is recommended to use explicit typenames, e.g.
+    @code{sizetab[INT]=l2zm(4L);} to keep it portable and allow
+    later extensions of the type system.
+
+    Also note that those values
+    may not be representable as constants by the host architecture and have to
+    be calculated using the functions for arithmetic on the target's data
+    types. E.g. the smallest representable value of a 32bit twos-complement
+    data type is not guaranteed to be valid on every ANSI C implementation.
+
+    You may not use simple operators on the target data types
+    but you have to use the functions or convert them to an elementary
+    type of the host machine before (if you know that it is representable
+    as such).
+
+@subsection Register Set
+
+The following variables have to be initialized to describe the
+register set of the target.
+
+@table @code
+@item MAXR
+    The valid registers are numbered from 1..@code{MAXR}.
+    @code{MAXR} must be @code{#define}d in @file{machine.h}.
+
+@item char *regnames[MAXR+1]
+This array must contain the names for every register. They do not
+necessarily have to be used in the assembly output but are used for
+explicit register arguments.
+
+@item zmax regsize[MAXR+1]
+This array must contain the size of each register in bytes.
+    It is used to create storage if registers have to be saved.
+
+@item int regscratch[MAXR+1]
+This array must contain information whether a register is
+    a scratchregister, i.e. may be destroyed during a function call (1 or 0).
+    vbcc will generate code to save/restore all scratch-registers which are
+    assigned a value when calling a function (unless it knows the register
+    will not be modified). However, if the code generator
+    uses additional scratch-registers it has to take care to save/restore
+    them.
+
+    Also, the code generator must take care that used non-scratch-registers
+    are saved/restored on function entry/exit.
+
+@item int regsa[MAXR+1]
+This array must contain information whether a register is in use
+    or not at the beginning of a function (1 or 0).
+    The compiler will not use any of those registers for register variables
+    or temporaries, therefore this can be used to mark special registers
+    like a stack- or frame-pointer and to reserve registers to the
+    code-generator. The latter may
+    be reasonable if for many ICs code cannot be generated without using
+    additional registers.
+
+    You must set @code{regsratch[i] = 0} if @code{regsa[i] == 1}. If you
+    want it to be
+    saved across function calls the code generator has to take care of this.
+
+@item int reg_prio[MAXR+1];
+This array must contain a priority (>=0) for every register. When the
+register allocator has to choose between several registers which seem
+to be equal, it will choose the one with the highest priority (if
+several registers have the same priority it is undefined which one
+will be taken).
+
+Note that this priority is only the last decision factor if everything
+else seems to be equal. If one register seems to give a higher cost saving
+(according to the estimation of the register allocator) but has a lower
+priority, it will nevertheless be used. The priority can be used to
+fine-tune the register selection. Some guidelines:
+@itemize @minus
+@item Scratch registers might have a higher priority than non-scratch
+        registers (although the register-allocator will usually handle
+        this anyway).
+@item Registers which are more restricted should have a higher priority
+        (if they seem to give the same saving it is usually better to use
+        the restricted registers and try to keep the more versatile ones
+        for situation in which they can give better savings).
+@item Registers which are used for argument-passing should have lower
+        priority than registers not used for arguments. The priority
+        within the argument-registers should decrease as the frequency
+        of usage as argument increases (typically the register for the first
+        argument is used most frequently, etc.).
+@end itemize
+
+@end table
+
+Note that for the array @code{zmax regsize[]} the same comments mentioned
+in the section on data types regarding initialization apply.
+
+
+@subsection Functions
+
+The following functions have to be implemented by the code generator.
+There may be optional additional functions described in other sections.
+
+@table @code
+@item int init_cg(void);
+    This function is called after the commandline arguments are parsed.
+    It can set up certain internal data, etc. The arrays regarding the
+    data types and the register set can be set up at this point rather
+    than with a static initialization, however the arrays regarding the
+    commandline options have to be static initialized.
+    The results of the commandline options are available at this point.
+
+    If something goes wrong, 0 has to be returned, otherwise 1.
+
+@item void cleanup_cg(FILE *f);
+    This function is called before the compiler exits. @code{f} is the output
+    file which must be checked against 0 before using.
+
+@item int freturn(struct Typ *t);
+    This function has to return the number of the register return
+    values of type @code{t} are passed in. If the type is not passed in a
+    register, 0 must be returned. Usually the decision can be made
+    only considering @code{t->flags}, ignoring the full type
+    (@pxref{compositetypes}).
+
+@item int regok(int r, int t, int mode);
+    Check whether the type t can be stored in register @code{r} and whether
+    the usual operations (for this type) can be generated. Return 0, if not.
+
+    If @code{t} is a pointer and @code{mode==0} the register only has to be
+    able to store the pointer and do arithmetic, but if @code{mode!=0} it has
+    to be able to dereference the pointer.
+
+    @code{mode==-1} is used with context-sensitive register-allocation
+    (@pxref{targetralloc}). If the backend does not support it, this case
+    can be handled equivalent to @code{mode==0}.
+
+    If @code{t==0} return whether the register can be used to store condition codes.
+    This is only relevant if @code{multiple_ccs} is set to 1.
+
+@item int dangerous_IC(struct IC *p);
+    Check if this IC can raise exceptions or is otherwise dangerous.
+    Movement of ICs which are dangerous is restricted to preserve the
+    semantics of the program.
+
+    Typical dangerous ICs are divisions or pointer dereferencing. On certain
+    targets floating point or even signed integer arithmetic can raise
+    exceptions, too.
+
+@item int must_convert(int from,int to,int const_expr);
+    Check if code must be generated to convert from type @code{from} to
+    type @code{to}. E.g. on
+    many machines certain types have identical representations (integers
+    of the same size or pointers and integers of the same size).
+
+    If @code{const_expr != 0} return if a conversion was necessary in
+    a constant expression.
+
+    For example, a machine may have identical
+    pointers and integers, but different sets of registers (one set
+    supports integer operations and the other pointer operations).
+    Therefore, @code{must_convert()} would return 1 (we need a
+    @code{CONVERT} IC to move the value from one register set to the
+    other).
+    
+    This would imply that @command{vbcc} would not allow a
+    cast from a pointer to an integer or vice-versa in constant expressions
+    (as it will not
+    generate code for static initializations). However, in this
+    case, a static initialization would be ok as the representation is
+    identical and registers are not involved. Therefore, the backend
+    can return 1 if @code{const_expr == 0} and 0 otherwise.
+
+@item int shortcut(int code, int t);
+    In C no operations are done with chars and shorts because of integral
+    promotion. However sometimes @command{vbcc} might see that an operation could
+    be performed with the short types yielding the same result.
+
+    Before generating such an instruction with short types @command{vbcc} will ask
+    the code generator by calling @code{shortcut()} to find out whether it
+    should do so. Return true iff it is a win to perform the operation
+    @code{code} with
+    type @code{t} rather than promoting the operands and using e.g. @code{int}.
+
+@item void gen_code(FILE *f, struct IC *p, struct Var *v, zmax offset);
+    This function has to emit code for a function to stream @code{f}.
+    @code{v} is the function being generated,
+    @code{p} is a pointer to the list of ICs, that has to be converted.
+    @code{offset} is the space needed for local variables in bytes.
+
+    This function has to take care that only scratchregisters are destroyed
+    by this function. The array @code{regused} contains information about the
+    registers that have been used by @command{vbcc} in this function. However if the
+    code generator uses additional registers it has to take care of them,
+    too.
+
+    The @code{regs[]} and @code{regused[]} arrays may be overwritten by @code{gen_code()} as well
+    as parts of the list of ICs. However the list of ICs must still be a
+    valid list of ICs after @code{gen_code()} returns.
+
+    All assembly output should be generated using the available
+    @code{emit} functions. These functions are able to keep several
+    lines of assembly output buffered and allow peephole optimizations
+    on assembly output (@pxref{asmpeephole}).
+
+@item void gen_ds(FILE *f, zmax size, struct Typ *t);
+    Has to emit output that generates @code{size} bytes of type @code{t}
+    initialized with proper 0.
+
+    @code{t} is a pointer to a @code{struct Typ} which contains the precise type of
+    the variable. On machines where every type can be initialized to 0
+    by setting all bits to zero, the type does not matter. Otherwise
+    @pxref{compositetypes}.
+
+    All assembly output should be generated using the available
+    @code{emit} functions.
+    
+
+@item void gen_align(FILE *f, zmax align);
+    Has to emit output that ensures the following data to be aligned to
+    @code{align} bytes.
+
+    All assembly output should be generated using the available
+    @code{emit} functions.
+
+@item void gen_var_head(FILE *f, struct Var *v);
+    Has to print the head of a static or external variable @code{v}. This includes
+    the label and necessary information for external linkage etc.
+
+    Typically variables will be generated by a call to @code{gen_align()} followed
+    by @code{gen_var_head()} and (a series of) calls to @code{gen_dc()} and/or @code{gen_ds()}. It may be necessary to keep track of the information passed
+    to @code{gen_var_head()}.
+
+    All assembly output should be generated using the available
+    @code{emit} functions.
+
+@item void gen_dc(FILE *f, int t, struct const_list *p);
+    Emit initialized data. @code{t} is the basic type that has to be
+    emitted. @code{p} points to a @code{struct const_list}.
+
+    If @code{p->tree != 0} then @code{p->tree->o} is a @code{struct obj}
+    which has to be emitted. This will usually be the address of a
+    variable of storage class static or unsigned, possibly with an offset
+    added (@pxref{operands} for further details).
+
+    if @code{p->tree == 0} then @code{p->val} is a @code{union atyps}
+    which contains (in the member corresponding to @code{t}) the constant
+    value to be emitted.
+
+    All assembly output should be generated using the available
+    @code{emit} functions.
+
+@item void init_db(FILE *f);
+    If debug-information is requested, this functions is called after
+    @code{init_cg()}, but before any code is generated.
+    See also @ref{debuginfo}.
+
+@item void cleanup_db(FILE *f);
+    If debug-information is requested, this functions is called prior to
+    @code{cleanup_cg()}.
+    See also @ref{debuginfo}.
+
+@end table
+
+@section Available Support Functions, Macros and Variables
+
+This section lists a series of general variables, macros and functions
+which are available to the backend and may prove useful. Note that there
+may be additional support specific to certain features which will be mentioned
+at appropriate sections in this manual.
+
+@table @code
+@item MAXINT
+A constant for the largest target integer type (@code{zmax}). It is outside
+the range of the other types and cannot be accessed by an application
+(although there will usually be an accessible type with the same 
+representation).
+
+@item MAX_TYPE
+The type number of the last type.
+
+@item NQ
+A mask. @code{t & NQ} will delete all type-qualifiers of a type.
+
+@item NU
+A mask. @code{t & NU} will delete all type-qualifiers but
+@code{UNSIGNED} of a type.
+
+@item q1typ(p)
+Yields the type of the first source operand of IC @code{p}.
+Undefined if the operand is not used!
+
+@item q2typ(p)
+Yields the type of the second source operand of IC @code{p}.
+Undefined if the operand is not used!
+
+@item ztyp(p)
+Yields the type of the destination operand of IC @code{p}.
+Undefined if the operand is not used!
+
+@item iclabel(p)
+Returns the label of an IC. Only defined if @code{p->code} is
+@code{LABEL, BEQ, BNE, BLT, BGT, BLE} or @code{BGE}.
+
+@item opsize(p)
+Returns the size of the operand of an @code{ASSIGN} or @code{PUSH}
+IC as @code{zmax}.
+
+@item pushsize(p)
+Returns the stack-adjustment value of a @code{PUSH} IC as @code{zmax}.
+It is always greater or equal than @code{opsize(p)}.
+
+@item pushedargsize(p)
+Returns the space occupied by arguments passed on the stack
+as parameters for a function call. Only valid for @code{CALL} ICs.
+
+@item isstatic(sc)
+Tests whether the storage-class @code{sc} denotes a variable with
+static storage and no external linkage.
+
+@item isextern(sc)
+Tests whether the storage-class @code{sc} denotes a variable with
+static storage and external linkage.
+
+@item isauto(sc)
+Tests whether the storage-class @code{sc} denotes a variable with
+automatic storage-duration.
+
+@item t_min(t)
+@itemx t_max(t)
+These macros yield the smallest and largest representable value of any
+target integer type, e.g. @code{t_min(INT)} or @code{t_max(UNSIGNED|LONG)}.
+
+@item ISPOINTER(t)
+@item ISINT(t)
+@item ISFLOAT(t)
+@item ISFUNC(t)
+@item ISSTRUCT(t)
+@item ISUNION(t)
+@item ISARRAY(t)
+@item ISSCALAR(t)
+@itemx ISARITH(t)
+These macros test whether the simple type @code{t} is a pointer type,
+an integral type, a floating point type, a function, a structure type,
+a union type, an array type, a scalar (integer, floating point or pointer)
+and an arithmetic type (integer or floating point), respectively.
+
+@item int label;
+The number of the last label used so far. For a new label number, use
+@code{++label}.
+
+@item zmax falign(struct Typ *t);
+This function returns the alignment of a full type. Contrary to the
+@code{align[]} array provided by the backend (which is used by this function),
+it will yield correct values for composite types like structures and arrays.
+
+@item zmax szof(struct Typ *t);
+This function returns the size in bytes of a full type. Contrary to the
+@code{sizetab[]} array provided by the backend (which is used by this function),
+it will yield correct values for composite types like structures and arrays.
+
+@item void *mymalloc(size_t size);
+@item void *myrealloc(void *p,size_t size);
+@itemx void myfree(void *p);
+Memory allocation functions similar to @code{malloc(), realloc()} and
+@code{free}. They will automatically
+clean up the exit in the case an allocation fails. Also, some debug
+possibilities are available.
+
+@item void emit(FILE *f,const char *fmt,...);
+@item void emit_char(FILE *f,int c) ;
+@item void emitval(FILE *f,union atyps *p,int t);
+@item void emitzm(FILE *f,zmax x);
+@item void emitzum(FILE *f,zumax x); 
+All output produced by the backend should be produced using these
+functions. @code{emit()} uses a format like @code{printf()},
+@code{emitval(), emitzm()} and @code{emitzum()} are suitable to
+output target integers as decimal text. Currently emitting floating
+point constants has to be done by the backend.
+
+@item int is_const(struct Typ *);
+Tests whether a full type is constant (e.g. to decide whether it can be
+put into a ROM section).
+
+@item int is_volatile_obj(struct obj *);
+@itemx int is_volatile_ic(struct IC *);
+Tests whether an object or IC is volatile. Only of interest to the backend
+in rare cases.
+
+@item int switch_IC(struct IC *p);
+This function checks whether @code{p->q2} and @code{p->z} use the
+same register (including register pairs). If they do, it will try
+to swap @code{p->q1} and @code{p->q2} (only possible if the IC is
+commutative). It is often possible to generate
+better code if @code{p->q2} and @code{p->z} do not collide. Note
+however, that it is not always possible to eliminate a conflict and
+the code generator still has to be able to handle such a case.
+
+The function returns 0 if no modification took place and non-zero if
+the IC has been modified.
+
+@item union atyps gval;
+@item void eval_const(union atyps *p,int t);
+@itemx void insert_const(union atyps *p,int t);
+For every target data type there is a corresponding global variable
+of that type, e.g. @code{zchar vchar, zuchar vuchar, zmax vmax} etc.
+These two functions simplify handling of target data types by transferring
+between a @code{union atyps} and these variables.
+
+@code{eval_const()} reads the member of the union corresponding to the
+type @code{t} and converts it into all the global variables while
+@code{insert_const()} takes the global variable according to @code{t}
+and puts it into the appropriate member of the @code{union atyps}.
+
+The global variable @code{gval} may be used as a temporary
+@code{union atyps} by the backend.
+
+@item void printzm(FILE *f,zmax x);
+@item void printzum(FILE *f,zumax x) ;
+@item void printval(FILE *f,union atyps *p,int t);
+@item void printtype(FILE *o,struct Typ *p);
+@item void printobj(FILE *f,struct obj *p,int t);
+@item void printic(FILE *f,struct IC *p);
+@itemx void printiclist(FILE *f,struct IC *first);
+This is a series of functions which print a more or less human
+readable version of the corresponding type to a stream. These functions
+are to be used only for debugging purposes, not for generating code.
+Also, the arguments must contain valid values.
+
+@item bvtype
+@itemx BVSIZE(n)
+@command{vbcc} provides macros and functions for handling bit-vectors
+which may also be used by the backend. @code{bvtype} is the basic type
+to create bit-vectors of. @code{BVSIZE(n)} yields the number of
+bytes needed to implement a bit-vector with @code{n} elements.
+@example
+bvtype *mybv = mymalloc(BVSIZE(n));
+@end example
+
+@item BSET(bv,n)
+@item BCLR(bv,n)
+@itemx BTST(bv,n)
+Macros which set, clear and test the @code{n}-th bit in bit-vector @code{bv}.
+
+@item void bvunite(bvtype *dest,bvtype *src,size_t len);
+@item void bvintersect(bvtype *dest,bvtype *src,size_t len);
+@itemx void bvdiff(bvtype *dest,bvtype *src,size_t len);
+These functions calculate the union, intersection and difference of two
+bit-vectors. @code{dest} is the first operand as well as the destination.
+@code{len} is the length of the bit-vectors in bytes, not in bits.
+
+@item void bvcopy(bvtype *dest,bvtype *src,size_t len);
+@item void bvclear(bvtype *dest,size_t len);
+@itemx void bvsetall(bvtype *dest,size_t len);
+These functions copy, clear and fill bit-vectors.
+
+@item int bvcmp(bvtype *bv1,bvtype *bv2,size_t len);
+@itemx int bvdointersect(bvtype *bv1,bvtype *bv2,size_t len);
+These functions test whether two bit-vectors are equal or
+have a non-empty intersection, respectively. The do not modify the
+bit-vectors.
+
+@end table
+
+
+@section Hints for common Optimizations
+
+While it is no easy job to produce a stable code generator for a new target
+architecture, there is a huge difference between a simple backend and
+a highly optimized code generator which produces small and efficient 
+high quality code. Although @command{vbcc} is able to do a lot machine
+independent global optimizations for every target automatically, it is still
+common for an optimized backend to produce code up to twice as fast on
+average as a simple one.
+
+Sometimes, a simple backend is sufficient and the
+work required to produce high-quality code is not worthwhile. However,
+this section lists a series of common backend optimizations which are
+often done in case that good code-quality is desired. Note that neither are
+all of these optimizations applicable (without modifications or at all)
+to all architectures nor is
+this an exhaustive list. It is just a list of recommendations to consider.
+You have to make sure that the optimization is safe and beneficial for
+the architecture you are targetting. 
+
+
+@subsection Instruction Combining
+
+While ICs are often a bit more powerful than instructions of a typical
+microprocessor, sometimes several of them can be implemented by a single
+instruction or more efficient code can be generated when looking at a
+few of them rather than at each one separately.
+
+In the simple case, this can be done by looking at the current IC,
+deciding whether it is a candidate for combining and then test whether
+the next IC (or ICs) are suitable for combining. This is relatively easy
+to perform, however some care has to be taken to verify that the
+combination is indeed legal (e.g. what happens if the first IC modifies
+a value which is used by the following IC).
+
+A more sophisticated implementation might look at a larger sequence of
+instructions to find more possibilities for optimization. Detecting
+whether the combination is legal becomes much more difficult then.
+
+Sometimes the IC migh compute a temporary result which would be eliminated by
+the complex machine instruction. Then it is necessary to verify that it
+was indeed a temporary result which is not used anywhere else. As long as
+the result is in a register, this can be done by checking for a
+@code{FREEREG} IC.
+
+Examples for instruction combining are multiply-and-add or bit-test
+instructions which are available on many architectures.
+Special cases are complex
+addressing modes and instructions which can automatically set condition
+codes which are described in the following sections.
+
+
+@node addressingmodes
+@subsection Addressing Modes
+
+The intermediate code generated by vbcc does not use any
+addressing-modes a target might offer. Therefore the code generator
+must find a way to combine several statements if it wants to make use
+of these modes. E.g. on the m68k the intermediate code
+@example
+        ADDI2P  int     a0,#20->a1
+        ASSIG   int     #10->(a1)
+        FREEREG         a1
+@end example
+could be translated to
+@example
+        move.l  #10,20(a0)
+@end example
+(notice the @code{FREEREG} which is important).
+
+To aid in this there is a pointer to a @code{struct AddressingMode} in every
+@code{struct obj}. A code generator could e.g. do a pass over the intermediate
+code, find possible uses for addressing-modes, allocate a
+@code{struct AddressingMode} and store a pointer in the
+@code{struct obj}, effectively replacing the obj.
+
+If the code generator supports extended addressing-modes, you have to think
+of a way to represent them and define the @code{struct AddressingMode} so that
+all modes can be stored in it. The machine independent part of
+@command{vbcc} will
+not use these modes, so your code generator has to find a way to combine
+several statements to make use of these modes.
+
+A possible implementation of a structure to handle the addressing mode
+described above as well as a register-indirect mode could be:
+@example
+#define IMM_IND 1
+#define REG_IND 2
+
+struct AddressingMode @{
+  int flags;   /* either IMM_IND or REG_IND */
+  int base;    /* base register */
+  zmax offset; /* offset in case of IMM_IND */
+  int idx;     /* index register in case of REG_IND */
+@}
+@end example
+
+When the code generator is done that pointer in every @code{struct obj} must
+either be zero or point to a @code{mymalloc}ed @code{struct AddressingMode}
+which will be free'd by @command{vbcc}.
+
+Following is an example of a function which traverses a list of ICs and
+inserts addressing modes with constant offsets where possible.
+@example
+/* search for possible addressing-modes */
+static void find_addr_modes(struct IC *p)
+@{
+  int c,c2,r;
+  struct IC *p2;
+  struct AddressingMode *am;
+
+  for(;p;p=p->next)@{
+    c=p->code;
+
+    if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&
+       isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST)@{
+      /* we have found addi2p q1,#const->reg */
+      int base;zmax of;struct obj *o;
+
+      eval_const(&p->q2.val,p->typf);
+      /* handle sub instead of add */
+      if(c==SUBIFP)
+        of=zmsub(l2zm(0L),vmax);
+      else
+        of=vmax;
+
+      /* Is the offset suitable for an addressing mode? */
+      if(ISVALID_OFFSET(vmax))@{
+        r=p->z.reg;
+        /* If q1 is a register, we use it as base-register,
+           otherwise q1 is loaded in the temporary register
+           and this one used as base register. */
+        if(isreg(q1))
+          base=p->q1.reg;
+        else
+          base=r;
+
+        o=0;
+        /* Now search the following instructions. */
+        for(p2=p->next;p2;p2=p2->next)@{
+          c2=p2->code;
+
+          /* End of a basic block. We have to abort. */
+          if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+
+          /* The temporary register is used. We have to abort. */
+          if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&
+             p2->q1.reg==r)
+              break;
+      	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&
+             p2->q2.reg==r) 
+              break;
+
+          if(c2!=CALL&&(c2<LABEL||c2>BRA)&&c2!=ADDRESS)@{
+            /* See, if we find a valid use (dereference) of the
+               temporary register. */
+            if(!p->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+              p2->q1.reg==r)@{
+              if(o) break;
+              o=&p2->q1;
+            @}
+            if(!p->q1.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+               p2->q2.reg==r)@{
+              if(o) break;
+              o=&p2->q2;
+            @}
+            if(!p->q1.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+               p2->z.reg==r)@{
+              if(o) break;
+              o=&p2->z;
+            @}
+          @}
+          if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG)@{
+            int m;
+            if(c2==FREEREG)
+              m=p2->q1.reg;
+            else
+              m=p2->z.reg;
+            if(m==r)@{
+            /* The value of the temporary register is not used any more
+               (either due to FREEREG or because it is overwritten).
+               If we have found exactly one dereference, we can use
+               a target addressing mode. */
+              if(o)@{
+                o->am=am=mymalloc(sizeof(*am));
+                am->flags=IMM_IND;
+                am->base=base;
+                am->offset=zm2l(of);
+                if(isreg(q1))@{
+                  /* The base already was in a register. We can
+                     eliminate the ADDI2P IC. */
+                  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+                @}else@{
+                  /* The base was not in a register.
+                     We have to load it . */
+                  p->code=c=ASSIGN;p->q2.flags=0;
+                  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+                @}
+              @}
+              break;
+            @}
+            if(c2!=FREEREG&&m==base) break;
+            continue;
+          @}
+        @}
+      @}
+    @}
+  @}
+@}
+@end example
+
+@subsection Implicit setting of Condition Codes
+
+Many architectures have instruction that automatically set the
+condition codes according to the computed result. For these architectures
+it is generally a good idea to keep track of the setting of condition
+codes (e.g. if they reflect the state of some object or register). A
+subsequent @code{TEST} or @code{COMPARE} instruction can then often be
+eliminated.
+
+Care has to be taken to delete this information if either the condition
+codes may be modified or the object they represent is modified. Also,
+this optimization is usually hard to do across labels.
+
+Some architectures provide versions of instructions which set condition
+codes as well as versions which do not. This obviously enable more
+optimizations, but it is more difficult to make use of this. One
+possibility is to search the list of ICs backwards starting from
+every suitable @code{TEST} or @code{COMPARE} instruction. If an IC
+is found which computes the tested object, the IC can be marked
+(extended ICs can be used for marking, @pxref{extic}).
+
+
+@node regparm
+@subsection Register Parameters
+
+While passing of arguments to functions can be done by pushing them on
+the stack, it is often more efficient to pass them in registers if the
+architecture has enough registers.
+
+To use register parameters you have to add the line
+@example
+#define HAVE_REGPARMS 1
+@end example
+to @file{machine.h} and define a
+@example
+        struct reg_handle @{...@}
+@end example
+This struct is used by the compiler to find out which register should be used
+to pass an argument. @file{machine.c} has to contain an initialized
+variable
+@example
+        struct reg_handle empty_reg_handle;
+@end example
+which represents the default state, and a function
+@example
+        int reg_parm(struct reg_handle *, struct Typ *, int vararg, struct Typ *);
+@end example
+which returns the number of the register the next argument will be
+passed in (or 0 if the argument is not passed in a register). Also,
+it has to update the reg_handle in a way that successive calls to
+@code{reg_parm()}
+yield the correct register for every argument.
+
+@code{vararg} is different from zero, if the argument is part of the variable
+arguments of a function accepting a variable number of arguments.
+
+It is also possible to return a negative number @code{x}. In this case,
+the argument will be passed in register number @code{-x}, but also a
+stack-slot will be reserved for this argument (i.e. a @code{PUSH} IC
+without an operand will be generated). If @option{-double-push} is
+specified, the argument will also be written to the stack-slot (i.e.
+it will be passed twice, in a register and on the stack).
+
+@node regpairs
+@subsection Register Pairs
+
+Often, there are types which cannot be stored in a single machine register,
+but it may be more efficient to store them in two registers rather than
+in memory. Typical examples are integers which are bigger than the
+register size or architectures which combine two floating point registers
+into one register of double precision.
+
+To make use of register pairs, the line
+@example
+#define HAVE_REGPAIRS 1
+@end example
+has to be added to @file{machine.h}. The register pairs are declared
+as normal registers (each register pair counts as an own register and
+@code{MAXR} has to be adjusted). Usually only adjacent registers are
+declared as register pairs. Note that @code{regscratch} must be identical
+for both registers of a pair.
+
+Now the function
+@example
+int reg_pair(int r,struct rpair *p);
+@end example
+must be implemented. If register @code{r} is a register pair, the function
+has to set @code{p->r1} and @code{p->r2} to the first and second register
+which comprise the pair and return 1. Otherwise, zero has to be returned.
+
+
+@subsection Elimination of Frame-Pointer
+
+Local variables on the stack can usually be addressed via a so-called
+frame-pointer which is set set to current stack-pointer at the entry
+of a function. However, in the code generated by @command{vbcc}, the
+difference between the stack-pointer and the frame-pointer is fixed
+at any instruction.
+
+Therefore it is possible to keep track of this offset (by counting the
+bytes every time code for pushing or popping from the stack is generated).
+Using this offset, local variables can perhaps be addressed using the
+stack-pointer directly. Benefit would be smaller function entry/exit code
+as well as an additional free register which can be used for other
+purposes.
+
+Note that only few debuggers can handle such a situation.
+
+@subsection Delayed popping of Stack-Slots
+
+In most ABIs arguments which are pushed on the stack are not popped
+by the called function but the caller pops them by adjusting the stack
+after the callee returns (otherwise variable arguments would be hard
+to implement).
+
+If several functions are called in sequence, it is not necessary to
+adjust the stack after each call but the arguments for several calls
+can be popped at once. It can be implemented by keeping track of the
+size to be popped and deferring popping to a point where it has to be
+done (e.g. a label or a branch). Also, in the case of nested calls,
+care has to be taken to pop arguments at the right time.
+
+Note that this usually saves code-size and execution time but will
+increase stack-usage. Therefore, it may not be advisable for small systems.
+
+@subsection Optimized Return
+
+Return instructions are not explicitly represented in ICs. Rather, they are
+branches to a label which is the last IC in the list (except possible
+@code{FREEREG}s).
+
+It is possible to generate working code by translating
+these branches normally, but directly inserting the function exit code
+instead of a branch is often faster. It is most recommendable if the
+exit code is small (e.g. no registers have to be restored and no
+stack-frame removed).
+
+Another common possibility for optimization is a function call as the last
+IC. If return addresses are pushed on the stack and no function exit code
+is needed, it is usually possible to generate a jump-instruction, i.e.
+replace
+@example
+    call  somefunc
+    ret
+@end example
+by
+@example
+    jmp   somefunc
+@end example
+
+@node jumptables
+@subsection Jump Tables
+
+An important optimization is the creation of jump-tables for a series of
+comparisons with constants. Such series are usually created by a C
+@code{switch} construct, but vbcc can also recognize some of them if they
+are created through @code{if}-sequences.
+
+@file{supp.c} provides the function @code{calc_case_table(<IC>,<density>)}
+to check for constructs that can be replaced by a jump table. The arguments
+are the start IC to look for (it has to be a @code{COMPARE}-IC with a 
+constant as @code{q2}) and a minimal density. The density reflects the
+number of cases that are used divided by the range of cases. If the density
+is high, vbcc will use jump-tables only for sequences that have few unused
+cases inside. If the case tables occupy multiple ranges, vbcc is able to split
+them up and create multiple jump-tables.
+
+@code{calc_case_table} returns a pointer to a @code{struct case_table} with
+the following content:
+
+@table @code
+@item num
+The number of cases.
+
+@item typf
+The type of the case IDs.
+
+@item next_ic
+The first IC after the list of ICs that can be replaced by the jump-table.
+
+@item density
+The case density.
+
+@item vals
+The values of the case IDs (array containing @code{num} entries).
+
+@item labels
+The labels of the code corresponding to the case IDs
+(array containing @code{num} entries).
+
+@item min
+The lowest case ID.
+
+@item max
+The highest case ID.
+
+@item diff
+@code{max-min}.
+
+@end table
+
+If the backend decides to emit a jump-table, it has to generate code that
+will check that the control expression lies between @code{min} and @code{max}.
+If not, the jump-table must not be executed. Code for the computed jump
+must then be generated. The actual table can be emitted using
+@code{emit_jump_table()}. Processing can then continue with @code{next_ic}.
+
+@node targetralloc
+@subsection Context-sensitive Register-Allocation
+
+The @code{regok()} function is only a simple means of telling the
+register allocator which registers to use. It works fairly well with
+orthogonal register and instruction sets. However, it does not really
+care about the operations performed and it allocates variables to registers
+only according to their type, not according to the operations performed.
+
+Some architectures provide different kinds of registers which are able to
+store a type, but not all of them are able to perform all operations or some
+operations are more expensive with some registers. To do good register
+allocation for these systems, the operations which are used on variables
+have to be considered.
+
+If the backend wants to support this kind of register allocation, it has
+to define @code{HAVE_TARGET_RALLOC} and provide the following functions
+or macros:
+
+@table @code
+@item int cost_move_reg(int x,int y);
+The cost of copying register @code{x} to register @code{y}.
+@item int cost_load_reg(int r,struct Var *v);
+The cost of loading register @code{r} from variable @code{v}.
+@item int cost_save_reg(int r,struct Var *v);
+The cost of storing register @code{r} into variable @code{v}.
+@item int cost_pushpop_reg(int r);
+The cost of storing register @code{r} during function prologue and
+restoring it in the epilogue.
+@item int cost_savings(struct IC *p,int r,struct obj *o);
+Estimate the savings which would be obtained if the object @code{o}
+in IC @code{p} would be assigned to register @code{r} (in this IC). If the
+backend was not able
+to emit code in this case, @code{INT_MIN} must be returned.
+
+If @code{(o->flags & VKONST) != 0}, the register allocator is thinking
+about putting a constant (or address of a static variable) in a register.
+In this case, the real object which would be put in a register is found
+in @code{o->v->cobj}.
+@end table
+
+The unit of the costs can be chosen by the backend, but should be some
+reasonable small values.
+
+If @code{regok()} is called with a third parameter of -1, it is possible
+to return non-zero for a register which cannot perform all operations.
+The register allocator will call @code{cost_savings()} and returning
+@code{INT_MIN} can be used to prevent this register from being allocated,
+if the register is not suitable for a certain operation.
+
+
+@node regsmodified
+@subsection Inter-procedural Register-Allocation
+
+To support inter-procedural register allocation, the backend must tell the
+optimizer which registers are used by a function. As the backend might use
+some registers internally, the frontend can not know this.
+
+Apart from defining @code{HAVE_REGS_MODIFIED} in @file{machine.h}, the
+backend has to mark all registers that are modified in the bitfield
+@code{regs_modified}. A register can be marked with
+@code{BSET(regs_modified,<reg>)}. For a call IC, the function @code{calc_regs()}
+(from @file{supp.h}) can be called to mark the registers used by a call IC.
+It will return 1 if it was able to determine all registers used by this IC.
+
+If the register usage could be determined for the entire function, the
+backend can set the bit @code{ALL_REGS} in the fi-member of the function
+variable (@code{v->fi->flags|=ALL_REGS;}).
+
+
+@subsection Conditional Instructions
+
+FIXME: To be written.
+
+@node extic
+@subsection Extended ICs
+
+If the backend defines @code{HACE_EXT_IC}, it has to define a
+@code{struct ext_ic} in @file{machine.h}. This structure will be added
+to each IC and can be used by the backend for private use.
+
+@node asmpeephole
+@subsection Peephole Optimizations on Assembly Output
+
+Some optimizations are easier to do on the generated assembly code rather
+than doing them before emitting code. Therefore it is possible to do
+peephole optimizations on the emitted code before it is really
+written to a file.
+
+@code{EMIT_BUF_DEPTH} lines will be stored in a ring buffer and are available
+to examination and modification by a function @code{emit_peephole()}. The
+actual assembly output is stored in @code{emit_buffer}, the index of
+the first line to be output in @code{emit_f} and the index of the last one
+in @code{emit_l} (note that you have to calculate modulo @code{EMIT_BUF_DEPTH}
+- it is a ring buffer).
+
+The output may be modified in memory and the first line may be removed
+using @code{remove_asm()}. If a modification took place, a non-zero value
+has to be returned (0 otherwise). The following example code would combine
+two consecutive additions to the same register:
+@example
+int emit_peephole(void)
+@{
+  int entries,i,r1,r2;
+  long x,y;
+  /* pointer to the lines in order of output */
+  char *asmline[EMIT_BUF_DEPTH];
+  i=emit_l;
+  /* compute number of entries in ring buffer */
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  /* the first line */
+  asmline[0]=emit_buffer[i];
+  if(entries>=2)@{
+    /* we have at least two line sin the buffer */
+    /* calculate the next line (modulo EMIT_BUF_DEPTH) */
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+    if(sscanf(asmline[0],"\tadd\tR%d,#%ld",&r1,&x)==2&&
+       sscanf(asmline[1],"\tadd\tR%d,#%ld",&r2,&y)==2&&
+       r1==r2)@{
+      sprintf(asmline[1],"\tadd\tR%d,#%ld\n",r1,x+y);
+      remove_asm();
+      return 1;
+    @}
+  @}
+  return 0;                                                                    
+@}
+@end example
+
+Be very careful when doing such optimizations. Only perform optimizations
+which are really legal. Especially assembly code often has side effects
+like setting of flags.
+
+Depending on command line flags inline assembly code may or may not be
+passed through this peephole optimizer. By default, it will be done,
+enabling optimizations between generated code and inline assembly.
+
+
+@node markeffics
+@subsection Marking of efficient ICs
+
+If the backend sets @code{HAVE_EFF_ICS} in @file{machine.h}, it has to
+provide a function @code{void mark_eff_ics(void)}. This function will be
+called (possibly multiple times) by the frontend. The function has to set
+or clear the bit @code{EFF_IC} in the member @code{flags} of every IC.
+
+The flag should be set when the operation is in a context that suggests
+it will translate to efficient machine code. The optimizer will transform
+this IC less aggressively.
+
+As this is all happens before register allocation, the decision is of a very
+heuristic nature.
+
+@subsection Function entry/exit Code
+
+At entry and exit of function, there is usually some code to set up
+the new environment for this function. For example, registers will
+have to be saved/restored, a frame pointer may be set up and a stack
+frame will be created. It is generally worthwile to optimize this 
+entry/exit code. For example, if no registers need to be saved and no
+local variables are used on the stack, it may not be necessary to
+create a stack frame.
+
+The exact possibilities for optimization depend on the architecture and the
+ABI.
+
+
+@subsection Multiplication/division with Constants
+
+Many architectures do not provide instruction for multiplication,
+division or modulo calculation. And on most architectures providing
+such instructions they are rather slow. Therefore, it is recommended
+to emit cheaper instructions, if possible.
+
+Usually, this can only be done if one operand of the operation is a
+constant. Multiplications may be replaced by a series of shift and
+add instructions, for example. The simplest and most important cases
+to replace are multiplication, division and modulo with a power of two.
+Multiplication by x can be replaced by a left shift of log2(x),
+unsigned division of x can be replaced by logical right shift of log2(x)
+and unsigned modulo by x can be replaced by anding with x-1.
+
+Note that
+signed division and modulo can usually not be replaced that simple because
+most division instructions give different results for some negative
+values. An additional adjustment would be necessary to get correct results.
+Whether this is still an improvement, depends on the architecture details.
+
+The following function can be used to test whether a value is a power of
+two:
+@example
+static long pof2(zumax x)
+/*  Yields log2(x)+1 or 0. */
+@{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x))@{
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  @}
+  return 0;
+@}
+@end example
+
+@subsection Block copying
+
+There are many cases of copying of larger data. For the backend, those
+will mostly be used in @code{PUSH} and @code{ASSIGN} ICs. It is very
+important to implement those as efficient as possible.
+
+Some things to consider:
+
+@itemize @minus
+@item When alignment is known, use word-copy instead of byte-copy.
+
+@item Copy small blocks by a series of copy instructions.
+
+@item For larger blocks, loading addresses in registers may help.
+
+@item For large blocks, use a loop. Implement it efficiently and try to
+unroll the loop a few times.
+
+@item For very large blocks, calling a library function may be useful. While
+this creates some overhead, the function can dynamically check the alignment
+or perhaps even use special hardware, if available.
+
+@item Set @code{INLINEMEMCOPY} to reasonable values. Set it to a very high
+value if you implement very good block copying.
+
+@end itemize
+
+
+@subsection Optimized Library Functions
+
+FIXME: To be written.
+
+@subsection Instruction Scheduler
+
+FIXME: To be written.
+
+
+@section Hints for common Extensions
+
+This section lists some common extensions to the C language which are
+often very helpful when using a compiler in practice. Depending on the
+kind of target system they may range from nobody-really-cares to
+absolutely essential. For example, consider the ability to specify the section
+within an object file a variable or function should be placed in. This is
+rarely of any interest when targeting a Unix-like operating system. On
+a stand-alone embedded system, however, it may be absolutely necessary.
+
+Therefore, consider this list as a recommendation of ideas that might
+be helpful.
+
+@subsection Inline Assembly
+
+The possibility to insert assembly code into C source is very handy in
+many cases. It can be used in headers to implement specially optimized
+versions of time-critical library routines or enable access to CPU
+features which are not otherwise accessible by normal C constructs.
+
+In general, almost all work is done by the frontend and only a few lines
+have to be inserted in the backend to make it work. Therefore, it is
+recommended to always support this important feature.
+
+Everything that has to be done is to check a certain condition when code for
+a @code{CALL} IC is generated. Instead of emitting a normal call instruction,
+call the @code{emit_inline_asm()} function:
+@example
+if((p->q1.flags & (VAR|DREFOBJ)) == VAR &&
+    p->q1.v->fi &&
+    p->q1.v->fi->inline_asm)@{
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+    @}else@{
+        emit(f,"\tcall\t");
+        emit_obj(f,&p->q1,t);
+        emit(f,"\n");
+    @}
+@end example
+Note that argument-passing, adjusting the stack after a @code{CALL} IC etc.
+is not affected. Only the actual emitting of call code is changed in the
+case of inline assembly.
+
+@subsection -speed/-size
+
+Often it is desired to generate code which runs as fast as possible
+but sometimes small code is needed. The command line options
+@option{-speed} and @option{-size} are provided for the user to specify
+his intention.
+
+These options already may change the intermediate code produced by the
+frontend, but the backend should also respect these switches, if possible.
+The variables @code{optspeed} and @code{optsize} can be queried to see
+if these options were specified.
+
+If e.g. @code{optspeed} was specified, the backend should choose faster
+code-sequences, even if code-size is increased significantly. Vice-versa,
+if @code{optsize} is specified, it should always choose the shorter code
+if there is a trade-off between size and speed.
+
+Typical cases for such tradeoffs are for example, block-copy (@code{ASSIGN}
+and @code{PUSH}) ICs. Often it is possible to call a library function or
+generate a simple short loop for small code, but an unrolled inlined loop
+for fast code.
+
+@node targetmacros
+@subsection Target-specific Macros
+
+A backend is able to provide macro definitions which are automatically
+active. It is recommended to define macros which allow applications to
+query the target architecture and the selected chip (if possible).
+Also, it is recommended to provide internal macros for backend specific
+attributes using the @code{__attr()} and @code{__vattr()} attributes.
+
+The definition of these macros can be done in @code{init_cg()} (the
+results of command line parsing are available at this point). There is
+a variable
+@example
+char **target_macros;
+@end example
+which can be set to an array of pointers to strings which contain the
+macro definitions. The array has to be terminated by a null pointer and
+the syntax of the macro definitions is similar to the command line
+option @option{-D}:
+@example
+static char *marray[] = @{
+  "__TARGET_ARCH__",
+  "__section(x)=__vattr(\"section(\"#x\")\")",
+  0
+@};
+...
+target_macros = marray;
+@end example
+
+@subsection stdarg.h
+
+FIXME: To be written.
+
+
+@subsection Section Specifiers
+
+Especially for embedded systems it can be very important to be able to
+place variables and functions in specific section to override default
+placement. This can relatively easily be done using variable attributes
+(@pxref{targetattributes}).
+
+
+@node targetattributes
+@subsection Target-specific Attributes
+
+There are two ways of adding target-specific attributes to variables and
+functions. A general way is the use of @code{__vattr()} which will add
+the string argument to the @code{vattr} member of the corresponding
+@code{struct Var}, separating it by a semi-colon. The backend can use
+this information by parsing the string. The frontend will just build
+the string, it will not interpret it. If a backend offers attributes
+using the @code{__vattr()} mechanism, it is recommended to provide
+target-specific macros (@pxref{targetmacros}) which expand to the
+appropriate @code{__vattr()}-syntax. Only these macros should be
+documented.
+
+A second way to specify attributes is enabled by adding
+@example
+#define HAVE_TARGET_PRAGMAS 1
+@end example
+to @file{machine.h} and adding an array
+@example
+char *g_attr_name[];
+@end example
+to @file{machine.c}. This array should point to the strings used
+for the attributes, terminated by a null-pointer, e.g.:
+@example
+char *g_attr_name[] = @{
+  "__far",
+  "__near",
+  "__interrupt",
+  0
+@};
+@end example
+These attributes can be queried in the member
+@example
+unsigned long tattr;
+@end example
+of a @code{struct Var}. The first attribute is represented by bit 1, the
+second by bit 2 and so on. Using this mechanism, the frontend will check for
+redeclarations with different setting of attributes or multiple specification
+of attributes. However, only boolean attributes are possible. If parameters
+have to be specified, the @code{__vattr()}-mechanism has to be used.
+
+@node targetpragmas
+@subsection Target-specific @code{#pragma}s
+
+FIXME: To be written.
+
+@node exttypes
+@subsection Target-specific extended Types
+
+FIXME: To be written.
+
+@node tgtprintval
+@subsection Target-specific @code{printval}
+
+FIXME: To be written.
+
+@node debuginfo
+@subsection Debug Information
+
+Debug information which enables (source level) debugging of compiled
+programs is an important feature to improve the user-friendliness of a
+compiler. Depending on the object format and debugger used, the format
+and capabilities of debug information can vary widely. Therefore, it is
+the responsibility of each backend to generate debug information. However,
+for common debug standards there will be modules which can be used by
+the backends and will do most of the work. Currently there is one such
+module for the DWARF2 debug standard.
+
+The compiler frontend provides a variable @code{debug_info} which can
+be queried to test whether debug information is desired. Also, the
+functions @code{init_db()} and @code{cleanup_db()} are helpful.
+
+Each @code{struct Var} contains the members @code{char *dfilename} and
+@code{int dline} which specify the file and line number of the variable's
+definition. Also, every IC contains the members @code{char *file} and
+@code{int line} with the file name and line number this IC belongs to. Note
+however, that there may be ICs with @code{file == 0} - not all ICs can
+be assigned a certain code location. Also, ICs do not always have increasing
+line numbers and line numbers may repeat. Not all debuggers may be able
+to deal with this.
+
+@subsubsection DWARF2
+
+There is support for the DWARF2 debug standard which can be added to a backend
+rather easily. The following additions are necessary:
+
+@enumerate
+@item Add the line
+@example
+#include "dwarf2.c"
+@end example
+to @file{machine.c}.
+@item Add the following lines to @code{init_db()}:
+@example
+dwarf2_setup(sizetab[POINTER],
+             ".byte",
+             ".2byte",
+             ".4byte",
+             ".4byte",
+             labprefix,
+             idprefix,
+             ".section");
+dwarf2_print_comp_unit_header(f);
+@end example
+The arguments to @code{dwarf2_setup()} have the following meanings:
+@enumerate
+@item The size of an address on the target.
+@item An assembler directive to create one byte of initialized storage.
+@item An assembler directive to create two bytes of initialized storage
+      (without any padding for alignment).
+@item An assembler directive to create four bytes of initialized storage
+      (without any padding for alignment).
+@item An assembler directive to create initialized storage representing
+      a target address (without any padding for alignment).
+@item A prefix which is used for emitting numbered labels (or empty string).
+@item A prefix which is used for emitting external identifiers
+      (or empty string).
+@item An assembler directive to switch to a new named section.
+@end enumerate
+@item Add the line
+@example
+dwarf2_cleanup(f);
+@end example
+to @code{cleanup_db()}.
+@item Write the function
+@example
+static int dwarf2_regnumber(int r);
+@end example
+which
+      returns the DWARF2 regnumber for a @command{vbcc} register number.
+@item Write the function
+@example
+static zmax dwarf2_fboffset(struct Var *v);
+@end example
+      which returns the offset of variable @code{v} from the DWARF2
+      frame-pointer.
+@item Write the function
+@example
+static void dwarf2_print_frame_location(FILE *f,struct Var *v);
+@end example
+which prints a DWARF2 location of the frame pointer. It can use the
+function
+@example
+void dwarf2_print_location(FILE *f,struct obj *o);
+@end example
+to output the location. For example, if the frame pointer is a simple
+register, it might look like this:
+@example
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+@{
+  struct obj o;
+  o.flags=REG;
+  o.reg=frame_pointer_register;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+@}
+@end example
+@item Before emitting code for an IC @code{p}, execute the code
+@example
+if(debug_info)
+  dwarf2_line_info(f,p);
+@end example
+@item After emitting code for a function @code{v}, a new numbered label
+      has to be emitted after the function code and the function
+@example
+void dwarf2_function(FILE *f,struct Var *v,int endlabel);
+@end example
+must be called.
+
+@end enumerate
+
+Note that the DWARF2 standard supports use of location lists which can be
+used to describe a variable whose location changes during the program (e.g.
+in a register for some time, then in memory and again in a register) as well
+as a moving frame pointer (very useful if no separate frame pointer is used
+but all local variables are accessed through a moving stack pointer).
+Unfortunately, none of the debuggers I have tried so far could handle these
+location lists. Therefore, the current DWARF2 module does not output
+location lists, but future version will probably offer them as an option.
+
+Without location lists, accessing local variables will only work with
+a fixed frame pointer and no register variables. Even with these restrictions,
+function parameters which are passed in registers will not be correctly
+displayed during the function entry code.
+
+@subsection Interrupt Handlers
+
+Especially for embedded systems, support for writing interrupt handlers in
+C is a common feature. Variable attributes (@pxref{targetattributes}) can
+be used to mark functions which are used as interrupt handlers.
+
+Typical changes which might be necessary for interrupt handlers are:
+@itemize @minus
+@item Using a different return instruction.
+@item Saving all modified registers, including scratch-registers.
+@item Creating an entry in the interrupt vector table.
+@end itemize
+
+
+@subsection Stack checking
+
+Dynamic checking of the stack used (or possibly extending the stack size
+if possible) is another useful feature. If the variable @code{stack_check}
+is set, stack-checking code should be emitted, if possible. Every function
+should call a library function (usually called @code{__stack_check}) and
+pass the maximum size of stack used in this function as argument. This
+obviously has to be done before allocating the stack-frame.
+
+The library function is responsible to take into account its own
+stack-frame.
+
+@subsection Profiling
+
+FIXME: To be written.
+
+@node{vlas}
+@subsection Variable-length Arrays
+
+With the @code{-c99} option, vbcc supports variable-length arrays that
+are allocated on the stack. The backend has to take several steps to
+support this:
+
+@table @code
+@item vlas
+When this variable is non-zero, the current function uses variable-length
+arrays. The backend may take necessary steps to support this. For example,
+if local variables are usually addressed via stackpointer, switching to a
+separate framepointer may be necessary.
+
+@item ALLOCVLA_INLINEASM
+This define must contain inline code that is called when a vla is
+allocated. It has to create additional room on the stack and return a
+pointer to the beginning of the new space.
+
+@item ALLOCVLA_REG
+The register in which to pass the size to be allocated on the stack. 0 will
+pass on the stack.
+
+@item FREEVLA_INLINEASM
+This define must contain inline code that is called when a vla is
+freed. It has to restore the old stack pointer.
+
+@item FREEVLA_REG
+The register in which to pass the old stack pointer. 0 will
+pass on the stack.
+
+@item OLDSPVLA_INLINEASM
+This define must contain inline code that is called before the first vla is
+allocated. It has to return the current stack pointer before any vla has
+been allocated.
+
+@item FPVLA_REG
+An additional register used in functions containing vlas. The backend can
+specify a register (usually framepointer) that can not be used in functions
+with vlas. Therefore, it is possible to use this register in other functions
+(for example, if local variables are usually addressed directly through the
+stackpointer).
+
+@end table
+
+@node{libcalls}
+@subsection Library Calls
+
+Sometimes operations may be very complicated to generate code for (e.g.
+floating-point operations for machines without FPU, multiplication/division
+on some architectures or big data types like @code{long long}). Those are
+usually implemented by calling library functions.
+
+vbcc can be told to generate calls to library functions for certain ICs. When
+defining @code{HAVE_LIBCALLS}, the backend must provide the function
+@code{char *use_libcall(<code>,<typf>,<typf2>)}. This function gets
+called with the elements @code{code}, @code{typf} and @code{typf2} of an IC.
+If @code{use_libcall} returns a name, this library function will be called
+instead of the IC. Otherwise, 0 must be returned.
+
+All library functions have to be declared in @code{init_cg()} with
+@code{declare_builtin()}, supporting the following arguments:
+
+@table @code
+
+@item name
+The name of the library function. Usually, a reserved identifier should be
+chosen (e.g. starting with @code{__}).
+
+@item ztyp
+The return type of the function (only integral and float types are supported).
+
+@item q1typ
+The type of the first parameter (only integral and float types are supported).
+
+@item q1reg
+The register to pass the first argument in (0 passes via stack).
+
+@item q2typ
+The type of the second parameter (only integral and float types are supported).
+For functions with a single parameter, use 0.
+
+@item q2reg
+The register to pass the second argument in (0 passes via stack).
+
+@item nosidefx
+If this is non-zero, the function will be declared to have no side-effects
+and allow some more optimizations.
+
+@item inline_asm
+Inline assembly can be specified for the function.
+
+@end table
+
+Note that not all ICs can be converted to library calls.
+
+
+@section Changes from 0.7 Interface
+
+The backend interface has changed in several ways since @command{vbcc} 0.7.
+The following list mentions most(all?) differences between the old
+and new interfaces (not including new optional features which do not have
+to be used):
+
+@itemize @minus
+@item There are more types (@code{LLONG, LDOUBLE, MAXINT}). Therefore
+      the @code{align[]} and @code{sizetab[]} arrays have dimension
+      @code{MAX_TYPES+1} rather than 16.
+@item The representation and access of @code{t_min[]} and @code{t_max[]}
+      has been changed.
+@item @code{zmax} replaces @code{zlong} as largest integer target
+      type. @code{zlong} is only used when actually referring to a
+      @code{long} on the target. Also, the macros for target arithmetic
+      are available for @code{zmax/zumax} instead of @code{zlong/zulong}.
+@item @code{PUSH} ICs contain a second size (actual stack-adjustment).
+@item The second argument of @code{SHIFT} ICs has an own type.
+@item @code{DREFOBJ} objects contain the type of the dereferenced pointer
+      (only meaningful if there are different pointer types).
+@item The new @code{CONVERT} IC replaces the series of old ICs
+      (@code{CONVINT} etc.).
+@item @code{emit()}-functions have to be used to generate output rather
+      than @code{fprintf()}.
+@item The functions @code{init_db()} and @code{cleanup_db()} have to be
+      provided (they do not have do to anything).
+@item A new array @code{reg_prio[]} is needed and controls the order
+      in which registers are allocated.
+@item The parameters of @code{must_convert()} have changed.
+@item Static functions must not use identifiers, but have to use numbered
+      labels.
+
+@end itemize
+
+Volker Barthelmann                                      vb@@compilers.de
+
diff --git a/doc/ucpp.texi b/doc/ucpp.texi
new file mode 100755
index 0000000..6a8821d
--- /dev/null
+++ b/doc/ucpp.texi
@@ -0,0 +1,40 @@
+vbcc contains the C preprocessor ucpp by Thomas Pornin.
+
+Attached is the copyright notice from the ucpp-distribution (note that
+apart from ucpp no other part of this distribution falls under this
+license).
+
+
+Volker Barthelmann                                      vb@compilers.de
+
+
+-------------- 
+
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/doc/vbcc.texi b/doc/vbcc.texi
new file mode 100644
index 0000000..1ccfeaa
--- /dev/null
+++ b/doc/vbcc.texi
@@ -0,0 +1,461 @@
+\ifx\pdfminorversion\undefined
+ \pdfoptionpdfminorversion=3
+\else
+ \pdfminorversion=3
+\fi
+\input texinfo
+
+@setfilename index.texi
+@settitle vbcc manual
+@setchapternewpage odd
+@set UPDATED February 2022
+
+@ifinfo
+
+This is the manual for the vbcc compiler system.
+
+Copyright 1995-2022 Volker Barthelmann
+
+@end ifinfo
+
+@titlepage
+@title vbcc compiler system
+@author Volker Barthelmann
+@subtitle @value{UPDATED}
+
+@page
+
+@end titlepage
+
+@paragraphindent 0
+
+@contents
+
+@chapter General
+
+@section Introduction
+
+    vbcc is a highly optimizing portable and retargetable ISO C compiler.
+    It supports ISO C according to ISO/IEC 9899:1989 and a subset of the
+    new standard ISO/IEC 9899:1999 (C99).
+
+    It is split into a target-independent and a target-dependent part, and
+    provides complete abstraction of host- and target-arithmetic. Therefore,
+    it fully supports cross-compiling for 8, 16, 32 and 64bit architectures.
+
+    Embedded systems are supported by features like different pointer-sizes
+    (e.g. differently sized function- and object-pointers or near- and
+    far-pointers), ROM-able code, inline-assembly, bit-types,
+    interrupt-handlers, section-attributes, stack-calculation and many
+    others (depending on the backend).
+
+    vbcc provides a large set of aggressive high-level optimizations
+    (@pxref{Optimizations})
+    as well as target-specific optimizations to produce faster or smaller
+    code. Rather than restricting analysis and optimization to single
+    functions or files, vbcc is able to optimize across functions and
+    even modules. Target-independent optimizations include:
+
+@itemize @minus
+    @item cross-module function-inlining
+    @item partial inlining of recursive functions
+    @item inter-procedural data-flow analysis
+    @item inter-procedural register-allocation
+    @item register-allocation for global variables
+    @item global common-subexpression-elimination
+    @item global constant-propagation
+    @item global copy-propagation
+    @item dead-code-elimination
+    @item alias-analysis
+    @item loop-unrolling
+    @item induction-variable elimination
+    @item loop-invariant code-motion
+    @item loop-reversal
+@end itemize
+
+
+@section Legal
+
+    vbcc is copyright in 1995-2022 by Volker Barthelmann.
+
+    This archive may be redistributed without modifications and used
+    for non-commercial purposes.
+
+    An exception for commercial usage is granted, provided that the target
+    CPU is M68k and the target OS is AmigaOS. Resulting binaries may be
+    distributed commercially without further licensing.
+
+    An exception for commercial usage is granted, provided that the target
+    CPU is 6502 with MEGA65 extensions and the target HW is MEGA65.
+    Resulting binaries may be
+    distributed commercially without further licensing.
+
+    In all other cases you need my written consent.
+
+    This copyright applies to vc, vbcc, vsc and vcpr.
+
+    This archive may contain other tools (e.g. assemblers or linkers)
+    which do not fall under this license. Please consult the corresponding
+    documentation of these tools.
+
+    vbcc contains the preprocessor ucpp by Thomas Pornin. Included is the
+    copyright notice of ucpp (note that this license does not apply to vbcc
+    or any other part of this distribution):
+
+@example
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+@end example
+
+
+@section Installation
+
+The vbcc directory tree looks as follows:
+
+@table @file
+
+@item vbcc/bin
+                The executables.
+
+@item vbcc/config
+                Config files for the frontend.
+
+@item vbcc/targets/<target>
+                Subdirectory containing all files specific to a certain
+                target (e.g. m68k-amigaos or ppc-eabi).
+@end table
+
+@subsection Installing for Unix
+
+    @enumerate
+
+    @item Extract the archive.
+
+    @item Set the environment variable @env{VBCC} to the vbcc directory.
+        Depending on your shell this might be done e.g. by
+
+        @example
+        VBCC=<prefix>/vbcc
+        @end example
+
+        or
+
+        @example
+        setenv VBCC <prefix>/vbcc
+        @end example
+
+    @item Include <prefix>/vbcc/bin to your search-path. Depending on your
+        shell this might be done e.g. by
+
+        @example
+        PATH=<prefix>/vbcc/bin:"$PATH"
+        @end example
+
+        or
+
+        @example
+        setenv PATH <prefix>/vbcc/bin:"$PATH"
+        @end example
+
+    @end enumerate
+
+
+@subsection Installing for DOS/Windows
+
+    @enumerate
+
+    @item Extract the archive.
+
+    @item Set the environment variable @env{VBCC} to the vbcc directory.
+
+        @example
+        set VBCC=<prefix>\vbcc
+        @end example
+
+    @item Include <prefix>/vbcc/bin to your search-path.
+
+        @example
+        set PATH=<prefix>\vbcc\bin;%PATH%
+        @end example
+
+    @end enumerate
+
+
+@subsection Installing for AmigaOS
+
+    There is an Amiga Installer, which lets
+    you install the binary and target archives with a simple mouse click.
+    @command{vbcc} for AmigaOS/MorphOS is divided into the following
+    packages:
+
+    @table @file
+    @item vbcc_bin_amigaos68k
+	Binaries for AmigaOS 2.x/3.x (68020+).
+    @item vbcc_bin_amigaosppc
+	Binaries for AmigaOS 4.x (PowerPC).
+    @item vbcc_bin_morphos
+	Binaries for MorphOS (PowerPC).
+    @item vbcc_bin_powerup
+	Additional PPC-native binaries using the PowerUp kernel for
+	AmigaOS 3.x.
+    @item vbcc_bin_warpos
+	Additional PPC-native binaries using the WarpOS kernel for
+	AmigaOS 3.x.
+    @item vbcc_target_m68k-kick13
+	Header files and libraries for AmigaOS 1.x/M68k.
+    @item vbcc_target_m68k-amigaos
+	Header files and libraries for AmigaOS 2.x/3.x/M68k.
+    @item vbcc_target_ppc-amigaos
+	Header files and libraries for AmigaOS 4.x.
+    @item vbcc_target_ppc-morphos
+	Header files and libraries for MorphOS.
+    @item vbcc_target_ppc-powerup
+	Header files and libraries for PowerUp.
+    @item vbcc_target_ppc-warpos
+	Header files and libraries for WarpOS.
+    @end table
+   
+    Usually you will install the binary archive for your host architecture
+    of choice, then add as many target archives you need.
+
+    When installing manually it is recommended to add the following
+    assigns to your @file{s:User-Startup} file (only do the assignments
+    required for the installed targets): 
+
+@example
+assign >NIL: vbcc: <path to vbcc directory>
+assign >NIL: C: vbcc:bin add
+ 
+assign >NIL: vincludeos1: vbcc:targets/m68k-kick13/include
+assign >NIL: vincludeos1: <path to your Kickstart 1.x header files> ADD
+assign >NIL: vlibos1: vbcc:targets/m68k-kick13/lib
+
+assign >NIL: vincludeos3: vbcc:targets/m68k-amigaos/include
+assign >NIL: vincludeos3: <path to your AmigaOS3 header files> ADD
+assign >NIL: vlibos3: vbcc:targets/m68k-amigaos/lib
+
+assign >NIL: vincludeos4: vbcc:targets/ppc-amigaos/include
+assign >NIL: vincludeos4: <path to your AmigaOS4 header files> ADD
+assign >NIL: vlibos4: vbcc:targets/ppc-amigaos/lib
+
+assign >NIL: vincludemos: vbcc:targets/ppc-morphos/include
+assign >NIL: vincludemos: <path to your MorphOS header files> ADD
+assign >NIL: vlibmos: vbcc:targets/ppc-morphos/lib
+
+assign >NIL: vincludepup: vbcc:targets/ppc-powerup/include
+assign >NIL: vincludepup: <path to your PowerUp header files> ADD
+assign >NIL: vincludepup: <path to your AmigaOS3 header files> ADD
+assign >NIL: vlibpup: vbcc:targets/ppc-powerup/lib
+
+assign >NIL: vincludewos: vbcc:target/ppc-warpos/include
+assign >NIL: vincludewos: <path to your WarpOS header files> ADD
+assign >NIL: vincludewos: <path to your AmigaOS3 header files> ADD
+assign >NIL: vlibwos: vbcc:target/ppc-warpos/lib
+
+@end example
+
+    Also, the stack-size has to be increased from the default, for those
+    binaries which don't do that automatically (e.g. AmigaOS4).
+    64KB is a sensible value, for very large projects higher
+    values might be necessary.
+
+    For writing AmigaOS/MorphOS programs you will need the appropriate
+    system header files. Please use NDK 3.9 or later for AmigaOS 2.x/3.x, as
+    the proto/inline headers have been created with it.
+
+    For AmigaOS 1.x you should use the old Kickstart 1.x headers from that
+    time. It makes sure that you don't use a feature of later OS releases.
+
+    There are different configuration files provided in the
+    @file{config}-subdirectory to choose different targets (i.e.
+    the system you want to generate programs for) and hosts
+    (i.e. the system you want the compiler an tools to run on).
+    The general naming-scheme for these files is <target>_<host>.
+
+    Available config files, when all targets are installed, are
+@table @file
+@item aos68k
+    AmigaOS 2.x/3.x.
+@item aos68km
+    AmigaOS 2.x/3.x with minimal startup code.
+@item aos68kr
+    AmigaOS 2.x/3.x for resident programs.
+@item kick13
+    AmigaOS 1.x.
+@item kick13m
+    AmigaOS 1.x with minimal startup code.
+@item kick13r
+    AmigaOS 1.x for resident programs.
+@item aosppc
+    AmigaOS 4.x on PPC using vclib.
+@item newlib
+    AmigaOS 4.x on PPC using newlib.
+@item morphos
+    PPC systems running MorphOS.
+@item powerup
+    PPC boards using the PowerUp system.
+@item warpos
+    PPC boards using the WarpOS system.
+@end table
+
+    You can choose one of these systems using the @option{+}-option
+    of @command{vc}, e.g.
+
+@example
+    vc +aos68k_powerup ...
+@end example
+
+    will compile for AmigaOS/68k using the compiler running on PowerUp.
+
+    You may choose to create copies of some of these configuration
+    files with simpler names. E.g. if you usually want the compiler
+    to run on WarpOS you could copy @file{aos68k_warpos} to @file{aos68k},
+    @file{warpos_warpos} to @file{warpos} and so on. Then you can just specify
+    the target and your preferred host system will be chosen automatically.
+
+    Additionally, you may copy the configuration file for your preferred
+    host/target-combination to
+    @file{vc.config}. This configuration will be chosen by default if
+    you do not specify anything.
+
+    By default, the target-only-specifications use 68020-native tools on
+    AmigaOS 2.x/3.x - e.g. @option{+warpos} will create code for WarpOS,
+    but the compiler and tools will run on the 68k. The default
+    @file{vc.config} will then create code for 68k using tools running
+    on 68k. Having installed the MorphOS-native binary archive instead,
+    the default @file{vc.config} will create PPC code for MorphOS using
+    tools running on MorphOS.
+
+@section Tutorial
+
+    Now you should be able to use vbcc. To compile and
+    link the program @file{hello.c}, type
+ 
+@example
+        vc hello.c
+@end example
+ 
+    The file @file{hello.c} will be compiled and linked, using the
+    default configuration from @file{vc.config}, to create
+    the executable a.out in the current directory.
+
+@example
+        vc hello.c -o hello
+@end example
+ 
+    will do the same, but the created executable will be called @file{hello}.
+ 
+@example
+        vc -c t1.c t2.c
+@end example
+ 
+    will compile @file{t1.c} and @file{t2.c} without linking, creating the
+    object files @file{t1.o} and @file{t2.o}.
+ 
+@example
+        vc t1.o t2.o -o tt
+@end example
+ 
+    will link them together and create the executable @file{tt}.
+ 
+    If your program uses floating point, you may have to link with a
+    math-library. The details are dependent on the target, but usually
+    @option{-lm} will be suitable (for AmigaOS on m68k choose one of
+    @option{-lmieee}, @option{-lm881}, @option{-lm040} or @option{-lm060}).
+
+@example 
+        vc calc.c -o calc -lm
+@end example
+
+
+@node The Frontend
+@chapter The Frontend
+@include vc.texi
+
+@node The Compiler
+@chapter The Compiler
+@include vbcc_main.texi
+
+
+@node M68k/Coldfire Backend
+@chapter M68k/Coldfire Backend
+@include vbccm68k.texi
+
+@node PowerPC Backend
+@chapter PowerPC Backend
+@include vbccppc.texi
+
+@node DEC Alpha Backend
+@chapter DEC Alpha Backend
+@include vbccalpha.texi
+
+@node i386 Backend
+@chapter i386 Backend
+@include vbcci386.texi
+
+@node c16x Backend
+@chapter c16x Backend
+@include vbccc16x.texi
+
+@node 68hc12 Backend
+@chapter 68hc12 Backend
+@include vbcchc12.texi
+
+@node VideoCore IV Backend
+@chapter VideoCore IV Backend
+@include vbccvidcore.texi
+
+@node 6502 Backend
+@chapter 6502 Backend
+@include vbcc6502.texi
+
+
+@node Instruction Scheduler
+@chapter Instruction Scheduler
+@include vsc.texi
+
+@node Code Compressor
+@chapter Code Compressor
+@include vcpr.texi
+
+@node C Library
+@chapter C Library
+@include vclib.texi
+
+@node List of Errors
+@chapter List of Errors
+
+@enumerate 0
+@include errors.texi
+@end enumerate
+
+@chapter Backend Interface
+@include interface.texi
+
+@bye
diff --git a/doc/vbcc6502.texi b/doc/vbcc6502.texi
new file mode 100644
index 0000000..e79bdaa
--- /dev/null
+++ b/doc/vbcc6502.texi
@@ -0,0 +1,517 @@
+This chapter documents the backend for the 6502
+processor family.
+
+@section Additional options
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -c02
+    @item -65c02
+              Generate code using 65C02 extensions.
+
+    @item -ce02
+              Generate code using CSG 65CE02/4510 extensions.
+
+    @item -mega65
+              Generate code using the MEGA65 extensions.           
+
+    @item -m65io
+              When using the MEGA65 multiplier/divider, assume that the IO area
+              is directly accessible to generate smaller and faster code.
+
+    @item -div-bug
+              Do not generate code using the MEGA65 divider as this is buggy in
+              early versions.
+
+    @item -std-syntax
+              Generate code for the std syntax module of vasm rather than
+              the default oldstyle syntax module.
+
+    @item -cbmascii
+              Convert string-constants and character-constants to CBM ASCII.
+
+    @item -atascii
+              Convert string-constants and character-constants to Atari ASCII.
+
+    @item -ieee
+              Use 32/64bit IEEE format for floating point rather than wozfp format.
+
+    @item -softstack
+              Try to use the hardware stack as little as possible. Use this if your
+              hardware stack is overflowing.
+
+    @item -mainargs
+              Some targets may need special initializations when using the command
+              line arguments to main(). vbcc will emit a call to a library function
+              when those are used and @code{-mainargs} is specified.
+
+    @item -no-bank-vars
+              Do not automatically handle accesses to banked variables, but only
+              function calls. See chapter on banking.
+
+    @item -manual-banking
+              Do not automatically handle banking. Useful if you want to use the
+              section mapping of the @code{__bank}-attribute or @code{#pragma bank}
+              but you prefer handle bank switching yourself.
+
+    @item -avoid-bank-switch
+              Prefer calling @code{__bankload/__bankstore} instead of @code{__bankswitch}.
+              Useful for banking mechanisms that do not provide quick switching
+              of an entire bank (e.g. the C64 REU).
+
+    @item -common-banknr=<n>
+              Specify the bank number of the common bank. See chapter on banking. The
+              default number is 0.
+
+    @item -large
+              Use large memory model. All pointers will be far pointers. A corresponding
+              library is required. This feature is experimental.
+
+    @item -glob-acc
+              By default, the register allocator will only assign temporary
+              variables to the accumulator register or @code{a/x} register pair.
+              Usually this reduces necessary storing/loading of the accumulator
+              as it is needed during most operations. This option allows the
+              register allocator to assign variables with bigger live ranges to
+              the accumulator. This option is likely to create worse code in
+              most cases. Use only for experimentation.
+
+@end table
+
+@section ABI
+
+    The current version generates assembler output for use with 
+    @command{vasm6502_oldstyle} or  @command{vasm6502_std}. 
+    The option @command{-opt-branch} is needed.
+
+    The register names provided by this backend are:
+
+@example
+        a, sp, r0..r31, btmp0..btmp3
+@end example
+
+        @code{a} is the accumulator. It can be used for type @code{char}.
+
+        @code{r0} ... @code{r31} are 8bit variables that can be used for type
+        @code{char}. They have to be mapped
+        to zero page during linking. The compiler expects registers that can
+        be used as register pairs (see below) to be mapped to contiguous
+        memory locations. Some library routines may have additional requirements.
+
+        @code{sp} is a 16bit variable that has to be mapped to zero page. It is
+        used by the compiler and not available for use. @code{sp} must be
+        initialized to a suitable memory area. This stack is used for local variables,
+        saved registers etc. The hardware stack is used mainly for return addresses
+        and sometimes saved registers.
+
+        @code{btmp0}..@code{btmp3} are 32bit variables. The code generated by vbcc
+        does not require them in zero page, but the current library implementation
+        expects them to be located to contiguous zero page locations.
+
+        The following register pairs can be used for
+        16bit values.
+
+@example
+        a/x, r0/r1, r2/r3 ... r30/r31
+@end example        
+
+       @code{a/x} can be used for types @code{short} and @code{int}, the other
+       register pairs can also be used for pointer types.
+
+        The following register pairs can be used for
+        64bit values (IEEE doubles or long long).
+
+@example
+        btmp0/btmp1, btmp2/btmp3
+@end example         
+
+
+       Registers @code{a, r0..r15, r28..r31, btmp0..btmp3} are volatile
+       (i.e. they can be destroyed in function calls). @code{r16..r27} are
+       preserved across function calls.   
+
+       @code{r0..r7} are used for passing function arguments of type
+       @code{char, short, int} and pointer types. @code{btmp0..btmp3} are
+       used for passing arguments of type @code{long, long long, float, double,
+       long double} and far pointers. All other types are passed on the stack.
+
+       For functions with a variable-argument-list, arguments that are part
+       of the variable-argument-list are always passed on the stack. It is
+       therefore required that a prototype is in scope when calling such functions
+       (as required by C).
+
+       Scalar types are returned as follows:
+@example
+    type        registers
+
+    char        a
+    short       a/x
+    int         a/x
+    long        btmp0
+    long long   n/a
+    pointers    a/x
+    far-pointer btmp0
+    float       btmp0
+    double      btmp0 or btmp0/btmp1 (IEEE)
+    long double btmp0 or btmp0/btmp1 (IEEE)
+@end example
+
+       All other types are returned by passing the function the address
+       of the result as a hidden argument - such a function must not be called
+       without a proper declaration in scope.
+
+The basic data types are represented like this:
+
+@example
+    type        size in bits        alignment in bytes
+
+    char                8                       1
+    short              16                       1
+    int                16                       1
+    long               32                       1
+    long long          64                       1       (currently not supported)
+    near pointers      16                       1
+    far pointers       24                       1       
+    float              32                       1       see below
+    double             32/64                    1       see below
+    long double        32/64                    1       see below
+@end example
+
+
+@section Math
+
+
+    For certain operations @code{vbcc} will emit calls to routines that have
+    to be provided by a library.
+    For integer code, the following operations are handled by library routines
+    (some special cases involving constants may be handled by inline code).
+
+@example
+     __mulint16                 16x16=>16 multiplication
+     __mulint32                 32x32=>32 multiplication
+     __divint16                 16x16=>16 signed division
+     __divint32                 32x32=>32 signed division
+     __divuint16                16x16=>16 unsigned division
+     __divuint32                32x32=>32 unsigned division
+     __modint16                 16x16=>16 signed modulo
+     __modint32                 32x32=>32 signed modulo
+     __moduint16                16x16=>16 unsigned modulo
+     __moduint32                32x32=>32 unsigned modulo
+@end example
+
+@subsection Floating Point
+
+    By default, all floating point types are implemented as 32bit values.
+    The format used by the floating point routines published by Roy Rankin
+    and Steve Wozniak is used. While this does work for many use cases, it
+    is not fully C compliant by any means. Calculation of constants in the
+    compiler is not done in that format. Therefore, the results of
+    calculations done at compile-time may be different from those at run-time.
+    The corresponding math library must be linked using @code{-lm}.
+
+    As an alternative, @code{vbcc} can use IEEE format by specifying
+    @code{-ieee}. This will solve the problems mentioned above and provide
+    accurate results using the SANE floating point environment. However,
+    these routines are slower and much bigger. Also, you may have to clarify
+    their legal status before using them. The IEEE routines will likely not
+    work when running from ROM.
+
+    In addition to @code{-ieee}, the SANE library has to be linker using
+    @code{-lmieee}.
+
+    When using floating point, the following library routines are needed
+    (without @code{-ieee}):
+
+@example
+    __addflt32                 floating point addition
+    __subflt32                 floating point subtraction
+    __mulflt32                 floating point multiplication
+    __divflt32                 floating point division
+    __negflt32                 floating point negation (-x)
+    __cmpsflt32                floating point comparison
+                               (sets @code{a} to pos., neg. or zero, depending on
+                               the comparison result)
+    __sint16toflt32            convert signed 16bit integer to floating point
+    __uint16toflt32            convert unsigned 16bit integer to floating point
+    __sint32toflt32            convert signed 32bit integer to floating point
+    __uint32toflt32            convert unsigned 32bit integer to floating point
+    __flt32tosint16            convert floating point value to signed 16bit integer
+    __flt32touint16            convert floating point value to unsigned 16bit integer
+    __flt32tosint32            convert floating point value to signed 32bit integer
+    __flt32touint32            convert floating point value to unsigned 32bit integer
+@end example
+
+     Further math library functions may be needed by user code or the C library.
+
+
+
+@section Target-Specific Variable Attributes
+
+    This backend offers the following variable attributes:
+
+@table @code
+    @item __interrupt
+          Used for writing interrupt handlers. All used registers
+          (including volatiles and accumulator) are saved/restored and
+          @code{rti} is used to leave the function. Also, the user stack
+          pointer is set to @code{__isrstack}. This value for the interrupt
+          stack has to be provided e.g. by the linker script.
+
+    @item __zpage
+              Place variable in section @code{zpage} and instruct @code{vbcc}
+              to use it with zero-page addressing.
+
+    @item __nocpr
+          Turn off code compression for this function even if @code{-size} is used.
+          Useful for time-critical functions.
+
+    @item __bank(<n>)
+          Place the variable/function in bank n. See chapter on banking for details.
+
+@end table
+
+@section Target-Specific #pragmas
+
+    This backend offers the following #pragmas
+
+@table @code
+    @item #pragma section <sec>
+              The following functions and variables are placed in section <sec>.
+
+    @item #pragma section default
+              The following functions and variables are placed in default sections.
+
+    @item #pragma bank <n>
+              The following functions and variables are placed in bank <n>. See the
+              chapter on banking for details.
+
+    @item #pragma bank -1
+              The following functions and variables are placed in the default bank. See the
+              chapter on banking for details.
+
+@end table
+
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __6502__
+        
+        @item __SIZE_T_INT
+
+@end table
+
+
+@section Stack
+
+    Local variables and function arguments are put on the user stack. It
+    can be up to 64KB, but accessing variables outside the lower 256 bytes
+    is significantly slower. @code{vbcc} will put small variables on lower
+    offsets to increase the number of variables that can be addressed fast.
+    However, accessing the stack is always rather slow on the 6502.
+
+    The stack pointer is adjusted once during function entry/exit to avoid
+    multiple costly adjustments to the stack pointer.
+
+    Variable-length-arrays as specified in c99 should be fully supported.
+
+
+@section Banking
+
+    Many 6502 systems offer/need different banking mechanisms. vbcc offers different
+    levels of support for those schemes. Depending on the target integration, more
+    or less support is offered.
+
+@subsection Manual Banking
+
+    Banking can usually be implemented manually if there is no suitable target
+    integration or if manual optimization is preferred.
+
+    For manual banking, functions and/or data can be mapped to sections using
+    the @code{section} attribute or the @code{#pragma section} directive. Note that
+    string constants will be mapped to banked memory only when using the @code{#pragma}
+    approach.
+
+    After placing the objects in suitable sections, they have to be located using a
+    linker command file. See the documentation on vlink. Switching between banks has
+    to done manually in a system-specific way.
+
+    If initialized variables are mapped into banked sections, be aware that you may have
+    to provide means to initialize them on startup. It is probably not handled by
+    startup code for non-banked systems. This is not relevant for systems that only
+    provide banked ROM.
+    
+
+@subsection Automated Banking
+
+    If a suitable target integration is available, vbcc is able to automatically
+    handle bank switching.
+
+@subsubsection Memory Model
+
+    vbcc assumes a memory model which provides non-banked
+    memory for code and data that is always visible. Additionally there can be a
+    number of up to 255 memory banks, one of which can be visible at a time.
+
+    If several banks can be visible at the same time, this will also work, but vbcc
+    does not make use of this feature.
+
+@subsubsection Mapping
+
+    Code/data can be put into banks using the @code{bank}-attribute or 
+    @code{#pragma bank}. Note that string constants will be mapped to banked memory only
+    when using the @code{#pragma} approach. Code/data not mapped to a bank will be
+    mapped to the always visible non-banked area.
+
+    Banked objects will be mapped to sections suffixed with the bank number, e.g. in
+
+@example
+__bank(0) int i = 1;
+__bank(1) void f() { }
+@end example
+
+    @code{i} will be put into section @code{data0} and @code{f} will be put
+    into section @code{text1}.
+
+@subsubsection Bank Switching
+
+    vbcc will try to determine when a bank switch has to
+    be made and it will call library functions to map in the required data. This
+    requires that when accessing an object, vbcc has to know which bank the object is
+    assigned to. Therefore a declaration specifying the correct bank number (either
+    using the @code{__bank()}-attribute or @code{#pragma bank}). If an object is
+    accessed which has not been declared with a bank number, it is assumed that it
+    can be accessed without bank switching.
+
+@subsubsection Far Pointers
+
+    When accessing an object through a normal pointer, the bank number is not known.
+    All accesses through normal pointers assume that the target is always visible.
+    For all other cases, far-ointers have to be used. Far-pointers contain the bank number
+    as additional information, resulting in a size of 3 bytes.
+
+    They are declared using the @code{__far}-qualifier. @code{__far} is used like a type
+    qualifier, similar to @code{const}.
+
+@example
+       __bank(0) i0;
+       __bank(1) i1;
+       __far int *fp;
+       ...
+
+       if(..)
+         fp = &i0;
+       else
+         fp = &i1;
+@end example
+    
+    Converting a far-pointer to a normal pointer will loose the bank information.
+    Converting a normal pointer to a far-pointer will insert the bank number of the current
+    function. Care must be taken not to loose bank information when working with
+    pointers.
+
+@subsubsection Performance Considerations
+
+   Accessing objects through bank switching generates much slower and larger code than
+   direct accesses. Therefore it is crucial to organize your objects in a way that 
+   reduces task switches as much as possible. Following is a list of hints and
+   explanations.
+
+@itemize
+@item Using far pointers will always incur overhead. Try to use them only when
+      necessary.
+
+@item Accessing objects from the non-banked area is always fast (unless done through
+      far-pointers).
+
+@item Accessing objects from the same bank the function is mapped to is usually fast
+      (unless done through far-pointers).
+
+@item Accessing banked objects from non-banked code is usually faster than accessing
+      them from banked code in another bank.
+
+@item Calling functions in another bank is a reasonably small overhead on systems with a
+      fast bank switch. It can be much more overhead on RAM expansions that have to
+      copy code.
+
+@item Be careful when using function inlining. Inlined code will be executed in
+      the bank of the caller.
+@end itemize
+
+In general, try to reduce cross-bank accesses and far-pointer usage as much as possible.
+For best performance you can always only use the @code{section}-features to map everything
+and handle all bank-switching yourself.
+
+@subsubsection Library
+
+To use the automated bank switching, a series of library functions must be available
+(TODO: add more detailed information, may change):
+
+
+@table @code
+@item ___bankswitch
+      Make the bank in @code{y} accessible.
+
+@item ___bankjsr
+      Call the function pointer @code{r30/r31} in bank @code{y}. Return to the caller
+      in bank @code{a}.
+
+@item ___bankload<n> (n=1,2,3,4,8)
+      Copy <n> bytes from @code{r30/r31} in bank @code{y} to non-banked variable
+      @code{___bankv} with offset @code{x}. Caller bank in @code{a}.
+
+@item ___bankstore<n> (n=1,2,3,4,8)
+      Copy <n> bytes from non-banked variable @code{___bankv} with offset @code{x} to
+      @code{r30/r31} in bank @code{y}. Caller bank in @code{a}.
+
+@item ___bankcopy
+      Copy @code{___bankcopy_len/___bankcopy_len+1} bytes from @code{r28/r29} in bank @code{y} to
+      @code{r30/r31} in bank @code{x}. Caller bank in @code{a}.
+@end table
+
+
+@section Debugging
+
+    The 6502 backend has some limited support for debugging.
+
+    When using vlink, the @code{-vicelabels} options can be used to output symbol
+    values in a format that can be read by the vice emulator/debugger.
+
+    With the @code{-g} option, line numbers and file names of source code will
+    be added to the assembly output. Using some tools, it should be possible to
+    create a mixed C/assembly file for inspection.
+    Depending on the optimization level, the
+    results may be more or less usable, see section Debugging Optimized Code.
+    Note that the added comments will affect the assembly peephole
+    optimizer, resulting in worse code than without @code{-g}.
+    
+
+@section Code compressor
+
+    The @code{vcpr6502} code compressor supports the 6502 target. It should
+    be called automatically on higher optimization levels when using the
+    frontend @code{vc}. As the code will be slowed down when using compression,
+    the 6502 backend will only enable compression when using the @code{-size}
+    option.
+
+    TODO: manual overriding
+
+
+@section Known problems
+
+@itemize @minus
+    @item @code{long long} not yet supported
+
+    @item return value of cross-bank function calls may not work
+
+    @item banking not tested very much
+    
+
+@end itemize
+
+
+
diff --git a/doc/vbcc_main.texi b/doc/vbcc_main.texi
new file mode 100644
index 0000000..b58722f
--- /dev/null
+++ b/doc/vbcc_main.texi
@@ -0,0 +1,1990 @@
+This chapter describes the target-independent part of the compiler. It
+documents the options and extensions which are not specific to a certain
+target. Be sure to also read the chapter on the backend you are using. It will
+likely contain important additional information like data-representation
+or additional options.
+
+@node General Compiler Options
+@section General Compiler Options
+
+    Usually @command{vbcc} will be called by @command{vc}. However, if called
+    directly it expects the following syntax:
+
+@example
+      @command{vbcc<target> [options] file}
+@end example
+
+    The following options are supported by the machine independent part
+    of @command{vbcc} (and will be passed through by @command{vc}):
+
+@table @option
+
+    @item -quiet      
+        Do not print the copyright notice.
+
+    @item -ic1        
+        Write the intermediate code before optimizing to file.ic1.
+
+    @item -ic2        
+        Write the intermediate code after optimizing to file.ic2.
+
+    @item -debug=n    
+        Set the debug level to n.
+
+    @item -o=ofile    
+        Write the generated assembler output to <ofile> rather than
+                the default file.
+
+    @item -noasm      
+        Do not generate assembler output (only for testing).
+
+    @item -O=n
+                Turns optimizing options on/off; every bit set in n turns
+                on an option. Usually the predefined optimization options
+                by the compiler driver should be used.
+                @xref{Optimizations}.
+
+    @item -speed
+              Turns on optimizations which improve speed even if they
+                increase code-size quite a bit.
+
+    @item -size
+               Turns on optimizations which improve code-size even if
+                they have negative effect on execution-times.
+
+    @item -final
+              This flag is useful only with higher optimization levels.
+                It tells the compiler that all relevant files have been
+                provided to the compiler (i.e. it is the link-stage).
+                The compiler will try to eliminate all functions and
+                variables which are not referenced.
+
+                @xref{Unused Object Elimination}.
+
+    @item -wpo
+                Create a high-level pseudo object for cross-module
+                optimization (@pxref{Cross-Module Optimizations}).
+
+
+    @item -g
+                Create debug output. Whether this is supported as well as the
+                format of the debug information depends on the backend.
+                Some backends may offer additional options to control the
+                generation of debug output.
+
+                Usually DWARF2-output will be generated by default, if
+                possible.
+
+                Also, options regarding optimization and
+                code-generation may affect the debug output
+                (@pxref{Debugging Optimized Code}).
+
+        
+    @item -cmd=<file>
+                A file containing additional command line options can
+                be specified using this command. This may be useful for
+                very long command lines.
+
+    @item -c89
+    @item -c99
+                Set the C standard to be used.
+                The default is the 1999 ISO C standard (ISO/IEC9899:1999).
+                Currently the following changes of C99 are handled:
+@itemize @minus
+                @item long long int (not supported by all backends)
+                @item flexible array members as last element of a struct
+                @item mixed statements and declarations
+                @item declarations within for-loops
+                @item @code{inline} function-specifier
+                @item @code{restrict}-qualifier
+                @item new reserved keywords
+                @item @code{//}-comments
+                @item vararg-macros
+                @item @code{_Pragma}
+                @item implicit int deprecated
+                @item implicit function-declarations deprecated
+                @item increased translation-limits
+                @item designated initializers
+                @item non-constant initializers for automatic aggregates
+                @item compound literals
+                @item variable-length arrays (incomplete)
+@end itemize
+
+    @item -unsigned-char
+		Make the unqualified type of @code{char} unsigned.
+
+    @item -maxoptpasses=n
+                Set maximum number of optimizer passes to n.
+                @xref{Optimizations}.
+
+    @item -inline-size=n
+                Set the maximum 'size' of functions to be inlined.
+                @xref{Function Inlining}.
+
+
+    @item -inline-depth=n
+                Inline functions up to n nesting-levels (including recursive
+                calls). The default value is 1. Be careful with values greater
+                than 2.
+                @xref{Function Inlining}.
+
+    @item -unroll-size=n
+                Set the maximum 'size' of unrolled loops.
+                @xref{Loop Unrolling}.
+
+    @item -unroll-all
+                Unroll loops with a non-constant number of iterations if
+                the number can be calculated at runtime before entering
+                the loop. @xref{Loop Unrolling}.
+
+    @item -no-inline-peephole
+                Some backends provide peephole-optimizers which perform
+                simple optimizations on the assembly code output by @command{vbcc}.
+                By default, these optimizations will also be performed
+                on inline-assembly code of the application. This switch
+                turns off this behaviour. @xref{Inline-Assembly Functions}.
+
+    @item -fp-associative
+                Floating point operations do not obey the law of
+                associativity, e.g. @code{(a+b)+c==a+(b+c)} is not true for all
+                floating point numbers @code{a},@code{b},@code{c}. Therefore
+                certain optimizations
+                depending on this property cannot be performed on floating
+                point numbers.
+
+                This option tells @command{vbcc} to treat floating point
+                operations as associative and perform those optimizations
+                even if that may change the results in some cases (not
+                ISO conforming).
+
+    @item -no-alias-opt
+                Do not perform type-based alias analysis.
+                @xref{Alias Analysis}.
+
+    @item -no-multiple-ccs
+                If the backend supports multiple condition code
+                registers, @command{vbcc} will try to use them when optimizing.
+                This flag prevents @command{vbcc} from using them.
+
+    @item -double-push
+                On targets where function-arguments are passed in registers
+                but also stack-slots are left empty for such arguments,
+                pass those arguments both in registers and on the stack.
+
+                This generates less efficient code but some broken code
+                (e.g. code which calls varargs functions without correct
+                prototypes in scope) may work.
+
+    @item -short-push
+                In the presence of a prototype, no promotion will be done
+                on function arguments. For example, <char> will be passed
+                as <char> rather than <int> and <float> will not be
+                promoted to <double>. This may be more efficient on small
+                targets.
+
+                However, please note that this feature may not be
+                supported by all backends and that using this option
+                breaks ANSI/ISO conformance. For example, a function
+                with a <char> parameter must never be called without a
+                prototype in scope.
+
+    @item -soft-float
+                On targets supporting this flag, software floating point
+                emulation will be used rather than a hardware FPU. Please
+                consult the corresponding backend documentation when
+                using this flag.
+
+    @item -stack-check
+                Insert code for dynamic stack checking/extending if the
+                backend and the environment support this feature.
+
+    @item -ansi
+    @itemx -iso
+       Switch to ANSI/ISO mode.
+
+
+@itemize @minus
+@item  In ISO mode warning 209 will be printed by default.
+@item  Inline-assembly functions are not recognized.
+@item  Assignments between pointers to <type> and pointers
+                to unsigned <type> will cause warnings.
+@end itemize
+
+    @item -maxerrors=n
+                Abort the compilation after n errors; do not stop if n==0.
+
+    @item -dontwarn=n[,n...]
+                Suppress warning number n; suppress all warnings if n<0.
+                Multiple warnings may be separated by commas.
+                @xref{Errors and Warnings}
+
+    @item -warn=n
+                Turn on warning number n; turn on all warnings if n<0.
+                @xref{Errors and Warnings}
+
+    @item -no-cpp-warn
+                Turn off all preprocessor warnings.
+
+    @item -warnings-as-errors
+                Treat all enabled warnings as errors.
+
+    @item -strip-path
+                Strip the path of filenames from error messages.
+                Error messages may look more convenient that
+                way, but message browsers or
+                similar programs might need full paths.
+
+    @item -no-include-stack
+                Do not display the include stack in error messages.
+
+
+    @item -+
+    @itemx -cpp-comments
+                Allow C++ style comments (not ISO89 conforming).
+
+    @item -no-trigraphs
+                Do not recognize trigraphs (not ISO conforming).
+
+    @item -E
+                Write the preprocessor output to <file>.i.
+
+    @item -deps
+                Write a make-style dependency-line to <file>.dep.
+
+    @item -deps-for-libs
+                By default, @code{-deps} will not include files that are
+                included using the syntax @code{#include <...>}. Specify this option
+                to add those files as well.
+
+    @item -depobj=<file>
+                Use the specified filename as target in the generated dependency
+                file instead of basing it on the input file name.
+
+    @item -reserve-reg=<register>
+                Reserve that register not to be used by the backend.
+                This option is dangerous and must only be used for registers
+                otherwise available for the register allocator. If it used
+                for special registers or registers used internally by the
+                backend, it may be ignored, lead to corrupt code or even
+                cause internal errors from the compiler.
+
+                Only use if you know what you are doing!
+
+    @item -dontkeep-initialized-data
+                By default @command{vbcc} keeps all data of initializations in memory
+                during the whole compilation (it can sometimes make use
+                of this when optimizing). This can take some amount of
+                memory, though. This options tells @command{vbcc} to
+                keep as little of this data in memory as possible.
+                This has not yet been tested very well.
+
+    @item -prefer-statics
+                Assign auto variables to static memory rather than the stack if it
+                can be deduced that the function is not called recursively, i.e. the
+                behaviour is still C compliant. This may be more efficient on targets
+                that can access static data faster than stack. While stack-usage is
+                reduced, total memory consumption is usually increased.
+
+                Functions will not be re-entrant any more.
+
+                This option only has effect on higher optimization levels (@code{-O3}).
+
+    @item -force-statics
+                Like @code{-prefer-statics}, but assume all functions as non-recursive.
+                This will break C compliance.
+
+                This option only has effect on higher optimization levels (@code{-O}).
+
+    @item -range-opt
+                Perform additional optimizations based on value range analysis. This
+                option is under development and considered experimental. The following
+                optimizations are currently implemented:
+
+                @itemize @minus
+                @item Induction variables of some loops are transformed to smaller
+                      types if it can be determined that they will only get assigned
+                      values that fit into a smaller type.
+                @end itemize
+
+    @item -merge-strings
+                Overlay identical string-constants to save memory. Currently
+                only strings identical to string-constants on top-level are
+                recognized.
+
+    @item -sec-per-obj
+                Tells the backend to put every function/object into its own
+                separate section. This allows more fine-grained elimination
+                of unused functions/objects by the linker. On the other hand,
+                it may prevent some optimizations by the assembler.
+
+                This option only has effect if it is supported by the backend.
+
+    @item -mask-opt
+                Perform mask optimizations on suitable library function. This
+                will create calls to optimized versions of e.g. the printf/scanf
+                family of functions.
+
+@end table
+
+
+    The assembler output will be saved to @file{file.asm}
+    (if @file{file} already contained
+    a suffix, this will first be removed; same applies to .ic1/.ic2)
+
+
+@node Errors and Warnings
+@section Errors and Warnings
+
+    @command{vbcc} knows the following kinds of messages:
+
+@table @asis
+
+    @item Fatal Errors
+                        Something is badly wrong and further compilation is
+                        impossible or pointless. @command{vbcc} will abort.
+                        E.g. no source file or really corrupt source.
+
+    @item Errors
+                      There was an error and @command{vbcc} cannot generate useful
+                        code. Compilation continues, but no code will be
+                        generated.
+                        E.g. unknown identifiers.
+
+    @item Warnings (1)
+                        Warnings with ISO-violations. The program is not
+                        ISO-conforming, but @command{vbcc} will generate code that
+                        could be what you want (or not).
+                        E.g. missing semicolon.
+
+    @item Warnings (2)
+                        The code has no ISO-violations, but contains some
+                        strange things you should perhaps look at.
+                        E.g. unused variables.
+@end table
+
+    Errors or the first kind of warnings are always displayed and cannot
+    be suppressed.
+
+    Only some warnings of the second kind are turned on by default.
+    Many of them are very useful for some but annoying to others, and
+    their usability may depend on programming style.
+    Everybody is recommended to find their own preferences.
+
+    A good way to do this is starting with all warnings turned on by
+    @option{-warn=-1}. Now all possible warnings will be issued. Everytime 
+    a warning that is not considered useful appears, turn that one off with
+    @option{-dontwarn=n}.
+
+    See @ref{List of Errors} for a list of all diagnostic messages available.
+
+    See @ref{The Frontend} to find out how to configure @command{vc} to your
+    preferences.
+
+
+@section Data Types
+
+    @command{vbcc} can handle the following atomic data types:
+
+@table @code
+@item signed char
+@item unsigned char
+@item signed short
+@item unsigned short
+@item signed int
+@item unsigned int
+@item signed long int
+@item unsigned long int
+@item signed long long int
+        (with @option{-c99})
+@item unsigned long long int
+        (with @option{-c99})
+@item float
+@item double
+@item long double
+@end table
+
+The default signedness for integer types is @code{signed}.
+
+Depending on the backend, some of these types can have identical
+representation. The representation (size, alignment etc.) of these types
+usually varies between different backends. @command{vbcc} is able to support
+arbitrary implementations.
+
+Backends may be restricted and omit some types (e.g. floating point on small
+embedded architectures) or offer additional types. E.g. some backends
+may provide special bit types or different pointer types.
+
+
+@node Optimizations
+@section Optimizations
+
+    @command{vbcc} offers different levels of optimization, ranging from fast
+    compilation with straight-forward code suitable for easy debugging
+    to highly aggressive cross-module optimizations delivering very
+    fast and/or tight code.
+
+    This section describes the general phases of compilation and gives
+    a short overview on the available optimizations.
+
+    In the first compilation phase every function is parsed into a tree
+    structure one expression after the other. Type-checking and some
+    minor optimizations like constant-folding or some algebraic
+    simplifications are done on the trees.
+    This phase of the translation is identical in optimizing and
+    non-optimizing compilation.
+
+    Then intermediate code is generated from the trees. In non-optimizing
+    compilation temporaries needed to evaluate the expression are
+    immediately assigned to registers while in optimizing
+    compilation, a new variable is generated for each temporary.
+    Slightly different intermediate code
+    is produced in optimizing compilation.
+    Some minor optimizations are performed while generating the intermediate
+    code (simple elimination of unreachable code, some optimizations on
+    branches etc.).
+
+    After intermediate code for the whole function has been generated,
+    simple register allocation may be done in non-optimizing compilation
+    if bit 1 has been set in the @option{-O} option.
+    Afterwards, the intermediate code is passed to the code generator and
+    then all memory for the function, its variables etc. is freed.
+
+    In optimizing compilation flowgraphs are constructed, data flow analysis
+    is performed and many passes are made over the function's intermediate
+    code. Code may be moved around, new variables may be added, other
+    variables removed etc. etc. (for more detailed information on the
+    optimizations look at the description for the
+    @option{-O} option below).
+
+    Many of the optimization routines depend on each other. If one
+    routine finds an optimization, this often enables other routines to
+    find further ones. Also, some routines only do a first step and let
+    other routines 'clean up' afterwards. Therefore @command{vbcc} usually
+    makes many passes until no further optimizations are found.
+    To avoid possible extremely long optimization times, the number of
+    those passes can be limited with @option{-maxoptpasses} (the
+    default is max. 10 passes).
+    @command{vbcc} will display a warning if more passes might be useful.
+
+    Depending on the optimization level, a whole translation-unit or
+    even several translation-units will be read at once. Also, the
+    intermediate code for all functions may be kept in memory during
+    the entire compilation. Be aware that higher optimization levels
+    can take much more time and memory to complete.
+
+    The following table lists the optimizations which are activated by
+    bits in the argument of the @option{-O} option. Note that not all
+    combinations are valid. It is heavily recommended not to fiddle with
+    this option but just use one of the settings provided by @command{vc}
+    (e.g. @option{-O0} - @option{-O4}). These options also automatically
+    handle actions like invoking the scheduler or cross-module optimizer.
+
+@table @asis
+
+@item Bit 0 (1)
+                 Perform Register allocation. @xref{Register Allocation}.
+
+@item Bit 1 (2)
+    This flag turns on the optimizer. If it is set to zero, no global
+    optimizations will be performed, no matter what the other flags are set
+    to.
+    Slightly different intermediate code will be generated
+    by the first translation phases and a flowgraph will be constructed.
+    @xref{Flow Optimizations}.
+
+@item Bit 2 (4)
+    Perform common subexpression elimination
+    (@pxref{Common Subexpression Elimination}) and copy propagation
+    (@pxref{Copy Propagation}).
+    This can be done globally or only within basic blocks
+    depending on bit 5.
+
+@item Bit 3 (8)
+    Perform constant propagation (@pxref{Constant Propagation}).
+    This can be done globally or only within basic blocks
+    depending on bit 5.
+
+@item Bit 4 (16)
+    Perform dead code elimination (@pxref{Dead Code Elimination}).
+
+
+@item Bit 5 (32)
+    Some optimizations are available in local and global versions. This
+    flag turns on the global versions. Several major optimizations
+    will not be performed and only one optimization pass is done unless 
+    this flag is set.
+
+@item Bit 6 (64)
+    Reserved.
+
+@item Bit 7 (128)
+    @command{vbcc} will try to identify loops and perform some loop optimizations.
+    See @ref{Strength Reduction} and @ref{Loop-Invariant Code Motion}.
+    These only work if bit 5 (32) is set.
+
+
+@item Bit 8 (256)
+    @command{vbcc} tries to place variables at the same memory addresses if possible
+    (see @ref{Unused Object Elimination}).
+
+
+@item Bit 9 (512)
+    Reserved.
+
+@item Bit 10 (1024)
+    Pointers are analyzed and more precise alias-information is generated
+    (@pxref{Alias Analysis}).
+    Using this information, better data-flow analysis is possible.
+
+    Also, @command{vbcc} tries to place global/static variables and variables which
+    have their address taken in registers, if possible
+    (@pxref{Register Allocation}).
+
+
+@item Bit 11 (2048)
+    More aggressive loop optimizations are performed (see 
+    @ref{Loop Unrolling} and @ref{Induction Variable Elimination}).
+    Only works if bit 5 (32) and bit 7 (128) are set.
+
+@item Bit 12 (4096)
+    Perform function inlining (@pxref{Function Inlining}).
+
+@item Bit 13 (8192)
+    Reserved.
+
+@item Bit 14 (16384)
+    Perform inter-procedural analysis (@pxref{Inter-Procedural Analysis})
+    and cross-module optimizations (@pxref{Cross-Module Optimizations}).
+
+@end table
+
+    Also look at the documentation for the target-dependent part of @command{vbcc}.
+    There may be additional machine specific optimization options.
+
+
+@node Register Allocation
+@subsection Register Allocation
+
+This optimization tries to assign variables or temporaries into machine
+registers to save time and space. The scope and details of this optimization
+vary on the optimization level.
+
+With @option{-O0} only temporaries during expression-evaluation are put
+into registers. This may be useful for debugging.
+
+At the default level (without the optimizer), additionally local variables
+whose address has not been taken may be put into registers for a whole
+function. The decision which variables to assign to registers is based
+on very simple heuristics.
+
+In optimizing compilation a different algorithm will be used which uses
+hierarchical live-range-splitting. This means that variables may be assigned
+to different registers at different time. This typically allows to put the
+most used variables into registers in all inner loops. Note that this
+means that a variable can be located in different registers at different
+locations. Most debuggers can not handle this.
+
+Also, the use of
+registers can be guided by information provided by the backend, if
+available. For architectures which are not very orthogonal this allows
+to choose registers which are better suited to certain operations.
+Constants can also be assigned to registers, if this is beneficial for
+the architecture.
+
+The options @option{-speed} and @option{-size} change the behaviour of the
+register-allocator to optimize for speed or size of the generated code.
+
+On low optimization levels, only local variables whose address has not
+been taken will be assigned to registers. On higher optimization levels,
+@command{vbcc} will also try to assign global/static variables and variables which
+had their address taken, to registers. Typically, this occurs during
+loops. The variables will be loaded into a register before entering a loop
+and stored back after the loop. However, this can only be done if @command{vbcc}
+can detect that the variable is not modified in unpredictable ways.
+Therefore, alias-analysis is crucial for this optimization.
+
+During register-allocation @command{vbcc} will use information on
+register usage of functions to minimize loading/saving of registers between
+function-calls. Therefore, other optimizations will affect register
+allocation.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Flow Optimizations
+@subsection Flow Optimizations
+
+When optimizing @command{vbcc} will construct a flowgraph for every function and
+perform optimizations based on control-flow. For example, code which is
+unreachable will be removed and branches to other branches or branches
+around branches will be simplified.
+
+Also, unused labels will be removed and basic blocks united to allow further
+optimizations.
+
+For example, the following code
+
+@example
+void f(int x, int y)
+@{
+  if(x > y)
+    goto label1;
+  q();
+label1:
+  goto label2;
+  r();
+label2:
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int x, int y)
+@{
+  if(x <= y)
+    q();
+@}
+@end example
+
+Identical code at the beginning or end of basic blocks will be moved to
+the successors/predecessors under certain conditions.
+
+
+@node Common Subexpression Elimination
+@subsection Common Subexpression Elimination
+
+If an expression has been computed on all paths leading to a second
+evaluation and @command{vbcc} knows that the operands have not been changed,
+then the result of the original evaluation will be reused instead of
+recomputing it. Also, memory operands will be loaded into registers and
+reused instead of being reloaded, if possible.
+
+For example, the following code
+
+@example
+void f(int x, int y)
+@{
+  q(x * y, x * y);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int x, int y)
+@{
+  int tmp;
+
+  tmp = x * y;
+  q(tmp, tmp);
+@}
+@end example
+
+Depending on the optimization level, @command{vbcc} will perform this optimization
+only locally within basic blocks or globally across an entire function.
+
+As this optimization requires detecting whether operand of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Copy Propagation
+@subsection Copy Propagation
+
+If a variable is assigned to another one, the original variable will be
+used as long as it is not modified. This is especially useful in
+conjunction with other optimizations, e.g. common subexpression elimination.
+
+For example, the following code
+
+@example
+int y;
+
+int f()
+@{
+  int x;
+  x = y;
+  return x;
+@}
+@end example
+
+will be optimized like:
+
+@example
+int y;
+
+int f()
+@{
+  return y;
+@}
+@end example
+
+Depending on the optimization level, @command{vbcc} will perform this optimization
+only locally within basic blocks or globally across an entire function.
+
+As this optimization requires detecting whether a variable
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Constant Propagation
+@subsection Constant Propagation
+
+If a variable is known to have a constant value (this includes addresses
+of objects) at some use, it will be replaced by the constant.
+
+For example, the following code
+
+@example
+int f()
+@{
+  int x;
+  x = 1;
+  return x;
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f()
+@{
+  return 1;
+@}
+@end example
+
+Depending on the optimization level, @command{vbcc} will perform this optimization
+only locally within basic blocks or globally across an entire function.
+
+As this optimization requires detecting whether a variable
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Dead Code Elimination
+@subsection Dead Code Elimination
+
+If a variable is assigned a value which is never used (either because it
+is overwritten or its lifetime ends), the assignment will be removed.
+This optimization is crucial to remove code which has become dead due
+to other optimizations.
+
+For example, the following code
+
+@example
+int x;
+
+void f()
+@{
+  int y;
+  x = 1;
+  y = 2;
+  x = 3;
+@}
+@end example
+
+will be optimized like:
+
+@example
+int x;
+
+void f()
+@{
+  x = 3;
+@}
+@end example
+
+As this optimization requires detecting whether a variable
+may be read, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+@node Loop-Invariant Code Motion
+@subsection Loop-Invariant Code Motion
+
+If the operands of a computation within a loop will not change
+during iterations, the computation will be moved outside of the
+loop.
+
+For example, the following code
+
+@example
+void f(int x, int y)
+@{
+  int i;
+
+  for (i = 0; i < 100; i++)
+    q(x * y);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int x, int y)
+@{
+  int i, tmp = x * y;
+
+  for (i = 0; i < 100; i++)
+    q(tmp);
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Strength Reduction
+@subsection Strength Reduction
+
+This is an optimization applied to loops in order to replace more costly
+operations (usually multiplications) by cheaper ones (typically additions).
+Linear functions of an induction variable (a variable which is changed by
+a loop-invariant value in every iteration) will be replaced by new
+induction variables. If possible, the original induction variable will be
+eliminated.
+
+As array accesses are actually composed of multiplications and additions,
+they often benefit significantly by this optimization.
+
+For example, the following code
+
+@example
+void f(int *p)
+@{
+  int i;
+
+  for (i = 0; i < 100; i++)
+    p[i] = i;
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int *p)
+@{
+  int i;
+
+  for (i = 0; i < 100; i++)
+    *p++ = i;
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Induction Variable Elimination
+@subsection Induction Variable Elimination
+
+If an induction variable is only used to determine the number of
+iterations through the loop, it will be removed. Instead, a new variable
+will be created which counts down to zero. This is generally faster
+and often enables special decrement-and-branch or decrement-and-compare
+instructions.
+
+For example, the following code
+
+@example
+void f(int n)
+@{
+  int i;
+
+  for (i = 0; i < n; i++)
+    puts("hello");
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int n)
+@{
+  int tmp;
+
+  for(tmp = n; tmp > 0; tmp--)
+    puts("hello");
+
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Loop Unrolling
+@subsection Loop Unrolling
+
+@command{vbcc} reduces the loop overhead by replicating the loop body
+and reducing the number of iterations. Also,  additional optimizations between
+different iterations of the loop will often be enabled by creating larger
+basic blocks. However, code-size as well as compilation-times can
+increase significantly.
+
+This optimization can be controlled by @option{-unroll-size} and
+@option{-unroll-all}. @option{-unroll-size} specifies the maximum number
+of intermediate instructions for the unrolled loop body. @command{vbcc} will try
+to unroll the loop as many times to suit this value.
+
+If the number of iterations is constant and the size of the loop body
+multiplied by this number is less or equal to the value specified by
+@option{-unroll-size}, the loop will be unrolled completely. If
+the loop is known to be executed exactly once, it will always be unrolled
+completely.
+
+For example, the following code
+
+@example
+void f()
+@{
+  int i;
+
+  for (i = 0; i < 4; i++)
+    q(i);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f()
+@{
+  q(0);
+  q(1);
+  q(2);
+  q(3);
+@}
+@end example
+
+If the number of iteration is constant the loop will be unrolled as many
+times as permitted by the size of the loop and @option{-unroll-size}. If the
+number of iterations is not a multiple of the number of replications, the
+remaining iterations will be unrolled separately.
+
+For example, the following code
+
+@example
+void f()
+@{
+  int i;
+
+  for (i = 0; i < 102; i++)
+    q(i);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f()
+@{
+  int i;
+  q(0);
+  q(1);
+  for(i = 2; i < 102;)@{
+    q(i++);
+    q(i++);
+    q(i++);
+    q(i++);
+  @}
+@}
+@end example
+
+By default, only loops with a constant number of iterations will be
+unrolled. However, if @option{-unroll-all} is specified, @command{vbcc} will also
+unroll loops if the number of iterations can be calculated at entry to
+the loop.
+
+For example, the following code
+
+@example
+void f(int n)
+@{
+  int i;
+
+  for (i = 0; i < n; i++)
+    q(i);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int n)
+@{
+  int i, tmp;
+
+  i = 0;
+  tmp = n & 3;
+  switch(tmp)@{
+  case 3:
+    q(i++);
+  case 2:
+    q(i++);
+  case 1:
+    q(i++);   
+  @}
+  while(i < n)@{
+    q(i++);
+    q(i++);
+    q(i++);
+    q(i++);
+  @}
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Function Inlining
+@subsection Function Inlining
+
+To reduce the overhead, a function call can be expanded inline. Passing
+parameters can be optimized as the arguments can be directly accessed
+by the inlined function. Also, further optimizations are enabled, e.g.
+constant arguments can be evaluated or common subexpressions between
+the caller and the callee can be eliminated. An inlined function call is
+as fast as a macro. However (just as with using large macros), code size and
+compilation time can increase significantly.
+
+Therefore, this optimization can be controlled with @option{-inline-size} and
+@option{-inline-depth}. @command{vbcc} will only inline functions which contain
+less intermediate instructions than specified with this option.
+
+For example, the following code
+
+@example
+int f(int n)
+@{
+  return q(&n,1);
+@}
+
+void q(int *x, int y)
+@{
+  if(y > 0)
+    *x = *x + y;
+  else
+    abort();
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f(int n)
+@{
+  return n + 1;
+@}
+
+void q(int *x, int y)
+@{
+  if(y > 0)
+    *x = *x + y;
+  else
+    abort();
+@}
+@end example
+
+If a function to be inlined calls another function, that function can also be
+inlined. This also includes a recursive call of the function.
+
+For example, the following code
+
+@example
+int f(int n)
+@{
+  if(n < 2)
+    return 1;
+  else
+    return f(n - 1) + f(n - 2);
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f(int n)
+@{
+  if(n < 2)
+    return 1;
+  else@{
+    int tmp1 = n - 1, tmp2, tmp3 = n - 2, tmp4;
+    if(tmp1 < 2)
+      tmp2 = 1;
+    else
+      tmp2 = f(tmp1 - 1) + f(tmp2 - 2);
+    if(tmp3 < 2)
+      tmp4 = 1;
+    else
+      tmp4 = f(tmp3 - 1) + f(tmp3 - 2);
+    return tmp2 + tmp4;
+  @}
+@}
+@end example
+
+By default, only one level of inlining is done. The maximum nesting of
+inlining can be set with @option{-inline-depth}. However, this option
+should be used with care. The code-size can increase very fast and in
+many cases the code will be slower. Only use it for fine-tuning after
+measuring if it is really beneficial.
+
+
+At lower optimization levels a function must be defined in the same
+translation-unit as the caller to be inlined. With cross-module
+optimizations, @command{vbcc} will also inline functions which are defined in
+other files. @xref{Cross-Module Optimizations}.
+
+
+See also @ref{Inline-Assembly Functions}.
+
+
+
+@node Intrinsic Functions
+@subsection Intrinsic Functions
+
+This optimization will replace calls to some known functions
+(usually library functions) with calls to different functions or
+special inline-code. This optimization usually depends on the
+arguments to a function. Typical candidates are the @code{printf}
+family of functions and string-functions applied to string-literals.
+
+For example, the following code
+
+@example
+int f()
+@{
+  return strlen("vbcc");
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f()
+@{
+  return 4;
+@}
+@end example
+
+Note that there are also other possibilities of providing specially
+optimized library functions. See @ref{Inline-Assembly Functions} and
+@ref{Function Inlining}.
+
+
+@node Unused Object Elimination
+@subsection Unused Object Elimination
+
+Depending on the optimization level, @command{vbcc} will try to eliminate different
+objects and reduce the size needed for objects.
+
+Generally, @command{vbcc} will try to use common storage for local non-static variables
+with non-overlapping live-ranges .
+
+At some optimization levels and with @option{-size} specified, @command{vbcc} will try to
+order the placement of variables with static storage-duration to minimize
+padding needed due to different alignment requirements. This optimization
+generally benefits from an increased scope of optimization.
+@xref{Cross-Module Optimizations}.
+
+At higher optimization levels objects and functions which are not
+referenced are eliminated. This includes functions which have always
+been inlined or variables which have always been replaced by constants.
+
+When using separate compilation, objects and functions with external
+linkage usually cannot be eliminated, because they might be referenced
+from other translation-units. This precludes also elimination of anything
+referenced by such an object or function.
+
+However, unused objects and functions with
+external linkage can be eliminated if @option{-final} is specified.
+In this case @command{vbcc} will assume that basically the entire program is presented
+and eliminate everything which is not referenced directly or indirectly
+from main(). If some objects are not referenced but must not be
+eliminated, they have to be declared with the @code{__entry} attribute.
+Typical examples are callback functions which are called from a library
+function or from anywhere outside the program, interrupt-handlers or
+other data which should be preserved.
+@xref{Cross-Module Optimizations}.
+
+
+
+@node Alias Analysis
+@subsection Alias Analysis
+
+Many optimizations can only be done if it is known that two expressions
+are not aliased, i.e. they do not refer to the same object.
+If such information is not available, worst-case assumptions have to be
+made in order to create correct code. In the C
+language aliasing can occur by use of pointers. As pointers are generally
+a very frequently used feature of C and also array accesses are just
+disguised pointer arithmetic, alias analysis is very important.
+
+@command{vbcc} uses the following methods to obtain aliasing information:
+
+@itemize @minus
+@item The C language does not allow accessing an object using an lvalue
+        of a different type. Exceptions are accessing an object using a
+        qualified version of the same type and accessing an object using
+        a character type. In the following example @code{p1} and @code{p2}
+        must not point to the same object:
+
+@example
+f(int *p1, long *p2)
+@{
+  ...
+@}
+@end example
+
+        @command{vbcc} will assume that the source is correct and does not break
+        this requirement of the C language. If a program does break this
+        requirement and cannot be fixed, then @code{-no-alias-opt} must be
+        specified and some performance will be lost.
+
+@item At higher optimization levels, @command{vbcc} will try to keep track of all
+        objects a pointer can point to. In the following example, @command{vbcc}
+        will see that @code{p1} can only point to @code{x} or @code{y}
+        whereas @code{p2} can only point to @code{z}. Therefore it
+        knows that @code{p1} and @code{p2} are not aliased.
+
+@example
+int x[10], y[10], z[10];
+
+int f(int a, int b, int c)
+@{
+  int *p1, *p2;
+
+  if(a < b)
+    p1 = &x[a];
+  else
+    p1 = &y[b];
+
+  p2 = &z[c];
+
+  ...
+@}
+@end example
+
+        As pointers itself may be aliased and function calls might
+        modify pointers, this analysis sometimes benefits from a larger
+        scope of optimization.
+        See @ref{Inter-Procedural Analysis} and
+        @ref{Cross-Module Optimizations}.
+
+        This optimization will alter the behaviour of broken code which uses
+        pointer arithmetic to step from one object into another.
+
+@item The 1999 C standard provides the @code{restrict}-qualifier to help
+        alias analysis. If a pointer is declared with this qualifier, the
+        compiler may assume that the object pointed to by this pointer is
+        only aliased by pointers which are derived from this pointer.
+        For a formal definition of the rules for @code{restrict} please
+        consult ISO/IEC9899:1999.
+
+        @command{vbcc} will make use of this information at higher optimization
+        levels (@option{-c99} must be used to use this new keyword).
+
+        A very useful application for @code{restrict} are function
+        parameters. Consider the following example:
+
+@example
+void cross_prod(float *restrict res, 
+                float *restrict x,
+                float *restrict y)
+@{
+  res[0] = x[1] * y[2] - x[2] * y[1];
+  res[1] = x[2] * y[0] - x[0] * y[2];
+  res[2] = x[0] * y[1] - x[1] * y[0];
+@}
+@end example
+
+        Without @code{restrict}, a compiler has to assume that writing the
+        results through @code{res} can modify the object pointed to by
+        @code{x} and @code{y}. Therefore, the compiler has to reload all
+        the values on the right side twice. With @code{restrict} @command{vbcc}
+        will optimize this code like:
+
+@example
+void cross_prod(float *restrict res,
+                float *restrict x,
+                float *restrict y)
+@{
+  float x0 = x[0], x1 = x[1], x2 = x[2];
+  float y0 = y[0], y1 = x[1], y2 = y[2];
+
+  res[0] = x1 * y2 - x2 * y1;
+  res[1] = x2 * y0 - x0 * y2;
+  res[2] = x0 * y1 - x1 * y0;
+@}
+@end example
+
+
+@end itemize
+
+
+@node Inter-Procedural Analysis
+@subsection Inter-Procedural Analysis
+
+Apart from the number of different optimizations a compiler offers, another
+important point is the scope of the underlying analysis. If a compiler only
+looks at small parts of code when deciding whether to do an optimization,
+it often cannot prove that a transformation does not change the
+behaviour and therefore has to reject it.
+
+Simple compilers only look at single expressions,  simple optimizing
+compilers often restrict their analysis to basic blocks or extended basic
+blocks. Analyzing a whole function is common in today's optimizing compilers.
+
+This already allows many optimizations but often worst-case assumptions
+have to be made when a function is called.
+To avoid this, @command{vbcc} will not restrict its analysis to single functions
+at higher optimization levels. Inter-procedural data-flow analysis often
+allows for example to eliminate more common subexpressions or dead code.
+Register allocation and many other optimizations also sometimes benefit
+from inter-procedural analysis.
+
+Further extension of the scope of optimizations is possible by activating
+cross-module optimizations. @xref{Cross-Module Optimizations}.
+
+
+@node Cross-Module Optimizations
+@subsection Cross-Module Optimizations
+
+Separate compilation has always been an important feature of the C language.
+Splitting up an application into several modules does not only reduce
+turn-around times and resource-requirements for compilation, but it also
+helps writing reusable well-structured code.
+
+However, an optimizer has much more possibilities when it has access to the
+entire source code. In order to provide maximum possible optimizations
+without sacrificing structure and modularity of code, @command{vbcc} can do
+optimizations across different translation-units. Another benefit is
+that cross-module analysis also will detect objects which are declared
+inconsistently in different translation-units.
+
+Unfortunately common object-code does not contain enough information to
+perform aggressive optimization, To overcome this problem, @command{vbcc} offers
+two solutions:
+
+@itemize @minus
+@item If cross-module optimizations are enabled and several files are
+        passed to @command{vbcc}, it will read in all files at once, perform
+        optimizations across these files and generate a single object
+        file as output. This file is similar to what would have been
+        obtained by separately compiling the files and linking the
+        resulting objects together.
+
+@item The method described above often requires changes in makefiles and
+        somewhat different handling. Therefore @command{vbcc} also provides means
+        to generate some kind of special pseudo object files which pretain
+        enough high-level information to perform aggressive optimizations
+        at link time.
+
+        If @option{-wpo} is specified (which will automatically be done by
+        @command{vc} at higher optimization levels) @command{vbcc} will generate such files
+        rather than normal assembly or object files. These files can
+        not be handled by normal linkers. However, @command{vc} will detect these
+        files and before linking it will pass all such files to @command{vbcc} again.
+        @command{vbcc} will optimize the entire code and generate real code which
+        is then passed to the linker.
+
+        It is possible to pass @command{vc} a mixture of real and pseudo object
+        files. @command{vc} will detect the pseudo objects, compile them and link
+        them together with the real objects. Obviously, @command{vc} has to be used
+        for linking. Directly calling the linker with pseudo objects will
+        not work.
+
+        Please note that optimization and code generation is deferred to
+        link-time. Therefore, all compiler options related to optimization and
+        code generation have to be specified at the linker command as well.
+        Otherwise they would be ignored. Other options (e.g. setting paths
+        or defining macros) have to be specified when compiling.
+
+        Also, turn-around times will obviously increase as usually everything
+        will be rebuild even if makefiles are used. While only the
+        corresponding pseudo object may be rebuilt if one file is changed,
+        all the real work will be done at the linking stage.
+
+@end itemize
+
+@node Instruction Scheduling
+@subsection Instruction Scheduling
+
+Some backends provide an instruction scheduler which is automatically run
+by @command{vc} at higher optimization levels. The purpose is to reorder
+instructions to make better use of the different pipelines a CPU may
+offer.
+
+The exact details depend heavily on the backend, but in general the
+scheduler will try to place instructions which can be executed in parallel
+(e.g. on super-scalar architectures) close to each other. Also,
+instructions which depend on the result of another instruction will be
+moved further apart to avoid pipeline-stalls.
+
+Please note that it may be crucial to specify the correct derivate of a
+CPU family in order to get best results from the sceduler. Different
+variants of an architecture may have a different number and behaviour of
+pipelines requiring different scheduling decisions.
+
+Consult the backend documentation for details.
+
+
+@node Target-Specific Optimizations
+@subsection Target-Specific Optimizations
+
+In addition to those optimzations which are available for all targets,
+every backend will provide a series of additional optimizations. These
+vary between the different backends, but optimizations frequently done by
+backends are:
+
+@itemize @minus
+@item use of complex or auto-increment addressing-modes
+@item implicit setting of condition-codes
+@item instruction-combining
+@item delayed popping of stack-slots
+@item optimized function entry- and exit-code
+@item elimination of a frame pointer
+@item optimized multiplication/division by constants
+@item inline code for block-copying
+@end itemize
+
+
+
+@node Debugging Optimized Code
+@subsection Debugging Optimized Code
+
+Debugging of optimized code is usually not possible without problems.
+Many compilers turn off almost all optimizations when debugging.
+@command{vbcc} allows debugging output together with optimizations and
+tries to still do all optimizations (some restrictions have to be made
+regarding instruction-scheduling).
+
+However, depending on the debugger and debugging-format used, the
+information displayed in the debugger may differ from the real
+situation. Typical problems are:
+
+@itemize @minus
+
+@item Incorrectly displayed values of variables.
+
+        When optimizing vbcc will often remove certain variables or
+        eliminate code which sets them. Sometimes it is possible, to
+        tell the debugger that a variable has been optimized away, but
+        most of the time the debugger does not allow this and you
+        will just get bogus values when trying to inspect a variable.
+
+        Also, variables whose locations differs at various locations
+        of the program (e.g. a variable is in a register at one place
+        and in memory at another) can only be correctly displayed, if
+        the debugger supports this.
+
+        Sometimes, this can even occur in non-optimized code (e.g.
+        with register-parameters or a changing stack-pointer).
+
+@item Strange program flow.
+
+        When stepping through a program, you may see lines of code
+        be executed out-of-order or parts of the code skipped. This
+        often occurs due to code being moved around or eliminated/combined.
+
+@item Missed break-points.
+
+        Setting break-points (especially on source-lines) needs some
+        care when optimized code is debugged. E.g. code may have been
+        moved or even replicated at different parts. A break-point
+        set in a debugger will usually only be set on one instance of
+        the code. Therefore, a different instance of the code may have been
+        executed although the break-point was not hit.
+
+@end itemize
+
+@node Extensions
+@section Extensions
+
+This section lists and describes all extensions to the C language provided
+by @command{vbcc}. Most of them are implemented in a way which does not break
+correct C code and still allows all diagnostics required by the C standard
+by using reserved identifiers.
+
+The only exception (@pxref{Inline-Assembly Functions}) can be turned off
+using @option{-iso} or @option{-ansi}.
+
+@subsection Pragmas
+
+      @command{vbcc} accepts the following @code{#pragma}-directives:
+
+@table @code
+
+      @item #pragma printflike <function>
+      @itemx #pragma scanflike <function>    
+           @command{vbcc} will handle @code{<function>} specially.
+           @code{<function>} has to be an already declared
+           function, with external linkage, that
+           takes a variable number of arguments
+           and a @code{const char *} as the last fixed
+           parameter.
+
+           If such a function is called with a
+           string-constant as format-string, @command{vbcc}
+           will check if the arguments seem to
+           match the format-specifiers in the
+           format-string, according to the rules
+           of printf or scanf.
+           Also, @command{vbcc} will replace the call by a
+           call to a simplified version according
+           to the following rules, if such a
+           function has been declared with external
+           linkage:
+
+@itemize @minus
+        @item   If no format-specifiers are used at all,
+           @code{__v0<function>} will be called.
+
+        @item   If no qualifiers are used and only
+           @code{d,i,x,X,o,s,c} are used, @code{__v1<function>}
+           will be called.
+
+        @item   If no floating-point arguments are used,
+           @code{__v2<function>} will be called.
+@end itemize
+
+      @item #pragma dontwarn <n>
+        Disables warning number n. Must be followed by @code{#pragma popwarn}.
+
+      @item #pragma warn <n>
+        Enables warning number n. Must be followed by @code{#pragma popwarn}.
+
+      @item #pragma popwarn
+        Undoes the last modification done by @code{#pragma warn} or
+        @code{#pragma dontwarn}.
+
+      @item #pragma only-inline on
+        The following functions will be parsed and are available for
+        inlining (@pxref{Function Inlining}), but no out-of-line code
+        will be generated, even if some calls could not be inlined.
+
+           Do not use this with functions that have
+           local static variables!
+
+      @item #pragma only-inline off
+           The following functions are translated
+           as usual again.
+
+      @item #pragma opt <n>
+           Sets the optimization options to <n>
+           (similar to -O=<n>) for the following
+           functions.
+           This is only used for debugging purposes. Do not use!
+
+      @item #pragma begin_header
+        Used to mark the beginning of a system-header. Must be followed
+        by @code{#pragma end_header}. Not for use in applications!
+
+      @item #pragma end_header
+        The counterpart to @code{#pragma begin_header}. Marks the end
+        of a system-header. Not for use in applications!
+
+      @item #pragma pack(n)
+        Set alignment of structure members to a multiple of @code{n} bytes.
+
+      @item #pragma pack()
+        Restores structure alignment to the target's default alignment,
+        which was in effect when the compilation started.
+
+      @item #pragma pack(push[,n])
+        Pushes the current structure alignment onto an internal stack and
+        optionally sets a new alignment to a multiple of @code{n} bytes.
+
+      @item #pragma pack(pop)
+        Restores the topmost structure alignment, saved by @code{pack(push)},
+        from an internal stack. Restores the default alignment, when the
+        stack is empty.
+
+@end table
+
+
+@subsection Register Parameters
+
+      If the parameters for certain functions should be passed in certain
+      registers, it is possible to specify the registers using
+      @code{__reg("<reg>")} in the
+      prototype, e.g.
+
+@example
+        void f(__reg("d0") int x, __reg("a0") char *y) @{ ... @}
+@end example
+
+      The names of the available registers depend on the backend and will
+      be listed in the corresponding part of the documentation.
+      Note that a matching prototype must be in scope when calling such
+      a function - otherwise wrong code will be generated.
+      Therefore it is not useful to use register parameters in an old-style
+      function-definition.
+
+      If the backend cannot handle the specified register for a
+      certain type, this will cause an error. Note that this may happen
+      although the register could store that type, if the backend
+      does not provide the necessary support.
+
+      Also note that this may force @command{vbcc} to create worse code.
+
+
+@node Inline-Assembly Functions
+@subsection Inline-Assembly Functions
+
+      Only use them if you know what you are doing!
+
+      A function-declaration may be followed by '=' and a string-constant.
+      If a function is called with such a declaration in scope, no
+      function-call will be generated but the string-constant will be
+      inserted in the assembly-output.
+      Otherwise the compiler and optimizer will treat this like a
+      function-call, i.e. the inline-assembly must not modify any callee-save
+      registers without restoring them. However, it is also possible to
+        specify the side-effects of inline-assembly functions like 
+        registers used or variables used and modified
+        (@pxref{Specifying side-effects}).
+
+      Example:
+
+@example
+        double sin(__reg("fp0") double) = "\tfsin.x\tfp0\n";
+@end example
+
+      There are several issues to take care of when writing inline-assembly.
+
+@itemize @minus
+@item As inline-assembly is subject to loop unrolling or function inlining
+        it may be replicated at different locations. Unless it is absolutely
+        known that this will not happen, the code should not define any
+        labels (e.g. for branches). Use offsets instead.
+
+@item If a backend provides an instruction scheduler, inline-assembly code
+        will also be scheduled. Some schedulers make assumptions about
+        their input (usually compiler-generated code) to improve the
+        code. Have a look at the backend documentation to see if there
+        are any issues to consider.
+
+@item If a backend provides a peephole optimizer which optimizes the
+        assembly output, inline-assembly code will also be optimized
+        unless @option{-no-inline-peephole} is specified.
+        Have a look at the backend documentation to see if there are any
+        issues to consider.
+
+@item @command{vbcc} assumes that inline-assembly does not introduce any new
+        control-flow edges. I.e. control will only enter inline-assembly
+        if the function call is reached and if control leaves
+        inline-assembly it will continue after the call.
+
+@end itemize
+
+      Inline-assembly-functions are not recognized when ANSI/ISO mode is
+      turned on.
+
+
+@node Variable Attributes
+@subsection Variable Attributes
+
+        @command{vbcc} offers attributes to variables or functions. These attributes
+        can be specified at the declaration of a variable or function and
+        are syntactically similar to storage-class-specifiers
+        (e.g. @code{static}).
+
+        Often, these attributes are specific to one backend and will be
+        documented in the backend-documentation (typical attributes would
+        e.g. be @code{__interrupt} or @code{__section}). Attributes may
+        also have parameters. A generally available
+        attribute s @code{__entry} which is used to preserve unreferenced
+        objects and functions (@pxref{Unused Object Elimination}):
+
+@example
+__entry __interrupt __section("vectab") void my_handler()
+@end example
+
+        Additional non-target-specific attributes are available to
+        specify side-effects of functions (@pxref{Specifying side-effects}).
+
+
+        Please note that some common extensions like @code{__far} are
+        variable attributes on some architectures, but actually type
+        attributes (@pxref{Type Attributes}) on others. This is due to
+        significantly different meanings on different architectures.
+
+
+@node Type Attributes
+@subsection Type Attributes
+
+      Types may be qualified by additional attributes, e.g. @code{__far},
+        on some backends. Regarding the availability of type attributes
+        please consult the backend documentation. 
+
+      Syntactically type attributes have to be placed like a type-qualifier
+        (e.g. @code{const}).
+      As example, some backends know the attribute @code{__far}.
+
+      Declaration of a pointer to a far-qualified character would be
+
+@example
+        __far char *p;
+@end example
+
+      whereas
+
+@example
+        char * __far p;
+@end example
+
+      is a far-qualified pointer to an unqualified char.
+
+        Please note that some common extensions like @code{__far} are
+        type attributes on some architectures, but actually variable
+        attributes (@pxref{Variable Attributes}) on others. This is due to
+        significantly different meanings on different architectures.
+
+@subsection @code{__typeof}
+
+      @code{__typeof} is syntactically equivalent to sizeof, but its result is of
+      type int and is a number representing the type of its argument.
+      This may be necessary for implementing @file{stdarg.h}.
+
+
+@subsection @code{__alignof}
+
+      @code{__alignof} is syntactically equivalent to sizeof, but its result is of
+      type int and is the alignment in bytes of the type of the argument.
+      This may be necessary for implementing @file{stdarg.h}.
+
+
+@subsection @code{__offsetof}
+
+      @code{__offsetof} is a builtin version of the @code{offsetof}-macro
+        as defined in the C language. The first argument is a structure
+        type and the second a member of the structure type. The result
+        will be a constant expression representing the offset of the
+        specified member in the structure.
+
+@node Specifying side-effects
+@subsection Specifying side-effects
+
+Only use if you know what you are doing!
+
+When optimizing and generating code, @command{vbcc} often has to take
+into account side-effects of function-calls, e.g. which registers might
+be modified by this function and what variables are read or modified.
+
+A rather imprecise way to make assumptions on side-effects is given by
+the ABI of a certain system (that defines which registers have to be
+preserved by functions) or rules derived from the language (e.g. local
+variables whose address has not been taken cannot be accessed by another
+function).
+
+On higher optimization levels (@pxref{Inter-Procedural Analysis} and
+@pxref{Cross-Module Optimizations})) @command{vbcc} will try to analyse
+functions and often gets much more precise informations regarding
+side-effects.
+
+However, if the source code of functions is not visible to @command{vbcc},
+e.g. because the functions are from libraries or they are
+written in assembly (@pxref{Inline-Assembly Functions}), it is obviously
+not possible to analyze the code. In this case, it is possible to specify
+these side-effects using the following special variable-attributes
+(@pxref{Variable Attributes}).
+
+The @code{__regsused(<register-list>)} attribute specifies the volatile
+registers used or modified by a function. The register list is a list of
+register names (as defined in the backend-documentation) separated by
+slashes and enclosed in double-quotes, e.g.
+
+@code{        __regsused("d0/d1") int abs();}
+
+declares a function @code{abs} which only uses registers @code{d0} and
+@code{d1}.
+
+@code{__varsmodified(<variable-list>)} specifies a list of variables with
+external linkage
+which are modified by the function. @code{__varsused} is similar, but
+specifies the external variables read by the function. If a variable is
+read and written, both attributes have to be specified. The variable-list
+is a list of identifiers, separated by slashes and enclosed in double
+quotes.
+
+The attribute @code{__writesmem(<type>)} is used to specify that the
+function accesses memory using a certain type. This is necessary if the
+function modifies memory accessible to the calling function which cannot
+be specified using @code{__varsmodified} (e.g. because it is accessed via
+pointers). @code{__readsmem} is similar, but specifies memory which is
+read.
+
+If one of @code{__varsused}, @code{varsmodified}, @code{__readsmem} and
+@code{__writesmem} is specified, all relevant side-effects must be
+specified. If, for example, only @code{__varsused("my_global")} 
+is specified, this implies that the function only reads @code{my_global}
+and does not modify any variable accessible to the caller.
+
+All of these attributes may be specified multiple times.
+
+@subsection Automatic constructor/destructor functions
+
+The linker @command{vlink} provides a feature to collect pointers to
+all functions starting with the names @code{_INIT} or @code{_EXIT} in
+a prioritized array, labeled by @code{__CTOR_LIST__} and
+@code{__DTOR_LIST__}. The C-library (vclib) calls the constructor functions
+before entering @code{main()} and the destructor functions on program
+exit.
+
+The format of these special function names is:
+@example
+    void _INIT[_<pri>][_<name>](void)
+    void _EXIT[_<pri>][_<name>](void)
+@end example
+The optional priority @code{<pri>} may be a digit between 1 and 9, where
+a constructor with a priority of 1 is executed first while a destructor
+with a priority of 1 is executed last. @code{<name>} is an optional name,
+used to differentiate functions of the same level.
+
+@subsection @code{__noinline}
+
+@code{__noinline} will prevent inlining of a given function. The heuristic
+used for deciding whether a function should be inlined generally makes a good
+trade-off between code size and performance, but sometimes it can be useful to override
+this behaviour. Use-cases include keeping "cold" functions out-of line to reduce code
+size, or to allow safe use of inline assembly with labels.
+
+@subsection Predefined macros
+The following macros are defined by the compiler.
+@example
+  #define __VBCC__
+  #define __entry __vattr("entry")
+  #define __str(x) #x
+  #define __asm(x) do{static void inline_assembly()=x;inline_assembly();}while(0)
+  #define __regsused(x) __vattr("regused("x")")
+  #define __varsused(x) __vattr("varused("x")")
+  #define __varsmodified(x) __vattr("varchanged("x")")
+  #define __noreturn __vattr("noreturn()")
+  #define __alwaysreturn __vattr("alwaysreturn()")
+  #define __nosidefx __vattr("nosidefx()")
+  #define __stack(x) __vattr(__str(stack1(x)))
+  #define __stack2(x) __vattr(__str(stack2(x)))
+  #define __noinline __vattr("noinline()")
+  #define __STDC_VERSION__ 199901L
+@end example
+@code{__STDC_VERSION__} is defined in C99-mode only.
+
+@subsection Masked symbols
+Together with vlink, this feature allows to provide a family of specially tailored
+functions in a library.
+
+A symbol can be attached a mask using the @code{__mask} attribute, e.g.
+
+@example
+  __mask(15) void myfunc(void);
+@end example
+
+The symbol of this function will get the suffix @code{.15} attached.
+
+A reference to a masked symbol can either be created by vbcc itself when using the
+option @code{-mask-opt}, or manually by referencing a symbol prefixed with
+@code{__maskm_<mask>}.
+
+@example
+ extern __mask(15) void myfunc(void);
+ ...
+   __maskm_15_myfunc();
+@end example
+
+If there are several masked references to a symbol, the linker will pull the first
+symbol containing a mask that has at least all bits set that are set in any masked
+reference. If no masked symbols matching that requirement are available, the symbol
+without a mask is used. Also, a non-masked reference will only pull a non-masked
+symbol from a library.
+
+Masked objects may only be defined in libraries and zero masks are not allowed.
+
+
+@section Known Problems
+
+    Some known target-independent problems of @command{vbcc} at the moment:
+
+@itemize @minus
+
+    @item Some exotic scope-rules are not handled correctly.
+
+    @item Debugging-infos may have problems on higher optimization-levels.
+
+    @item String-constants are not merged (partially done).
+
+@end itemize
+
+@section Credits
+
+    All those who wrote parts of the @command{vbcc} distribution, made suggestions,
+    answered my questions, tested @command{vbcc}, reported errors or were otherwise
+    involved in the development of @command{vbcc} (in descending alphabetical order,
+    under work, not complete):
+
+@itemize
+    @item Frank Wille
+    @item Gary Watson
+    @item Andrea Vallinotto
+    @item Johnny Tevessen
+    @item Eero Tamminen
+    @item Gabriele Svelto
+    @item Dirk Stoecker
+    @item Ralph Schmidt
+    @item Markus Schmidinger
+    @item Thorsten Schaaps
+    @item Anton Rolls
+    @item Michaela Pruess
+    @item Thomas Pornin
+    @item Joerg Plate
+    @item Gilles Pirio
+    @item Bartlomiej Pater
+    @item Elena Novaretti
+    @item Gunther Nikl
+    @item Constantinos Nicolakakis
+    @item Timm S. Mueller
+    @item Robert Claus Mueller
+    @item Joern Maass
+    @item Aki M Laukkanen
+    @item Kai Kohlmorgen
+    @item Uwe Klinger
+    @item Andreas Kleinert
+    @item Julian Kinraid
+    @item Acereda Macia Jorge
+    @item Dirk Holtwick
+    @item Matthew Hey
+    @item Tim Hanson
+    @item Kasper Graversen
+    @item Jens Granseuer
+    @item Volker Graf
+    @item Marcus Geelnard
+    @item Franta Fulin
+    @item Matthias Fleischer
+    @item Alexander Fichtner
+    @item Olivier Fabre
+    @item Robert Ennals
+    @item Thomas Dorn
+    @item Walter Doerwald
+    @item Aaron Digulla
+    @item Lars Dannenberg
+    @item Sam Crow
+    @item Michael Bode
+    @item Michael Bauer
+    @item Juergen Barthelmann
+    @item Thomas Arnhold
+    @item Alkinoos Alexandros Argiropoulos
+    @item Thomas Aglassinger
+@end itemize
diff --git a/doc/vbccalpha.texi b/doc/vbccalpha.texi
new file mode 100755
index 0000000..a5e9e5c
--- /dev/null
+++ b/doc/vbccalpha.texi
@@ -0,0 +1,132 @@
+This chapter documents the Backend for the DEC Alpha processor family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+
+    @item -merge-constants
+                Place identical floating point constants at the same
+                memory location. This can reduce program size and increase
+                compilation time.
+
+    @item -const-in-data
+                By default constant data will be placed in the code
+                section (and therefore is accessable with faster pc-relative
+                addressing modes). Using this option it will be placed in the
+                data section.
+                Note that on operating systems with memory protection this
+                option will disable write-protection of constant data.
+
+    @item -no-builtins
+                Do not replace certain builtin functions by inline code.
+                This may be useful if you use this code generator with
+                another frontend than vbcc.
+                stdarg.h will not work with -no-builtins.
+
+    @item -stabs
+                Generate stabs debug infos (if -g is specified) rather than
+                DWARF2 which is the default. Consider this obsolete.
+
+@end table
+
+@section ABI
+
+
+        This backend supports the following registers:
+
+        @itemize @minus
+        @item @code{$0} through @code{$31} for the general purpose registers and
+        @item @code{$f0} through @code{$f31} for the floating point registers.
+        @end itemize
+
+    The current version generates assembly output for use with the GNU
+    assembler. The generated code should work on systems with 21064,
+    21066, 21164 and higher Alpha CPUs.
+
+    The registers @code{$0-$8, $16-$28, $f0, $f1} and @code{$f10-$f30}
+    are used as scratch registers (i.e. they can be destroyed in function
+    calls), all other registers are preserved. Of course @code{$31} and
+    @code{$f31} cannot be used.
+
+    The first 6 function arguments which have arithmetic or pointer types
+    are passed in registers @code{$16/$f16} through @code{$21/$f21}.
+
+    Integers and pointers are returned in @code{$0}, floats and doubles in
+    @code{$f0}.
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - so when you call such a function
+    without a proper declaration in scope you can expect a crash.
+
+    The elementary data types are represented like:
+
+    @example
+    type        size in bits        alignment in bytes 
+
+    char                8                       1 
+    short              16                       2 
+    int                32                       4 
+    long               64                       8
+    long long          64                       8 
+    all pointers       64                       8 
+    float              32                       4 
+    double             64                       8 
+    @end example
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __ALPHA__
+        
+@end table
+
+
+@section Stdarg
+
+    A possible <stdarg.h> could look like this:
+
+@example
+
+    typedef struct @{
+      char *regbase;
+      char *membase;
+      int arg;
+    @} va_list;
+
+    char *__va_start(void);
+    int __va_fixargs(void);
+
+    #define va_start(vl,dummy) \
+    (vl.arg=__va_fixargs(),vl.regbase=__va_start(),vl.membase=vl.regbase+(6-vl.arg)*16)
+
+    #define va_end(vl) (vl.regbase=vl.membase=0)
+
+    #define __va_size(type) ((sizeof(type)+7)/8*8)
+    #define va_arg(vl,type) \
+     ( \
+      ((__typeof(type)&15)<=10&&++vl.arg<=6) ? \
+       ( \
+        ((__typeof(type)&15)>=6&&(__typeof(type)&15)<=8) ? \
+          (vl.regbase+=16,*(type *)(vl.regbase-8)) \
+        : \
+          (vl.regbase+=16,*(type *)(vl.regbase-16)) \
+       ) \
+      : \
+       (vl.membase+=__va_size(type),*(type *)(vl.membase-__va_size(type))) \
+     )
+
+@end example
+
+
+@section Known problems
+
+@itemize @minus
+    @item generated code is rather poor
+    @item several other problems
+@end itemize
+
+
diff --git a/doc/vbccc16x.texi b/doc/vbccc16x.texi
new file mode 100644
index 0000000..99be78e
--- /dev/null
+++ b/doc/vbccc16x.texi
@@ -0,0 +1,258 @@
+This chapter documents the Backend for the c16x/st10 microcontroller family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -merge-constants
+                Place identical floating point constants at the same
+                memory location. This can reduce program size and increase
+                compilation time.
+
+    @item -const-in-data
+                By default constant data will be placed in a read-only
+                section. Using this option it will be placed in the
+                data section.
+
+    @item -no-delayed-popping
+                By default arguments of function calls are not always popped
+                from the stack immediately after the call, so that the
+                arguments of several calls may be popped at once.
+                With this option vbcc can be forced to pop them after every
+                function call.
+                This may simplify debugging and very slightly reduce the
+                stack size needed by the compiled program.
+
+    @item -no-peephole
+                Do not perform peephole-optimizations.
+
+    @item -tasking
+                Produce output for the Tasking assembler.
+
+    @item -mtiny
+              Assume all functions are within one code-segment.
+                Shorter instructions for calling functions are used and
+                function-pointers will be only 2 bytes long.
+                This results in shorter and faster code.
+
+    @item -mlarge
+             All objects which are not explicitly qualified are assumed
+                to be far (i.e. they may be in different segments but must
+                not cross one segment-boundary). The default pointer size
+                will be 4.
+
+    @item -mhuge
+              All objects which are not explicitly qualified are assumed
+                to be huge (i.e. they may be in different segments and may
+                cross segment-boundaries). The default pointer size will
+                be 4.
+
+    @item -int32
+              Do not use.
+@end table
+
+@section ABI
+
+        This backend supports the following registers:
+
+        @itemize @minus
+        @item @code{R0} through @code{R15} for the general purpose registers
+        @end itemize
+
+        Additionally, the register pairs
+        @code{R2/R3, R3/R4, R4/R5, R6/R7, R7/R8, R8/R9, R12/R13, R13/R14,}
+        and @code{R15/R15}
+        are available.
+
+        @code{R1, R11} and @code{R12} are reserved by the backend.
+
+    The current version generates assembly output for use with the vasm
+    assembler. Optionally, assembly code for the Tasking
+    assembler can be generated.
+    The default memory model corresponds to the Tasking small-memory
+    model with 16bit data-pointers and 32bit function-pointers.
+    However, the @code{DPPx} registers have to be set up in a way to
+    create a linear 16bit address space (i.e. @code{DPPx=x}).
+    The generated code should work on systems with c161, c163, c164, c165
+    and c167 microcontrollers as well as ST10 derivates. Old versions like
+    the c166 are not supported
+
+    The registers @code{R1-R5} and @code{R10-R15} are used as scratch registers (i.e. they
+    can be destroyed in function calls), all other registers are preserved.
+
+    @code{R0} is used as user stack pointer. Automatic variables and temporaries
+    are put on the user stack. Return addresses are pushed on the system
+    stack.
+
+    The first 4 function arguments which have integer or pointer types
+    are passed in registers @code{R12} through @code{R15}.
+
+    Integers and pointers are returned in @code{R4/R5}.
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - so when you call such a function
+    without a proper declaration in scope you can expect a crash.
+
+    The elementary data types are represented like:
+
+    @example
+    type        size in bits        alignment in bytes
+
+    char                8                       1 
+    short              16                       2 
+    int                16                       2 
+    long               32                       2 
+    long long          n/a                     n/a 
+    near pointers      16                       2
+    far pointers       32                       2
+    huge pointers      32                       2
+    float              n/a                     n/a
+    double             n/a                     n/a
+    @end example
+
+
+@section Target-specific variable-attributes
+ 
+    The c16x-backend offers the following variable attributes:
+
+@table @code
+
+    @item __interrupt
+                 Return with rfi rather than blr.
+                 @code{MDL/MDH} will be saved, however it is recommended
+                 to switch to a new register bank as the gprs are
+                 not saved.
+                 Also, @code{DPP0-DPP3} are not saved (the compiler does not
+                 use them).
+
+    @item __interrupt(<vector>)
+                Like @code{__interrupt}, but also places a jump-instruction
+                to the interrupt service at the corresponding vector table
+                address (needs support from library and linker file).
+
+    @item __section(<name>)
+                 Place this object/function in section <name>.
+
+    @item __rbank(<bank>)
+                 Switch to another register-bank for this function.
+@end table
+
+
+@section Target-specific type-attributes
+ 
+    The c16x-backend offers the following type attributes:
+
+@table @code
+    @item __near
+          Object resides within the same segment.
+
+    @item __far
+           Object may reside in a different segment, but does not cross
+             a segment-boundary.
+
+    @item __huge
+          Object may reside in a different segment and may cross a
+             segment-boundary
+
+     @item __section(<name>)
+           Place this function or object in section <name>.
+
+     @item __sfr(<addr>)
+           Used to declare a special function register at <addr>.
+
+ Example:
+ @example
+         __sfr(0xff10) volatile unsigned int PSW;
+ @end example
+
+     @item __esfr(<addr>)
+           The same for extended special function registers.
+
+     @item __sfrbit(<addr>,<bit>)
+           Declare a single bit in the bit-addressable area.
+
+ Example:
+ @example
+         __sfr(0xff10,11) volatile __bit IEN;
+ @end example
+
+     @item __esfrbit(<addr>,<bit>)
+           The same for the extended bit-addressable area.
+
+@end table
+
+@section Target-specific types
+
+    The c16x-backend offers the following additional types:
+
+@table @code
+    @item __bit
+           A single bit in the bit-addressable internal RAM-area.
+             Only static and external variables may use this type.
+             It is not allowed for auto or register storage-class.
+             Also, arrays of bits, pointers to bits or bits within
+             aggregates are not allowed.
+             Conversion of a bit to an integral type yields 0 if the
+             bit is cleared and 1 if it is set..
+             Conversion of an integral type to a bit clears the bit if
+             the integer is equal to 0 and sets it otherwise.
+@end table
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __C16X__
+        @item __C167__
+        @item __ST10__        
+@end table
+
+
+
+@section Stack
+
+    If the @option{-stack-check} option is used, every function-prologue will
+    call the function @code{__stack_check} with the stacksize needed by this
+    function in register @code{R1}. This function has to consider its own
+    stacksize and must restore all registers.
+
+    Only stack-checking of the user-stack is supported. Checking the
+    system-stack is supported by hardware.
+
+
+
+@section Stdarg
+
+    A possible <stdarg.h> could look like this:
+
+@example
+    typedef char *va_list;
+
+    va_list __va_start(void);
+
+    #define __va_rounded_size(__TYPE)  \
+      (((sizeof (__TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+
+    #define va_start(__AP,__LA) (__AP=__va_start())
+
+    #define va_arg(__AP, __TYPE) \
+     (__AP = ((char *) (__AP) + __va_rounded_size (__TYPE)),     \
+      *((__TYPE *)((__AP) - __va_rounded_size (__TYPE))))
+ 
+    #define va_end(__AP) ((__AP) = 0)
+@end example
+
+
+@section Known Problems
+
+@itemize @minus
+    @item no floating-point
+    @item huge-pointers are sometimes derferenced as far-pointers
+    @item addressing-modes sometimes ignore huge
+    @item initialized data is placed in RAM, bits are not initialized
+    @item struct-copy only works with near-pointers
+    @item near/far-conversion assumes DPP0-DPP3 linear
+@end itemize
+
diff --git a/doc/vbcchc12.texi b/doc/vbcchc12.texi
new file mode 100755
index 0000000..c89224b
--- /dev/null
+++ b/doc/vbcchc12.texi
@@ -0,0 +1,163 @@
+This chapter documents the Backend for the 68hc12 and 6809/6309 microcontroller families.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -merge-constants
+                Place identical floating point constants at the same
+                memory location. This can reduce program size and increase
+                compilation time. (No fp support yet.)
+
+    @item -const-in-data
+                By default constant data will be placed in a read-only
+                section. Using this option it will be placed in the
+                data section.
+
+    @item -no-delayed-popping
+                By default arguments of function calls are not always popped
+                from the stack immediately after the call, so that the
+                arguments of several calls may be popped at once.
+                With this option vbcc can be forced to pop them after every
+                function call.
+                This may simplify debugging and very slightly reduce the
+                stack size needed by the compiled program.
+
+    @item -no-peephole
+                Do not perform peephole-optimizations.
+
+    @item -mem-cse
+                Try to hold values loaded from memory in registers and
+                reuse them. Due to the small register-set of the hc12
+                this is disabled by default as it increases register-
+                pressure and tends to spill to the stack.
+
+    @item -cpu=<n>
+                Specify the processor family. Currently supported values are:
+@itemize
+@item 6812: Generate code for the Motorola 68hc12 series (default).
+
+@item 6809: Generate code for the Motorola 6809 series.
+
+@item 6309: Generate code for the Hitachi 6309 series (currently identical to 6809).
+@end itemize
+
+
+     @item -acc-glob
+                Make the accumulator available for global register allocation.
+                By default, the accumulator will only be used for register allocation
+                within basic blocks. In many cases, global allocation will result in
+                worse code, because the accumulator has to be pushed/popped many times.
+
+     @item -pcrel
+                Generate PC-relative code. May not fully work with 68hc12.
+
+     @item -drel
+                Generate code that accesses data relative to register @code{u}. Does not
+                work with 68hc12.
+
+@end table
+
+@section ABI
+
+    The current version generates assembly output for use with vasm6809_std or the GNU
+    assembler using the non-banked model.
+
+        This backend supports the following registers:
+
+        @itemize @minus
+        @item @code{d}  for the accumulator (also used for byte, i.e. @code{b})
+        @item @code{x}  for index register x
+        @item @code{y}  for index register y
+        @item @code{u}  for index register u (not on 68hc12)
+        @item @code{sp} for the stack-pointer
+        @end itemize
+
+    The accumulator and @code{x} are caller-save. The @code{y} register is callee-save.
+    The @code{u} register is used as data-page pointer with @code{-drel}.
+
+    The first function argument which has integer or pointer type up to 16 bits
+    is passed in the accumulator @code{d}.
+    The remaining arguments are passed on the stack.
+
+    Integers and pointers are returned in @code{d} or @code{d/x} (@code{x} contains the higher bits).
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - so when you call such a function
+    without a proper declaration in scope you can expect a crash.
+
+    The elementary data types are represented like:
+@example
+    type        size in bits        alignment in bytes
+
+    char                8                       1
+    short              16                       1
+    int                16                       1
+    long               32                       1 
+    near pointers      16                       1
+    far pointers       24                       1 (not yet)
+    huge pointers      24                       1 (not yet)
+    float              32                       1 (not yet)
+    double             64                       1 (not yet)
+    long double        64                       1 (not yet)
+@end example
+
+
+@section Target-specific variable-attributes
+ 
+    The 6809/hc12-backend offers the following variable attributes:
+
+@table @code 
+    @item __interrupt
+         Return with @code{rti} rather than @code{rts}.
+
+    @item __section("name","attr")
+                 Place this function/object in section "section"
+                 with attributes "attr".
+
+    @item __dpage
+          Place the variable in section @code{.dpage} and use direct addressing.
+
+@end table
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+    @item __HC12__
+                If code for 68hc12 is generated.
+
+    @item __6809__
+                If code for 6809 is generated.
+
+    @item __6309__
+                If code for 6309 is generated.
+@        
+@end table
+
+@section Stack
+
+    If the @option{-stack-check} option is used, every function-prologue will
+    call the function @code{__stack_check} with the stacksize needed by this
+    function in register @code{y}. This function has to consider its own
+    stacksize and must restore all registers.
+
+
+@section Stdarg
+
+	Stdarg is supported by the provided include.
+
+@section Known Problems
+
+@itemize @minus
+    @item Support for floating point and long long is still missing.
+    @item U register is not really used yet.
+    @item No support for 6309 extensions yet.
+    @item Many optimizations still missing.
+    @item Some code generation bugs to be fixed.
+
+@end itemize
+
+
diff --git a/doc/vbcci386.texi b/doc/vbcci386.texi
new file mode 100755
index 0000000..3d79d77
--- /dev/null
+++ b/doc/vbcci386.texi
@@ -0,0 +1,123 @@
+This chapter documents the Backend for the Intel i386 processor family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -longalign
+                 Align multibyte-values on 4-byte-boundaries. Needed by some
+                operating systems.
+
+    @item -elf
+               Do not use a '_'-prefix in front of external identifiers.
+                Use a '.'-prefix for label names.
+
+    @item -merge-constants
+                Place identical floating point constants at the same
+                memory location. This can reduce program size and increase
+                compilation time.
+
+    @item -const-in-data
+                By default constant data will be placed in a read-only
+                section. Using this option it will be placed in the data section
+                Note that on operating systems with memory protection this
+                option will disable write-protection of constant data.
+
+    @item -no-delayed-popping
+                By default arguments of function calls are not always popped
+                from the stack immediately after the call, so that the
+                arguments of several calls may be popped at once.
+                With this option vbcc can be forced to pop them after every
+                function call.
+                This may simplify debugging and very slightly reduce the
+                stack size needed by the compiled program.
+
+    @item -safe-fp 
+                Do not use the floating-point-stack for register variables.
+                At the moment this is necessary as vbcci386 still has problems
+                in some cases otherwise.
+@end table
+
+
+@section ABI
+
+        This backend supports the following registers:
+
+        @itemize @minus
+        @item @code{%eax, %ebx, %ecx, %edx}
+        @item @code{%esi, %edi, %ebp, %esp}
+        @end itemize
+
+        (And @code{%st(0)-%st(7)} for the floating point stack but these must not
+         bes used for register variables because they cannot be handled like
+         normal registers.)
+
+    The current version generates assembly output for use with the GNU
+    assembler. The generated code should work on systems with Intel 80386
+    or higher CPUs with FPU and compatible chips.
+
+    The registers @code{%eax, %ecx} and @code{%edx} (as well as the floating point stack)
+    are used as scratch registers (i.e. they can be destroyed in function
+    calls), all other registers are preserved.
+
+    All elementary types up to 4 bytes are returned in register @code{%eax}
+    Floating point values are returned in %st(0).
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - so when you call such a function
+    without a proper declaration in scope you can expect a crash.
+
+    @code{vbcc} uses @code{%eax, %ebx, %ecx, %edx, %esi, %edi, %ebp} and the floating point
+    stack for temporary results and register variables. Local variables
+    are created on the stack and addressed via @code{%esp}.
+
+    The elementary data types are represented like:
+
+    @example
+    type        size in bits        alignment in bytes (-longalign)
+
+    char                8                       1 (1)
+    short              16                       2 (4)
+    int                32                       2 (4)
+    long               32                       2 (4)
+    long long          n/a                      n/a
+    all pointers       32                       2 (4)
+    float              32                       2 (4)
+    double             64                       2 (4)
+    @end example
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __I386__
+        @item __X86__
+        
+@end table
+
+
+@section Stdarg
+
+    A possible <stdarg.h> could look like this:
+
+@example
+    typedef unsigned char *va_list;
+
+    #define va_start(ap, lastarg) ((ap) = (va_list)(&lastarg + 1))
+    #define va_arg(ap, type) ((ap) += \
+      (sizeof(type)<sizeof(int)?sizeof(int):sizeof(type)), ((type *)(ap))[-1])
+    #define va_end(ap) ((ap) = 0L)
+@end example
+
+
+@section Known Problems
+
+@itemize @minus
+    @item generated code is rather poor
+    @item  functions which return floating-point values sometimes are broken(?)
+    @item  in some cases (scare registers) non-reentrant code is generated
+@end itemize
+
+
diff --git a/doc/vbccm68k.texi b/doc/vbccm68k.texi
new file mode 100644
index 0000000..9999f9d
--- /dev/null
+++ b/doc/vbccm68k.texi
@@ -0,0 +1,474 @@
+This chapter documents the backend for the M68k and Coldfire
+processor families.
+
+@section Additional options
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -a2scratch
+              Allow using @code{A2} as scratch register.
+
+    @item -amiga-softfloat
+              Call AmigaOS MathIEEE library functions via direct inline
+              code, instead of callling stub routines from @file{mieee.lib}.
+              It still requires that you either link with @file{mieee.lib} or
+              define @code{MathIeeeSingBasBase}, @code{MathIeeeDoubBasBase}
+              and @code{MathIeeeDoubTransBase} yourself.
+
+    @item -conservative-sr
+              Restrict strength-reduction. Experimental.
+
+    @item -const-in-data
+              By default constant data will be placed in the code
+              section (and therefore is accessible with faster pc-relative
+              addressing modes). Using this option it will be placed in the
+              data section.
+
+              This could e.g. be useful if you want to use small data and
+              small code, but your code gets too big with all the constant
+              data.
+
+              Note that on operating systems with memory protection this
+              option will disable write-protection of constant data.
+
+    @item -cpu=n
+              Generate code for cpu n (e.g. @option{-cpu=68020}),
+              defaults to 68000.
+
+    @item -d2scratch
+              Allow using @code{D2} as scratch register.
+
+    @item -fastcall
+              Pass function arguments in volatile registers, when possible.
+
+    @item -fp2scratch
+              Allow using @code{FP2} as scratch register.
+
+    @item -fpu=n
+              Generate code for fpu n (e.g. @option{-fpu=68881}), default: 0.
+
+    @item -gas
+              Create output suitable for the GNU assembler.
+
+    @item -hunkdebug
+              When creating debug-output (@option{-g} option) create
+              Amiga debug hunks rather than DWARF2.
+              Does not work with @option{-gas}.
+
+    @item -no-delayed-popping
+              By default arguments of function calls are not always popped
+              from the stack immediately after the call, so that the
+              arguments of several calls may be popped at once.
+              With this option @command{vbcc} can be forced to pop them after every
+              function call.
+              This may simplify debugging and reduce the
+              stack size needed by the compiled program.
+
+    @item -no-fp-return
+
+              Do not return floats and doubles in floating-point registers
+              even if code for an fpu is generated.
+
+    @item -no-intz
+              When generating code for FPU do quick&dirty conversions
+              from floating-point to integer. The code may be somewhat
+              faster but will not correctly round to zero.
+              Only use it if you know what you are doing.
+
+    @item -no-mreg-return
+              Do not use multiple registers to return types that do not
+              fit into a single register. This is mainly for backwards
+              compatibility with certain libraries.
+
+    @item -no-peephole
+              Do not perform peephole-optimizations.
+
+    @item -no-reserve-regs
+              Do not reserve temporary registers for the backend. Can lead to
+              worse code generation.
+
+    @item -old-softfloat
+              Use old libcall mechanism for software floating point.
+              Should not be used, will usually generate worse code.
+
+    @item -old-libcalls
+              Use old libcall mechanism for (some) integer support routines.
+              Should not be used, will usually generate worse code.
+
+    @item -phxass
+              Generate assembly output for the PhxAss assembler.
+
+    @item -prof
+              Insert code for profiling.
+
+    @item -sc
+              Use small code model (see below).
+
+    @item -sd
+              Use small data model (see below).
+
+    @item -use-commons
+              Use real common symbols instead of bss symbols for
+              non-initialized external variables.
+
+    @item -use-framepointer
+              By default automatic variables are addressed through a7
+              instead of a5. This generates slightly better code, because
+              the function entry and exit overhead is reduced and a5 can be
+              used as register variable etc.
+
+              However this may be a bit confusing when debugging and you
+              can force @command{vbcc} to use a5 as a fixed framepointer.
+
+
+
+
+@end table
+
+@section ABI
+
+    The current version generates assembler output for use with the
+    @command{vasmm68k_mot}. Most peephole optimizations are done by the
+    assembler so @command{vbcc} only does some that the assembler cannot make.
+    The generated executables will probably only work with OS2.0 or higher.
+
+    With @option{-gas} assembler output suitable for the GNU assembler is generated
+    (the version must understand the Motorola syntax - some old ones do not).
+    The output is only slightly modified from the @command{vasm}-output and will
+    therefore result in worse code on @command{gas}.
+
+    The register names provided by this backend are:
+
+@example
+         a0,  a1,  a2,  a3,  a4,  a5,  a6,  a7
+         d0,  d1,  d2,  d3,  d4,  d5,  d6,  d7
+        fp0, fp1, fp2, fp3, fp4, fp5, fp6, fp7
+@end example
+
+        The registers @code{a0} - @code{a7} are supported to hold pointer
+        types. @code{d0} - @code{d7} can be used for integers types
+        excluding @code{long long}, pointers and @code{float} if no
+        FPU code is generated. @code{fp0} - @code{fp7} can be used for
+        all floating point types if FPU code is generated.
+
+        Additionally the following register pairs can be used for
+        @code{long long}:
+
+@example
+        d0/d1, d2/d3, d4/d5, d6/d7
+@end example        
+
+    The registers @code{d0, d1, a0, a1, fp0} and @code{fp1}  are used as scratch registers
+    (i.e. they can be destroyed in function calls), all other registers are
+    preserved.
+
+        By default, all function arguments are passed on the stack.
+
+    All scalar types up to 4 bytes are returned in register @code{d0},
+        @code{long long} is returned in @code{d0/d1}.
+        If compiled for FPU, floating point values are returned in
+    @code{fp0} unless @option{-no-fpreturn} is specified.
+    Types which are 8, 12 or 16 bytes large will be returned in several
+    registers (@code{d0/d1/a0/a1}) unless @option{-no-mreg-return} is specified.
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - such a function must not be called
+    without a proper declaration in scope.
+
+    Objects which have been compiled with different settings must not be
+        linked together.
+
+        @code{a7} is used as stack pointer. If @option{-sd} is used,
+        @code{a4} will be used as small data pointer. If 
+        @option{-use-framepointer} is used, @code{a5} will be used as
+        frame pointer. All other registers will be used by the
+        register allocator and can be used for register parameters.
+
+        The size of the stack frame is limited to 32KB for early members
+        of the 68000 family prior to 68020.
+
+
+The basic data types are represented like:
+
+@example
+    type        size in bits        alignment in bytes
+
+    char                8                       1
+    short              16                       2
+    int                32                       2
+    long               32                       2
+    long long          64                       2
+    all pointers       32                       2
+    float(fpu)         32                       2       see below
+    double(fpu)        64                       2       see below
+    long double(fpu)   64                       2       see below
+@end example
+
+
+
+@section Small data
+
+    @command{vbcc} can access static data in two ways. By default all such data will
+    be accessed with full 32bit addresses (large data model).
+    However there is a second way. You can set up an address register 
+        (@code{a4})
+    to point into the data segment and then address data with a 16bit
+    offset through this register.
+
+    The advantages of the small data model are that the program will
+    usually be smaller (because the 16bit offsets use less space and no
+    relocation information is needed) and faster.
+
+    The disadvantages are that one address register cannot be used by the
+    compiler and that it can only be used if all static data occupies
+    less than 64kb. Also object modules and libraries that
+    have been compiled with different data models must not be mixed
+    (it is possible to call functions
+    compiled with large data model from object files compiled with small
+    data model, but not vice versa and only functions can be called that
+    way - other data cannot be accessed).
+
+    If small data is used with functions which are called from
+    functions which have not been compiled with @command{vbcc} or without the small data
+    model then those functions must be declared with the @code{__saveds} attribute
+    or call @code{geta4()} as the first statement (do not use
+    automatic initializations prior to the call to @code{geta4}).
+    Note that @code{geta4()} must not be called through a function pointer!
+
+
+@section Small code
+
+    In the small code model calls to external functions (i.e. from
+    libraries or other object files) are done with 16bit offsets through
+    the program counter rather than with absolute 32bit addresses.
+
+    The advantage is slightly smaller and faster code.
+    The disadvantages are that all the code (including library functions)
+    must be small enough. Objects/libraries can be linked together if they
+    have been compiled with different code models.
+
+
+@section CPUs
+
+    The values of @option{-cpu=n} have those effects:
+
+@table @option
+
+    @item n<68000     
+        Code for the Coldfire family is generated.
+
+    @item n>=68000    
+        Code for the 68k family is generated.
+
+    @item n>=68020
+@itemize @minus
+   @item 32bit multiplication/division/modulo is done with the
+                  mul?.l, div?.l and div?l.l instructions.
+   @item tst.l ax is used.
+   @item extb.l dx is used.
+   @item 16/32bit offsets are used in certain addressing modes.
+   @item link.l is used.
+   @item Addressing modes with scaling are used.
+@end itemize
+
+    @item n==68040
+@itemize @minus
+   @item 8bit constants are not copied in data registers.
+   @item Static memory is not subject to common subexpression elimination.
+@end itemize
+
+@end table
+
+
+@section FPUs
+
+    At the moment the values of -fpu=n have those effects:
+
+@table @option
+    @item n>68000    
+        Floating point calculations are done using the FPU.
+    @item n=68040
+    @itemx n=68060    
+        Instructions that have to be emulated on these FPUs
+                  will not be used; at the moment this only includes
+                  the @code{fintrz} instruction in case of the 040.
+@end table
+
+@section Math
+
+    Long multiply
+    on CPUs <68020 uses inline routines. This may increase code size a bit,
+    but it should be significantly faster, because function call overhead
+    is not necessary. 
+    Long division and modulo is handled by calls to library
+    functions.
+    (Some operations involving constants (e.g. powers of two) are always
+    implemented by more efficient inline code.)
+
+    If no FPU is specified floating point math is done using
+    math libraries. 32bit IEEE format is used for float and 64bit IEEE
+    for double and long double.
+
+    If floating point math is done with the FPU
+    floating point values are kept in registers and therefore may
+    have extended precision sometimes. This is not ANSI compliant but
+    will usually cause no harm. When floating point values are stored in
+    memory they use the same IEEE formats as without FPU.
+    Return values are passed in @code{fp0}.
+
+    Note that you must not link object files together if they were not
+    compiled with the same @code{-fpu} settings and that
+    a proper math library must be linked.
+
+
+@section Target-Specific Variable Attributes
+
+    This backend offers the following variable attributes:
+
+@table @code
+    @item __amigainterrupt
+                Used to write interrupt-handlers for AmigaOS. Stack-checking
+                for a function with this attribute will be disabled and if a value
+                is returned in d0, the
+                condition codes will be set accordingly.
+
+    @item __chip
+              Place variable in chip-memory. Only applicable on
+                 AmigaOS to variables with static storage-duration.
+
+    @item __far
+               Do not place this variable in the small-data segment
+                 in small data mode. No effect in large data mode.
+                 Only applicable to variables with static
+                storage-duration.
+
+    @item __interrupt
+                 This is used to declare interrupt-handlers. The
+                 function using this attribute will save all registers
+                 it destroys (including scratch-registers) and return
+                 with @code{rte} rather than @code{rts}.
+
+    @item __near
+              Currently ignored.
+
+    @item __regargs
+            Declare function to use the @option{-fastcall} ABI. The
+            first arguments are passed in volatile registers.
+
+    @item __saveds
+            Load the pointer to the small data segment at
+                 function-entry. Applicable only to functions.
+
+    @item __section(<string-literal>)
+                 Places the variable/function in a section named
+                 according to the argument.
+
+    @item __stdargs
+            Declare function to use the standard ABI (default),
+            which passes all arguments on the stack.
+@end table
+
+@section Target-specific pragmas
+
+    This backend offers the following #pragmas:
+
+@table @code
+
+    @item #pragma stdargs-on
+          Automatically declare the following functions with the
+          @code{__stdargs} attribute.
+
+    @item #pragma stdargs-off
+          Stop automatically declaring the following functions with the
+          @code{__stdargs} attribute.
+
+@end table
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __AMIGADATE__
+                This is set to current date as @code{"(DD.MM.YYYY)"},
+                useful with version strings.
+
+        @item __COLDFIRE
+                (If a Coldfire CPU is selected.)
+        
+        @item __INTSIZE
+                Is set to the size of the @code{int} type.
+                Either 16 (vbccm68ks) or 32 (vbccm68k).
+
+        @item __M680x0
+                (Depending on the settings of @option{-cpu}, e.g.
+                @code{__M68020}.)
+
+        @item __M68881 
+                (If @option{-fpu=68881} is selected.)
+
+        @item __M68882
+                (If code for another FPU is selected;
+                @option{-fpu=68040} or @option{-fpu=68060} will
+                set @code{__M68882}.)
+
+        @item __M68K__
+
+        @item __SMALL_DATA__
+                (If @option{-sd} is selected to enable small data.)
+@end table
+
+
+@section Stack
+
+    If the @option{-stack-check} option is used, every function-prologue will
+    call the function @code{__stack_check} with the stacksize needed by the
+    current function on the stack. This function has to consider its own
+    stacksize and must restore all registers.
+
+    If the compiler is able to calculate the maximum stack-size of a
+    function including all callees, it will add a comment in the
+    generated assembly-output (subject to change to labels).
+
+
+@section Stdarg
+
+    A possible @file{<stdarg.h>} could look like this:
+
+@example
+
+typedef unsigned char *va_list;
+
+#define __va_align(type) (__alignof(type)>=4?__alignof(type):4)
+
+#define __va_do_align(vl,type) ((vl)=(char *)((((unsigned int)(vl))+__va_align(type)-1)/__va_align(type)*__va_align(type)))
+
+#define __va_mem(vl,type) (__va_do_align((vl),type),(vl)+=sizeof(type),((type*)(vl))[-1])
+
+#define va_start(ap, lastarg) ((ap)=(va_list)(&lastarg+1))
+ 
+#define va_arg(vl,type) __va_mem(vl,type)
+ 
+#define va_end(vl) ((vl)=0)
+
+#define va_copy(new,old) ((new)=(old))
+
+#endif
+
+
+@end example
+
+@section Known problems
+
+@itemize @minus
+    @item The extended precision of the FPU registers can cause problems if
+      a program depends on the exact precision. Most programs will not
+      have trouble with that, but programs which do exact comparisons
+      with floating point types (e.g. to try to calculate the number
+      of significant bits) may not work as expected (especially if the
+      optimizer was turned on).
+@end itemize
+
+
+
diff --git a/doc/vbccppc.texi b/doc/vbccppc.texi
new file mode 100644
index 0000000..9d7fe3e
--- /dev/null
+++ b/doc/vbccppc.texi
@@ -0,0 +1,349 @@
+This chapter documents the Backend for the PowerPC processor family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -amiga-align
+
+                Do not require any alignments greater than 2 bytes.
+                This is needed when accessing Amiga system-structures, but
+                can cause a performance penalty.
+
+    @item -baserel32mos
+
+                Use 32bit base-relative addressing as used by MorphOS.
+
+    @item -baserel32os4
+
+                Use 32bit base-relative addressing as used by AmigaOS 4.
+
+    @item -const-in-data
+
+                By default constant data will be placed in the @code{.rodata}
+                section. Using this option it will be placed in the 
+                @code{.data} section.
+                Note that on operating systems with memory protection this
+                option will disable write-protection of constant data.
+
+    @item -eabi
+               Use the PowerPC Embedded ABI (eabi).
+
+    @item -elf
+
+                Do not prefix symbols with '_'. Prefix labels with '.'.
+
+    @item -fsub-zero
+
+                Use fsub to load a floating-point-register with zero.
+                This is faster but requires all registers to always contain
+                valid values (i.e. no NaNs etc.) which may not be the case
+                depending on startup-code, libraries etc.
+
+    @item -gas
+                Create code suitable for the GNU assembler.
+
+    @item -madd
+               Use the @code{fmadd/fmsub} instructions for combining
+                multiplication with addition/subtraction in one instruction.
+                As these instructions do not round between the operations,
+                they have increased precision over separate addition and
+                multiplication.
+
+                While this usually does no harm, it is not ISO conforming
+                and therefore not the default behaviour.
+
+    @item -merge-constants
+
+                Place identical floating point constants at the same
+                memory location. This can reduce program size.
+
+    @item -no-align-args
+
+                Do not align function arguments on the stack stricter
+                than 4 bytes. Default with @option{-poweropen}.
+
+    @item -no-peephole
+
+                Do not perform several peephole optimizations.
+                Currently includes:
+                @itemize @minus
+                 @item better use of d16(r) addressing
+                 @item use of indexed addressing modes
+                 @item use of update-flag
+                 @item use of record-flag
+                 @item use of condition-code-registers to avoid certain branches
+                @end itemize
+
+    @item -no-regnames
+
+                Do not use register names but only numbers in the assembly
+                output. This is necessary
+                to avoid name-conflicts when using @option{-elf}.
+
+    @item -poweropen
+
+                Generate code for the PowerOpen ABI like used in AIX.
+                This does not work correctly yet.
+
+    @item -sc
+
+                Generate code for the modified PowerOpen ABI used in the
+                StormC compiler (aka WarpOS ABI).
+
+    @item -sd
+                 Place all objects in small data-sections.
+
+    @item -setccs
+
+                The V.4 ABI requires signalling (in a bit of the condition code
+                register) when arguments to varargs-functions
+                are passed in floating-point registers.
+                vbcc usually does not make use of this and
+                therefore does not set that bit by default.
+                This may lead to problems when linking objects compiled by
+                vbcc to objects/libraries created by other
+                compilers and calling varargs-functions with floating-point
+                arguments.
+                @option{-setccs} will fix this problem.
+
+    @item -use-commons
+
+                Use real common symbols instead of bss symbols for
+                non-initialized external variables.
+
+    @item -use-lmw
+
+                Use @code{lmw/stmw}-instructions. This can significantly reduce
+                code-size. However these instructions may be slower on
+                certain PPCs.
+
+@end table
+
+@section ABI
+
+        This backend supports the following registers:
+
+        @itemize @minus
+        @item @code{r0} through @code{r31} for the general purpose registers,
+        @item @code{f0} through @code{f31} for the floating point registers and
+        @item @code{cr0} through @code{cr7} for the condition-code registers.
+        @end itemize
+
+        Additionally, the register pairs @code{r3/r4, r5/r6, r7/r8, r9/r10,
+        r14/r15, r16/r17, r18/r19,
+        r20/r21, r22/r23, r24/r25, r26/r27, r28/r29} and @code{r30/r31} are
+        available.
+
+        @code{r0, r11, r12, f0, f12} and @code{f13} are reserved by the
+        backend.
+
+        
+
+    The current version generates assembly output for use with @file{vasmppc}
+    or the GNU assembler. The generated code should
+    work on 32bit systems based on a PowerPC CPU using the V.4 ABI or the
+    PowerPC Embedded ABI (eabi).
+
+
+    The registers r0, r3-r12, f0-f13 and cr0-cr1 are used as scratch registers
+    (i.e. they can be destroyed in function calls), all other registers are
+    preserved. r1 is the stack-pointer and r13 is the small-data-pointer if
+    small-data-mode is used.
+
+    The first 8 function arguments which have integer or pointer types
+    are passed in registers r3 through r10 and the first 8 floating-point
+    arguments are passed in registers f1 through f8. All other arguments
+    are passed on the stack.
+
+    Integers and pointers are returned in r3 (and r4 for long long),
+    floats and doubles in f1.
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - so when you call such a function
+    without a proper declaration in scope you can expect a crash.
+
+    The elementary data types are represented like:
+
+    @example
+    type        size in bits        alignment in bytes (-amiga-align)
+
+    char                8                       1 (1)
+    short              16                       2 (2)
+    int                32                       4 (2)
+    long               32                       4 (2)
+    long long          64                       8 (2)
+    all pointers       32                       4 (2)
+    float              32                       4 (2)
+    double             64                       8 (2)
+    @end example
+
+@section Target-specific variable-attributes
+
+    The PPC-backend offers the following variable-attributes:
+
+@table @code
+
+    @item __saveds
+                    Load the pointer to the small data segment at
+                 function-entry. Applicable only to functions.
+
+    @item __chip
+                      Place variable in chip-memory. Only applicable on
+                 AmigaOS to variables with static storage-duration.
+
+    @item __far
+                       Do not place this variable in the small-data segment
+                 in small-data-mode. No effect in large-data-mode.
+                 Only applicable to variables with static storage-
+                 duration.
+
+    @item __near
+              Currently ignored.
+
+    @item __saveall
+                Make sure all registers are saved by this function. On lower
+                optimization levels, all volatile registers will be saved
+                additionally. On higher levels, only the ones that may be
+                destroyed, are saved.
+
+    @item __interrupt
+                Return with en @code{rfi}-instruction rather than @code{blr}.
+
+    @item __section("name","attr")
+                 Place this function/object in section "name" with
+                 attributes "attr".
+@end table
+
+
+@section Target-specific pragmas
+
+    The PPC-backend offers the following #pragmas:
+
+@table @code
+
+    @item #pragma amiga-align
+             Set alignment like -amiga-alignment option.
+
+    @item #pragma natural-align
+           Align every type to its own size.
+
+    @item #pragma default-align
+           Set alignment according to command-line options.
+
+@end table
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __PPC__
+        
+        @item __AMIGADATE__
+                This is set to current date as @code{"(DD.MM.YYYY)"},
+                useful with version strings.
+@end table
+
+@section Stack
+
+    If the @option{-stack-check} option is used, every function-prologue will
+    call the function @code{__stack_check} with the stacksize needed by this
+    function in register r12. This function has to consider its own
+    stacksize and must restore all registers.
+
+@section Stdarg
+
+    A possible <stdarg.h> for V.4 ABI could look like this:
+
+@example
+
+typedef struct @{
+  int gpr;
+  int fpr;
+  char *regbase;
+  char *membase;
+@} va_list;
+
+char *__va_start(void);
+char *__va_regbase(void);
+int __va_fixedgpr(void);
+int __va_fixedfpr(void);
+
+#define va_start(vl,dummy) \
+  ( \
+    vl.gpr=__va_fixedgpr(), \
+    vl.fpr=__va_fixedfpr(), \
+    vl.regbase=__va_regbase(), \
+    vl.membase=__va_start() \
+  )
+
+#define va_end(vl) ((vl).regbase=(vl).membase=0)
+
+#define va_copy(new,old) ((new)=(old))
+
+#define __va_align(type) (__alignof(type)>=4?__alignof(type):4)
+
+#define __va_do_align(vl,type) ((vl).membase=(char *)((((unsigned int)((vl).membase))+__va_align(type)-1)/__va_align(type)*__va_align(type)))
+
+#define __va_mem(vl,type) (__va_do_align((vl),type),(vl).membase+=sizeof(type),((type*)((vl).membase))[-1])
+
+#define va_arg(vl,type) \
+ ( \
+  (__typeof(type)&127)>10? \
+    __va_mem((vl),type) \
+  : \
+   ( \
+    (((__typeof(type)&127)>=6&&(__typeof(type)&127)<=8)) ? \
+     ( \
+      ++(vl).fpr<=8 ? \
+        ((type*)((vl).regbase+32))[(vl).fpr-1] \
+      : \
+        __va_mem((vl),type) \
+     ) \
+    : \
+     ( \
+      ++(vl).gpr<=8 ? \
+        ((type*)((vl).regbase+0))[(vl).gpr-1] \
+      : \
+        __va_mem((vl),type) \
+     ) \
+   ) \
+ )
+
+@end example
+
+    A possible <stdarg.h> for PowerOpen ABI could look like this:
+
+@example
+
+typedef unsigned char *va_list;
+
+#define __va_align(type) (4)
+
+#define __va_do_align(vl,type) ((vl)=(char *)((((unsigned int)(vl))+__va_align(type)-1)/__va_align(type)*__va_align(type)))
+
+#define __va_mem(vl,type) (__va_do_align((vl),type),(vl)+=sizeof(type),((type*)(vl))[-1])
+
+#define va_start(ap, lastarg) ((ap)=(va_list)(&lastarg+1))
+ 
+#define va_arg(vl,type) __va_mem(vl,type)
+ 
+#define va_end(vl) ((vl)=0)
+
+#define va_copy(new,old) ((new)=(old))
+
+@end example
+
+
+@section Known problems
+
+@itemize @minus
+  @item  composite types are put on the stack rather than passed via pointer
+  @item indication of fp-register-args with bit 6 of cr is not done well
+@end itemize
+
+
+
+
diff --git a/doc/vbccvidcore.texi b/doc/vbccvidcore.texi
new file mode 100644
index 0000000..64430c6
--- /dev/null
+++ b/doc/vbccvidcore.texi
@@ -0,0 +1,157 @@
+This chapter documents the Backend for the VideoCore IV processor family.
+
+The backend is in a very early stage, it is not complete, and it can not
+yet be considered useful!
+
+Also note that it is based on freely available, unofficial, and possibly
+incorrect information on the target processor.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+    @item -short-double
+
+                Use native 32bit floating point for double and long double.
+                This is much more efficient, but not ISO C conforming.
+
+    @item -one-section
+
+                Put all code and data in the same section (.text).
+
+
+    @item -no-delayed-popping
+
+                By default arguments of function calls are not always popped
+                from the stack immediately after the call, so that the
+                arguments of several calls may be popped at once.
+                With this option @command{vbcc} can be forced to pop them after every
+                function call.
+                This may simplify debugging and reduce the
+                stack size needed by the compiled program.
+
+    @item -no-peephole
+
+                Disable most backend peephole optimizations.
+                Just for testing.
+
+    @item -noext-regs
+
+                Do not use registers r16-r23. Just for testing.
+
+    @item -cond-limit=<n>
+
+                Set the limit (in number of intermediate code instructions)
+                for the length of code-sequences considered for conditional
+                execution (default: 2).
+
+
+@end table
+
+@section ABI
+
+        This backend supports the following registers:
+
+        @itemize @minus
+        @item @code{r0} through @code{r31} for the general purpose registers
+        @end itemize
+
+        Additionally, the register pairs @code{r0/r1} @code{r2/r3, r4/r5, r6/r7, r8/r9,
+        r10/r11, r12/r13, r14/r15,
+        r16/r17, r18/r19, r20/r21, r22/r23} are
+        available.
+
+        @code{r14, r15, r24-r31} are currently reserved by the
+        backend.
+
+        
+
+    The current version generates assembly output for use with @file{vasm}.
+
+
+    The registers r0-r5 and r14-r15 are used as scratch registers
+    (i.e. they can be destroyed in function calls), all other registers are
+    preserved. r25 is the stack-pointer.
+
+    The first 6 function arguments which have integer, float32 or pointer types
+    are passed in registers r0 through r5. All other arguments
+    are passed on the stack.
+
+    Integers, float32 and pointers are returned in r0.
+    All other types are returned by passing the function the address
+    of the result as a hidden argument - so when you call such a function
+    without a proper declaration in scope you can expect a crash.
+
+    The elementary data types are represented like:
+
+    @example
+    type        size in bits        alignment in bytes
+
+    char                8                       1 
+    short              16                       2 
+    int                32                       4 
+    long               32                       4 
+    long long          64                       8    not yet supported
+    all pointers       32                       4 
+    float              32                       4 
+    double             64 (32)                  4 
+    long double        64 (32)                  4
+    @end example
+
+@section Target-specific variable-attributes
+
+    The vidcore-backend offers the following variable-attributes:
+
+@table @code
+
+    @item __section("name","attr")
+                 Place this function/object in section "name" with
+                 attributes "attr".
+@end table
+
+
+@section Target-specific pragmas
+
+    The vidcore-backend offers the following #pragmas:
+
+@table @code
+
+       @item none at the moment...
+
+@end table
+
+@section Predefined Macros
+
+        This backend defines the following macros:
+
+@table @code
+        @item __VIDEOCORE__
+
+        @item __SHORT_DOUBLE__ (if -short-double is used)        
+@end table
+
+@section Stdarg
+
+stdarg-implementation is not yet fully working. One restriction is that
+when calling a varargs function, the prototype must be in scope (this is
+ISO C conforming). Another one is that the stdarg-macros only work as
+long as all fixed arguments are passed in registers.
+
+This will be fixed in the future.
+
+
+@section Known problems
+
+@itemize @minus
+         @item no support for long long
+         @item no support for 64bit floating point
+         @item stdarg problems mentioned above
+         @item suboptimal code quality
+         @item ...
+@end itemize
+
+
+
+
diff --git a/doc/vc.texi b/doc/vc.texi
new file mode 100644
index 0000000..89de471
--- /dev/null
+++ b/doc/vc.texi
@@ -0,0 +1,254 @@
+This chapter describes @command{vc}, the frontend for vbcc. It knows how
+to deal with different file types and optimization settings and will
+call the compiler, assembler and linker.
+It is not recommended to call the different translation-phases directly.
+@command{vc} provides an easy-to-use interface which is mostly compatible to
+Unix @command{cc}.
+
+@section Usage
+
+    The general syntax for calling @command{vc}
+
+@example
+    @command{vc [options] file1 file2 ...}
+@end example
+
+    processes all files according to their suffix and links all objects
+    together (unless any of @option{-E}, @option{-S}, @option{-c} is specified).
+ The following file types are recognized:
+
+@table @file
+    @item .c      
+                C source
+    @item .i      
+                already preprocessed C source
+    @item .scs    
+                assembly source to be fed to the scheduler
+    @item .asm
+    @item .s      
+                assembly source
+    @item .obj
+    @item .o      
+                object file
+@end table
+
+    Usually pattern matching is supported - however this depends on the
+    port and the host system.
+
+    The options recognized by @command{vc} are:
+
+@table @option
+
+    @item -v      
+                Verbose mode. Prints all commands before executing them.
+
+    @item -vv     
+                Very verbose. Displays some internals as well.
+
+    @item -Ox     
+                Sets the optimization level.@*
+            -O0 is equivalent to -O=0.@*
+            -O  will activate some optimizations (at the moment -O=991).@*
+            -O2 will activate most optimizations (at the moment -O=1023 -schedule).@*
+            -O3 will activate all optimizations (at the moment -O=~0 -schedule).@*
+            -O4 will activate full cross-module-optimization.@*
+
+            Also, -O3 will activate cross-module-optimizations. All source
+            files specified on the command line will be passed to the compiler
+            at once. Only one assembly/object-file will be produced (by default
+            the name is the name of the first source file with corresponding
+            suffix).
+
+            When compiling with -O4 and -c vbcc will not produce real object
+            files but special files containing all necessary information to
+            defer optimization and code-generation to link-time. This is
+            useful to provide all files of a project to the optimizer and
+            make full use of cross-module optimizations.
+            Note that you must use vc to do the linking. vc will detect and
+            handle these files correctly. They can not be linked directly.
+            Also, make sure to pass all relevant compiler options also to
+            the linker-command.
+
+            Higher values may or may not activate even more optimizations.
+            The default is -O=1.
+            It is also possible to specify an exact value with -O=n.
+            However, I do not recommend this unless you know exactly what
+            you are doing.
+
+    @item -o file 
+                Save the target as @file{file} (default for executables is
+                @file{a.out}).
+
+    @item -E      
+                Save the preprocessed C sources with .i suffix.
+
+    @item -S      
+                Do not assemble. Save the compiled files with .asm suffix.
+
+    @item -SCS    
+                Do not schedule. Save the compiled files with .scs suffix.
+
+    @item -c      
+                Do not link. Save the compiled files with .o suffix.
+
+    @item -k      
+                Keep all intermediate files. By default all generated files
+            except the source files and the targets are deleted.
+
+    @item -Dstr   
+                @code{#define} a preprocessor symbol, e.g. -DAMIGA or -DCPU=68000.
+                The former syntax is equivalent to:
+@example
+ #define AMIGA 1
+@end example
+                The latter form is equivalent to:
+@example
+ #define CPU 68000
+@end example
+
+    @item -Ipath  
+                Add @file{path} to the include-search-path.
+                An empty @file{path} adds the current directory.
+
+    @item -lulib  
+                Link with library @file{ulib}.
+
+    @item -Lpath  
+                Add @file{path} to the library-search-path.
+            This is passed through to the linker.
+
+    @item -static
+                Instruct the linker to link against static libraries.
+                This may override the default to link against dynamic
+                libraries first.
+
+    @item -nostdlib   
+                Do not link with standard-startup/libraries. Useful only
+                for people who know what they are doing.
+
+    @item -notmpfile  
+                Do not use names from tmpnam() for temporary files.
+
+    @item -schedule   
+                Invoke the instruction-scheduler, if available.
+
+    @item -rmcfg-<opt>
+                Ignore all lines from the config file starting with -<opt>.
+
+    @item +file   
+        Use @file{file} as config-file.
+
+@end table
+
+
+    All other options are passed through to @command{vbcc}.
+
+
+
+
+
+@section Configuration
+
+    @command{vc} needs a config file to know how to call all the translation
+    phases (compiler, assembler, linker). Unless a different file is
+    specified using the @option{+}-option, it will look for a file
+    @file{vc.config} (@file{vc.cfg} for DOS/Windows).
+
+    On AmigaOS @command{vc} will search in the current
+    directory, in @file{ENV:} and @file{VBCC:}.
+
+    On Unix @command{vc} will search in the current directory followed
+    by @file{/etc/}.
+
+    On DOS/Windows it will search in the current directory.
+
+    If the config file was not found in the default search-paths and
+    an environment variable @env{$VBCC} is set, @command{vc} will also look
+    in @env{$VBCC}@file{/config}.
+
+    Once a config file is found, it will
+    be treated as a collection of additional command line arguments. Every
+    line of the file will be used as one argument. So no quoting shall be
+    used and furthermore must each argument be placed on its own line.
+
+
+    The following options can be used to tell @command{vc} how to call the
+    translation phases (they will usually be contained in the config-file):
+
+@table @option
+
+    @item -pp=string
+                The preprocessor will be called like in
+                @code{printf(string,opts,infile,outfile)}, e.g. the default for @command{vcpp}
+                searching the includes in @file{vinclude:} and defining @code{__STDC__})
+                is @option{-pp=vcpp -Ivinclude: -D__STDC__=1 %s %s %s}.
+                Note that there is an internal preprocessor, called
+                @command{ucpp}, since V0.8, you usually don't need this
+                option any more.
+
+    @item -cc=string
+                For the compiler. Note that you cannot use @command{vc} to call
+                another compiler than @command{vbcc}. But you can call different
+                versions of @command{vbcc} this way, e.g.:
+                @option{-cc=vbccm68k -quiet} or
+                @option{-cc=vbcci386 -quiet}
+
+    @item -isc=string
+                The same for the scheduler, e.g.:
+                @option{-isc=vscppc -quiet %s %s}
+                Omit, if there is no scheduler for the architecture.
+
+    @item -as=string
+                The same for the assembler, e.g.:
+                @option{-as=vasmm68k_mot -quiet -Fhunk -phxass -opt-pea -opt-clr %s -o %s} or
+                @option{-as=as %s -o %s}
+
+    @item -rm=string 
+                This is the string for the delete command and takes only
+                one argument, e.g.
+                @option{-rm=delete quiet %s} or
+                @option{-rm=rm %s}
+
+    @item -ld=string
+                This is for the linker and takes three arguments. The first
+                one are the object files (separated by spaces), the second
+                one the user specified libraries and the last one the name
+                of the resulting executable.
+                This has to link with proper startup-code and c-libraries,
+                e.g.:
+                @option{-ld=vlink -x -Bstatic -Cvbcc -nostdlib -Lvlibos3: vlibos3:startup.o %s %s -lvc -o %s} or
+                @option{-ld=ld /usr/lib/crt0.o %s %s -lc -o %s}
+
+    @item -l2=string
+                The same like -ld, but standard-startup and -libraries should
+                not be linked; used when -nostdlib is specified.
+
+    @item -ldnodb=string
+                This option string is inserted in the linker command before
+                specifying the libraries, whenever an executable without
+                debugging information and symbols should be created (AKA
+                as a 'stripped' executable).
+
+    @item -ldstatic=string
+                This option string is inserted in the linker command before
+                specifying the libraries when static linking was requested
+                with option @option{-static}.
+                
+@end table
+
+    All those strings should tell the command to omit any output apart from
+    error messages if possible. However for every of those options there
+    exists one with an additional @samp{v}, i.e. @option{-ppv=}, @option{-asv=}, etc. which should
+    produce some output, if possible.
+    If vc is invoked with the @option{-vv} option the verbose commands will be called,
+    if not the quiet ones will be used.
+
+@table @samp
+    @item -ul=string  
+                Format for additional libraries specified with @option{-l<lib>}.
+                The result of @code{printf(string,lib)} will be added to the
+                command invoking the linker. Examples are:
+                @option{-ul=vlib:%s.lib} or @option{-ul=-l%s}
+
+@end table
+
diff --git a/doc/vclib.texi b/doc/vclib.texi
new file mode 100644
index 0000000..45dff3f
--- /dev/null
+++ b/doc/vclib.texi
@@ -0,0 +1,2818 @@
+This chapter describes the C library usually provided with @command{vbcc}.
+
+
+@section Introduction
+
+To execute code compiled by @command{vbcc}, a library is needed. It
+provides basic interfaces to the underlying operating system or
+hardware as well as a set of often used functions.
+
+A big part of the library is portable across all architectures. However,
+some functions (e.g. for input/output or memory allocation) are
+naturally dependent on the operating system or hardware. There are
+several sections in this chapter dealing with different versions of
+the library.
+
+The library itself often is split into several parts. A startup-code
+will do useful initializations, like setting up IO, parsing the command
+line or initializing variables and hardware.
+
+The biggest part of the functions will usually be stored in one library file.
+The name and format of this file depends on the conventions of the underlying
+system (e.g. @file{vc.lib} or @file{libvc.a}).
+
+Often, floating point code (if available) is stored in a different file
+(e.g. @file{m.lib} or @file{libm.a}). If floating point is used in an
+application, it might be necessary to explicitly link with this library
+(e.g. by specifying @file{-lm}).
+
+In many cases, the include files provide special inline-code or similar
+optimizations. Therefore, it is recommended to always include the
+corresponding include file when using a library function. Even if it
+is not necessary in all cases, it may affect the quality of the generated
+code.
+
+The library implements the functions specified by ISO9899:1989 as well
+as a part of the new functions from ISO9899:1999.
+
+@section Legal
+
+Most parts of this library are public domain. However, for some systems,
+parts may be under a different license. Please consult the system
+specific documentation. Usually, linking against this library will
+not put any restrictions on the created executable unless otherwise
+mentioned.
+
+Parts of the math library (e.g. transcendental functions) are derived
+from Sun's free math library:
+@example
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+@end example
+
+@node SoftfloatHauser
+The softfloat functions, used by some targets, are derived from John
+Hauser's IEC/IEEE Floating-point Artithmetic Package:
+
+@example
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+@end example
+
+
+@section Global Variables
+
+@subsection timezone
+
+On some host operating systems vclib might be unable to determine the
+current time zone, which is required for functions like
+@code{mktime()} or @code{localtime()} to work. Here you can overwrite
+the following variables:
+
+@table @code
+@item long __gmtoffset
+  Offset in minutes, west of Greenwich Mean Time (GMT).
+@item int __dstflag
+  Set to non-zero, when Daylight Saving Time is active.
+@end table
+
+Targets which can determine their current time zone, will do so by
+initializing these variables on startup.
+
+
+@section Embedded Systems
+
+This section describes specifics of the C library for embedded systems.
+
+@subsection Startup
+
+The startup is usually split into two parts. The first part is done by
+assembly code that produces the object file @file{lib/startup.o}. This
+assembly code is usually provided with vbcc and may have to be adapted to
+the hardware you are using. The key actions that have to be performed by this
+code are:
+
+@table @minus
+@item hardware initialization
+        It may be necessary to perform some hardware initialization right
+        at the beginning, e.g. to configure the memory system. This has to
+        be modified by the user.
+
+@item variable initializations
+        When running code from ROM, some memory sections have to be
+        initialized. Usually, the init-values of initialized variables
+        have to be copied from ROM to the data segment and the values of
+        un-initialized variables have to be cleared in the bss segment.
+        This code is usually provided in the startup code.
+
+@item stack pointer
+        The stack pointer has to be set to a suitable memory area.
+        The startup code
+        will set the stack pointer to the value of the pointer @code{__stack}.
+        There is a default stack provided in the C library which will be used
+        unless the application defines its own stack using, for example, the
+        following code (assuming that the stack grows downwards):
+@example
+#define STACKSIZE <whatever>
+
+static long mystack[STACKSIZE/sizeof(long)];
+char *__stack=((char*)mystack)+STACKSIZE;
+@end example
+
+@item calling @code{__main}
+        After all the above initializations have been performed, the function
+        @code{__main()} has to be called. This function is provided by the
+        library and performs high-level initializations, if necessary (mainly
+        it calls constructors created by the linker) and will then call the
+        user @code{main()} function. Note that the library
+        may not work correctly if the user @code{main()} function is called
+        directly from the startup code.
+
+@end table
+
+@subsection Heap
+
+When dynamic memory management is used (e.g. by using the @code{malloc()}
+function), a heap memory area is needed to allocate memory from. The
+@code{malloc()} function assumes that @code{__heapptr} is a variable pointing
+to the beginning of the heap memory and that @code{__heapsize} specifies
+the size of the heap area in bytes. The library will provide a default heap
+memory area that can be replaced by adding, for example, the following file
+to the application:
+@example
+#define HEAPSIZE <whatever>
+
+char __heap[HEAPSIZE],*__heapptr=__heap;
+size_t __heapsize=HEAPSIZE;
+@end example
+
+
+@subsection Input/Output
+
+The standard C input/output functions are provided also for embedded systems.
+Reading/writing to a stream will be directed to void unless the following
+low-level I/O-functions are provided by the application:
+@example
+int __open(const char *name,const char *mode);
+void __close(int h);
+size_t __read(int h,char *p,size_t l);
+size_t __write(int h,const char *p,size_t l);
+off_t __seek(int h,off_t offset,int origin);
+@end example
+
+The @code{__open()} function receives a name and a mode string (as in the C
+@code{fopen()} function) as arguments and has to return a file-descriptor if
+it is possible to open this file. The other functions are equivalent to the
+corresponding POSIX functions. @code{__seek} can be implemented to return 
+@code{-1} if the functionality is not needed.
+
+Also, @code{stdin, stdout} and @code{stderr} can be used with the standard
+descriptors.
+
+@subsection CTRL-C Handling
+
+Some targets implement handlers to terminate the program on ctrl-c or a
+similar signal. This usually has the same effect as calling
+@code{exit(20)}.
+
+If you want to change or disable the ctrl-c handling, you can overwrite
+the function @code{void _chkabort(void)}.
+
+@subsection Floating Point
+
+Whether floating point is supported, depends on the target architecture and
+chip. If it is supported, there will usually be a math-library that has to
+be linked (using option @option{-lm}) when floating point is used.
+
+@subsection Useless Functions
+
+Of course, some of the C library functions can not be implemented reasonably on
+embedded systems. These functions are contained in the library but will
+always return an error value. Mainly affected are:
+
+@table @minus
+@item locale
+@item time
+@item signal
+@item filesystem functions
+@end table
+
+Depending on the hardware provided by a system it is possible to implement
+these functions and add them to the application. In this case, the new
+functions will be used rather than the default ones returning only error
+values.
+
+@subsection Linking/Locating
+
+To produce ROM images (e.g. in the form of absolute ELF executables, Intel
+Hex files or Motorola S-Records), the linker is called with a linker script.
+This script can be used to join together different sections of the input files
+and locate them to suitable absolute memory areas. Also, this linker script
+can be used to set symbols that may be used by the application or the startup
+code, e.g. addresses of data sections, initialization values or small data
+pointers.
+
+Code or data that has to reside at special locations can be put into a special
+section using the @code{__section} attribute. This section can then be
+placed at the desired location using the linker script.
+
+Usually, an example linker script will be provided. While this is often not
+suitable for different chips, it may serve as a starting point.
+
+
+@section AmigaOS/68k
+
+This section describes specifics of the C library for AmigaOS/68k
+provided by the target @file{m68k-amigaos}.
+The relevant files are @file{startup.o}, @file{minstart.o}, @file{minres.o},
+@file{vc.lib}, @file{vcs.lib}, @file{mieee.lib}, @file{mieees.lib},
+@file{m881.lib}, @file{m881s.lib}, @file{m040.lib}, @file{m040s.lib},
+@file{m060.lib}, @file{m060s.lib}, @file{msoft.lib}, @file{msofts.lib},
+@file{amiga.lib}, @file{amigas.lib}, @file{auto.lib} and @file{autos.lib},
+@file{reaction.lib}, @file{reactions.lib}.
+
+Note that @file{extra.lib} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+The following config files are available:
+@table @code
+@item aos68k
+  Standard startup code (@file{startup.o}) with command line parsing
+  and optional Workbench startup (@xref{Standard Startup}).
+@item aos68km
+  Minimal startup code (@file{minstart.o}) without command line
+  parsing. You have to open all libraries yourself (@xref{Minimal Startup}).
+@item aos68kr
+  Minimal startup code (@file{minres.o}) for resident programs.
+  Always compiles in small data mode and links with @file{vcs.lib}
+  (@xref{Minimal Resident}).
+@end table
+
+@node Standard Startup
+@subsection Startup
+
+    The startup code currently consists of a slightly modified standard
+    Amiga startup (@file{startup.o}). The startup code sets up some
+    global variables and initializes stdin, stdout and stderr.
+    The exit code closes all open files and frees all memory.
+    If you link with a math library the startup/exit code will be taken
+    from there if necessary.
+
+
+@node Floating point
+@subsection Floating point
+
+    Note that you have to link with a math library if you want to use
+    floating point. All math functions, special startup code and
+    printf/scanf functions which support floating point are contained in
+    the math libraries only.
+    At the moment there are five math libraries:
+ 
+@table @file
+@item mieee.lib
+   This one uses the C= math libraries. The startup code
+                    will always open MathIeeeSingBas.library,
+                    MathIeeeDoubBas.library and MathIeeeDoubTrans.library.
+                    Float return values are passed in d0, double return
+                    values are passed in d0/d1.
+                    A 68000 is sufficient to use this library.
+                    You must not specify @option{-fpu=...}
+                    when you use this library.
+   By default all floating point routines are provided via stub functions in
+   @file{mieee.lib}. With the option @option{-amiga-softfloat} you can tell
+   @command{vbccm68k} to generate inline code for calling the
+   MathIeee libraries directly.
+ 
+@item msoft.lib
+    This one is based on John Hauser's IEC/IEEE Floating-point Arithmetic
+    Package (@xref{SoftfloatHauser}) and doesn't need any system libraries for
+    FP emulation. May be slower than the ROM libraries, though.
+    Otherwise everything mentioned for @file{mieee.lib} applies here
+    as well.
+    Note that you have to call the @command{vc} frontend with the
+    @option{-rmcfg-amiga-softfloat} option, when your config file contains
+    @option{-amiga-softfloat} (which is the case for @file{aos68k}
+    since vbcc V0.9h).
+
+@item m881.lib
+    This one uses direct FPU instructions and function
+                    return values are passed in fp0. You must have a
+                    68020 or higher and an FPU to use this library. You
+                    also have to specify @option{-fpu=68881} or
+                    @option{-fpu=68882}.
+                    Several FPU instructions that have to be emulated on
+                    040/060 may be used.
+ 
+@item m040.lib
+    This one uses only direct FPU instructions that do not
+                    have to be emulated on a 68040. Other functions use
+                    the Motorola emulation routines modified by
+                    Aki M Laukkanen and Matthew Hey.
+                    It should be used for programs compiled for 68040
+                    with FPU.
+                    Return values are passed in fp0.
+
+@item m060.lib
+    This one uses only direct FPU instructions that do not
+                    have to be emulated on a 68060. Other functions use
+                    the Motorola emulation routines modified by
+                    Aki M Laukkanen and Matthew Hey.
+                    It should be used for programs compiled for 68060
+                    with FPU.
+                    Return values are passed in fp0.
+@end table
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@node amiga-stack
+@subsection Stack
+
+An application can specify the stack-size needed by defining a variable
+@code{__stack} (of type @code{size_t}) with external linkage, e.g.
+
+@example
+size_t __stack=65536; /* 64KB stack-size */
+@end example
+
+The startup code will check whether the stack-size specified is larger
+than the default stack-size (as set in the shell) and switch to a new
+stack of appropriate size, if necessary.
+
+If the @option{-stack-check} option is specified when compiling, the
+library will check for a stack overflow and abort the program, if the
+stack overflows. Note, however, that only code compiled with this
+option will be checked. Calls to libraries which have not been compiled
+with @option{-stack-check} or calls to OS function may cause a stack
+overflow which is not noticed.
+
+Additionally, if @option{-stack-check} is used, the maximum stack-size
+used can be read by querying the external variable @code{__stack_usage}.
+
+@example
+#include <stdio.h>
+
+extern size_t __stack_usage;
+
+main()
+@{
+    do_program();
+    printf("stack used: %lu\n",(unsigned long)__stack_usage);
+@}
+@end example
+
+Like above, the stack used by functions not compiled using
+@option{-stack-check} or OS functions is ignored.
+
+@node amigasmalldata
+@subsection Small data model
+
+When using the small data model of the 68k series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+
+To compile and link a program using the small data model a command like
+
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+
+might be used.
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@node Minimal Startup
+@subsection Minimal Startup 
+
+If you want to write programs that use only Amiga functions and none from
+vc.lib you can use @file{minstart.o} instead of @file{startup.o} and
+produce smaller executables. You can also achieve that by simply using
+the @file{aos68km} config file instead.
+
+This startup code does not set up everything needed by vc.lib, so you
+must not use most of these functions (string and ctype functions are ok,
+but most other functions - especially I/O and memory handling - must not
+be used).
+@code{exit()} is supplied by minstart and can be used.
+ 
+The command line is not parsed, but passed to @code{main()} as a single
+string,
+so you can declare main as
+@code{int main(char *command)} or @code{int main(void)}.
+ 
+Also no Amiga libraries are opened (but @code{SysBase} is set up), so you
+have to define and open @code{DOSBase} yourself if you need it.
+If you want to use floating point with the IEEE libraries
+or @option{-amiga-softfloat} you have to
+define and open MathIeeeSingBas.library, MathIeeeDoubBas.library and
+MathIeeeDoubTrans.library (in this order!) and link with mieee.lib (if
+compiled for FPU this is not needed).
+ 
+A hello world using minstart could look like this:
+
+@example 
+#include <proto/exec.h>
+#include <proto/dos.h>
+ 
+struct DosLibrary *DOSBase;
+ 
+int main()
+@{
+    if(DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",0))@{
+        Write(Output(),"Hello, world!\n",14);
+        CloseLibrary((struct Library *)DOSBase);
+    @}
+    return 0;
+@}
+
+@end example
+
+This can yield an executable of under 256 bytes when compiled with
+@option{-sc -sd} and linked with @file{minstart.o} and @code{amigas.lib}
+(using @command{vlink} - may not work with other linkers).
+
+@node Minimal Resident
+@subsection Minimal Startup for resident programs
+
+AmigaOS can keep special "pure" programs resident in RAM, and restart them
+from there without having to load them again from disk. To make it easy to
+create such reentrant programs, even with static data, you can link with the
+special startup code @file{minres.o}, which is a minimal startup code for
+resident programs. Or simply use the config file @file{aos68kr} instead.
+Everything mentioned for @file{minstart.o} in the previous section is also
+valid for @file{minres.o}.
+
+To create real resident programs you have to follow the following rules:
+@itemize @minus
+
+@item Compile all your code for the small data model (@option{-sd} option).
+
+@item Avoid absolute references to small data symbols.
+      Usually these are constant pointers to static data.
+      The following example creates such an illegal relocation:
+@example
+int x;
+int const *p = &x;
+@end example
+@command{vlink} warns about all potential problems.
+
+@item Link with the @file{minres.o} startup code,
+      and use the small data
+      versions of linker libraries (@file{vcs.lib}, @file{amigas.lib}, etc.).
+
+@item Set the Pure flag in the file attributes.
+      Load the program into RAM
+      with the AmigaDOS @command{resident} command.
+
+@end itemize
+
+
+@node amigalib
+@subsection amiga.lib
+
+To write programs using AmigaOS (rather than standard C functions
+only), a replacement for the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement is adapted to vbcc,
+does not cause collisions with some functions (e.g. @code{sprintf})
+provided by the original @file{amiga.lib} and is available for the
+small data mode as well. It is recommended to always use this library
+rather than the original version.
+
+Additionally, there are header files (in the @file{proto}- and
+@file{inline}-subdirectories) which cause inlined calls to Amiga
+library functions.
+
+Besides some support functions @file{amiga.lib} contains stub routines
+to call functions from all common AmigaOS libraries with stack arguments.
+By including the library's proto header file you make sure that AmigaOS
+functions are called directly by inline code, unless @code{_NO_INLINE}
+is defined.
+
+Preprocessor defines to control the behaviour of vbcc's proto headers:
+@table @code
+@item __NOLIBBASE__
+  Do not declare the library base symbol.
+@item _NO_INLINE
+  Do not use optimized inline code for library function calls.
+@end table
+
+Note that the OS-call inlines have been generated using the NDK3.2 clib
+header files, while trying to keep compatibility to NDK3.9, so it is
+advised to use one of the two NDKs for development.
+Otherwise you will get warnings about missing @code{CONST} typedefs and
+similar.
+
+Specify @option{-lamiga} to link with @file{amiga.lib}.
+
+@node autolib
+@subsection auto.lib
+
+    To link with @file{auto.lib} (or the small data version
+    @file{autos.lib}) specify
+    the @option{-lauto} or @option{-lautos} option to @command{vc}.
+ 
+    When you are calling a standard Amiga library function without
+    having defined the corresponding library base, then the library base
+    as well as code to open/close it will be taken from @file{auto.lib}.
+ 
+    By default, @file{auto.lib} will try to open any library version. If you
+    need at least a certain version you can define and set a variable
+    _<library-base>Ver with external linkage, e.g. (on file-scope):
+
+@example 
+        int _IntuitionBaseVer = 39;
+@end example
+
+    Note that your program will abort before reaching @code{main()} if one
+    of the libraries cannot be opened. Also note that @file{auto.lib}
+    depends on constructor/destructor handling in vclib, which means it
+    cannot work when linking without vclib, without standard startup code,
+    or only with a minimal startup code, like @file{minstart.o}.
+
+@subsection reaction.lib
+
+The @file{reaction.lib} in @command{vbcc} is a port of Stephan Rupprecht's
+rewrite of the copyrighted linker library, extended and fixed by
+Olaf Barthel for the NDK 3.2 release. This version should work in
+combination with NDK 3.9 as well.
+
+To link with @file{reaction.lib} (or the small data version
+@file{reactions.lib}) specify the @option{-lreaction} or
+@option{-lreactions} option to @command{vc}.
+
+The library contains ReAction GUI class support functions and their
+autoinitialization code. Refer to @file{reaction_lib.doc} from your
+NDK Autodocs for more information. As documented there, the version
+used to automatically open the classes can be defined by the variable
+@code{__reactionversion} with external linkage. Otherwise a default
+of version 0 is used.
+
+
+@section Kickstart1.x/68k
+
+This section describes specifics of the C library for Amiga Kickstart 1.2
+and 1.3 provided by the target @file{m68k-kick13}.
+The relevant files are @file{startup.o}, @file{minstart.o}, @file{minres.o},
+@file{startup16.o}, @file{minstart16.o}, @file{minres16.o},
+@file{vc.lib}, @file{vcs.lib}, @file{m13.lib}, @file{m13s.lib},
+@file{msoft.lib}, @file{msofts.lib}, @file{m881.lib}, @file{m881s.lib},
+@file{amiga.lib}, @file{amigas.lib}, @file{auto.lib} and @file{autos.lib},
+@file{vc16.lib}, @file{vc16s.lib}, @file{m1316.lib}, @file{m1316s.lib},
+@file{msoft16.lib}, @file{msoft16s.lib}, @file{m88116.lib}, @file{m88116s.lib},
+@file{amiga16.lib}, @file{amiga16s.lib}, @file{auto16.lib} and
+@file{auto16s.lib}.
+
+This target makes it possible to develop programs targeted for these older
+versions of the Amiga operating system, using the original Commodore
+Kickstart 1.3 header files. Note that there are also libraries and
+config files for using a 16-bit int ABI, which was common at that time,
+and may have some advantages on 16-bit CPUs, like the 68000 or 68010.
+
+The following config files are available:
+@table @code
+@item kick13
+  Standard startup code (@file{startup.o}) with command line parsing
+  and optional Workbench startup (@xref{Startup13}) using 32-bit int.
+@item kick13m
+  Minimal startup code (@file{minstart.o}) without command line
+  parsing. You have to open all libraries yourself (@xref{Minimal Startup})
+  using 32-bit int.
+@item kick13r
+  Minimal startup code (@file{minres.o}) for resident programs.
+  Always compiles in small data mode and links with @file{vcs.lib}
+  (@xref{Minimal Resident}) using 32-bit int.
+@item kick13s
+  Standard startup code (@file{startup.o}) with command line parsing
+  and optional Workbench startup (@xref{Startup13}) using 16-bit int.
+@item kick13sm
+  Minimal startup code (@file{minstart.o}) without command line
+  parsing. You have to open all libraries yourself (@xref{Minimal Startup})
+  using 16-bit int.
+@item kick13sr
+  Minimal startup code (@file{minres.o}) for resident programs.
+  Always compiles in small data mode and links with @file{vcs.lib}
+  (@xref{Minimal Resident}) using 16-bit int.
+@end table
+
+@node Startup13
+@subsection Startup
+
+    The startup code currently consists of a slightly modified standard
+    AmigaOS 1.3 startup (@file{startup.o}). The startup code sets up some
+    global variables and initializes stdin, stdout and stderr.
+    The exit code closes all open files and frees all memory.
+    If you link with a math library the startup/exit code will be taken
+    from there if necessary.
+
+
+@subsection Floating point
+
+    Note that you have to link with a math library if you want to use
+    floating point. All math functions, special startup code and
+    printf/scanf functions which support floating point are contained in
+    the math libraries only.
+    At the moment there are two math libraries:
+ 
+@table @file
+@item m13.lib
+   This one uses the C= math libraries present under Kickstart 1.2 and 1.3.
+   The startup code will always open mathffp.library,
+   MathIeeeDoubBas.library and MathIeeeDoubTrans.library.
+   Note that all single precision floating point calculations take place
+   in FFP format and have to be converted between FFP and IEEE by the
+   library.
+                    Float return values are passed in d0, double return
+                    values are passed in d0/d1.
+                    A 68000 is sufficient to use this library.
+                    You must not specify @option{-fpu=...}
+                    when you use this library.
+
+@item msoft.lib
+    This one is based on John Hauser's IEC/IEEE Floating-point Arithmetic
+    Package (@xref{SoftfloatHauser}) and doesn't need any system libraries for
+    FP emulation. May be slower than the ROM libraries, though.
+    Otherwise everything mentioned for @file{m13.lib} applies here
+    as well.
+ 
+@item m881.lib
+    This one uses direct FPU instructions and function
+                    return values are passed in fp0. You must have a
+                    68020 or higher and an FPU to use this library. You
+                    also have to specify @option{-fpu=68881}.
+                    Several FPU instructions that have to be emulated on
+                    040/060 may be used.
+@end table
+
+@subsection Stack
+
+Stack-checking is available similar to AmigaOS/68k (@xref{amiga-stack}).
+But there is no automatic stack-extension under Kickstart 1.3 and a
+@code{__stack} variable will be ignored.
+
+@subsection Small data model
+
+Small data is supported as described for AmigaOS/68k (@xref{amigasmalldata}).
+The startup code takes care of clearing the unititalized part of a
+small data section (which Kickstart 1.x fails to do).
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@subsection amiga.lib
+
+@xref{amigalib}.
+
+This version of @file{amiga.lib} only supports the functionality present
+in Kickstart 1.2/1.3.
+
+@subsection auto.lib
+
+This library corresponds to the AmigaOS/68k version (@xref{autolib}), but
+only supports libraries of Kickstart 1.3.
+
+@subsection Minimal Startup 
+
+You can use @file{minstart.o} similar to AmigaOS/68k (@xref{Minimal Startup}).
+
+@subsection Minimal Startup for Resident Programs
+
+You can use @file{minres.o} similar to AmigaOS/68k (@xref{Minimal Resident}).
+
+
+@section PowerUp/PPC
+
+This section describes specifics of the C library for PowerUp/PPC
+provided by the target @file{ppc-powerup}.
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libvcs.a}, @file{libm.a}, @file{libms.a}
+@file{libamiga.a}, @file{libamigas.a},
+@file{libauto.a} and @file{libautos.a}.
+
+Note that @file{libextra.a} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+@subsection Startup
+ 
+    The startup code @file{startup.o} sets up some
+    global variables and initializes stdin, stdout and stderr.
+    The exit code closes all open files and frees all memory.
+    If you link with a math library the startup/exit code will be taken
+    from there if necessary.
+
+@subsection Floating point
+ 
+    Note that you have to link with a math library if you want to use
+    floating point. All math functions, special startup code and
+    printf/scanf functions which support floating point are contained in
+    the math libraries only.
+
+    The math library (@file{libm.a}) is linked against the floating point
+    library libmoto by Motorola.
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+Stack-handling is similar to AmigaOS/68k (@xref{amiga-stack}).
+The only difference is that stack-swapping cannot be done. If the
+default stack-size is less than the stack-size specified with
+@code{__stack} the program will abort.
+
+@subsection Small data model
+ 
+When using the small data model of the PPC series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+ 
+To compile and link a program using the small data model a command like
+ 
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+ 
+might be used.
+
+@subsection Restrictions
+ 
+The following list contains some restrictions of this version of the
+library:
+ 
+@table @code
+ 
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+ 
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@subsection Minimal Startup
+
+The provided minimal startup code (@file{minstart.o}) is used
+similarly like the one for 68k (@xref{Minimal Startup}). Only use
+it if you know what you are doing.
+
+@subsection libamiga.a
+
+To write programs accessing AmigaOS (rather than standard C functions
+only), a replacement for the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement (@file{libamiga.a})
+automatically performs a necessary context switch to the 68k to execute
+the system call. Furthermore, it is adapted to vbcc,
+does not cause collisions with some functions (e.g. @code{sprintf})
+provided by the original @file{amiga.lib} and is available in
+small data.
+
+Specify @option{-lamiga} to link with @file{libamiga.a}.
+ 
+@subsection libauto.a
+ 
+This library corresponds to the AmigaOS/68k version (@xref{autolib}).
+
+@section WarpOS/PPC
+ 
+This section describes specifics of the C library for WarpOS/PPC
+provided by the target @file{ppc-warpos}.
+The relevant files are @file{startup.o}, 
+@file{vc.lib}, @file{m.lib}, @file{amiga.lib} and @file{auto.lib}.
+
+Note that @file{extra.lib} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+@subsection Startup
+ 
+    The startup code @file{startup.o} sets up some
+    global variables and initializes stdin, stdout and stderr.
+    The exit code closes all open files and frees all memory.
+    If you link with a math library the startup/exit code will be taken
+    from there if necessary. 
+
+@subsection Floating point
+ 
+    Note that you have to link with a math library if you want to use
+    floating point. All math functions, special startup code and
+    printf/scanf functions which support floating point are contained in
+    the math libraries only.
+
+    The math library (@file{m.lib}) contains functions from Sun's
+    portable floating point library. Additionally, there is a
+    @command{vbcc} version of Andreas Heumann's @file{ppcmath.lib}.
+    These routines are linked against Motorola's floating point
+    routines optimized for PowerPC and therefore are much faster.
+
+    To make use of this library, link with @file{ppcmath.lib} before
+    @file{m.lib}, e.g.
+
+@example
+    vc test.c -lppcmath -lm
+@end example
+    
+
+ 
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+Stack-handling is similar to AmigaOS/68k (@xref{amiga-stack}).
+
+@subsection Restrictions
+ 
+The following list contains some restrictions of this version of the
+library:
+ 
+@table @code
+ 
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+ 
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+ 
+@end table
+
+@subsection amiga.lib
+ 
+To write programs accessing AmigaOS (rather than standard C functions
+only), a replacement for the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement
+automatically performs a necessary context switch to the 68k to execute
+the system call. Furthermore, it is adapted to vbcc,
+does not cause collisions with some functions (e.g. @code{sprintf})
+provided by the original @file{amiga.lib} and is available in
+small data.
+ 
+Specify @option{-lamiga} to link with @file{amiga.lib}.
+
+ 
+@subsection auto.lib
+ 
+This library corresponds to the AmigaOS/68k version (@xref{autolib}).
+ 
+
+@section MorphOS/PPC
+ 
+This section describes specifics of the C library for MorphOS/PPC
+provided by the target @file{ppc-morphos}.
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libvcs.a}, @file{libm.a}, @file{libms.a}
+@file{libamiga.a}, @file{libamigas.a},
+@file{libauto.a} and @file{libautos.a}.
+
+Note that @file{libextra.a} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+ 
+@subsection Startup
+ 
+    The startup code @file{startup.o} sets up some
+    global variables and initializes stdin, stdout and stderr.
+    The exit code closes all open files and frees all memory.
+    If you link with a math library the startup/exit code will be taken
+    from there if necessary.
+ 
+@subsection Floating point
+ 
+    Note that you have to link with a math library if you want to use
+    floating point. All math functions, special startup code and
+    printf/scanf functions which support floating point are contained in
+    the math libraries only.
+ 
+    The math library (@file{libm.a}) is linked against the floating point
+    library libmoto by Motorola.
+ 
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+Stack-handling is similar to AmigaOS/68k (@xref{amiga-stack}).
+
+@subsection Small data model
+ 
+When using the small data model of the PPC series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+ 
+To compile and link a program using the small data model a command like
+ 
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+ 
+might be used.
+
+@subsection Restrictions
+ 
+The following list contains some restrictions of this version of the
+library:
+ 
+@table @code
+ 
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+ 
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on MorphOS it is not possible to
+obtain the time used by the calling process.
+ 
+@end table
+
+@subsection libamiga.a
+
+To write programs using AmigaOS compatible functions, a replacement for
+the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement (@file{libamiga.a})
+will invoke the MorphOS 68k emulator to execute the system function.
+Furthermore, it is adapted to vbcc and
+does not cause collisions with some functions (e.g. @code{sprintf})
+and is available in small data.
+
+Specify @option{-lamiga} to link with @file{libamiga.a}.
+
+
+@subsection libauto.a
+ 
+This library corresponds to the AmigaOS/68k version (@xref{autolib}).
+ 
+
+@section AmigaOS4/PPC
+ 
+This section describes specifics of the C library for AmigaOS4/PPC
+provided by the target @file{ppc-amigaos}.
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libvcs.a}, @file{libm.a}, @file{libms.a}
+@file{libamiga.a}, @file{libamigas.a},
+@file{libauto.a} and @file{libautos.a}.
+
+Note that @file{libextra.a} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+ 
+@subsection Startup
+ 
+The startup code @file{startup.o} sets up some
+global variables and initializes stdin, stdout and stderr.
+Then it runs all constructors of dynamically linked libraries, before
+entering the main program.
+The exit code runs all destructors of dynamically linked libraries,
+closes all open files and frees all memory.
+If you link with a math library the startup/exit code will be taken
+from there if necessary.
+ 
+@subsection Floating point
+ 
+Note that you have to link with a math library if you want to use
+floating point. All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math libraries only.
+
+The math library (@file{libm.a}) is linked against the floating point
+library libmoto by Motorola.
+ 
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+There is no automatic stack extension for AmigaOS 4! This should be
+done automatically by the operating system.
+
+@subsection Small data model
+ 
+When using the small data model of the PPC series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+ 
+To compile and link a program using the small data model a command like
+ 
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+ 
+might be used.
+
+@subsection Dynamic linking
+Since @file{elf.library} @code{V52.2} AmigaOS4 supports dynamic linking with
+shared object files (@file{.so} extension), similar to Unix. The default
+behaviour is to prefer linking against a shared object over a static
+library. To force static linking you might want to give the
+@option{-static} option to the @file{vc} frontend.
+
+@subsection Restrictions
+ 
+The following list contains some restrictions of this version of the
+library:
+ 
+@table @code
+ 
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+ 
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@item Small data in dynamically linked executables
+There is a bug in @file{elf.library} @code{V52.4} (and earlier), which
+doesn't load @code{.sdata} and @code{.sbss} as a contiguous block into
+memory, when the executable requires dynamic linking. I decided against
+writing a workaround, as the bug should be fixed in OS4.
+
+@end table
+
+@subsection libamiga.a
+
+In contrast to other amigalibs the OS4 @file{libamiga.a} doesn't contain
+any stubs for calling system functions. AmigaOS 4 system calls are done
+through special macros in the SDK's interface header files.
+
+The library only includes some remaining amigalib functions, not already
+integrated into the OS, like @code{CreateIO()}, but its use is discouraged.
+
+Specify @option{-lamiga} to link with @file{libamiga.a}.
+
+
+@subsection libauto.a
+
+Include auto-open and -close functions for the most common OS libraries and
+interfaces. May also be used together with newlib (see below).
+ 
+
+@subsection newlib
+
+@subsubsection Introduction
+
+    newlib.library is a shared AmigaOS4 library, which is covered by
+    several BSD like licenses,
+    and includes standard ANSI and POSIX functions as well as some
+    functions common in Unix, BSD and similar operating systems. It is
+    part of the OS4 SDK.
+
+    The config file @file{newlib} will be created on installation to
+    use the paths for header files and libraries pointing to the
+    newlib from the SDK. 
+
+    What are the main differences between vclib and newlib?
+
+@itemize @minus
+@item vclib contains (almost) only standard ANSI-C and some ISO-C99
+      functions. If you want to port Unix programs you will probably
+      miss a lot of functions.
+      Also newlib supports things like mapping Unix directory paths to
+      Amiga paths or expanding wildcards in command lines automatically.
+ 
+@item Programs compiled for newlib will be shorter because the code for all
+      functions is not contained in the executable itself.
+
+@item Programs compiled for newlib will need the shared object
+      @file{libc.so} present when started.
+
+@item Programs compiled for newlib will probably need more memory because
+      the entire (rather large) @file{libc.so} will be loaded into memory.
+      With vclib only the functions your program uses will be in RAM.
+      However if you have several programs using newlib at the same
+      time only one copy of @file{libc.so} should be loaded.
+@end itemize
+
+    Things you should note:
+ 
+@itemize @minus
+@item With newlib you do not need extra math-libraries.
+ 
+@item You must link with a vbcc-specific @file{startup.o} from the newlib
+      @file{lib/} directory as startup code.
+      The config-file @file{newlib} will usually take care of this.
+ 
+@item You _must_ use the newlib-includes from the SDK
+      rather than the ones which are for vc.lib.
+      The config-file @file{newlib} will usually take care of this.
+
+@item There may be vbcc-related bugs in the SDK-newlib. Patches are
+      automatically installed when using the Amiga Installer. When
+      installing the target manually, you also have to fix the SDK
+      manually. For a list of known SDK bugs at this point of time,
+      @xref{Known Newlib Bugs}.
+@end itemize
+
+@node Known Newlib Bugs
+@subsubsection Known Newlib Bugs
+
+@itemize @minus
+
+@item The @code{__asm_toupper()} and @code{__asm_tolower()} assembler inlines
+      in @file{newlib/include/ctype.h} are wrong, which makes
+      @code{toupper()} and @code{tolower()} fail when including
+      @file{ctype.h}. Fix:
+@example
+--- ctype.h.orig	2006-04-03 18:00:00.000000000 +0200
++++ ctype.h	2017-05-07 19:32:00.000000000 +0200
+@@@@ -64,8 +64,8 @@@@
+ #elif defined(__VBCC__)
+ int __asm_toupper(__reg("r3") int) =
+         "\t.extern\t__ctype_ptr\n"
+-        "\tlis\t11,(__ctype_ptr)@@ha\n"
+-        "\taddi\t11,11,(__ctype_ptr)@@l\n"
++        "\tlis\t11,__ctype_ptr@@ha\n"
++        "\tlwz\t11,11,__ctype_ptr@@l(11)\n"
+         "\tlbzx\t12,11,3\n"
+         "\tandi.\t12,12,2\n"
+         "\tbeq\t$+8\n"
+@@@@ -73,8 +73,8 @@@@
+         "#barrier";
+ int __asm_tolower(__reg("r3") int) =
+         "\t.extern\t__ctype_ptr\n"
+-        "\tlis\t11,(__ctype_ptr)@@ha\n"
+-        "\taddi\t11,11,(__ctype_ptr)@@l\n"
++        "\tlis\t11,__ctype_ptr@@ha\n"
++        "\tlwz\t11,11,__ctype_ptr@@l(11)\n"
+         "\tlbzx\t12,11,3\n"
+         "\tandi.\t12,12,1\n"
+         "\tbeq\t$+8\n"
+@end example
+Note: This should be fixed with the latest OS4 SDK, and the V0.9h
+installer will no longer install a patch!
+
+@item Newlib's @file{libauto.a} contains no working vbcc-style
+constructors or destructors for auto-opening or -closing of libraries.
+You can work-around it, by copying vclib's @file{libauto.a} to
+newlib's lib-directory. Rename it, if you don't want to overwrite
+the gcc-version of it.
+
+@item Some header files, like @file{sys/stat.h}, use the reserved vbcc
+attribute @code{__mask} as an argument name. The config file should
+take care of that, by redefining it as @code{___mask}.
+
+@end itemize
+
+@subsubsection Usage
+
+To compile a program to use newlib for OS4 you must make sure the proper
+config-file (@file{newlib}) is used, e.g.
+ 
+@example
+        vc +newlib hello.c
+@end example
+
+With a new SDK this will usually generate a dynamically linked executable,
+which requires @file{libc.so}. To force a statically linked executable:
+
+@example
+        vc +newlib -static hello.c
+@end example
+
+
+@section Atari TOS/MiNT
+
+This section describes specifics of the C library for Atari TOS and MiNT.
+M680x0 processors are supported by the target @file{m68k-atari}, while
+ColdFire processors are supported by the target @file{cf-atari}. Both
+share the same startup-code and are based on common library sources and
+header files. Executables linked with this C library run on plain TOS as
+well as on MiNT, without modifications.
+
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libm.a}, @file{libgem.a}. For the M68k target
+there are also math libs with FPU support (@file{libm881.a},
+@file{libm040.a} and @file{libm060.a}) and 16-bit integer versions
+of all libraries (@file{lib*16.a}).
+
+The following config files are available:
+@table @code
+@item tos
+  M68k 32-bit @code{int} for classic TOS machines.
+@item tos16
+  M68k 16-bit @code{int} for classic TOS machines.
+@item mint
+  M68k 32-bit @code{int} for MiNT. Also works on classic machines,
+  but uses an embedded a.out header for MiNT, includes a changeable
+  @code{__stksize} and sets the FastLoad, FastRAM and FastAlloc flags
+  in the header.
+@item mintcf
+  ColdFire 32-bit @code{int}. Otherwise same as @file{mint}.
+@end table
+
+@subsection Startup
+ 
+The startup code @file{startup.o} sets up some
+global variables and initializes stdin, stdout and stderr and returns
+the unneeded memory to the system.
+The exit code closes all open files and frees all memory.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point. All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math libraries only.
+
+On the M68k target you have the option to enable FPU support with
+the @option{-fpu} option and choose the appropriate math library
+(@xref{Floating point}). Otherwise, there is a soft-float library,
+which is compatible with all the Atari models without an FPU.
+
+@subsection Stack
+
+The default stack size is 64k. There is a MiNT tool called @file{stack}
+which can adjust the stack size of an executable to any value, by looking
+for a symbol named @code{__stksize} (defined by vclib's startup code).
+
+Additionally the required stack size can be specified by defining a
+variable @code{__stack} (of type @code{size_t}) with external linkage, as
+in other vbcc targets.
+
+@subsection 16-bit integer model
+
+The default libraries use 32-bit @code{int} types, but you may want to
+use 16-bit @code{int} types for compatibility reasons. In this case you
+have to specify the config file @code{tos16} and link with the appropriate
+16-bit libraries (which have a '@file{16}' attached to their name).
+
+To compile and link a program using 16-bit integers a command like
+
+@example
+vc +tos16 test.c -o test -lm16 -lvc16
+@end example
+ 
+may be used. There are no 16-bit versions for ColdFire targets,
+because this is strictly a 32-bit CPU.
+
+@subsection Restrictions
+ 
+The following list contains some restrictions of this version of the
+library:
+ 
+@table @code
+ 
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+ 
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because neither under TOS nor under MiNT it
+is possible to obtain the time used by the calling process.
+
+@end table
+
+@section VideoCore/Linux
+
+This section describes specifics of the C library for VideoCore under Linux
+provided by the target @file{vidcore-linux}.
+
+The relevant files are @code{vcload}, @file{startup.o},
+@file{libvc.a}, @file{libm.a}, @file{libms.a}.
+
+The config file @code{vc4-linux} is part of the library.
+
+@subsection Startup
+ 
+The startup code @file{startup.o} sets up stack and heap and provides
+a function @code{__armcall()} to transfer control to the loader on
+the ARM side.
+The startup process calls constructors to set up some
+global variables and initialize stdin, stdout and stderr if needed.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point operations that are not natively implemented.
+All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math libraries only.
+
+@subsection Stack
+
+The library contains a default stack of 32KB. If another size is needed,
+you can add the following to your project:
+
+@example
+        .align  4
+        .space  <desired-size, suitably aligned>
+___stackend:
+        .global ___stackend
+@end example
+
+@subsection Heap
+
+Currently, a global variable of 16KB is used to get memory for
+malloc() etc.  If another size is needed,
+you can add the following to your project:
+
+@example
+#define HEAPSIZE <desired size>
+
+char __heap[HEAPSIZE],*__heapptr=__heap;
+size_t __heapsize=HEAPSIZE;
+@end example
+
+Note that this mechanism will likely be changed in the future!
+
+@subsection System Calls
+
+To access system functions from the VideoCore-side, the function
+@code{__armcall()} can be used. It will save the current context and return
+to the loader. Registers @code{r0-r5} (the function arguments) will be saved
+and are available to the loader. The loader can then execute the system
+call and resume execution, passing the return value of the system
+function.
+
+Resuming is done by calling the image with offset 2.
+
+This functionality can also be used for debugging purposes.
+
+@subsection Loader
+
+A loader is required to execute VideoCore code from the ARM side. For
+standalone VideoCore code, the provided loader can be used. Usually, it
+will be necessary to adapt the loader to communicate between ARM and
+VideoCore side during runtime.
+
+@subsubsection Object Format
+
+Currently, the loader loads an simple binary image that must be pc-relative
+and located to address 0x00000000. Additionally, if present, a file
+with extension @file{.reltext} will be loaded for some limited
+relocation. This file contains a 32bit word containing the number of
+relocations followed by n 32bit words containing an offset. For each
+offset, the address will be relocated to the image load address.
+
+@subsubsection Command line arguments
+
+@code{vcload [-debug] [-cache] [-offset] <image-name>}
+
+The loader currently has the following options:
+
+@table @code
+
+@item -debug
+
+    The loader will enter debug mode (see below).
+
+@item -cache
+
+    The loader will set the LSB in the start address when executing
+    code. This is supposed to inhibit a cache flush.
+
+    Just for testing!
+
+@item -offset
+
+    The loader will allocate 1 KB more memory than required and leaves
+    this space unused at the beginning of the allocated memory.
+
+    Just for testing!
+
+@end table
+
+@subsubsection Debug Mode
+
+In debug mode, the loader will wait for user input before starting the
+VideoCore code as well as after every @code{__armcall}.
+
+The following commands are available:
+
+@table @code
+@item w <addr> [<num>]
+      Display <num> 32bit words starting at <addr>.
+      <addr> must be the offset into the image. If <num> is omitted,
+      one unit is displayed.
+
+      If one word is displayed, it is additionally displayed translated
+      as an offset into the image.
+
+@item h <addr> [<num>]
+      Display <num> 16bit halfwords starting at <addr>.
+      <addr> must be the offset into the image. If <num> is omitted,
+      one unit is displayed.
+
+@item b <addr> [<num>]
+      Display <num> 8bit bytes starting at <addr>.
+      <addr> must be the offset into the image. If <num> is omitted,
+      one unit is displayed.
+
+@item c
+      Start/continue execution.
+
+@item q
+      Quit.
+
+@item bp <addr>
+      Set a breakpoint at <addr>.
+
+      This is currently a very crude implementation. It will just write
+      a branch to @code{__armcall()} to <addr>. If everything works well,
+      you will end in the debugger if <addr> is reached. However, the
+      arguments passed are random (and might be dangerous syscalls by 
+      accident). Also, the old code at this address is currently not
+      restored.
+
+      As a result, you must not continue execution after hitting a
+      breakpoint!
+@end table
+
+
+@subsection Restrictions
+ 
+The following list contains some restrictions of this version of the
+library:
+ 
+@itemize @minus
+ 
+@item no real floating point support yet
+
+@item lots, lots, lots...
+
+
+@end itemize
+
+@section ATARI Jaguar/68k
+
+This section describes specifics of the C library for ATARI Jaguar
+provided by the target @file{m68k-jaguar}.
+
+The relevant files are @file{startup.o},
+@file{libvc.a}, @file{libm.a}, @file{libjag.a}.
+
+The config files @code{jaguar_unix} and @code{jaguar_windows} are part of the library.
+
+@subsection Startup
+ 
+The startup code @file{startup.o} sets up stack and heap.
+The startup process calls constructors to set up some
+global variables and initialize stdin, stdout and stderr.
+
+The ATARI Jaguar has no OS, so it is impossible to define how input, output and files
+can be handled. There are a few set of function you have to define if you want to use stdio.
+
+Alternatively you can use the @file{libjag.a}. This library initializes a console window with stdout
+support and uses optionally a SkunkBoard to redirect stderr and file I/O.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point operations that are not natively implemented.
+All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math library only. Consider the ATARI Jaguar does not own a FPU so this library is pretty slow.
+
+@subsection Stack
+
+The library contains a default stack of 32KB. If another size is needed,
+you can add a global variable named __stack to your code:
+
+@example
+
+/* Set 64kB stack */
+unsigned long __stack = 65536;
+
+@end example
+
+@subsection Heap
+
+Currently the free RAM is used as global heapsize for malloc() etc.
+
+It is necessary to place a symbol named _BSS_END at the end of the BSS segment.
+The heap allocates the free RAM between _BSS_END and the bottom of the stack.
+
+If less size is needed feel free to manipulate the value of _BSS_END.
+
+All allocated heap objects can be used as internal JAGUAR objects, because they are qhrase aligned.
+
+@subsection stdio support
+
+The ATARI Jaguar lacks stdio support. So the @file{libvc.a} has just empty stub functions for
+open, close, read and write, which you may overwrite if you need stdio.
+Alternatively you can use @file{libjag.a} which has simple stdio
+and file I/O functionality.
+
+@example
+/**
+ * param name: name mentioned in fopen
+ * param mode: mode mentioned in fopen
+ * returns: > 0 a valid file handle
+ *          < 0 to indicate an error
+ *          the values 0,1,2 are used by stdin, stdout and stderr
+ *
+ * No need to handle stdin, stdout and stderr here
+ */
+int jagopen(const char *name,const char *mode)
+
+/**
+ * param handle: handle from jagopen
+ *
+ * No need to handle stdin, stdout and stderr here
+ */
+void jagclose(int handle)
+
+/**
+ * param handle: handle from jagopen
+ * param p: points to the char buffer to fill.
+ * param l: buffer size of p
+ * returns: >=0 number of read bytes
+            <0 indicate an error
+ *
+ * Handle stdin, stdout and stderr here
+ */
+size_t jagread(int handle,char *p,size_t l)
+
+/**
+ * param handle: handle from jagopen
+ * param p: points to the char buffer to write.
+ * param l: number of bytes of p
+ * returns: >=0 number of bytes written
+            <0 indicate an error
+ *
+ * Handle stdin, stdout and stderr here
+ */
+size_t jagwrite(int handle,const char *p, size_t l)
+
+/**
+ * param handle: handle from jagopen
+ * param offset: number of bytes to seek.
+ * param direction: see fseek direction
+ * returns: =0 successful seek
+            <>0 indicate an error
+            -1: seek not supported
+ *
+ * Handle stdin, stdout and stderr here
+ */
+long jagseek(int handle,long offset,int direction)
+@end example
+
+@subsection The jaglib
+
+The jaglib @file{libjag.a} provides simple functions to support your first
+steps in ATARI Jaguar programming. It initializes a simple console output window and comes with 
+an old ATARI character set.
+If a SkunkBoard is available I/O functionality can be redirected.
+
+Your first Jaguar program can look like this:
+
+@example
+
+#include <stdio.h>
+
+int main()
+@{
+    printf("Hello, world\n");
+@}
+
+@end example
+
+Keep in mind: Your JAGUAR will get a red background color to indicate @code{main()} has exited.
+
+The jaglib API documentation is available in a separate document. There is more demo code
+available in the @uref{https://github.com/toarnold/jaglib-demo, jaglib-demo} gibhub repository.
+
+@section 6502/C64
+
+This is a port of vclib to the C64.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x801. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. The startup code
+will turn off the BASIC ROM to allow usage of RAM until 0xD000 and most of the
+zero page without need for any special handling. The BSS segment will be cleared
+during startup.
+
+With the default configuration, after exiting the C program, an infinite loop will
+be entered. When using the @code{+c64r} config, the program will return to BASIC
+an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal. 
+
+Command-lines look like these lines:
+
+@example
+   run
+   run : rem
+   run:rem arg1 " arg 2 is quoted "  arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0x8d}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0xC800..0xD000}. The size can be
+changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+The following banking models are supported:
+
+@table @code
+@item -reuflat
+      This library supports a REU using a flat 16MB address space. The memory has to
+      be addressed through far-pointers. It is not possible to declare variables in
+      the REU nor to place code in the REU. The memory is addressed as 0x000000 to
+      0xFFFFFF. All accesses through far-pointers are addressing the REU. It is not
+      possible to address the C64 memory through a far-pointer.
+
+      Far-pointer arithmetic only works on the lower 16bits. It is not possible to
+      cross a bank boundary using far-pointers. Huge-pointers will support this, but
+      are not yet fully implemented. In the meantime it is possible to use long integers
+      and cast them to far-pointers.
+
+      Use @code{-lreuflat} to link with this library. Note that the library does
+      not check for the presence of a REU.
+
+@item -reubank
+      This configuration reserves a 16KB memory space within the C64 memory as window
+      for banking. As the bank number is stored as a single byte (with bank
+      255 denoting the unbanked memory), it is only possible to address up to
+      about 4MB of memory in the REU.
+
+      Variables and code can be mapped into the REU using the @code{__bank()} attribute
+      or @code{#pragma bank}. When calling a banked function, the corresponding bank
+      will be copied from the REU into the C64 memory window.
+
+      Use the @code{+c64reu} configuration to use this mechanism. Currently the
+      linker file provides 8 banks resulting in a 128K REU image. More banks can
+      be added for larger expansions.
+
+      The configuration will create a usually C64 prg file containing the unbanked
+      code and data as well as a REU image with extension @code{.b0}. It must
+      be loaded (e.g. with an emulator or the TurboChameleon) before the prg file
+      can is executed.
+@end table
+
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+stdio supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+
+Furthermore, file IO with standard C functions is supported 
+for 1541 and compatible disk drives. Other devices have not been tested.
+Only sequential reading and writing of files is supported. No seeking etc.
+There are hardcoded limits for the maximum number of open files and the
+maximum length of filenames.
+
+The @code{remove()} and @code{rename()} functions are supported using 1541
+
+By default, device ID 8 is used. Another device ID can be specified as prefix
+to the filename:
+
+@example
+  /* try to open file "test" on the second drive */
+  FILE *f;
+  f=fopen("9:test","r"); 
+  ...
+@end example
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/NES
+
+This is a port of vclib to the NES console.
+
+
+@subsection Startup and Memory
+
+Startup and memory layout is dependent on the ROM used. Currently two example configurations
+are provided. They can be selected with @code{+nrom256v} and @code{+unrom512v}. Have a
+look at the corresponding linker scripts in @code{vbcc/targets/6502-nes} for further
+details.
+
+The necessary library routines to support configurations with several ROM banks are
+included.
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. The entire zero page can be used, but this can be changed
+in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack starts from @code{0x0800} growing downwards.
+
+@subsubsection Heap
+
+By default, code and data/BSS are mapped starting after the system stack at @code{0x0200}.
+The heap is placed in the remaining space to stack start.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (simple input via joypad).
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+For input, up/down changes the current character, left/right moves the cursor,
+the B button deletes from the cursor position, and the A button confirms the input.
+You do not want to use this in real code.
+
+The library contains a default character set. To replace it, link an object that
+contains a character set mapped to section @code{chars} and defines the global symbol
+@code{___stdchr}.
+
+To replace stdio, the function @code{__read()} and @code{__write()} have to be
+implemented.
+
+@subsection Interrupts
+
+The library contains a default NMI implementation that is used for stdio handling
+and the @code{clock()}-function. It can be replaced by linking with an own
+implementation that starts at the global symbol @code{___nmi}. In this case the stdio and
+timing functions from vclib can not be used.
+
+@code{___irq} can be used to overwrite the other IRQ vector. The default implementation
+in the library immediately returns.
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+IEEE floating point is currently not available for this target.
+
+
+@section 6502/Atari
+
+This is a port of vclib to Atari 8bit computers.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x600. The memory area can be adapted by changing @code{MEMSTART} and
+@code{MEMEND} in @code{vlink.cmd}.
+
+With the default configuration, after exiting the C program, it will wait
+for pressing the return key before returning to DOS.
+
+@subsubsection Command line
+
+Command line parameters are not yet supported.
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x82..0xFF}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the startup code maps the user stack from
+@code{MEMTOP-STACKLEN..MEMTOP}.
+The size can be changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting at @code{MEMSTART}.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+Banking support for this target has not yet been implemented.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are line-buffered by default.
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/BBC Micro/Master
+
+This is a port of vclib to BBC 8bit computers.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x1900 up to 0x7B00 with 256 bytes of software stack. The memory area can be adapted by
+changing @code{OSHWM}, @code{HIMEM} and @code{STACKSTART} in @code{vlink.cmd}.
+
+With the default configuration (@code{+bbc}), after exiting the C program, the code will 
+enter an endless loop. If the reentrant configs are used (@code{+bbcr} or
+@code{+bbcbr}), the program will return to the command prompt. As this
+requires saving the zero page, a bit more memory is used.
+
+
+@subsubsection Command line
+
+If @code{main()} uses arguments, the command line parameters will be passed
+accordingly. There are hardcoded limits to the number of arguments (currently 8)
+and the maximum total command length (currently 80).
+
+Space is used to separate arguments. The quote character (@code{"}) can be used
+to group arguments containing spaces.
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x00..0x90}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the startup code maps the user stack from
+@code{STACKSTART..HIMEM}.
+The size can be changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting at @code{OSHWM}.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+When using the @code{+bbcb} or @code{bbcbr} configurations, vbcc supports
+banked memory, including automated bank-switching. Up to 16 sections of 16K
+size are supported. Each section starts at 0x8000.
+
+The corresponding linker
+files @code{vlinkb.cmd} and @code{vlinkbr.cmd} can be edited to choose the
+banks that are required. Unused banks can be removed by commenting out
+(using old-style C-comments) the corresponding entries in the @code{SECTIONS}
+part of the linker file. When using bank 1-3 the section in the linker file
+could look like this:
+
+@example
+  ...
+
+SECTIONS
+@{
+  text : @{*(text)@} >ram
+  .dtors : @{ *(.dtors) @} > ram
+  .ctors : @{ *(.ctors) @} > ram
+  rodata : @{*(rodata)@} >ram
+  data: @{*(data)@} >ram
+  init : @{*(init)@} >ram
+  zpage (NOLOAD) : @{*(zpage) *(zp1) *(zp2)@} >zero
+  bss (NOLOAD): @{*(bss)@} >ram
+
+/*
+  b0 : @{.=PAGEADDR; *(text0) *(rodata0) *(data0) *(bss0)
+       RESERVE(PAGEADDR+PAGESIZE-.);
+      @} >b0 AT>dummy0
+*/
+
+  b1 : @{.=PAGEADDR; *(text1) *(rodata1) *(data1) *(bss1)
+       RESERVE(PAGEADDR+PAGESIZE-.);
+      @} >b1 AT>dummy1
+
+  b2 : @{.=PAGEADDR; *(text2) *(rodata2) *(data2) *(bss2)
+       RESERVE(PAGEADDR+PAGESIZE-.);
+      @} >b2 AT>dummy2
+
+  b3 : @{.=PAGEADDR; *(text3) *(rodata3) *(data3) *(bss3)
+       RESERVE(PAGEADDR+PAGESIZE-.);
+      @} >b3 AT>dummy3
+/*
+  b4 : @{.=PAGEADDR; *(text4) *(rodata4) *(data4) *(bss4)
+       RESERVE(PAGEADDR+PAGESIZE-.);
+      @} >b4 AT>dummy4
+*/
+
+  ...
+
+@end example
+
+During the linking process, apart from the normal output file, a 16K large
+image for each bank and a loader script will be generated. E.g. when using banks 
+1-3 and using the output file name test, the following files will be generated:
+
+@table @code
+@item @code{test}
+      The unbanked code/data.
+
+@item @code{test.inf}
+      Info file with start address.
+
+@item @code{testb1}
+      Image for bank1.
+
+@item @code{testb2}
+      Image for bank2.
+
+@item @code{testb2}
+      Image for bank2.
+
+@item @code{loadtest}
+ Loader
+
+@end table
+
+The contents of the loader @code{loadtest} will look like this:
+
+@example
+*srload testb1 8000 1
+*srload testb2 8000 2
+*srload testb3 8000 3
+*run test
+@end example
+
+The program can be started with @code{*exec loadtest}.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+@code{stdout}, @code{stderr} (both using the screen) and @code{stdin} (keyboard)
+are supported. Furthermore normal file operations are possible using the 
+usual C functions. There are hardcoded limits on the maximum number of
+simultaneously open files as well as the length of filenames.
+
+Sequential reading and writing is supported, but no seeking. Furthermore, the
+@code{remove()} call is supported.
+
+When using stdio to emit VDU control sequences, the function
+@code{__vdu_sequence()} is available to ensure verbatim 1:1 transmission
+of all characters:
+
+@example
+ /* print diagonal line */
+ __vdu_sequence(1);
+ for(int i=0;i<20;i++)
+   printf("\x1f%c%cO",i,i);
+ __vdu_sequence(0);
+@end example
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+
+
+@section 6502/MEGA65
+
+This is a port of vclib to the MEGA65. This port is intended for the C65 mode
+with a C65 or compatible ROM (although the ROM is not used after the
+program is started). The C64 configuration can be used to create programs for
+the C64 mode.
+
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+The following basic configurations are available. See below for more details:
+
+@table @code
+@item +m65s
+      Standard unbanked configuration.
+
+@item +m65sr
+      Standard unbanked reentrant configuration.
+
+@item +m65sb
+      Standard banked configuration.
+
+@item +m65l
+      Large unbanked configuration.
+
+@item +m65lr
+      Large unbanked reentrant configuration.
+
+@item +m65lb
+      Large banked configuration.
+
+@end table
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x2001. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. The startup code
+will switch to VIC-IV mode, remove write protection of ROM banks, turn on full
+speed and change to a suitable mapping.
+The BSS segment will be cleared during startup.
+
+There are two sets of configurations that affect the configuration of
+upper memory. The standard versions (@code{+m65s, +m65sr, +m65sb})
+will keep the IO area mapped in at $D000.
+This will limit the contiguous memory block for unbanked configurations to 0xCFFF. 
+For banked configurations (see below) it will make a 16K window from
+0x8000..0xBFFF available for banking. The large configurations
+(@code{+m65l, +m65lr, +m65lb}) will move the upper bound for unbanked programs
+to 0xFFFF. With banking, 32K window will be available from 0x8000..0xFFFF.
+In both cases the total amount of memory available for banking is the same in
+both configurations.
+
+While the large configurations provide larger contiguous memory areas, accesses
+to the IO area have to be made through extended 28bit instructions which are
+much larger and slower. For programs doing many IO accesses, the standard
+configurations are recommended.
+
+With the default configurations, after exiting the C program, an infinite loop will
+be entered. When using the reentrant (@code{+m65sr, +m65lr}) configs, the
+program will return to BASIC an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+Caution: The current configuration assumes that the Z register always contains 0.
+To work correctly, the Z register has to be 0 when C code is
+executed. The startup code will set it correctly and the compiler generated code will
+not touch it. However, when calling other code you may have to take care
+to save/restore the Z register or to set the Z register to 0 again.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal. 
+
+Command-lines look like these lines:
+
+@example
+   run
+   run : rem
+   run:rem arg1 " arg 2 is quoted "  arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0xFF}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0xB800..0xC000}. For the banked version,
+it is mapped from @code{0x7800..0x8000}.  The size can be
+changed at the top of @code{vlink.cmd} and @code{vlinkbank.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space depending on the configuration.
+
+@subsubsection Banking
+
+The following banking models are supported:
+
+@table @code
+@item +m65sb
+      16K window at 0x8000 with IO area mapped in at all times.
+
+@item +m65lb
+      32K window at 0x8000.
+@end table
+
+
+Automated bank switching is supported in both modes. The mapping of banks to
+real memory in the standard configuration is like this:
+@example
+Unbanked:       0x000000..0x007FFF
+Bank0:          0x008000..0x00BFFF
+Bank1:          0x00C000..0x00FFFF
+Bank2:          0x010000..0x013FFF
+Bank3:          0x014000..0x017FFF
+         ...
+@end example
+
+On the large configuration, it looks like this:
+@example
+Unbanked:       0x000000..0x007FFF
+Bank0:          0x008000..0x00FFFF
+Bank1:          0x010000..0x017FFF
+Bank2:          0x018000..0x01FFFF
+Bank3:          0x020000..0x027FFF
+         ...
+@end example
+
+In both cases, the program start is moved to 0x1000.
+When using the banked configurations, the code can not be simply loaded from
+BASIC. The linker will create on large image without any BASIC lines. The
+file can be executed from SD-card by using a special loader that can be loaded
+from BASIC off a disk or disk image. When specifying a name as command line
+argument (see above), the loader will try to load this image from SD-card. If
+no argument is given, the loader will look for a file of the same name.
+Therefore by renaming the loader it can be made to automatically run a
+specific file.
+
+If the loader is on the current disk/image and @code{myimage} on the SD:
+@example
+LOAD "LOADER"
+RUN:REM MYIMAGE
+@end example
+
+After renaming @code{LOADER} to @code{MYIMAGE}, it can be done like this:
+@example
+RUN "MYIMAGE"
+@end example
+
+The colour RAM will be relocated to 0xFF80800 before loading to avoid being
+overwritten through the window at 0x1F800.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+Using those streams will directly access the screen buffer and keyboard
+hardware. No ROM functions are needed once the program runs.
+
+Furthermore it is possible to read files on the SD-card using standard
+C functions after opening them using @code{fopen()}. Hyppo services are
+used to read those files. There are several limitations due to the
+restrictions of Hyppo:
+
+@itemize
+@item Files can only be read sequentially, no seeking etc.
+@item Files can not be written to.
+@item Only one file can be open at the same time.
+@end itemize
+
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+@subsection Multiplication/Division
+
+When generating code for the MEGA65, @code{vbcc} will make use of hardware
+multiplier/divider. This can greatly improve performance of such operations.
+Please note the following issues:
+
+@itemize
+@item Some versions of the MEGA65 core contain a bug in the hardware divider
+      which will calculate wrong results in certain cases. As workaround you can
+      specify option @code{-div-bug} to use (much slower) 6502 software
+      routines instead. Multiplication is not affected by the bug and will still
+      be using the hardware multiplier.
+
+@item The hardware multiplier registers are mapped in the IO area. When using
+      the large configurations (@code{+m65l, +m65lr, +m65lb}), they can only
+      be accessed using extended 28bit instructions. The code generator and
+      library functions will handle this, but there is some overhead (still
+      nowhere near using software multiplication). If your code is speed
+      critical and uses many multiplications we strongly recomment to use
+      the standard configurations (@code{+m65s, +m65sr, +m65sb}). Those will
+      set the option @code{-m65io} that tells @code{vbcc} to use faster
+      direct IO accesses.
+@end itemize
+      
+@subsection Interrupts
+
+The provided configurations will disable interrupts on the MEGA65. All the
+library functions are written to work with disabled interrupts and do not use
+any ROM routines. The interrupt handlers in existing C65 ROMs do not work well
+with assembly language code and deficiencies in the mapping hardware make it
+very hard to use the ROM in a non-BASIC environment.
+
+If an application wants to use interrupts, interrupt vectors have to be
+installed at 0xFFFA..0xFFFF. Take care that there are always valid vectors
+visible at this address (especially in a banked configuration). Also take
+care that those always point to a valid handler that is visible (i.e. do
+not use an ISR in banked memory).
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/X16
+
+This is a port of vclib to the Commander X16.
+
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x801. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. The startup code
+will turn off the BASIC ROM to allow usage of RAM until 0x9F00 and most of the
+zero page without need for any special handling. The BSS segment will be cleared
+during startup.
+
+With the default configuration, after exiting the C program, an infinite loop will
+be entered. When using the @code{+x16r} config, the program will return to BASIC
+an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal. 
+
+Command-lines look like these lines:
+
+@example
+   run
+   run : rem
+   run:rem arg1 " arg 2 is quoted "  arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0x7e}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0x9700..0x9F00}. The size can be
+changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+Banking support for this target is not yet implemented.
+
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/PET
+
+This is a port of vclib to the CBM PET series of computers.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x401. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. RAM is available until 0x7FFF and most of the
+zero page without need for any special handling. The BSS segment will be cleared
+during startup.
+
+With the default configuration, after exiting the C program, an infinite loop will
+be entered. When using the @code{+petr} config, the program will return to BASIC
+an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal. 
+
+Command-lines look like these lines:
+
+@example
+   run
+   run : rem
+   run:rem arg1 " arg 2 is quoted "  arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0x8d}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0x7F00..0x7FFF}. The size can be
+changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+Automated banking is currently not supported.
+
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
diff --git a/doc/vcpr.texi b/doc/vcpr.texi
new file mode 100755
index 0000000..2ae1942
--- /dev/null
+++ b/doc/vcpr.texi
@@ -0,0 +1,192 @@
+vcpr - code compressor for vbcc (c) in 2020 by Volker Barthelmann
+
+
+@section Introduction
+
+    vcpr is a code compressor which scans the assembly output of
+    vbcc and tries to reduce code size of the generated code by
+    moving common code sequences into separate subroutines. As a
+    trade-off, the code will usually run slower.
+
+    Like the compiler vbcc it is split into a target independent and a
+    target dependent part. However there may be code-generators for vbcc
+    which do not have a corresponding compressor.
+
+    This document only deals with the target independent parts of vcpr.
+    Be sure to read all the documents for your machine.
+
+
+@section Usage
+
+    Usually @command{vcpr} will be called by a frontend. However if you call it
+    directly, it has to be done like this:
+
+@example
+    vcpr [options] input-file output-file
+@end example
+
+    The following options are supported:
+
+@table @option
+    @item -quiet
+                      Do not print the copyright notice.
+
+    @item -debug=<n>
+                  Set debug-level to <n>.
+@end table
+
+
+    Note that depending on the target @command{vbcc} may insert hints into the
+    generated code. Assembly code that was not generated by @command{vbcc}
+    may not work correctly after running it through @command{vcpr}.
+
+
+@section Known problems
+
+@itemize @minus
+    @item still in early development
+@end itemize
+
+@section Backend Interface
+
+@subsection Building @code{vcpr}
+
+To write a backend for @code{vcpr}, the file @code{compress.c} has to be created
+in the machine subdirectory. The executable @code{vcpr<target>} can be built
+using:
+
+@example
+    make TARGET=<target> bin/vcpr<target>
+@end example
+
+@subsection Basic Function
+
+@code{vcpr} first reads the assembly source into a linked list of lines. It will
+call a backend function for each line to parse the line and fill in necessary
+information.
+
+The frontend looks for identical code sequences and calculates the
+savings that can be obtained by outlining the code. If code sequences are found
+that provide enough savings, they will be moved to subroutines using functions
+provided by the backend.
+
+Lines have to be textually identical to be considered for outlining. One exception
+are labels. The following sequences are considered equal as long as the labels
+are not used anywhere else:
+
+@example
+
+  a
+  bne l1
+  b
+l1:
+  c
+
+  a
+  bne l2
+  b
+l2:
+  c
+@end example
+
+Currently, @code{vcpr} only supports code sequences with one label.
+
+@subsection Data Types
+
+The main data type relevant for the backend represents the attributed source lines:
+
+@example
+typedef struct line @{
+  ...
+  char *code;
+  int flags;
+  int size;
+  ...
+  int l1,l2;
+@} line;
+@end example
+
+The following members are relevant to the backend:
+
+@code{code} points to the assembly text of the line.
+
+@code{size} contains the (estimated) size of the instruction.
+
+@code{l1, l2} specify up to two labels referenced by this instruction.
+
+@code{flags} specifies the type of instruction and can be a combination of:
+
+@itemize
+@item @code{LABDEF}: This line defines a label.
+@item @code{LABUSE}: This line references a label.
+@item @code{BARRIER}: This line must not be moved into a subroutine.
+@item @code{LBARRIER}: Used by the frontend.
+@end itemize
+
+@subsection Backend Variables
+
+The following variables have to be defined and initialized by the backend:
+
+@itemize
+
+@item @code{const char tg_copyright[]}
+A copyright string.
+
+@item @code{int minsave;}
+The minimum size units saved by outlining a function. Should at least be larger
+than the size of the code for a subroutine call.
+
+@end itemize
+
+@subsection Backend Functions
+
+The following functions have to be provided by the backend:
+
+@itemize
+
+@item @code{void parse_line(char *s,line *p);}
+
+This function parses assembly line @code{s} and has to fill the
+members @code{flags}, @code{l1}, @code{l2} and @code{size} of the line structure
+@code{p}.
+
+@item @code{add_header(line *after);}
+
+This function creates a line for the header of outlined code and inserts it into the
+line list.
+
+@item @code{add_ret(line *after);}
+
+This function adds a return line and inserts it into the line list.
+
+@item @code{add_jsr(line *after);}
+
+This function adds a subroutine call to the subroutine corresponding to the last
+call of @code{add_header()}.
+
+@end itemize
+
+@subsection Frontend Functions 
+
+The following functions are provided by the frontend and can be used by the
+backend:
+
+@itemize
+
+@item @code{void *mymalloc(size_t sz);}
+
+Allocate memory.
+
+@item @code{int new_label(void);}
+
+Create a new unused label number.
+
+@item @code{line *new_line(void);}
+
+Create a new line.
+
+@item @code{void insert_line(line *after, line *new);}
+
+Insert a line into the line list at a specified position.
+
+@end itemize
diff --git a/doc/vprof.texi b/doc/vprof.texi
new file mode 100644
index 0000000..7d449b6
--- /dev/null
+++ b/doc/vprof.texi
@@ -0,0 +1,33 @@
+
+INTRODUCTION
+
+    vprof is a portable utility to visualize the profiling information,
+    which are usually stored in the file "mon.out".
+    It shows the percentage of total time spent in a function, the
+    total time in seconds, the number of function calls and the time
+    by call in ms.
+
+
+LEGAL
+
+    vprof is freeware.
+
+
+USAGE
+
+    vprof [mon.out]
+
+    If the profiling file has another name than "mon.out", you may
+    specify it as an argument to vprof.
+
+    Some vbcc code generators are able to create profiling information
+    by compiling with the -prof option (vbccm68k, for example).
+
+
+BUGS
+
+    The percentage column is still not working and will always
+    display "n.a.".
+
+
+Frank Wille                                              frank@phoenix.owl.de
diff --git a/doc/vsc.texi b/doc/vsc.texi
new file mode 100755
index 0000000..93aecd4
--- /dev/null
+++ b/doc/vsc.texi
@@ -0,0 +1,52 @@
+vsc - scheduler for vbcc (c) in 1997-99 by Volker Barthelmann
+
+
+@section Introduction
+
+    vsc is an instruction-scheduler which reorders the assembly output of
+    vbcc and tries to improve performance of the generated code by avoiding
+    pipeline stalls etc.
+
+    Like the compiler vbcc it is split into a target independent and a
+    target dependent part. However there may be code-generators for vbcc
+    which do not have a corresponding scheduler.
+
+    This document only deals with the target independent parts of vsc.
+    Be sure to read all the documents for your machine.
+
+
+@section Usage
+
+    Usually @command{vsc} will be called by a frontend. However if you call it
+    directly, it has to be done like this:
+
+@example
+    vsc [options] input-file output-file
+@end example
+
+    The following options are supported:
+
+@table @option
+    @item -quiet
+                      Do not print the copyright notice.
+
+    @item -debug=<n>
+                  Set debug-level to <n>.
+@end table
+
+
+    Note that depending on the target @command{vbcc} may insert hints into the
+    generated code to tell vsc what CPU to schedule for. Code
+    scheduled for a certain CPU may run much slower on slightly different
+    CPUs. Therefore it is especially important to specify the correct
+    target-CPU when compiling.
+
+
+@section Known problems
+
+@itemize @minus
+    @item works only on basic-blocks
+@end itemize
+
+
+
diff --git a/dwarf2.c b/dwarf2.c
new file mode 100644
index 0000000..281deb3
--- /dev/null
+++ b/dwarf2.c
@@ -0,0 +1,1294 @@
+/*  $VER: vbcc (dwarf2.c) $Revision: 1.5 $     */
+
+enum dwarf_tag
+{
+  DW_TAG_padding = 0x00,
+  DW_TAG_array_type = 0x01,
+  DW_TAG_class_type = 0x02,
+  DW_TAG_entry_point = 0x03,
+  DW_TAG_enumeration_type = 0x04,
+  DW_TAG_formal_parameter = 0x05,
+  DW_TAG_imported_declaration = 0x08,
+  DW_TAG_label = 0x0a,
+  DW_TAG_lexical_block = 0x0b,
+  DW_TAG_member = 0x0d,
+  DW_TAG_pointer_type = 0x0f,
+  DW_TAG_reference_type = 0x10,
+  DW_TAG_compile_unit = 0x11,
+  DW_TAG_string_type = 0x12,
+  DW_TAG_structure_type = 0x13,
+  DW_TAG_subroutine_type = 0x15,
+  DW_TAG_typedef = 0x16,
+  DW_TAG_union_type = 0x17,
+  DW_TAG_unspecified_parameters = 0x18,
+  DW_TAG_variant = 0x19,
+  DW_TAG_common_block = 0x1a,
+  DW_TAG_common_inclusion = 0x1b,
+  DW_TAG_inheritance = 0x1c,
+  DW_TAG_inlined_subroutine = 0x1d,
+  DW_TAG_module = 0x1e,
+  DW_TAG_ptr_to_member_type = 0x1f,
+  DW_TAG_set_type = 0x20,
+  DW_TAG_subrange_type = 0x21,
+  DW_TAG_with_stmt = 0x22,
+  DW_TAG_access_declaration = 0x23,
+  DW_TAG_base_type = 0x24,
+  DW_TAG_catch_block = 0x25,
+  DW_TAG_const_type = 0x26,
+  DW_TAG_constant = 0x27,
+  DW_TAG_enumerator = 0x28,
+  DW_TAG_file_type = 0x29,
+  DW_TAG_friend = 0x2a,
+  DW_TAG_namelist = 0x2b,
+  DW_TAG_namelist_item = 0x2c,
+  DW_TAG_packed_type = 0x2d,
+  DW_TAG_subprogram = 0x2e,
+  DW_TAG_template_type_param = 0x2f,
+  DW_TAG_template_value_param = 0x30,
+  DW_TAG_thrown_type = 0x31,
+  DW_TAG_try_block = 0x32,
+  DW_TAG_variant_part = 0x33,
+  DW_TAG_variable = 0x34,
+  DW_TAG_volatile_type = 0x35,
+  /* SGI/MIPS Extensions */
+  DW_TAG_MIPS_loop = 0x4081,
+  /* GNU extensions */
+  DW_TAG_format_label = 0x4101,
+  DW_TAG_function_template = 0x4102,
+  DW_TAG_class_template = 0x4103
+};
+
+enum dwarf_children
+{
+  DW_children_no = 0,
+  DW_children_yes = 1
+};
+
+enum dwarf_form
+{
+  DW_FORM_addr = 0x01,
+  DW_FORM_block2 = 0x03,
+  DW_FORM_block4 = 0x04,
+  DW_FORM_data2 = 0x05,
+  DW_FORM_data4 = 0x06,
+  DW_FORM_data8 = 0x07,
+  DW_FORM_string = 0x08,
+  DW_FORM_block = 0x09,
+  DW_FORM_block1 = 0x0a,
+  DW_FORM_data1 = 0x0b,
+  DW_FORM_flag = 0x0c,
+  DW_FORM_sdata = 0x0d,
+  DW_FORM_strp = 0x0e,
+  DW_FORM_udata = 0x0f,
+  DW_FORM_ref_addr = 0x10,
+  DW_FORM_ref1 = 0x11,
+  DW_FORM_ref2 = 0x12,
+  DW_FORM_ref4 = 0x13,
+  DW_FORM_ref8 = 0x14,
+  DW_FORM_ref_udata = 0x15,
+  DW_FORM_indirect = 0x16
+};
+
+enum dwarf_attribute
+{
+  DW_AT_sibling = 0x01,
+  DW_AT_location = 0x02,
+  DW_AT_name = 0x03,
+  DW_AT_ordering = 0x09,
+  DW_AT_subscr_data = 0x0a,
+  DW_AT_byte_size = 0x0b,
+  DW_AT_bit_offset = 0x0c,
+  DW_AT_bit_size = 0x0d,
+  DW_AT_element_list = 0x0f,
+  DW_AT_stmt_list = 0x10,
+  DW_AT_low_pc = 0x11,
+  DW_AT_high_pc = 0x12,
+  DW_AT_language = 0x13,
+  DW_AT_member = 0x14,
+  DW_AT_discr = 0x15,
+  DW_AT_discr_value = 0x16,
+  DW_AT_visibility = 0x17,
+  DW_AT_import = 0x18,
+  DW_AT_string_length = 0x19,
+  DW_AT_common_reference = 0x1a,
+  DW_AT_comp_dir = 0x1b,
+  DW_AT_const_value = 0x1c,
+  DW_AT_containing_type = 0x1d,
+  DW_AT_default_value = 0x1e,
+  DW_AT_inline = 0x20,
+  DW_AT_is_optional = 0x21,
+  DW_AT_lower_bound = 0x22,
+  DW_AT_producer = 0x25,
+  DW_AT_prototyped = 0x27,
+  DW_AT_return_addr = 0x2a,
+  DW_AT_start_scope = 0x2c,
+  DW_AT_stride_size = 0x2e,
+  DW_AT_upper_bound = 0x2f,
+  DW_AT_abstract_origin = 0x31,
+  DW_AT_accessibility = 0x32,
+  DW_AT_address_class = 0x33,
+  DW_AT_artificial = 0x34,
+  DW_AT_base_types = 0x35,
+  DW_AT_calling_convention = 0x36,
+  DW_AT_count = 0x37,
+  DW_AT_data_member_location = 0x38,
+  DW_AT_decl_column = 0x39,
+  DW_AT_decl_file = 0x3a,
+  DW_AT_decl_line = 0x3b,
+  DW_AT_declaration = 0x3c,
+  DW_AT_discr_list = 0x3d,
+  DW_AT_encoding = 0x3e,
+  DW_AT_external = 0x3f,
+  DW_AT_frame_base = 0x40,
+  DW_AT_friend = 0x41,
+  DW_AT_identifier_case = 0x42,
+  DW_AT_macro_info = 0x43,
+  DW_AT_namelist_items = 0x44,
+  DW_AT_priority = 0x45,
+  DW_AT_segment = 0x46,
+  DW_AT_specification = 0x47,
+  DW_AT_static_link = 0x48,
+  DW_AT_type = 0x49,
+  DW_AT_use_location = 0x4a,
+  DW_AT_variable_parameter = 0x4b,
+  DW_AT_virtuality = 0x4c,
+  DW_AT_vtable_elem_location = 0x4d,
+  DW_AT_MIPS_fde = 0x2001,
+  DW_AT_MIPS_loop_begin = 0x2002,
+  DW_AT_MIPS_tail_loop_begin = 0x2003,
+  DW_AT_MIPS_epilog_begin = 0x2004,
+  DW_AT_MIPS_loop_unroll_factor = 0x2005,
+  DW_AT_MIPS_software_pipeline_depth = 0x2006,
+  DW_AT_MIPS_linkage_name = 0x2007,
+  DW_AT_MIPS_stride = 0x2008,
+  DW_AT_MIPS_abstract_name = 0x2009,
+  DW_AT_MIPS_clone_origin = 0x200a,
+  DW_AT_MIPS_has_inlines = 0x200b,
+  /* GNU */
+  DW_AT_sf_names = 0x2101,
+  DW_AT_src_info = 0x2102,
+  DW_AT_mac_info = 0x2103,
+  DW_AT_src_coords = 0x2104,
+  DW_AT_body_begin = 0x2105,
+  DW_AT_body_end = 0x2106
+};
+
+enum dwarf_location_atom
+{
+  DW_OP_addr = 0x03,
+  DW_OP_deref = 0x06,
+  DW_OP_const1u = 0x08,
+  DW_OP_const1s = 0x09,
+  DW_OP_const2u = 0x0a,
+  DW_OP_const2s = 0x0b,
+  DW_OP_const4u = 0x0c,
+  DW_OP_const4s = 0x0d,
+  DW_OP_const8u = 0x0e,
+  DW_OP_const8s = 0x0f,
+  DW_OP_constu = 0x10,
+  DW_OP_consts = 0x11,
+  DW_OP_dup = 0x12,
+  DW_OP_drop = 0x13,
+  DW_OP_over = 0x14,
+  DW_OP_pick = 0x15,
+  DW_OP_swap = 0x16,
+  DW_OP_rot = 0x17,
+  DW_OP_xderef = 0x18,
+  DW_OP_abs = 0x19,
+  DW_OP_and = 0x1a,
+  DW_OP_div = 0x1b,
+  DW_OP_minus = 0x1c,
+  DW_OP_mod = 0x1d,
+  DW_OP_mul = 0x1e,
+  DW_OP_neg = 0x1f,
+  DW_OP_not = 0x20,
+  DW_OP_or = 0x21,
+  DW_OP_plus = 0x22,
+  DW_OP_plus_uconst = 0x23,
+  DW_OP_shl = 0x24,
+  DW_OP_shr = 0x25,
+  DW_OP_shra = 0x26,
+  DW_OP_xor = 0x27,
+  DW_OP_bra = 0x28,
+  DW_OP_eq = 0x29,
+  DW_OP_ge = 0x2a,
+  DW_OP_gt = 0x2b,
+  DW_OP_le = 0x2c,
+  DW_OP_lt = 0x2d,
+  DW_OP_ne = 0x2e,
+  DW_OP_skip = 0x2f,
+  DW_OP_lit0 = 0x30,
+  DW_OP_lit1 = 0x31,
+  DW_OP_lit2 = 0x32,
+  DW_OP_lit3 = 0x33,
+  DW_OP_lit4 = 0x34,
+  DW_OP_lit5 = 0x35,
+  DW_OP_lit6 = 0x36,
+  DW_OP_lit7 = 0x37,
+  DW_OP_lit8 = 0x38,
+  DW_OP_lit9 = 0x39,
+  DW_OP_lit10 = 0x3a,
+  DW_OP_lit11 = 0x3b,
+  DW_OP_lit12 = 0x3c,
+  DW_OP_lit13 = 0x3d,
+  DW_OP_lit14 = 0x3e,
+  DW_OP_lit15 = 0x3f,
+  DW_OP_lit16 = 0x40,
+  DW_OP_lit17 = 0x41,
+  DW_OP_lit18 = 0x42,
+  DW_OP_lit19 = 0x43,
+  DW_OP_lit20 = 0x44,
+  DW_OP_lit21 = 0x45,
+  DW_OP_lit22 = 0x46,
+  DW_OP_lit23 = 0x47,
+  DW_OP_lit24 = 0x48,
+  DW_OP_lit25 = 0x49,
+  DW_OP_lit26 = 0x4a,
+  DW_OP_lit27 = 0x4b,
+  DW_OP_lit28 = 0x4c,
+  DW_OP_lit29 = 0x4d,
+  DW_OP_lit30 = 0x4e,
+  DW_OP_lit31 = 0x4f,
+  DW_OP_reg0 = 0x50,
+  DW_OP_reg1 = 0x51,
+  DW_OP_reg2 = 0x52,
+  DW_OP_reg3 = 0x53,
+  DW_OP_reg4 = 0x54,
+  DW_OP_reg5 = 0x55,
+  DW_OP_reg6 = 0x56,
+  DW_OP_reg7 = 0x57,
+  DW_OP_reg8 = 0x58,
+  DW_OP_reg9 = 0x59,
+  DW_OP_reg10 = 0x5a,
+  DW_OP_reg11 = 0x5b,
+  DW_OP_reg12 = 0x5c,
+  DW_OP_reg13 = 0x5d,
+  DW_OP_reg14 = 0x5e,
+  DW_OP_reg15 = 0x5f,
+  DW_OP_reg16 = 0x60,
+  DW_OP_reg17 = 0x61,
+  DW_OP_reg18 = 0x62,
+  DW_OP_reg19 = 0x63,
+  DW_OP_reg20 = 0x64,
+  DW_OP_reg21 = 0x65,
+  DW_OP_reg22 = 0x66,
+  DW_OP_reg23 = 0x67,
+  DW_OP_reg24 = 0x68,
+  DW_OP_reg25 = 0x69,
+  DW_OP_reg26 = 0x6a,
+  DW_OP_reg27 = 0x6b,
+  DW_OP_reg28 = 0x6c,
+  DW_OP_reg29 = 0x6d,
+  DW_OP_reg30 = 0x6e,
+  DW_OP_reg31 = 0x6f,
+  DW_OP_breg0 = 0x70,
+  DW_OP_breg1 = 0x71,
+  DW_OP_breg2 = 0x72,
+  DW_OP_breg3 = 0x73,
+  DW_OP_breg4 = 0x74,
+  DW_OP_breg5 = 0x75,
+  DW_OP_breg6 = 0x76,
+  DW_OP_breg7 = 0x77,
+  DW_OP_breg8 = 0x78,
+  DW_OP_breg9 = 0x79,
+  DW_OP_breg10 = 0x7a,
+  DW_OP_breg11 = 0x7b,
+  DW_OP_breg12 = 0x7c,
+  DW_OP_breg13 = 0x7d,
+  DW_OP_breg14 = 0x7e,
+  DW_OP_breg15 = 0x7f,
+  DW_OP_breg16 = 0x80,
+  DW_OP_breg17 = 0x81,
+  DW_OP_breg18 = 0x82,
+  DW_OP_breg19 = 0x83,
+  DW_OP_breg20 = 0x84,
+  DW_OP_breg21 = 0x85,
+  DW_OP_breg22 = 0x86,
+  DW_OP_breg23 = 0x87,
+  DW_OP_breg24 = 0x88,
+  DW_OP_breg25 = 0x89,
+  DW_OP_breg26 = 0x8a,
+  DW_OP_breg27 = 0x8b,
+  DW_OP_breg28 = 0x8c,
+  DW_OP_breg29 = 0x8d,
+  DW_OP_breg30 = 0x8e,
+  DW_OP_breg31 = 0x8f,
+  DW_OP_regx = 0x90,
+  DW_OP_fbreg = 0x91,
+  DW_OP_bregx = 0x92,
+  DW_OP_piece = 0x93,
+  DW_OP_deref_size = 0x94,
+  DW_OP_xderef_size = 0x95,
+  DW_OP_nop = 0x96
+};
+
+enum dwarf_type
+{
+  DW_ATE_void = 0x0,
+  DW_ATE_address = 0x1,
+  DW_ATE_boolean = 0x2,
+  DW_ATE_complex_float = 0x3,
+  DW_ATE_float = 0x4,
+  DW_ATE_signed = 0x5,
+  DW_ATE_signed_char = 0x6,
+  DW_ATE_unsigned = 0x7,
+  DW_ATE_unsigned_char = 0x8
+};
+
+enum dwarf_array_dim_ordering
+{
+  DW_ORD_row_major = 0,
+  DW_ORD_col_major = 1
+};
+
+enum dwarf_access_attribute
+{
+  DW_ACCESS_public = 1,
+  DW_ACCESS_protected = 2,
+  DW_ACCESS_private = 3
+};
+
+enum dwarf_visibility_attribute
+{
+  DW_VIS_local = 1,
+  DW_VIS_exported = 2,
+  DW_VIS_qualified = 3
+};
+
+enum dwarf_virtuality_attribute
+{
+  DW_VIRTUALITY_none = 0,
+  DW_VIRTUALITY_virtual = 1,
+  DW_VIRTUALITY_pure_virtual = 2
+};
+
+enum dwarf_id_case
+{
+  DW_ID_case_sensitive = 0,
+  DW_ID_up_case = 1,
+  DW_ID_down_case = 2,
+  DW_ID_case_insensitive = 3
+};
+
+enum dwarf_calling_convention
+{
+  DW_CC_normal = 0x1,
+  DW_CC_program = 0x2,
+  DW_CC_nocall = 0x3
+};
+
+enum dwarf_inline_attribute
+{
+  DW_INL_not_inlined = 0,
+  DW_INL_inlined = 1,
+  DW_INL_declared_not_inlined = 2,
+  DW_INL_declared_inlined = 3
+};
+
+enum dwarf_descrim_list
+{
+  DW_DSC_label = 0,
+  DW_DSC_range = 1
+};
+
+enum dwarf_line_number_ops
+{
+  DW_LNS_extended_op = 0,
+  DW_LNS_copy = 1,
+  DW_LNS_advance_pc = 2,
+  DW_LNS_advance_line = 3,
+  DW_LNS_set_file = 4,
+  DW_LNS_set_column = 5,
+  DW_LNS_negate_stmt = 6,
+  DW_LNS_set_basic_block = 7,
+  DW_LNS_const_add_pc = 8,
+  DW_LNS_fixed_advance_pc = 9
+};
+
+enum dwarf_line_number_x_ops
+{
+  DW_LNE_end_sequence = 1,
+  DW_LNE_set_address = 2,
+  DW_LNE_define_file = 3
+};
+
+enum dwarf_call_frame_info
+{
+  DW_CFA_advance_loc = 0x40,
+  DW_CFA_offset = 0x80,
+  DW_CFA_restore = 0xc0,
+  DW_CFA_nop = 0x00,
+  DW_CFA_set_loc = 0x01,
+  DW_CFA_advance_loc1 = 0x02,
+  DW_CFA_advance_loc2 = 0x03,
+  DW_CFA_advance_loc4 = 0x04,
+  DW_CFA_offset_extended = 0x05,
+  DW_CFA_restore_extended = 0x06,
+  DW_CFA_undefined = 0x07,
+  DW_CFA_same_value = 0x08,
+  DW_CFA_register = 0x09,
+  DW_CFA_remember_state = 0x0a,
+  DW_CFA_restore_state = 0x0b,
+  DW_CFA_def_cfa = 0x0c,
+  DW_CFA_def_cfa_register = 0x0d,
+  DW_CFA_def_cfa_offset = 0x0e,
+  DW_CFA_MIPS_advance_loc8 = 0x1d
+};
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_low_user   0x1c
+#define DW_CFA_high_user  0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+enum dwarf_source_language
+{
+  DW_LANG_C89 = 0x0001,
+  DW_LANG_C = 0x0002,
+  DW_LANG_Ada83 = 0x0003,
+  DW_LANG_C_plus_plus = 0x0004,
+  DW_LANG_Cobol74 = 0x0005,
+  DW_LANG_Cobol85 = 0x0006,
+  DW_LANG_Fortran77 = 0x0007,
+  DW_LANG_Fortran90 = 0x0008,
+  DW_LANG_Pascal83 = 0x0009,
+  DW_LANG_Modula2 = 0x000a,
+  DW_LANG_Mips_Assembler = 0x8001
+};
+
+
+enum dwarf_macinfo_record_type
+{
+  DW_MACINFO_define = 1,
+  DW_MACINFO_undef = 2,
+  DW_MACINFO_start_file = 3,
+  DW_MACINFO_end_file = 4,
+  DW_MACINFO_vendor_ext = 255
+};
+
+
+
+#define HAVE_LOCATION_LISTS 0
+
+/* provided by the code generator */
+static void dwarf2_print_frame_location(FILE *,Var *);
+static zmax dwarf2_fboffset(Var *);
+static int dwarf2_regnumber(int);
+
+static int abbrev_label,info_start,info_end,line_start,line_end;
+
+static int sizeof_addr;
+static char *dwarfd1,*dwarfd2,*dwarfd4,*da,*lp,*ip,*dsec;
+static int addr_form;
+static char **names;
+static int namecount;
+
+extern Var *merk_varf,*first_var[],*first_ext; /*FIXME: not nice */
+extern struct_declaration *first_sd[];
+
+#define COMP_UNIT 1UL
+#define SUBPROGRAM 2UL
+#define SUBPROGRAMVOID 3UL 
+#define BASETYPE 4UL
+#define POINTERTYPE 5UL
+#define CONSTTYPE 6UL
+#define VOLATILETYPE 7UL
+#define FORMALPARAMETER 8UL
+#define VARIABLE 9UL
+#define ARRAYTYPE 10UL
+#define ARRAYDIM 11UL
+#define STRUCTTYPE 12UL
+#define UNIONTYPE 13UL
+#define STRUCTTAG 14UL
+#define UNIONTAG 15UL
+#define TYPEDEFTYPE 16UL
+#define MEMBERTYPE 17UL
+#define FUNCTYPE 18UL
+#define VOIDFUNCTYPE 19UL
+#define PARMTYPE 20UL
+
+typedef struct dwarf2_line_info {
+  struct dwarf2_line_info *next;
+  char *id;
+  int file,line,label;
+} tdwarf2_line_info;
+
+static tdwarf2_line_info *dwarf2_first_li,*dwarf2_last_li;
+
+static void dwarf2_add_line(int file,int line,int label,char *id)
+{
+  tdwarf2_line_info *new,*p,*lp;
+  new=mymalloc(sizeof(*new));
+  new->file=file;
+  new->line=line;
+  new->label=label;
+  if(id){
+    new->id=mymalloc(strlen(id)+1);
+    strcpy(new->id,id);
+  }else{
+    new->id=0;
+  }
+  new->next=0;
+#if 0
+  for(lp=p=dwarf2_first_li;p;p=p->next){
+    if(p!=lp&&p->file==file&&p->line>=line){
+      new->next=lp->next;
+      lp->next=new;
+      return;
+    }
+    lp=p;
+  }
+#endif
+  if(dwarf2_last_li){
+    dwarf2_last_li->next=new;
+    dwarf2_last_li=new;
+  }else{
+    dwarf2_first_li=dwarf2_last_li=new;
+  }
+#if 0
+  printf("linfo:\n");
+  for(p=dwarf2_first_li;p;p=p->next)
+    printf("li: line=%d\n",p->line);
+#endif
+}
+
+static void dwarf2_setup(int sa,char *dwarfd1s,char *dwarfd2s,char *dwarfd4s,char *das,char *lps,char *ips,char *ds)
+{
+  sizeof_addr=sa;
+  dwarfd1=dwarfd1s;
+  dwarfd2=dwarfd2s;
+  dwarfd4=dwarfd4s;
+  da=das;
+  lp=lps;
+  ip=ips;
+  dsec=ds;
+  if(sizeof_addr==2)
+    addr_form=DW_FORM_data2;
+  else if(sizeof_addr==4)
+    addr_form=DW_FORM_data4;
+  else if(sizeof_addr==8)
+    addr_form=DW_FORM_data8;
+  else
+    ierror(0);
+}
+static int dwarf2_uleb128_size(zumax value)
+{
+  int size=0;
+  do{
+    value=zumrshift(value,ul2zum(7UL));
+    size++;
+  }while(!zmeqto(value,ul2zum(0UL)));
+  return size;
+}
+static void dwarf2_print_uleb128(FILE *f,zumax value)
+{
+  unsigned long byte;
+  emit(f,"\t%s\t",dwarfd1);
+  do{
+    byte=zum2ul(zumand(value,ul2zum(127UL)));
+    value=zumrshift(value,ul2zum(7UL));
+    if(!zumeqto(value,ul2zum(0UL)))
+      emit(f,"%lu,",byte|0x80);
+    else
+      emit(f,"%lu\n",byte);
+  }while(!zumeqto(value,ul2zum(0UL)));
+}
+static int dwarf2_sleb128_size(zmax value)
+{
+  int more=1,size=0;
+  long byte;
+  do{
+    byte=zm2l(zmand(value,l2zm(127L)));
+    value=zmrshift(value,l2zm(7L)); /*FIXME*/
+    if((zmeqto(value,l2zm(0L))&&!(byte&0x40))||
+       (zmeqto(value,l2zm(-1L))&&(byte&0x40)))
+      more=0;
+    size++;
+  }while(more);
+  return size;
+}
+static void dwarf2_print_sleb128(FILE *f,zmax value)
+{
+  int more=1;
+  long byte;
+  emit(f,"\t%s\t",dwarfd1);
+  do{
+    byte=zm2l(zmand(value,l2zm(127L)));
+    value=zmrshift(value,l2zm(7L)); /*FIXME*/
+    if((zmeqto(value,l2zm(0L))&&!(byte&0x40))||
+       (zmeqto(value,l2zm(-1L))&&(byte&0x40))){
+      more=0;
+      emit(f,"%ld\n",byte);
+    }else{
+      emit(f,"%ld,",byte|0x80);
+    }
+  }while(more);
+}
+static void dwarf2_print_location(FILE *f,obj *o)
+{
+  if(o->flags&(KONST|DREFOBJ)) ierror(0);
+  if(!(o->flags&(VAR|REG))) ierror(0);
+  if(o->flags&REG){
+    int r=dwarf2_regnumber(o->reg);
+    if(r<=31){
+      emit(f,"\t%s\t%d\n",dwarfd2,1);
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_reg0+r);
+    }else{
+      emit(f,"\t%s\t%d\n",dwarfd2,1+dwarf2_uleb128_size(ul2zum((unsigned long)r)));
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_regx);
+      dwarf2_print_uleb128(f,ul2zum(r));
+    }
+  }else{
+    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
+      if(cross_module&&!(o->v->flags&REFERENCED)){
+	emit(f,"\t%s\t0\n",dwarfd1);
+      }else{
+	emit(f,"\t%s\t%d\n",dwarfd2,(int)(1+sizeof_addr));
+	emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_addr);
+	if(o->v->storage_class==STATIC)
+	  emit(f,"\t%s\t%s%ld\n",da,lp,zm2l(o->v->offset));
+	else
+	  emit(f,"\t%s\t%s%s\n",da,ip,o->v->identifier);
+      }
+    }else{
+      zmax of=dwarf2_fboffset(o->v);
+      emit(f,"\t%s\t%d\n",dwarfd2,1+dwarf2_sleb128_size(of));
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_fbreg);
+      dwarf2_print_sleb128(f,of);
+    }
+  }
+}
+static int dwarf2_file(const char *p)
+{
+  int i;
+  if(!p) ierror(0);
+  for(i=0;i<namecount;i++)
+    if(!strcmp(p,names[i]))
+      return i+1;
+  namecount++;
+  names=myrealloc(names,namecount*sizeof(*names));
+  names[namecount-1]=mymalloc(strlen(p)+1);
+  strcpy(names[namecount-1],p);
+  return namecount;
+}
+static int dwarf2_type(FILE *f,type *t)
+{
+  int l,lo;char *p;
+  if(ISPOINTER(t->flags)){
+    lo=dwarf2_type(f,t->next);
+    l=++label;
+    emit(f,"%s%d:\n",lp,l);
+    dwarf2_print_uleb128(f,ul2zum(POINTERTYPE));
+    emit(f,"\t%s\t%s%d\n",da,lp,lo);
+  }else if(ISINT(t->flags)||ISFLOAT(t->flags)||(t->flags&NQ)==VOID){
+    l=++label;
+    emit(f,"%s%d:\n",lp,l);
+    dwarf2_print_uleb128(f,ul2zum(BASETYPE));    
+    for(p=typname[t->flags&NQ];*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+    emit(f,"\t%s\t0\n",dwarfd1);
+    if(ISFLOAT(t->flags)){
+      lo=DW_ATE_float;
+    }else if((t->flags&NQ)==CHAR){
+      if(t->flags&UNSIGNED)
+	lo=DW_ATE_unsigned_char;
+      else
+	lo=DW_ATE_signed_char;
+    }else if((t->flags&NQ)==VOID){
+      lo=DW_ATE_unsigned_char;
+    }else{
+      if(!ISINT(t->flags)) ierror(0);
+      if(t->flags&UNSIGNED)
+	lo=DW_ATE_unsigned;
+      else
+	lo=DW_ATE_signed;
+    }
+    dwarf2_print_uleb128(f,ul2zum((unsigned long)lo));
+    dwarf2_print_uleb128(f,sizetab[t->flags&NQ]);
+  }else if(ISARRAY(t->flags)){
+    lo=dwarf2_type(f,t->next);
+    l=++label;
+    emit(f,"%s%d:\n",lp,l);
+    dwarf2_print_uleb128(f,ul2zum(ARRAYTYPE));
+    emit(f,"\t%s\t%s%d\n",da,lp,lo);
+    dwarf2_print_uleb128(f,ul2zum(ARRAYDIM));
+    dwarf2_print_uleb128(f,zumsub(t->size,ul2zum(1UL)));
+    emit(f,"\t%s\t0\n",dwarfd1);
+  }else if(ISSTRUCT(t->flags)||ISUNION(t->flags)){
+    if(t->exact->label>0){
+      l=t->exact->label;
+    }else{
+      int i,*tl;zmax offset=l2zm(0L),al;
+      type *tp;
+      l=++label;
+      t->exact->label=l;
+      tl=mymalloc(t->exact->count*sizeof(*tl));
+      for(i=0;i<t->exact->count;i++)
+	tl[i]=dwarf2_type(f,(*t->exact->sl)[i].styp);
+      emit(f,"%s%d:\n",lp,l);
+      if(t->exact->identifier){
+	if(ISSTRUCT(t->flags))
+	  dwarf2_print_uleb128(f,STRUCTTAG);
+	else
+	  dwarf2_print_uleb128(f,UNIONTAG);
+	dwarf2_print_uleb128(f,szof(t));
+	for(p=t->exact->identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+	emit(f,"\t%s\t0\n",dwarfd1);
+      }else{
+	if(ISSTRUCT(t->flags))
+	  dwarf2_print_uleb128(f,STRUCTTYPE);
+	else
+	  dwarf2_print_uleb128(f,UNIONTYPE);
+	dwarf2_print_uleb128(f,szof(t));
+      }
+      for(i=0;i<t->exact->count;i++){
+	dwarf2_print_uleb128(f,MEMBERTYPE);
+	for(p=(*t->exact->sl)[i].identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+	emit(f,"\t%s\t0\n",dwarfd1);
+	emit(f,"\t%s\t%s%d\n",da,lp,tl[i]);
+	dwarf2_print_uleb128(f,zumadd(dwarf2_uleb128_size(zm2zum(offset)),ul2zum(1L)));
+	tp=(*t->exact->sl)[i].styp;
+	al=falign(tp);
+	offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
+	emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_plus_uconst);
+	dwarf2_print_uleb128(f,zm2zum(offset));
+	if(ISSTRUCT(t->flags))
+	  offset=zmadd(offset,szof(tp));   	
+      }
+      emit(f,"\t%s\t0\n",dwarfd1);
+      free(tl);
+    }
+  }else if(ISFUNC(t->flags)){
+    int *tl,i;
+    l=++label;
+    tl=mymalloc(t->exact->count*sizeof(*tl));
+    for(i=0;i<t->exact->count;i++){
+      if(((*t->exact->sl)[i].styp->flags&NQ)!=VOID)
+	tl[i]=dwarf2_type(f,(*t->exact->sl)[i].styp);
+    }
+    if((t->next->flags&NQ)==VOID){
+      emit(f,"%s%d:\n",lp,l);
+      dwarf2_print_uleb128(f,VOIDFUNCTYPE);
+    }else{
+      lo=dwarf2_type(f,t->next);
+      emit(f,"%s%d:\n",lp,l);
+      dwarf2_print_uleb128(f,FUNCTYPE);
+      emit(f,"\t%s\t%s%d\n",da,lp,lo);
+    }
+    for(i=0;i<t->exact->count;i++){
+      if(((*t->exact->sl)[i].styp->flags&NQ)!=VOID){
+	dwarf2_print_uleb128(f,PARMTYPE);
+	emit(f,"\t%s\t%s%d\n",da,lp,tl[i]);
+      }
+    }
+    emit(f,"\t%s\t0\n",dwarfd1);
+    free(tl);
+  }else{
+    printf("%d\n",t->flags);
+    ierror(0);
+  }
+  if(t->flags&VOLATILE){
+    lo=l;l=++label;
+    emit(f,"%s%d:\n",lp,l);
+    dwarf2_print_uleb128(f,ul2zum(VOLATILETYPE));
+    emit(f,"\t%s\t%s%d\n",da,lp,lo);
+  }
+  if(t->flags&CONST){
+    lo=l;l=++label;
+    emit(f,"%s%d:\n",lp,l);
+    dwarf2_print_uleb128(f,ul2zum(CONSTTYPE));
+    emit(f,"\t%s\t%s%d\n",da,lp,lo);
+  }
+  return l;
+}
+static void dwarf2_var(FILE *f,Var *v)
+{
+  char *p;int l;
+  if(!(v->flags&(DEFINED|TENTATIVE))) return;
+  if(v->storage_class==STATIC&&v->nesting>0&&!(v->flags&(USEDASSOURCE|USEDASDEST))) return;
+
+  if(ISFUNC(v->vtyp->flags)) return;
+  if(*v->identifier&&v->storage_class!=TYPEDEF){
+    l=dwarf2_type(f,v->vtyp);
+    if((v->storage_class==AUTO||v->storage_class==REGISTER)&&(!zmleq(l2zm(0L),v->offset)||v->reg)){
+      dwarf2_print_uleb128(f,ul2zum(FORMALPARAMETER));
+    }else{
+      dwarf2_print_uleb128(f,ul2zum(VARIABLE));
+    }
+    for(p=v->identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+    emit(f,"\t%s\t0\n",dwarfd1);
+    emit(f,"\t%s\t%s%d\n",da,lp,l);
+    if((v->storage_class==AUTO||v->storage_class==REGISTER)&&(!zmleq(l2zm(0L),v->offset)||v->reg)){
+      /* no external flag for formal-parameter */
+    }else{
+      emit(f,"\t%s\t%d\n",dwarfd1,(v->storage_class==EXTERN));
+    }
+    if((!v->dfilename||!v->dline)&&(!v->filename||!v->line)) ierror(0);
+    if(v->dfilename){
+      dwarf2_print_uleb128(f,ul2zum((unsigned long)dwarf2_file(v->dfilename)));
+      dwarf2_print_uleb128(f,ul2zum((unsigned long)v->dline));
+    }else{
+      dwarf2_print_uleb128(f,ul2zum((unsigned long)dwarf2_file(v->filename)));
+      dwarf2_print_uleb128(f,ul2zum((unsigned long)v->line));
+    }
+    {  /*FIXME!*/
+      obj o;
+      o.flags=VAR;
+      o.val.vmax=l2zm(0L);
+      o.v=v;
+#if HAVE_LOCATION_LISTS
+      emit(f,"\t%s\t\".debug_loc\"\n",dsec);
+      ++label;
+      emit(f,"%s%d:\n",lp,label);
+      emit(f,"\t%s\t0\n",da);
+      emit(f,"\t%s\t-1\n",da);
+      dwarf2_print_location(f,&o);
+      emit(f,"\t%s\t0\n",da);
+      emit(f,"\t%s\t0\n",da);      
+      emit(f,"\t%s\t\".debug_info\"\n",dsec);
+      emit(f,"\t%s\t%s%d\n",da,lp,label);
+#else
+      dwarf2_print_location(f,&o);
+#endif      
+    }
+  }
+}
+static void dwarf2_print_comp_unit_header(FILE *f)
+{
+  char *p;
+  extern char *copyright; /* not nice */
+  extern char *inname; /* not nice */
+  
+  abbrev_label=++label;
+  emit(f,"\t%s\t\".debug_abbrev\"\n",dsec);
+  emit(f,"%s%d:\n",lp,abbrev_label);
+
+  dwarf2_print_uleb128(f,ul2zum(COMP_UNIT));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_compile_unit));
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes)); 
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_language));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_stmt_list));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_producer));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_identifier_case));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(0UL));
+  dwarf2_print_uleb128(f,ul2zum(0UL));
+
+  dwarf2_print_uleb128(f,ul2zum(SUBPROGRAM));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_subprogram));
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_low_pc));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_high_pc));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_external));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_flag));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_frame_base));
+#if HAVE_LOCATION_LISTS
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(SUBPROGRAMVOID));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_subprogram));
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_low_pc));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_high_pc));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_external));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_flag));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_frame_base));
+#if HAVE_LOCATION_LISTS
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(FORMALPARAMETER));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_formal_parameter));
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_location));
+#if HAVE_LOCATION_LISTS
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(VARIABLE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_variable));
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_external));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_flag));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_location));
+#if HAVE_LOCATION_LISTS
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(BASETYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_base_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_encoding));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(POINTERTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_pointer_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));  
+
+  dwarf2_print_uleb128(f,ul2zum(CONSTTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_const_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(VOLATILETYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_volatile_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(ARRAYTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_array_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(ARRAYDIM));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_subrange_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_upper_bound));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(STRUCTTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_structure_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(UNIONTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_union_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(STRUCTTAG));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_structure_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(UNIONTAG));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_union_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(MEMBERTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_member));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_data_member_location));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_block));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(FUNCTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_subroutine_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(VOIDFUNCTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_subroutine_type));  
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+  dwarf2_print_uleb128(f,ul2zum(PARMTYPE));
+  dwarf2_print_uleb128(f,ul2zum(DW_TAG_formal_parameter));
+  dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+  dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+  dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+  dwarf2_print_uleb128(f,ul2zum(0L));
+
+
+  info_start=++label;info_end=++label;
+  emit(f,"\t%s\t\".debug_info\"\n",dsec);
+  
+  /* header */
+  emit(f,"%s%d:\n",lp,info_start);
+  emit(f,"\t%s\t%s%d-%s%d-4\n",dwarfd4,lp,info_end,lp,info_start);
+  emit(f,"\t%s\t2\n",dwarfd2); /* version */
+  emit(f,"\t%s\t%s%d\n",dwarfd4,lp,abbrev_label);
+  emit(f,"\t%s\t%d\n",dwarfd1,sizeof_addr);
+  
+  /* compile_unit */
+  dwarf2_print_uleb128(f,ul2zum(COMP_UNIT));
+  dwarf2_print_uleb128(f,ul2zum(DW_LANG_C89));
+  line_start=++label;line_end=++label;
+  emit(f,"\t%s\t%s%d\n",da,lp,line_start);
+  for(p=copyright;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+  emit(f,"\t%s\t0\n",dwarfd1);
+  emit(f,"\t%s\t%d\n",dwarfd1,DW_ID_case_sensitive);
+  for(p=inname?inname:"<multiple>";*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+  emit(f,"\t%s\t0\n",dwarfd1);
+}
+static void dwarf2_cleanup(FILE *f)
+{
+  int i,line,file,label,length;char *p;
+  tdwarf2_line_info *li,*m;
+  Var *vl;
+  struct_declaration *sd;
+  emit(f,"\t%s\t\".debug_line\"\n",dsec);
+  /* line info */
+  emit(f,"%s%d:\n",lp,line_start);
+  emit(f,"\t%s\t%s%d-%s%d-4\n",dwarfd4,lp,line_end,lp,line_start); /* length */
+  emit(f,"\t%s\t2\n",dwarfd2); /* version */
+  length=16;
+  for(i=0;i<namecount;i++) length+=strlen(names[i])+4;
+  emit(f,"\t%s\t%d\n",dwarfd4,length); /* prologue length */
+  emit(f,"\t%s\t1\n",dwarfd1); /* instruction_length */
+  emit(f,"\t%s\t1\n",dwarfd1); /* is_stmt */
+  emit(f,"\t%s\t-10\n",dwarfd1); /* line_base */
+  emit(f,"\t%s\t245\n",dwarfd1); /* line_range */
+  emit(f,"\t%s\t10\n",dwarfd1); /* opcode_base */
+  emit(f,"\t%s\t0\n",dwarfd1); /* standard opcode arguments */
+  emit(f,"\t%s\t1\n",dwarfd1);
+  emit(f,"\t%s\t1\n",dwarfd1);
+  emit(f,"\t%s\t1\n",dwarfd1);
+  emit(f,"\t%s\t1\n",dwarfd1);
+  emit(f,"\t%s\t0\n",dwarfd1);
+  emit(f,"\t%s\t0\n",dwarfd1);
+  emit(f,"\t%s\t0\n",dwarfd1);
+  emit(f,"\t%s\t1\n",dwarfd1);
+  emit(f,"\t%s\t0\n",dwarfd1); /* include directories */
+  for(i=0;i<namecount;i++){
+    for(p=names[i];*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+    emit(f,"\t%s\t0\n",dwarfd1);
+    emit(f,"\t%s\t0\n",dwarfd1);
+    emit(f,"\t%s\t0\n",dwarfd1);
+    emit(f,"\t%s\t0\n",dwarfd1);
+  }
+  emit(f,"\t%s\t0\n",dwarfd1); /* file names */  
+  
+  file=-1;line=1;label=-1;
+  li=dwarf2_first_li;
+  while(li){
+    m=li->next;
+    if(li->file!=file){
+      file=li->file;
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_LNS_set_file);
+      dwarf2_print_uleb128(f,ul2zum((long)file));
+    }
+    if(!li->id&&li->label!=label){
+      label=li->label;
+      emit(f,"\t%s\t0\n",dwarfd1); /* extended opcode */
+      emit(f,"\t%s\t%d\n",dwarfd1,1+sizeof_addr); /* length */
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_LNE_set_address);
+      emit(f,"\t%s\t%s%d\n",da,lp,label);      
+    }
+    if(li->id){
+      emit(f,"\t%s\t0\n",dwarfd1); /* extended opcode */
+      emit(f,"\t%s\t%d\n",dwarfd1,1+sizeof_addr); /* length */
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_LNE_set_address);
+      emit(f,"\t%s\t%s%s\n",da,ip,li->id);
+      free(li->id);
+    }      
+    if(li->line!=line){
+      emit(f,"\t%s\t%d\n",dwarfd1,DW_LNS_advance_line);
+      dwarf2_print_sleb128(f,l2zm((long)(li->line-line)));
+      line=li->line;
+    }
+    emit(f,"\t%s\t%d\n",dwarfd1,DW_LNS_copy);
+    free(li);
+    li=m;
+  }
+  emit(f,"\t%s\t0,1,1\n",dwarfd1); /* end_sequence */
+  emit(f,"%s%d:\n",lp,line_end);
+  emit(f,"\t%s\t\".debug_info\"\n",dsec);
+  for(sd=first_sd[0];sd;sd=sd->next){
+    if(sd->identifier){
+      static type styp;
+      styp.flags=sd->typ;
+      styp.exact=sd;
+      sd->label=0;
+      dwarf2_type(f,&styp);
+    }
+  }
+  for(vl=first_var[0];vl;vl=vl->next)
+    dwarf2_var(f,vl);
+  for(vl=first_ext;vl;vl=vl->next)
+    dwarf2_var(f,vl);
+  emit(f,"\t%s\t0\n",dwarfd1);
+  emit(f,"%s%d:\n",lp,info_end);
+  for(i=0;i<namecount;i++) free(names[i]);
+  free(names);
+}
+/* generate line info for IC p, return 0 if nothing had to be generated */
+static void dwarf2_line_info(FILE *f,IC *p)
+{
+  static int line,file,n;
+  tdwarf2_line_info *new;
+  if(!f) return;
+  if(p->line==0) return;
+  if(!p->file) ierror(0);
+  n=dwarf2_file(p->file);
+  if(n!=file||p->line!=line){
+    file=n;
+    line=p->line;
+    emit(f,"%s%d:\n",lp,++label);
+    dwarf2_add_line(file,line,label,0);
+  }
+}
+
+static void dwarf2_function(FILE *f,Var *v,int endlabel)
+{
+  char *p;int l;Var *vl;
+  struct struct_identifier *si;
+  /* subprogram */
+  if(!f) return;
+  emit(f,"\t%s\t\".debug_info\"\n",dsec);
+  if(!v->vtyp||!v->vtyp->next) ierror(0);
+  if((v->vtyp->next->flags&NQ)==VOID){
+    dwarf2_print_uleb128(f,ul2zum(SUBPROGRAMVOID));
+  }else{
+    l=dwarf2_type(f,v->vtyp->next);
+    dwarf2_print_uleb128(f,ul2zum(SUBPROGRAM));
+  }
+  for(p=ip;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+  for(p=v->identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+  emit(f,"\t%s\t0\n",dwarfd1);
+  if(v->storage_class==EXTERN){
+    emit(f,"\t%s\t%s%s\n",da,ip,v->identifier);
+  }else{
+    emit(f,"\t%s\t%s%ld\n",da,lp,zm2l(v->offset));    
+  }
+  emit(f,"\t%s\t%s%d\n",da,lp,endlabel);
+  if((v->vtyp->next->flags&NQ)!=VOID)
+    emit(f,"\t%s\t%s%d\n",da,lp,l);
+  if(!v->dfilename||v->dline<=0) ierror(0);
+  emit(f,"\t%s\t%d\n",dwarfd1,(v->storage_class==EXTERN));
+  if(v->storage_class==EXTERN)
+    dwarf2_add_line(dwarf2_file(v->dfilename),v->dline,0,v->identifier);
+  else
+    dwarf2_add_line(dwarf2_file(v->dfilename),v->dline,(int)zm2l(v->offset),0);
+  dwarf2_print_uleb128(f,ul2zum((long)dwarf2_file(v->dfilename)));
+  dwarf2_print_uleb128(f,ul2zum((long)v->dline));
+#if HAVE_LOCATION_LISTS
+  emit(f,"\t%s\t\".debug_loc\"\n",dsec);
+  emit(f,"%s%d:\n",lp,++label);
+  emit(f,"\t%s\t0\n",da);
+  emit(f,"\t%s\t-1\n",da); 
+  dwarf2_print_frame_location(f,v);
+  emit(f,"\t%s\t0\n",da);
+  emit(f,"\t%s\t0\n",da);   
+  emit(f,"\t%s\t\".debug_info\"\n",dsec);
+  emit(f,"\t%s\t%s%d\n",da,lp,label);
+#else
+  dwarf2_print_frame_location(f,v);
+#endif
+
+  /* children */
+
+  /*FIXME: not nice */
+  if(cross_module){
+    if(!v->fi) ierror(0);
+    for(vl=v->fi->vars;vl;vl=vl->next)
+      dwarf2_var(f,vl);
+  }else{
+    for(vl=first_var[1];vl;vl=vl->next)
+      dwarf2_var(f,vl);
+    for(vl=merk_varf;vl;vl=vl->next)
+      dwarf2_var(f,vl);
+  }
+  
+  
+  emit(f,"\t%s\t0\n",dwarfd1);
+}
diff --git a/errors.h b/errors.h
new file mode 100644
index 0000000..5d1b4e0
--- /dev/null
+++ b/errors.h
@@ -0,0 +1,374 @@
+/*  $VER: vbcc (errors.h) V0.8  */
+
+"declaration expected",ERROR|ANSIV|FATAL,                           /*  0   */
+"only one input file allowed",ERROR|NOLINE|FATAL,                   /*  1   */
+"Flag <%s> specified more than once",NOLINE|WARNING,                /*  2   */
+"Flag <%s> needs string",NOLINE|FATAL|ERROR,                        /*  3   */
+"Flag <%s> needs value",NOLINE|FATAL|ERROR,                         /*  4   */
+"Unknown Flag <%s>",NOLINE|FATAL|ERROR,                             /*  5   */
+"No input file",ERROR|NOLINE|FATAL,                                 /*  6   */
+"Could not open <%s> for input",NOLINE|FATAL|ERROR,                 /*  7   */
+"need a struct or union to get a member",ERROR|ANSIV,
+"too many (%d) nested blocks",ERROR|FATAL,
+"left block 0",ERROR|ANSIV,                                         /*  10  */
+"incomplete struct",ERROR|ANSIV,
+"out of memory",ERROR|FATAL,
+"redeclaration of struct <%s>",ERROR|ANSIV,
+"incomplete type (%s) in struct",ERROR|ANSIV,
+"function (%s) in struct/union",ERROR|ANSIV,                        /*  15  */
+"redeclaration of struct/union member <%s>",ERROR|ANSIV,
+"redeclaration of <%s>",ERROR|ANSIV,
+"invalid constant expression",ERROR|ANSIV,
+"array dimension must be constant integer",ERROR|ANSIV,
+"no declarator and no identifier in prototype",ERROR|ANSIV|FATAL,         /*  20  */
+"invalid storage-class in prototype",ERROR|ANSIV,
+"void not the only function argument",ERROR|ANSIV,
+"<%s> no member of struct/union",ERROR|ANSIV,
+"increment/decrement is only allowed for aithmetic and pointer types",ERROR|ANSIV,
+"functions may not return arrays or functions",ERROR|ANSIV,         /*  25  */
+"only pointers to functions can be called",ERROR|ANSIV,
+"redefinition of var <%s>",ERROR|ANSIV,
+"redeclaration of var <%s> with new storage-class",ERROR|ANSIV,
+"first operand of conditional-expression must be arithmetic or pointer type",ERROR|ANSIV,
+"multiple definitions of var <%s>",ERROR|ANSIV,                     /*  30  */
+"operands of : do not match",ERROR|ANSIV,
+"function definition in inner block",ERROR|ANSIV,
+"redefinition of function <%s>",ERROR|ANSIV,
+"invalid storage-class for function",ERROR|ANSIV,
+"declaration-specifiers expected",ERROR|ANSIV,                      /*  35  */
+"declarator expected",ERROR|ANSIV,
+"<%s> is no parameter",ERROR|ANSIV,
+"assignment of different structs/unions",ERROR|ANSIV,
+"invalid types for assignment",ERROR|ANSIV,
+"only 0 can be compared against pointer",WARNING|ANSIV,             /*  40  */
+"pointers do not point to the same type",WARNING|ANSIV,
+"function initialized",ERROR|ANSIV|FATAL,
+"initialization of incomplete struct",ERROR|FATAL|ANSIV,
+"initialization of incomplete union",ERROR|FATAL|ANSIV,
+"empty initialization",ERROR|ANSIV,                                 /*  45  */
+"initializer not a constant",ERROR|ANSIV,
+"double type-specifier",WARNING|ANSIV,
+"illegal type-specifier",WARNING|ANSIV,
+"multiple storage-classes",WARNING|ANSIV,
+"storage-class specifier should be first",WARNING|ANSIV,            /*  50  */
+"bitfield type non-portable",WARNING,
+"bitfield width must be constant integer",WARNING|ANSIV,
+"struct/union member needs identifier",WARNING|ANSIV,
+"; expected",WARNING|ANSIV,
+"struct/union has no members",WARNING|ANSIV,                        /*  55  */
+"} expected",WARNING|ANSIV,
+", expected",WARNING|ANSIV,
+"invalid type-qualifier",WARNING|ANSIV,
+") expected",WARNING|ANSIV,
+"array dimension has sidefx (will be ignored)",WARNING|ANSIV,       /*  60  */
+"array of size <=0 (set to 1)",WARNING|ANSIV,
+"] expected",WARNING|ANSIV,
+"mixed identifier- and parameter-type-list",WARNING|ANSIV,
+"var <%s> was never assigned a value",WARNING|DONTWARN|INFUNC,
+"var <%s> was never used",WARNING|DONTWARN|INFUNC,                  /*  65  */
+"invalid storage-class",WARNING|ANSIV,
+"type defaults to int",WARNING|DONTWARN,
+"redeclaration of var <%s> with new type",WARNING|ANSIV,
+"redeclaration of parameter <%s>",WARNING|ANSIV,
+": expected",WARNING|ANSIV,                                         /*  70  */
+"illegal escape-sequence in string",WARNING|ANSIV,
+"character constant contains multiple chars",WARNING,
+"could not evaluate sizeof-expression",ERROR|ANSIV,
+"\" expected",ERROR|ANSIV,
+"something wrong with numeric constant",ERROR|ANSIV,                /*  75  */
+"identifier expected",ERROR|ANSIV|FATAL,
+"definition does not match previous declaration",WARNING|ANSIV,
+"integer added to illegal pointer",WARNING|ANSIV,
+"offset equals size of object",WARNING|DONTWARN,
+"offset out of object",WARNING|ANSIV,                               /*  80  */
+"only 0 should be cast to pointer",WARNING|DONTWARN,
+"unknown identifier <%s>",ERROR|ANSIV,
+"too few function arguments",WARNING|ANSIV,
+"division by zero (result set to 0)",WARNING|ANSIV,
+"assignment of different pointers",WARNING|ANSIV,                   /*  85  */
+"lvalue required for assignment",ERROR|ANSIV,
+"assignment to constant type",ERROR|ANSIV,
+"assignment to incomplete type",ERROR|ANSIV,
+"operands for || and && have to be arithmetic or pointer",ERROR|ANSIV,
+"bitwise operations need integer operands",ERROR|ANSIV,             /*  90  */
+"assignment discards const",WARNING|ANSIV,
+"relational expression needs arithmetic or pointer type",ERROR|ANSIV,
+"both operands of comparison must be pointers",ERROR|ANSIV,
+"operand needs arithmetic type",ERROR|ANSIV,
+"pointer arithmetic with void * is not possible",ERROR|ANSIV,       /*  95  */
+"pointers can only be subtracted",ERROR|ANSIV,
+"invalid types for operation <%s>",ERROR|ANSIV,
+"invalid operand type",ERROR|ANSIV,
+"integer-pointer is not allowed",ERROR|ANSIV,
+"assignment discards volatile",WARNING|ANSIV,                       /*  100 */
+"<<, >> and %% need integer operands",ERROR|ANSIV,
+"casting from void is not allowed",ERROR|ANSIV,
+"integer too large to fit into pointer",WARNING,
+"only integers can be cast to pointers",ERROR|ANSIV,
+"invalid cast",ERROR|ANSIV,                                         /*  105 */
+"pointer too large to fit into integer",WARNING|ANSIV,
+"unary operator needs arithmetic type",ERROR|ANSIV,
+"negation type must be arithmetic or pointer",ERROR|ANSIV,
+"complement operator needs integer type",ERROR|ANSIV,
+"pointer assignment with different qualifiers",WARNING|ANSIV,       /*  110 */
+"dereferenced object is no pointer",ERROR|ANSIV,
+"dereferenced object is incomplete",ERROR|ANSIV,
+"only 0 should be assigned to pointer",WARNING|ANSIV,
+"typedef <%s> is initialized",WARNING|ANSIV,
+"lvalue required to take address",ERROR|ANSIV,                      /*  115 */
+"unknown var <%s>",ERROR|ANSIV,
+"address of register variables not available",ERROR|ANSIV,
+"var <%s> initialized after \'extern\'",WARNING,
+"const var <%s> not initialized",WARNING,
+"function definition after \'extern\'",WARNING|ANSIV,               /*  120 */
+"return type of main is not int",WARNING|ANSIV,
+"invalid storage-class for function parameter",WARNING|ANSIV,
+"formal parameters conflict with parameter-type-list",WARNING|ANSIV,
+"parameter type defaults to int",WARNING|DONTWARN,
+"no declaration-specifier, used int",WARNING|ANSIV,                 /*  125 */
+"no declarator in prototype",WARNING|ANSIV,
+"static var <%s> never defined",WARNING,
+"} expected",WARNING,
+"left operand of comma operator has no side-effects",WARNING,
+"label empty",ERROR|ANSIV,                                          /*  130 */
+"redefinition of label <%s>",ERROR|ANSIV,
+"case without switch",ERROR|ANSIV,
+"case-expression must be constant",ERROR|ANSIV,
+"case-expression must be integer",ERROR|ANSIV,
+"empty if-expression",ERROR|ANSIV,                                  /*  135 */
+"if-expression must be arithmetic or pointer",ERROR|ANSIV,
+"empty switch-expression",ERROR|ANSIV,
+"switch-expression must be integer",ERROR|ANSIV,
+"multiple default labels",ERROR|ANSIV,
+"while-expression must be arithmetic or pointer",ERROR|ANSIV,       /*  140 */
+"empty while-expression",ERROR|ANSIV,
+"for-expression must be arithmetic or pointer",ERROR|ANSIV,
+"do-while--expression must be arithmetic or pointer",ERROR|ANSIV,
+"goto without label",ERROR|ANSIV,
+"continue not within loop",ERROR|ANSIV,                             /*  145 */
+"break not in matching construct",ERROR|ANSIV,
+"label <%s> was never defined",ERROR|ANSIV|INFUNC|NORAUS,
+"label <%s> was never used",WARNING|INFUNC,
+"register %s not ok",WARNING,
+"default not in switch",WARNING|ANSIV,                              /*  150 */
+"( expected",WARNING|ANSIV,
+"loop eliminated",WARNING,
+"statement has no effect",WARNING,
+"\'while\' expected",WARNING|ANSIV,
+"function should not return a value",WARNING|ANSIV,                 /*  155 */
+"function should return a value",WARNING,
+"{ expected",WARNING|ANSIV,
+"internal error %d in line %d of file %s !!",ERROR|INTERNAL|FATAL,
+"there is no message number %d",NOLINE|FATAL|ERROR,
+"message number %d cannot be suppressed",ERROR|NOLINE|FATAL,        /*  160 */
+"implicit declaration of function <%s>",WARNING|DONTWARN,
+"function call without prototype in scope",WARNING|DONTWARN,
+"#pragma used",WARNING|DONTWARN,
+"assignment in comparison context",WARNING|DONTWARN,
+"comparison redundant because operand is unsigned",WARNING,         /*  165 */
+"cast to narrow type may cause loss of precision",WARNING|DONTWARN,
+"pointer cast may cause alignment problems",WARNING|DONTWARN,
+"no declaration of global variable <%s> before definition",WARNING|DONTWARN,
+"'extern' inside function",WARNING|DONTWARN,
+"dead assignment to <%s%s> eliminated",WARNING|INFUNC|INIC|DONTWARN,/*  170 */
+"var <%s> is used before defined",WARNING|INFUNC,
+"would need more than %ld optimizer passes for best results",WARNING|INFUNC,
+"function <%s> has no return statement",WARNING|INFUNC,
+"function <%s> has no return statement",WARNING|DONTWARN|INFUNC,
+"this code is weird",WARNING|INFUNC,                                /*  175 */
+"size of incomplete type not available",WARNING|ANSIV,
+"line too long",FATAL|ERROR|ANSIV|PREPROC,
+"identifier must begin with a letter or underscore",FATAL|ERROR|ANSIV|PREPROC,
+"cannot redefine macro",ERROR|ANSIV|PREPROC,
+"missing ) after argumentlist",ERROR|ANSIV|PREPROC,                 /*  180 */
+"identifier expected",ERROR|ANSIV|PREPROC,
+"illegal character in identifier",ERROR|ANSIV|PREPROC,
+"missing operand before/after ##",ERROR|ANSIV|PREPROC,
+"no macro-argument after #-operator",ERROR|ANSIV|PREPROC,
+"macro redefinition not allowed",ERROR|ANSIV|PREPROC,               /*  185 */
+"unexpected end of file (unterminated comment)",FATAL|ERROR|PREPROC,
+"too many nested includes",FATAL|ERROR|PREPROC,
+"#else without #if/#ifdef/#ifndef",FATAL|ERROR|ANSIV|PREPROC,
+"#else after #else",ERROR|ANSIV|PREPROC,
+"#endif without #if",ERROR|ANSIV|PREPROC,                           /*  190 */
+"cannot include file",FATAL|ERROR|PREPROC,
+"expected \" or < in #include-directive",ERROR|ANSIV|PREPROC,
+"unknown #-directive",WARNING|PREPROC,
+"wrong number of macro arguments",ERROR|ANSIV|PREPROC,
+"macro argument expected",ERROR|ANSIV|PREPROC,                      /*  195 */
+"out of memory",FATAL|ERROR|PREPROC,
+"macro redefinition",WARNING|PREPROC,
+"/* in comment",WARNING|PREPROC,
+"cannot undefine macro",ERROR|ANSIV|PREPROC,
+"characters after #-directive ignored",WARNING|PREPROC,             /*  200 */
+"duplicate case labels",WARNING|ANSIV,
+"var <%s> is incomplete",WARNING|ANSIV,
+"long float is no longer valid",WARNING|ANSIV,
+"long double is not really supported by vbcc",WARNING,
+"empty struct-declarations are not yet handled correct",WARNING,    /*  205 */
+"identifier too long (only %d characters are significant)",WARNING,
+"illegal initialization of var <%s>",WARNING|ANSIV,
+"suspicious loop",WARNING|INFUNC,
+"ansi/iso-mode turned on",NOLINE|WARNING,
+"division by zero (result set to 0)",WARNING|ANSIV|INFUNC|INIC,     /*  210 */
+"constant out of range",WARNING|ANSIV,
+"constant is unsigned due to size",WARNING|DONTWARN,
+"varargs function called without prototype in scope",WARNING,
+"suspicious format string",WARNING,
+"format string contains \'\\0\'",WARNING,                           /*  215 */
+"illegal use of keyword <%s>",WARNING|ANSIV,
+"register <%s> used with wrong type",ERROR,
+"register <%s> is not free",ERROR,
+"'__reg' used in old-style function definition",WARNING,
+"unknown register \"%s\"",WARNING,                                  /*  220 */
+"'...' only allowed with prototypes",WARNING|ANSIV,
+"Hey, do you really know the priority of '&&' vs. '||'?",WARNING|DONTWARN,
+"be careful with priorities of <</>> vs. +/-",WARNING,
+"address of auto variable returned",WARNING,
+"void function returns a void expression",WARNING,                  /*  225 */
+"redeclaration of typedef <%s>",WARNING|ANSIV,
+"multiple specification of attribute \"%s\"",WARNING,
+"redeclaration of var \"%s\" with differing setting of attribute \"%s\"",WARNING,
+"string-constant expected",ERROR,
+"tag \"%s\" used for wrong type",WARNING|ANSIV,                     /*  230 */
+"member after flexible array member",ERROR|ANSIV,
+"illegal number",ERROR|ANSIV,
+"void character constant",PREPROC|ERROR|ANSIV,
+"spurious tail in octal character constant",PREPROC|ERROR|ANSIV,
+"spurious tail in hexadecimal character constant",PREPROC|ERROR|ANSIV,  /* 235 */
+"illegal escape sequence in character constant",PREPROC|ERROR|ANSIV,
+"invalid constant integer value",PREPROC|ERROR|ANSIV,
+"a right parenthesis was expected",PREPROC|ERROR|ANSIV,
+"a colon was expected",PREPROC|ERROR|ANSIV,
+"truncated constant integral expression",PREPROC|ERROR|ANSIV,       /*  240 */
+"rogue operator '%s' in constant integral expression",PREPROC|ERROR|ANSIV,
+"invalid token in constant integral expression",PREPROC|ERROR|ANSIV,
+"trailing garbage in constant integral expression",PREPROC|ERROR|ANSIV,
+"void condition for a #if/#elif",PREPROC|ERROR|ANSIV,
+"void condition (after expansion) for a #if/#elif",PREPROC|ERROR|ANSIV, /*  245 */
+"invalid '#include'",PREPROC|ERROR|ANSIV,
+"macro expansion did not produce a valid filename for #include",PREPROC|ERROR|ANSIV,
+"file '%s' not found",PREPROC|ERROR|ANSIV,
+"not a valid number for #line",PREPROC|ERROR|ANSIV,
+"not a valid filename for #line",PREPROC|ERROR|ANSIV,               /*  250 */
+"rogue '#'",PREPROC|ERROR|ANSIV,
+"rogue #else",PREPROC|ERROR|ANSIV,
+"rogue #elif",PREPROC|ERROR|ANSIV,
+"unmatched #endif",PREPROC|ERROR|ANSIV,
+"unknown cpp directive '#%s'",PREPROC|WARNING|ANSIV,                /*  255 */
+"unterminated #if construction",PREPROC|ERROR|ANSIV,
+"could not flush output (disk full ?)",PREPROC|ERROR|ANSIV,
+"truncated token",PREPROC|ERROR|ANSIV,
+"illegal character '%c'",PREPROC|ERROR|ANSIV,
+"unfinished string at end of line",PREPROC|ERROR|ANSIV,             /*  260 */
+"missing macro name",PREPROC|ERROR|ANSIV,
+"trying to redefine the special macro %s",PREPROC|ERROR|ANSIV,
+"truncated macro definition",PREPROC|ERROR|ANSIV,
+"'...' must end the macro argument list",PREPROC|ERROR|ANSIV,
+"void macro argument",PREPROC|ERROR|ANSIV,                          /*  265 */
+"missing comma in macro argument list",PREPROC|ERROR|ANSIV,
+"invalid macro argument",PREPROC|ERROR|ANSIV,
+"duplicate macro argument",PREPROC|ERROR|ANSIV,
+"'__VA_ARGS__' is forbidden in macros with a fixed number of arguments",PREPROC|ERROR|ANSIV,
+"operator '##' may neither begin nor end a macro",PREPROC|ERROR|ANSIV,  /*  270 */
+"operator '#' not followed by a macro argument",PREPROC|ERROR|ANSIV,
+"macro '%s' redefined unidentically",PREPROC|ERROR|ANSIV,
+"not enough arguments to macro",PREPROC|ERROR|ANSIV,
+"unfinished macro call",PREPROC|ERROR|ANSIV,
+"too many arguments to macro",PREPROC|ERROR|ANSIV,                   /*  275 */
+"operator '##' produced the invalid token '%s%s'",PREPROC|ERROR|ANSIV,
+"quad sharp",PREPROC|ERROR|ANSIV,
+"void macro name",PREPROC|ERROR|ANSIV,
+"macro %s already defined",PREPROC|ERROR|ANSIV,
+"trying to undef special macro %s",PREPROC|ERROR|ANSIV,             /*  280 */
+"illegal macro name for #ifdef",PREPROC|ERROR|ANSIV,
+"unfinished #ifdef",PREPROC|ERROR|ANSIV,
+"illegal macro name for #undef",PREPROC|ERROR|ANSIV,
+"unfinished #undef",PREPROC|ERROR|ANSIV,
+"illegal macro name for #ifndef",PREPROC|ERROR|ANSIV,               /*  285 */
+"unfinished #ifndef",PREPROC|ERROR|ANSIV,
+"reconstruction of <foo> in #include",PREPROC|WARNING|DONTWARN,
+"comment in the middle of a cpp directive",PREPROC|WARNING|DONTWARN,
+"null cpp directive",PREPROC|WARNING|DONTWARN,
+"rogue '#' in code compiled out",PREPROC|WARNING,                   /*  290 */
+"rogue '#' dumped",PREPROC|WARNING|DONTWARN,
+"#error%s",PREPROC|ANSIV|ERROR,
+"trigraph ?""?%c encountered",PREPROC|WARNING,
+"unterminated #if construction (depth %ld)",PREPROC|ERROR|ANSIV,
+"malformed identifier with UCN: '%s'",PREPROC|WARNING|ANSIV,        /*  295 */
+"truncated UTF-8 character",PREPROC|WARNING|ANSIV,
+"identifier not followed by whitespace in #define",PREPROC|WARNING|ANSIV,
+"assignment discards restrict",WARNING|ANSIV,                      
+"storage-class in declaration within for() converted to auto",WARNING|ANSIV,
+"corrupted special object",ANSIV|FATAL,                             /*  300 */
+"<inline> only allowed in function declarations",ERROR|ANSIV,
+"reference to static variable <%s> in inline function with external linkage",ERROR|ANSIV,
+"underflow of pragma popwarn",ERROR|FATAL|ANSIV,
+"invalid argument to _Pragma",ERROR|ANSIV|PREPROC,
+"missing comma before '...'",ERROR|ANSIV|PREPROC,                   /*  305 */
+"padding bytes behind member <%s>",WARNING|DONTWARN,
+"member <%s> does not have natural alignment",WARNING|DONTWARN,
+"function <%s> exceeds %s limit",WARNING,
+"%s could not be calculated for function <%s>",WARNING,
+"offsetof applied to non-struct",ERROR|ANSIV,                       /*  310 */
+"trailing garbage in #ifdef",WARNING|ANSIV|PREPROC,
+"too many arguments to macro",WARNING|ANSIV|PREPROC,
+"truncated comment",WARNING|ANSIV|PREPROC,
+"trailing garbage in preprocessing directive",WARNING|ANSIV|PREPROC,
+"variable-length array must have auto storage-class",ERROR|ANSIV,  /*  315 */
+"member <%s> has type with zero alignment/size (probably void)",ERROR|ANSIV|FATAL,
+"stack information for target <%s> unavailable",WARNING|INIC|DONTWARN,
+"used registers information unavailable for target <%s>",WARNING|INIC|DONTWARN,
+"computed %sstack usage %d but set to %d",WARNING|INFUNC,
+"unable to compute call targets",WARNING|INIC|DONTWARN,            /*  320 */
+"computed register usage differs from specified one",WARNING|INFUNC,
+"trailing garbage in #include",WARNING|ANSIV|PREPROC,
+"target-warning: %s",WARNING,
+"target-error: %s",ERROR|FATAL,
+"#warning%s",WARNING|PREPROC|ANSIV,                                /*  325 */
+"trailing garbage in #undef",WARNING|PREPROC|ANSIV,
+"Flag <%s>: syntax error",FATAL|ERROR|NOLINE,
+"Wrong MISRA version (%d) specified for flag %s%s",FATAL|ERROR|NOLINE,
+"No such MISRA 1998 Rule (%d) in flag %s%s",FATAL|ERROR|NOLINE,
+"No such MISRA 2004 Rule(%d.%d) in flag %s%s",FATAL|ERROR|NOLINE,  /*  330 */
+"unknown register <%s>",FATAL|ERROR|NOLINE,
+"illegal bitfield size",ERROR|ANSIV,
+"Flag <%s> conflicts with flag <%s>",FATAL|ERROR|NOLINE,
+"vbcc was not compiled with <%s> support",FATAL|ERROR|NOLINE,
+"{ expected",ERROR|ANSIV,                                          /*  335 */
+"base class <%s> has incomplete type",ERROR|ANSIV,
+"unknown class/struct <%s>",ERROR|ANSIV,
+"<%s> declared as a virtual field",ERROR|ANSIV,
+"<virtual> only allowed at method declarations",ERROR|ANSIV,
+"no such member function declared",ERROR|ANSIV,                    /* 340 */
+":: unexpected",ERROR|ANSIV,
+"polymorphic type <%s> must be initialized by constructor",ERROR|ANSIV,
+"unknown language in linkage specification <%s>",ERROR|ANSIV,
+"multiple initializations for <%s>",ERROR|ANSIV,
+"too many arguments for <%s>",ERROR|ANSIV,                         /* 345 */
+"no fitting overloaded function found",ERROR|ANSIV,
+"call of overloaded function <%s> is ambiguous",ERROR|ANSIV,
+"member differs from previous declaration",ERROR|ANSIV,
+"member not previously declared",ERROR|ANSIV,
+"access is %s",ERROR|ANSIV,                                        /* 350 */
+"jump into scope of variable-length-array",ERROR|ANSIV|INIC|FATAL,
+"variable-length-array (%s) in struct/union",ERROR|ANSIV,
+"encountered non-existent label during optimizing",ERROR|ANSIV|INFUNC|FATAL,
+"array designator not in valid range",ERROR|ANSIV,
+"'=' expected",ERROR|ANSIV,                                        /* 355 */
+"type has non-empty identifier",WARNING|ANSIV,
+"unterminated // comment",PREPROC|WARNING|ANSIV,
+"initialization of variable-length array",ERROR|ANSIV,
+"initialization of flexible array member",ERROR|ANSIV,
+"empty initializer",ERROR|FATAL|ANSIV,                             /* 360 */
+"redeclaration of var <%s> as new function",ERROR|FATAL|ANSIV,
+"constant implicitly sign-changed",WARNING|DONTWARN,
+"constant implicitly truncated",WARNING,
+"hexadecimal escape sequence overflow",WARNING,
+"missing identifier",ERROR|FATAL|ANSIV,                            /* 365 */
+"negative shift count is undefined",WARNING,
+"shift count too large for data type",WARNING,
+"redeclaration of function argument with different register",WARNING,
+"declaration expected",WARNING|ANSIV,
+"possible redeclaration of var <%s> with different attributes <%s> and <%s>",WARNING, /* 370 */
+"redeclaration of var <%s> with new attribute <%s>",WARNING,
diff --git a/flow.c b/flow.c
new file mode 100644
index 0000000..5be1c0c
--- /dev/null
+++ b/flow.c
@@ -0,0 +1,609 @@
+/*  $VER: vbcc (flow.c) $Revision: 1.13 $    */
+/*  Generierung des FLussgraphs und Optimierungen des Kontrollflusses   */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+int bvcmp(bvtype *dest,bvtype *src,size_t len)
+/*  vergleicht zwei Bitvektoren    */
+{
+  len/=sizeof(bvtype);
+  for(;len>0;len--)
+    if(*dest++!=*src++) return(0);
+  return(1);
+}
+/* Schnittmenge nicht leer? */
+int bvdointersect(bvtype *p1,bvtype *p2,size_t len)
+{
+  len/=sizeof(bvtype);
+  for(;len>0;len--)
+    if(*p1++&*p2++)
+      return 1;
+  return 0;
+}
+void bvunite(bvtype *dest,bvtype *src,size_t len)
+/*  berechnet Vereinigung zweier Bitvektoren    */
+{
+  len/=sizeof(bvtype);
+  for(;len>0;len--)
+    *dest++|=*src++;
+}
+void bvintersect(bvtype *dest,bvtype *src,size_t len)
+/*  berechnet Durchschnitt zweier Bitvektoren   */
+{
+  len/=sizeof(bvtype);
+  for(;len>0;len--)
+    *dest++&=*src++;
+}
+void bvdiff(bvtype *dest,bvtype *src,size_t len)
+/*  berechnet 'Differenz' zweier Bitvektoren    */
+{
+  len/=sizeof(bvtype);
+  for(;len>0;len--)
+    *dest++&=~(*src++);
+}
+
+unsigned int basic_blocks;
+
+flowgraph *new_flowgraph(void)
+{
+  flowgraph *new;
+  new=mymalloc(sizeof(*new));
+  new->av_in=new->av_out=new->av_gen=new->av_kill=0;
+  new->rd_in=new->rd_out=new->rd_gen=new->rd_kill=0;
+  new->ae_in=new->ae_out=new->ae_gen=new->ae_kill=0;
+  new->cp_in=new->cp_out=new->cp_gen=new->cp_kill=0;
+  new->pt=0;  
+  new->start=new->end=0;
+  new->normalout=new->branchout=0;
+  new->in=0;
+  new->loopend=0;
+#if ALEX_REG
+  new->loop_depth=0;
+#endif
+  return new;
+}
+
+flowgraph *construct_flowgraph(void)
+/*  entfernt ueberfluessige Labels und erzeugt Flussgraph   */
+{
+    IC *p,*cl;
+    int firstl,lcnt,currentl,i,code,l;
+    int *iseq,*used;
+    flowgraph **lg,*g,*fg;
+    if(cross_module){
+      int lastl;
+      firstl=0;lastl=0;lcnt=0;
+      for(p=first_ic;p;p=p->next){
+	if(p->code==LABEL){
+	  if(p->typf<firstl) firstl=p->typf;
+	  if(p->typf>lastl) lastl=p->typf;
+	}
+      }
+      lcnt=lastl-firstl+1;
+    }else{
+      firstl=lastlabel;
+      lcnt=label-firstl;
+    }
+    return_label=0;
+    if(last_ic&&last_ic->code==LABEL) return_label=last_ic->typf;
+    if(last_ic&&last_ic->code==SETRETURN&&last_ic->prev&&last_ic->prev->code==LABEL) return_label=last_ic->prev->typf;
+
+    iseq=mymalloc(lcnt*sizeof(int));
+    used=mymalloc(lcnt*sizeof(int));
+    lg=mymalloc(lcnt*sizeof(flowgraph *));
+    g=new_flowgraph();
+    fg=g;
+    g->start=first_ic;g->in=0;g->branchout=0;g->loopend=0;
+
+    for(i=0;i<lcnt;i++) {iseq[i]=used[i]=0;lg[i]=0;}
+    currentl=0;firstl++;
+    /*  Diese Schleife entfernt alle Labels, die mit anderen    */
+    /*  uebereinstimmen, merkt sich das und kennzeichnet alle   */
+    /*  Labels, die benutzt werden.                             */
+    /*  Ausserdem wird der Flussgraph teilweise aufgebaut.      */
+    if(DEBUG&1024) {puts("construct_flowgraph(): loop1");/*scanf("%d",&i);*/}
+    i=1;g->index=i;
+    for(p=first_ic;p;){
+        code=p->code;
+        if(code>=BEQ&&code<=BRA){
+            l=p->typf;
+            /*  als used markieren; falls aequivalent, das erste markieren  */
+            if(iseq[l-firstl]) used[iseq[l-firstl]-firstl]=1;
+                else           used[l-firstl]=1;
+            /*  Flussgraph beenden und evtl. naechsten Knoten erzeugen  */
+            g->end=p;
+            if(p->next){
+	      g->normalout=new_flowgraph();
+	      g->normalout->in=mymalloc(sizeof(flowlist));
+	      g->normalout->in->next=0;
+	      g->normalout->in->graph=g;
+	      g=g->normalout;
+	      g->start=p->next;
+	      g->branchout=0;
+	      g->loopend=0;
+	      g->index=++i;
+            }else g->normalout=0;
+
+            currentl=0;p=p->next;continue;
+        }
+        if(code==ALLOCREG||code==FREEREG){p=p->next; continue;}
+        if(code!=LABEL){currentl=0;p=p->next;continue;}
+        /*  ist ein Label   */
+        l=p->typf;
+        if(currentl){
+	    IC *m;
+            iseq[l-firstl]=currentl;
+	    if(l==return_label) return_label=currentl;
+            if(used[l-firstl]) used[currentl-firstl]=1;
+	    cl->flags|=p->flags;
+	    m=p;p=p->next;
+            remove_IC(m);
+	    continue;
+/*            if(DEBUG&1024) printf("label %d==%d\n",l,iseq[l-firstl]);*/
+        }else{
+            currentl=l;cl=p;
+            if(g->start!=p){
+                g->end=p->prev;
+                g->normalout=new_flowgraph();
+                g->normalout->in=mymalloc(sizeof(flowlist));
+                g->normalout->in->next=0;
+                g->normalout->in->graph=g;
+                g=g->normalout;
+                g->start=p;
+                g->branchout=0;
+                g->loopend=0;
+                g->index=++i;
+            }else g->branchout=0;
+            lg[l-firstl]=g;
+        }
+	p=p->next;
+    }
+    g->end=last_ic;g->normalout=g->branchout=0;
+    if(DEBUG&(16384|1024)) printf("%d basic blocks\n",i);
+    basic_blocks=i;
+
+/*    if(DEBUG&1024) for(i=firstl;i<=lcnt;i++) printf("L%d used: %d\n",i,used[i-firstl]);*/
+    /*  Diese Schleife entfernt alle nicht benutzten Labels und biegt alle  */
+    /*  Branches auf aequivalente Labels um.                                */
+    if(DEBUG&1024) {puts("construct_flowgraph(): loop2");/*scanf("%d",&i);*/}
+    g=fg;
+    while(g){
+        int flag=0;flowlist *lp;
+/*        printf("g=%p\n",(void *)g);*/
+        g->av_in=g->av_out=g->av_gen=g->av_kill=0;
+        g->rd_in=g->rd_out=g->rd_gen=g->rd_kill=0;
+        g->ae_in=g->ae_out=g->ae_gen=g->ae_kill=0;
+        g->cp_in=g->cp_out=g->cp_gen=g->cp_kill=0;
+	g->pt=0;
+        p=g->start;
+        while(p&&!flag){
+/*            pric2(stdout,p);*/
+            code=p->code;
+            if(code>=BEQ&&code<=BRA){
+                l=p->typf;
+                if(iseq[l-firstl]) p->typf=l=iseq[l-firstl];
+                /*  in Flussgraph eintragen */
+                g->branchout=lg[l-firstl];
+                if(!lg[l-firstl]) error(353);
+                lp=lg[l-firstl]->in;
+                /*  das hier sollte man noch schoener machen    */
+                if(!lp){
+                    lg[l-firstl]->in=mymalloc(sizeof(flowlist));
+                    lg[l-firstl]->in->next=0;
+                    lg[l-firstl]->in->graph=g;
+                }else{
+                    while(lp&&lp->next) lp=lp->next;
+                    lp->next=mymalloc(sizeof(flowlist));
+                    lp->next->next=0;
+                    lp->next->graph=g;
+                }
+            }
+/*            if(code==LABEL&&!used[p->typf-firstl]) remove_IC(p);*/
+            if(p==g->end) flag=1;
+            p=p->next;
+        }
+        g=g->normalout;
+    }
+    /*  Unbenutzte Labels entfernen und Bloecke verbinden   */
+    if(DEBUG&1024) {puts("construct_flowgraph(): loop3");/*scanf("%d",&i);*/}
+    for(g=fg;g;g=g->normalout){
+        if(g->end&&(g->end->code<BEQ||g->end->code>BRA)){
+            flowgraph *next=g->normalout;flowlist *lp;
+            if(next&&next->start&&next->start->code==LABEL&&!used[next->start->typf-firstl]){
+                if(next->end!=next->start) g->end=next->end;
+                g->normalout=next->normalout;
+                g->branchout=next->branchout;
+                free(next->in); /*  darf eigentlich nur einen Vorgaenger haben  */
+                /*  in im Nachfolgeknoten auf den ersten der beiden setzen  */
+                if(next->normalout&&next->normalout->in) next->normalout->in->graph=g;
+                /*  in im Ziel von next->branchout auf den ersten setzen    */
+                if(next->branchout){
+                    lp=next->branchout->in;
+                    while(1){
+                        if(lp->graph==next){ lp->graph=g;break;}
+                        lp=lp->next;if(!lp) ierror(0);
+                    }
+                }
+                if(DEBUG&1024){ printf("unused label deleted:\n");pric2(stdout,next->start);}
+                remove_IC(next->start);
+                free(next);
+            }
+        }
+        /*  unbenutzte Labels entfernen */
+        if(g->start&&g->start->code==LABEL&&!used[g->start->typf-firstl])
+            remove_IC_fg(g,g->start);
+    }
+    free(iseq);
+    free(used);
+    return(fg);
+}
+
+void print_flowgraph(flowgraph *g)
+/*  Gibt Flussgraph auf Bildschirm aus  */
+{
+    static int dontprint=0;
+    int flag,i;flowlist *lp;IC *ip;
+    if(dontprint>0) {dontprint--;return;}
+    if(dontprint!=-1){
+      puts("print_flowgraph()");scanf("%d",&i);
+      if(i<-1){dontprint=-i;return;}
+      if(!i) return;
+      if(i==-1){dontprint=-1; i=1;}
+    }else{
+      i=1;
+    }
+    while(g){
+        printf("\nBasic Block nr. %d\n",g->index);
+        printf("\tin from ");
+        lp=g->in;
+        while(lp){if(lp->graph) printf("%d ",lp->graph->index);lp=lp->next;}
+        printf("\n\tout to %d %d\n",g->normalout?g->normalout->index:0,g->branchout?g->branchout->index:0);
+        if(g->loopend) printf("head of a loop ending at block %d\n",g->loopend->index);
+	if(!(optflags&32)&&g->pt)
+	  ierror(0);
+        if(i&2){
+            printf("av_gen:\n"); print_av(g->av_gen);
+            printf("av_kill:\n"); print_av(g->av_kill);
+            printf("av_in:\n"); print_av(g->av_in);
+            printf("av_out:\n"); print_av(g->av_out);
+        }
+        if(i&4){
+            printf("rd_gen:\n"); print_rd(g->rd_gen);
+            printf("rd_kill:\n"); print_rd(g->rd_kill);
+            printf("rd_in:\n"); print_rd(g->rd_in);
+            printf("rd_out:\n"); print_rd(g->rd_out);
+        }
+        if(i&8){
+            printf("ae_gen:\n"); print_ae(g->ae_gen);
+            printf("ae_kill:\n"); print_ae(g->ae_kill);
+            printf("ae_in:\n"); print_ae(g->ae_in);
+            printf("ae_out:\n"); print_ae(g->ae_out);
+        }
+        if(i&16){
+            printf("cp_gen:\n"); print_cp(g->cp_gen);
+            printf("cp_kill:\n"); print_cp(g->cp_kill);
+            printf("cp_in:\n"); print_cp(g->cp_in);
+            printf("cp_out:\n"); print_cp(g->cp_out);
+        }
+        if(i&32){
+            int r;
+            for(r=1;r<=MAXR;r++)
+                if(g->regv[r]) printf("(%s),%ld assigned to %s\n",g->regv[r]->identifier,(long)zm2l(g->regv[r]->offset),regnames[r]);
+        }
+	if(i&64){
+	  print_pt(g->pt);
+	}
+        flag=0;ip=g->start;
+        while(ip&&!flag){
+            pric2(stdout,ip);
+            if(i&64){
+                int r;
+                printf("changes: ");
+                for(r=0;r<ip->change_cnt;r++)
+                    printf("(%s,%ld,%d,%d)",ip->change_list[r].v->identifier,(long)zm2l(ip->change_list[r].v->offset),ip->change_list[r].flags,ip->change_list[r].v->index);
+                printf("\nuses: ");
+                for(r=0;r<ip->use_cnt;r++)
+                    printf("(%s,%ld,%d,%d)",ip->use_list[r].v->identifier,(long)zm2l(ip->use_list[r].v->offset),ip->use_list[r].flags,ip->use_list[r].v->index);
+                printf("\n");
+            }
+            if(ip==g->end) flag=1;
+            ip=ip->next;
+        }
+        g=g->normalout;
+    }
+    printf("return_label=%d\n",return_label);
+}
+void free_flowgraph(flowgraph *g)
+/*  Gibt Flussgraph frei    */
+{
+    flowgraph *pm;flowlist *lp,*lpm;
+    if(DEBUG&(16384|1024)) puts("free_flowgraph()");
+    while(g){
+        lp=g->in;
+        while(lp){
+            lpm=lp->next;
+            free(lp);
+            lp=lpm;
+        }
+        free(g->av_in);
+        free(g->av_out);
+        free(g->av_gen);
+        free(g->av_kill);
+        free(g->rd_in);
+        free(g->rd_out);
+        free(g->rd_gen);
+        free(g->rd_kill);
+        free(g->ae_in);
+        free(g->ae_out);
+        free(g->ae_gen);
+        free(g->ae_kill);
+        free(g->cp_in);
+        free(g->cp_out);
+        free(g->cp_gen);
+        free(g->cp_kill);
+	free_pt(g->pt);
+
+        pm=g->normalout;
+        free(g);
+        g=pm;
+    }
+}
+static void mark_reachable(flowgraph *fg)
+/* negiert den index aller Bloecke, die reachable sind */
+{
+  fg->index=-fg->index;
+  if(fg->branchout&&fg->branchout->index>=0)
+    mark_reachable(fg->branchout);
+  if(fg->normalout&&(!fg->end||fg->end->code!=BRA)&&fg->normalout->index>=0)
+    mark_reachable(fg->normalout);
+}
+flowgraph *jump_optimization(void)
+/*  entfernt ueberfluessige Spruenge etc.                           */
+{
+    flowgraph *fg,*g;IC *p;int changed,i;
+    flowlist *lp;
+    do{
+        changed=0;
+        fg=construct_flowgraph();
+	mark_reachable(fg);
+        if(DEBUG&1024) {printf("jump_optimization() pass\n");print_flowgraph(fg);}
+        g=fg;
+        while(g){
+            /*  tote Bloecke entfernen                  */
+	    if(g->index<0){
+	        g->index=-g->index;
+	    }else{
+                IC *m;
+                if(DEBUG&1024) printf("deleting dead block %d\n",g->index);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+                p=g->start;i=0;
+                while(p&&!i){
+                    if(p==g->end) i=1;
+                    if(DEBUG&1024) pric2(stdout,p);
+                    m=p->next;
+                    remove_IC_fg(g,p);changed=gchanged=1;
+                    p=m;
+                }
+                if(g->branchout){
+                /*  Eintrag in Ziel loeschen (nur einmal, falls auch normalout)    */
+                    lp=g->branchout->in;
+                    while(lp){
+                        if(lp->graph==g){ lp->graph=0;break;}
+                        lp=lp->next;
+                    }
+                    g->branchout=0;
+                }
+                g=g->normalout;continue;
+            }
+            /*  Spruenge zum folgenden Code entfernen   */
+            if(g->normalout&&g->normalout==g->branchout){
+                p=g->end;
+                if(!p||p->code<BEQ||p->code>BRA) ierror(0);
+                if(DEBUG&1024){printf("branch to following label deleted:\n");pric2(stdout,p);}
+                remove_IC_fg(g,p);g->branchout=0;changed=gchanged=1;
+                p=g->end;
+                /*  vorangehenden Vergleich auch entfernen  */
+                if(p&&(p->code==COMPARE||p->code==TEST)){
+                    if(DEBUG&1024){printf("preceding comparison also deleted:\n");pric2(stdout,p);}
+                    remove_IC_fg(g,p);
+                }
+            }
+
+            /*  bcc l1;bra l2;l1 aendern    */
+            p=g->end;
+            if(p&&p->code>=BEQ&&p->code<BRA&&g->normalout){
+                if(g->normalout->start&&g->normalout->start->code==BRA){
+                    if(g->normalout->normalout==g->branchout){
+                        g->branchout=g->normalout->branchout;
+                        i=p->typf;
+                        p->typf=g->normalout->start->typf;
+                        if(DEBUG&1024) printf("changing bcc l%d;bra l%d;l%d to b!cc l%d\n",i,p->typf,i,p->typf);
+                        switch(p->code){
+                        case BEQ: p->code=BNE;break;
+                        case BNE: p->code=BEQ;break;
+                        case BLT: p->code=BGE;break;
+                        case BGE: p->code=BLT;break;
+                        case BGT: p->code=BLE;break;
+                        case BLE: p->code=BGT;break;
+                        }
+                        g->normalout->branchout=g->normalout->normalout;
+                        g->normalout->start->typf=i;
+                        changed=gchanged=1;
+                    }
+                }
+            }
+            /*  Haben alle Vorgaenger eines Blocks die selbe Anweisung am   */
+            /*  Blockende und keinen weiteren Nachfolger, dann kann die     */
+            /*  Anweisung in den Nachfogerblock geschoben werden            */
+            i=0;p=0;
+            for(lp=g->in;lp;lp=lp->next){
+                if(lp->graph){
+                    IC *np;
+                    flowgraph *ng=lp->graph;
+                    flowlist *l2;
+                    /*  doppelte Bloecke loeschen und ueberspringen */
+                    for(l2=g->in;l2;l2=l2->next)
+                        if(l2!=lp&&l2->graph==ng) break;
+                    if(l2){ lp->graph=0;continue;}
+                    np=ng->end;
+                    if(!np){ i=-1;break;}
+                    if(ng->branchout&&(np->code!=BRA||ng->branchout!=g)){i=-1;break;}
+                    if(np->code==BRA) np=np->prev;
+                    if(!np){ i=-1;break;}
+                    if(!p){
+                        i=1;
+                        p=np;
+                    }else{
+                        if(p->code==np->code&&p->typf==np->typf&&
+                           p->code!=CALL&&p->code!=GETRETURN&&p->code!=PUSH&&(p->code<TEST||p->code>COMPARE)&&
+                           !compare_objs(&p->q1,&np->q1,p->typf)&&
+                           !compare_objs(&p->q2,&np->q2,p->typf)&&
+                           !compare_objs(&p->z,&np->z,p->typf)){
+                            i++;
+                        }else{
+                            i=-1;
+                            break;
+                        }
+                    }
+                }
+            }
+            if(i>1&&g->start){
+                IC *new=new_IC();
+                if(DEBUG&1024){ printf("moving instruction from preceding blocks to successor:\n");pric2(stdout,p);}
+                changed=gchanged=1;
+                memcpy(new,p,ICS);
+                new->use_cnt=new->change_cnt=0;
+                new->use_list=new->change_list=0;
+                if(g->start->code==LABEL){
+                    insert_IC_fg(g,g->start,new);
+                }else{
+                    insert_IC_fg(g,g->start->prev,new);
+                }
+                for(lp=g->in;lp;lp=lp->next){
+                    flowgraph *ng=lp->graph;
+                    if(ng){
+                        if(!ng->end) ierror(0);
+                        if(ng->end->code==BRA){
+                            remove_IC_fg(ng,ng->end->prev);
+                        }else{
+                            remove_IC_fg(ng,ng->end);
+                        }
+                    }
+                }
+            }
+            /*  Haben alle Nachfolger eines Blocks die selbe Anweisung am   */
+            /*  Blockbeginn und keinen weiteren Vorgaenger, dann kann die   */
+            /*  Anweisung in den Vorgaengerblock geschoben werden           */
+            if(g->branchout&&g->normalout&&g->branchout!=g->normalout&&g->end&&g->end->code!=BRA){
+                flowgraph *a=g->normalout,*b=g->branchout;
+                IC *as=a->start,*bs=b->start,*tp;
+                int destroys;
+                if(as&&as->code==LABEL&&as!=a->end) as=as->next;
+                if(bs&&bs->code==LABEL&&bs!=b->end) bs=bs->next;
+
+                if(as&&bs&&as->code==bs->code&&as->code!=PUSH&&(as->code<TEST||as->code>COMPARE)&&as->typf==bs->typf&&
+                   !compare_objs(&as->q1,&bs->q1,as->typf)&&
+                   !compare_objs(&as->q2,&bs->q2,as->typf)&&
+                   !compare_objs(&as->z,&bs->z,as->typf)){
+                    i=0;
+                    for(lp=a->in;lp;lp=lp->next)
+                        if(lp->graph&&lp->graph!=g&&(lp->graph->branchout==a||!lp->graph->end||lp->graph->end->code!=BRA)) i=1;
+                    for(lp=b->in;lp;lp=lp->next)
+                        if(lp->graph&&lp->graph!=g&&(lp->graph->branchout==b||!lp->graph->end||lp->graph->end->code!=BRA)) i=1;
+		    if(as->code==CALL&&as->next&&(as->next->code==GETRETURN||as->code==NOP)) i=1;
+		    if(bs->code==CALL&&bs->next&&(bs->next->code==GETRETURN||bs->code==NOP)) i=1;
+                    if(!i){
+                        if(!(tp=g->end->prev)) ierror(0);
+                        if(tp->code!=TEST&&tp->code!=COMPARE)
+                            ierror(0);
+                        /*  schauen, ob die Anweisung eine evtl. TEST   */
+                        /*  oder COMPARE-Anweisung beeinflusst          */
+                        destroys=0;
+                        if(as->z.flags&DREFOBJ) destroys|=1;
+                        if(as->code==CALL) destroys|=2;
+                        if(tp->q1.flags&VAR){
+                            if(destroys&3){
+                                if((tp->q1.v->flags&USEDASADR)||
+                                   (tp->q1.flags&DREFOBJ)||
+                                   (tp->q1.v->storage_class==EXTERN)||
+                                   (tp->q1.v->nesting==0))
+                                    i=1;
+                                if((destroys&2)&&tp->q1.v->storage_class==STATIC)
+                                    i=1;
+                            }
+                            if((as->z.flags&VAR)&&as->z.v==tp->q1.v)
+                                    i=1;
+                        }
+                        if(tp->q2.flags&VAR){
+                            if(destroys&3){
+                                if((tp->q2.v->flags&USEDASADR)||
+                                   (tp->q2.flags&DREFOBJ)||
+                                   (tp->q2.v->storage_class==EXTERN)||
+                                   (tp->q2.v->nesting==0))
+                                    i=1;
+                                if((destroys&2)&&tp->q2.v->storage_class==STATIC)
+                                    i=1;
+                            }
+                            if((as->z.flags&VAR)&&as->z.v==tp->q2.v)
+                                i=1;
+                        }
+                        if(!i&&!(disable&2)){
+                            if(DEBUG&1024){ printf("moving instruction from following blocks to predecessor:\n");pric2(stdout,as);}
+                            p=new_IC();
+                            memcpy(p,as,ICS);
+                            remove_IC_fg(a,as);
+                            remove_IC_fg(b,bs);
+                            p->use_cnt=p->change_cnt=0;
+                            p->use_list=p->change_list=0;
+                            insert_IC_fg(g,g->end->prev->prev,p);
+                            changed=gchanged=1;
+                        }
+                    }
+                }
+            }
+            g=g->normalout;
+        }
+        g=fg;
+        while(g){
+            /*  Spruenge zu Spruengen umsetzen; einige Zeiger im Flussgraph */
+            /*  werden nicht korrekt aktualisiert, aber das sollte egal sein*/
+            p=g->start;
+            for(i=0;i<2;i++){
+                if(i){if(p&&p->code==LABEL) p=p->next; else break;}
+                if(p&&p->code>=BEQ&&p->code<=BRA){
+                    lp=g->in;
+                    while(lp){
+                        if(lp->graph&&lp->graph->branchout==g&&(/*lp->graph->end->code==p->code||*/p->code==BRA)&&lp->graph->end->typf!=p->typf){
+                            if(DEBUG&1024){printf("branch bypassed to L%d:\n",p->typf);pric2(stdout,lp->graph->end);}
+                            if(lp->graph->end->code<BEQ||lp->graph->end->code>BRA) ierror(0);
+                            lp->graph->branchout=g->branchout;
+                            lp->graph->end->typf=p->typf;changed=gchanged=1;
+                        }
+                        lp=lp->next;
+                    }
+                }
+            }
+
+
+	    g=g->normalout;
+	}
+        if(changed) free_flowgraph(fg);
+    }while(changed);
+    return fg;
+}
+
+void insert_IC_fg(flowgraph *fg,IC *p,IC *new)
+/*  fuegt ein IC hinter p ein unter Beibehaltung des Flussgraphen   */
+{
+    if(fg->start){
+        if(!p||p==fg->start->prev) fg->start=new;
+        if(p==fg->end) fg->end=new;
+    }else{
+        fg->start=fg->end=new;
+    }
+    insert_IC(p,new);
+}
diff --git a/frontend/vc.c b/frontend/vc.c
new file mode 100644
index 0000000..e94e643
--- /dev/null
+++ b/frontend/vc.c
@@ -0,0 +1,770 @@
+/*  Frontend for vbcc                       */
+/*  (c) in 1995-2016 by Volker Barthelmann  */
+/*  #define AMIGA for Amiga version         */
+/*  #define ATARI for Atari version         */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef AMIGA
+#pragma amiga-align
+#ifdef __amigaos4__
+#include <dos/anchorpath.h>
+#else
+#include <dos/dosasl.h>
+#endif
+#include <dos/dosextens.h>
+#include <dos/dostags.h>
+#include <exec/libraries.h>
+#include <proto/dos.h>
+#pragma default-align
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 20
+#endif
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#if !defined(__amigaos4__) && !defined(__MORPHOS__)
+extern struct DosLibrary *DOSBase;
+#endif
+
+/*  Must be 32bit-aligned - I know it will be if compiled with vbcc.    */
+struct FileInfoBlock fib;
+#endif
+
+struct NameList{
+    struct NameList *next;
+    char *obj;
+} *first_obj=0,*last_obj=0,*first_scratch=0,*last_scratch=0;
+
+/*  Limit fuer Laenge der Namen (wegen Wildcards)   */
+#define NAMEBUF 1000    /*  MUST BE >= ~TMPNAM_L+7  */
+#define USERLIBS 1000
+
+/*  Ab dieser Laenge werden Objektfiles nicht direkt uebergeben,    */
+/*  sondern aus einem File an den Linker uebergeben                 */
+#ifdef AMIGA
+int MAXCLEN=500;
+#else
+int MAXCLEN=32000;
+#endif
+
+#define WPO 16384
+#define CROSSMODULE 8192
+#define SCHEDULER 4096
+#define NOTMPFILE 2048
+#define OUTPUTSET 1024
+#define NOSTDLIB 512
+#define VERBOSE 256
+#define VERYVERBOSE 128
+#define KEEPSCRATCH 64
+
+#define PPSRC 1
+#define CCSRC 2
+#define SCSRC 3
+#define ASSRC 4
+#define OBJ 5
+
+char *vbccenv;
+char empty[]="";
+/*  Namen der einzelnen Phasen  */
+char *ppname=empty,*ccname=empty,*asname=empty,*ldname=empty,*l2name=empty;
+char *rmname=empty,*scname=empty;
+/*  dasselbe fuer VERBOSE   */
+char *ppv=empty,*ccv=empty,*asv=empty,*ldv=empty,*l2v=empty;
+char *rmv=empty,*scv=empty;
+
+/*  Linker-Commandfile  */
+char *cf="@%s";
+char *nodb="";
+char *staticflag="";
+char *ul="-l%s";
+
+#if defined(AMIGA)
+const char *config_name="vc.config";
+const char *search_dirs[]={"","ENV:","VBCC:config/","VBCC:"};
+#elif defined(_WIN32) || defined(MSDOS)
+const char *config_name="vc.cfg";
+const char *search_dirs[]={"","%VCCFG%\\"};
+#elif defined(ATARI)
+const char *config_name="vc.cfg";
+const char *search_dirs[]={"","C:\\"};
+#else
+const char *config_name="vc.config";
+const char *search_dirs[]={"","~/","/etc/"};
+#endif
+
+/*  String fuer die Default libraries   */
+char userlibs[USERLIBS];
+char *nomem="Not enough memory!\n";
+
+char *destname="a.out";
+char namebuf[NAMEBUF+1],namebuf2[NAMEBUF+1];
+char *oldfile;
+
+char *cmfiles,*cmoutput,*cmname;
+#if defined(AMIGA)||defined(_WIN32)||defined(MSDOS)
+#undef USECMDFILE
+#define USECMDFILE 1
+#endif
+#ifdef USECMDFILE
+FILE *cmdfile;
+#endif
+int final;
+int compressor;
+
+char *config;
+char **confp;
+
+char *command,*options,*linkcmd,*objects,*libs,*ppopts;
+#ifdef AMIGA
+struct AnchorPath *ap;
+#endif
+
+int linklen=10,flags=0;
+
+#if defined(MSDOS)||defined(ATARI)
+char *tmpnam(char *p)
+{
+  static int c=1675;
+  static char tmp[NAMEBUF];
+  char *env;
+
+  env=getenv("TEMP");
+  if(!env) env=".";
+  if(!p) p=tmp;
+  snprintf(p,NAMEBUF,"%s\\vbcc%04x",env,++c);
+  return p;
+}
+#endif
+
+static void free_namelist(struct NameList *p)
+{
+    struct NameList *m;
+    while(p){
+        m=p->next;
+        if(flags&VERYVERBOSE){
+            puts("free p->obj");
+            if(!p->obj) puts("IS ZERO!!"); else puts(p->obj);
+        }
+        free((void *)p->obj);
+        if(flags&VERYVERBOSE){puts("free p"); if(!p) puts("IS ZERO!!");}
+        free((void *)p);
+        p=m;
+    }
+}
+
+static void raus(int rc)
+{
+    if(confp)   free(confp);
+    if(config)  free(config);
+    if(objects) free(objects);
+    if(libs)    free(libs);
+    if(command) free(command);
+    if(ppopts)  free(ppopts);
+    if(options) free(options);
+    if(linkcmd) free(linkcmd);
+#ifdef AMIGA
+    if(ap)
+#ifdef __amigaos4__
+        FreeDosObject(DOS_ANCHORPATH,ap);
+#else
+        free(ap);
+#endif
+#endif
+    free_namelist(first_obj);
+    free_namelist(first_scratch);
+    exit(rc);
+}
+
+#ifdef NO_LONGER_NEEDED
+/* Launch command from "$VBCC\bin\", when no absolute path was specified. */
+static int runcmd(char *cmd)
+{
+    char *p;
+
+    for(p=cmd;*p!=0&&*p>' ';p++){
+        if(*p==':')  /* absolute path */
+            goto do_cmd;
+    }
+    if(vbccenv){
+        /* prepend "$VBCC\bin\" in front of our command */
+        int len=strlen(vbccenv);
+        if(vbccenv[len-1]=='\\') len--;
+        memmove(cmd+len+5,cmd,strlen(cmd)+1);
+        memcpy(cmd,vbccenv,len);
+        memcpy(cmd+len,"\\bin\\",5);
+    }
+do_cmd:
+    return system(cmd);
+}
+#else
+#define runcmd(c) system(c)
+#endif
+
+static void del_scratch(struct NameList *p)
+{
+    while(p){
+        sprintf(command,rmname,p->obj);
+        if(flags&VERBOSE) printf("%s\n",command);
+        if(runcmd(command)){printf("%s failed\n",command);raus(EXIT_FAILURE);}
+        p=p->next;
+    }
+}
+
+static void add_name(char *obj,struct NameList **first,struct NameList **last)
+{
+    struct NameList *new;
+    if(flags&VERYVERBOSE) printf("add_name: %s\n",obj);
+    if(!(new=malloc(sizeof(struct NameList))))
+        {printf(nomem);raus(EXIT_FAILURE);}
+    if(!(new->obj=malloc(strlen(obj)+1)))
+        {free((void *)new);printf(nomem);raus(EXIT_FAILURE);}
+    if(first==&first_obj) linklen+=strlen(obj)+1;
+    strcpy(new->obj,obj);
+    new->next=0;
+    if(!*first){
+        *first=*last=new;
+    }else{
+        (*last)->next=new;*last=new;
+    }
+}
+
+static int read_config(const char *cfg_name)
+{
+    int i,count; long size;
+    char *p,*name;
+    FILE *file=0;
+    for(i=0;i<sizeof(search_dirs)/sizeof(search_dirs[0]);i++){
+      name=malloc(strlen(search_dirs[i])+strlen(cfg_name)+1);
+      if(!name) {printf(nomem);raus(EXIT_FAILURE);}
+      strcpy(name,search_dirs[i]);
+      strcat(name,cfg_name);
+      file=fopen(name,"r");
+      free(name);
+      if(file) break;
+    }
+    if(!file){
+      if(p=vbccenv){
+        name=malloc(strlen(p)+strlen(cfg_name)+20);
+        if(!name){printf(nomem);raus(EXIT_FAILURE);}
+        strcpy(name,p);
+#if defined(_WIN32)||defined(MSDOS)||defined(ATARI)
+        strcat(name,"\\config\\");
+        strcat(name,cfg_name);
+#elif defined(AMIGA)
+        AddPart(name,"config",strlen(p)+strlen(cfg_name)+20);
+        AddPart(name,(STRPTR)cfg_name,strlen(p)+strlen(cfg_name)+20);
+#else
+        strcat(name,"/config/");
+        strcat(name,cfg_name);
+#endif
+        file=fopen(name,"r");
+        free(name);
+      }
+    }
+    if(!file) {puts("No config file!");raus(EXIT_FAILURE);}
+    if(fseek(file,0,SEEK_END)) return 0;
+    size=ftell(file);
+    if(fseek(file,0,SEEK_SET)) return 0;
+    config=malloc(size+1);
+    if(!config){printf(nomem);raus(EXIT_FAILURE);}
+    size=fread(config,1,size,file);
+    fclose(file);
+    count=0;p=config;
+    while(p<config+size&&*p){
+        count++;
+        while(p<config+size&&*p!='\n') p++;
+        if(*p=='\n') *p++=0;
+    }
+    config[size]=0;
+    confp=malloc(count*sizeof(char *));
+    for(p=config,i=0;i<count;i++){
+        confp[i]=p;
+        while(*p) p++;
+        p++;
+    }
+    return count;
+}
+
+static int typ(char *fp)
+{
+    char *p=strrchr(fp,'.');
+    if(p&&(!strcmp(p,".c")||!strcmp(p,".C"))) return ppname==empty?CCSRC:PPSRC;
+    if(p&&!strcmp(p,".i")) return CCSRC;
+    if(p&&(!strcmp(p,".s")||!strcmp(p,".S")||!strcmp(p,".asm"))) return ASSRC;
+    if(p&&!strcmp(p,".scs")) return SCSRC;
+    if(!p||!strcmp(p,".o")||!strcmp(p,".obj")){
+      FILE *f;
+      if(f=fopen(fp,"r")){
+        if(fgetc(f)==0&&fgetc(f)=='V'&&fgetc(f)=='B'&&fgetc(f)=='C'&&fgetc(f)=='C'){
+          fclose(f);     
+          return CCSRC;
+        }
+        fclose(f);
+      }
+      return OBJ;
+    }
+    return OBJ;
+}
+
+static char *add_suffix(char *s,char *suffix)
+{
+    static char str[NAMEBUF+3],*p;
+    if(strlen(s)+strlen(suffix)>NAMEBUF){printf("string too long\n");raus(EXIT_FAILURE);}
+    if(s!=str) strcpy(str,s);
+    p=strrchr(str,'.');
+    if(!p) p=str+strlen(s);
+    if(!p||p==str||(p==str+1&&str[0]=='\"')) p=str+strlen(s);
+    strcpy(p,suffix);
+    strcat(p,"\"");
+    return str;
+}
+
+#if defined(_WIN32)||defined(MSDOS)||defined(ATARI)||defined(AMIGA)
+static char *convert_path(char *path)
+{
+    char c,*p,*newpath;
+    newpath=p=malloc(strlen(path)+1);
+    while(c=*path++){
+#ifdef AMIGA
+        if(c=='.'){
+            if(*path=='/') continue;
+            if(*path=='.'&&*(path+1)=='/'){
+                path++;
+                continue;
+            }
+        }
+#else
+        if(c=='/') c='\\';
+#endif
+        *p++=c;
+    }
+    *p=0;
+    return newpath;
+}
+#else
+#define convert_path(p) (p)
+#endif
+
+int main(int argc,char *argv[])
+{
+  int tfl,i,len=10,pm,count,db=0,staticmode=0,deps=0;
+    char *parm;
+    long opt=1;
+    int rc=EXIT_SUCCESS;
+
+    for(i=1;i<argc;i++){
+        if(argv[i][0]=='+'){
+            config_name=argv[i]+1;
+            argv[i][0]=0;
+            break;
+        }
+    }
+    vbccenv=getenv("VBCC");
+    count=read_config(config_name);
+#ifdef AMIGA
+#if !defined(__amigaos4__) && !defined(__MORPHOS__)
+    if(pm=DOSBase->dl_lib.lib_Version>=36)
+#else
+    if(pm=1)
+#endif
+    {
+#ifdef __amigaos4__
+        if(!(ap=(struct AnchorPath *)AllocDosObjectTags(DOS_ANCHORPATH,
+                                                        ADO_Strlen,NAMEBUF,
+                                                        TAG_DONE)))
+          pm=0;
+#else
+        if(ap=(struct AnchorPath *)calloc(sizeof(struct AnchorPath)+NAMEBUF,1))
+            {ap->ap_Strlen=NAMEBUF;ap->ap_BreakBits=0;} else pm=0;
+#endif
+    }
+#endif
+    for(i=1;i<argc+count;i++){
+        if(i<argc) parm=argv[i]; else parm=confp[i-argc];
+        if(!strncmp(parm,"-ul=",4)){ul=parm+4;*parm=0;}
+    }
+    for(i=1;i<argc+count;i++){
+        if(i<argc) parm=argv[i]; else parm=confp[i-argc];
+/*        printf("Parameter %d=%s\n",i,parm);*/
+	if(!strncmp(parm,"-rmcfg-",7)){
+	  int j,len=strlen(parm);
+	  for(j=0;j<count;j++)
+	    if(!strncmp(confp[j],parm+6,len-6)) confp[j][0]=0;
+	  parm[0]=0;
+	  continue;
+	}
+        if(!strncmp(parm,"-ldnodb=",8)){nodb=parm+8;*parm=0;}
+        if(!strncmp(parm,"-ldstatic=",10)){staticflag=parm+10;*parm=0;}
+        if(!strcmp(parm,"-g")) db=1;
+	if(!strcmp(parm,"-deps")) deps=1;
+        if(!strcmp(parm,"-static")){staticmode=1;*parm=0;}
+        if(!strncmp(parm,"-ml=",4)){MAXCLEN=atoi(parm+4);*parm=0;}
+        if(!strncmp(parm,"-pp=",4)){ppname=parm+4;*parm=0;}
+        if(!strncmp(parm,"-cc=",4)){ccname=parm+4;*parm=0;}
+        if(!strncmp(parm,"-as=",4)){asname=parm+4;*parm=0;}
+        if(!strncmp(parm,"-ld=",4)){ldname=parm+4;*parm=0;}
+        if(!strncmp(parm,"-l2=",4)){l2name=parm+4;*parm=0;}
+        if(!strncmp(parm,"-rm=",4)){rmname=parm+4;*parm=0;}
+        if(!strncmp(parm,"-ppv=",5)){ppv=parm+5;*parm=0;}
+        if(!strncmp(parm,"-ccv=",5)){ccv=parm+5;*parm=0;}
+        if(!strncmp(parm,"-asv=",5)){asv=parm+5;*parm=0;}
+        if(!strncmp(parm,"-ldv=",5)){ldv=parm+5;*parm=0;}
+        if(!strncmp(parm,"-l2v=",5)){l2v=parm+5;*parm=0;}
+        if(!strncmp(parm,"-rmv=",5)){rmv=parm+5;*parm=0;}
+        if(!strncmp(parm,"-cf=",4)){cf=parm+4;*parm=0;}
+        if(!strncmp(parm,"-isc=",5)){scname=parm+5;*parm=0;}
+        if(!strncmp(parm,"-iscv=",6)){scv=parm+6;*parm=0;}
+	/* TODO: we re-use scheduler for compressor */
+        if(!strncmp(parm,"-cpr=",5)){scname=parm+5;*parm=0;compressor=1;}
+        if(!strncmp(parm,"-cprv=",6)){scv=parm+6;*parm=0;compressor=1;}
+        if(!strcmp(parm,"-schedule")) {flags|=SCHEDULER;*parm=0;}
+        if(!strcmp(parm,"-notmpfile")) {flags|=NOTMPFILE;*parm=0;}
+        /*if(!strcmp(parm,"-E")) {flags|=CCSRC;*parm=0;}*/
+        if(!strcmp(parm,"-S")) {flags|=ASSRC;*parm=0;}
+        if(!strcmp(parm,"-SCS")) {flags|=SCSRC;*parm=0;}
+        if(!strcmp(parm,"-c")) {flags|=OBJ;*parm=0;}
+        if(!strcmp(parm,"-v")) {flags|=VERBOSE;*parm=0;}
+        if(!strcmp(parm,"-h")) {flags|=VERBOSE;*parm=0;}
+        if(!strcmp(parm,"-k")) {flags|=KEEPSCRATCH;*parm=0;}
+        if(!strcmp(parm,"-vv")) {flags|=VERBOSE|VERYVERBOSE;*parm=0;}
+        if(!strcmp(parm,"-nostdlib")) {flags|=NOSTDLIB;*parm=0;}
+        if(parm[0] == ';') {*parm=0;}
+        if(!strncmp(parm,"-O",2)){
+          static int had_opt;
+          if(had_opt){
+            puts("Optimization flags specified multiple times");
+            exit(EXIT_FAILURE);
+          }
+          had_opt=1;
+          if(parm[2]=='0') opt=0;
+          else if(parm[2]=='1'||parm[2]==0) opt=991;
+          else if(parm[2]=='2') {opt=1023;flags|=SCHEDULER;}
+          else if(parm[2]=='3') {opt=~0;flags|=(SCHEDULER|CROSSMODULE);}
+          else if(parm[2]>='4'&&parm[2]<='9') {opt=~0;flags|=(SCHEDULER|WPO);}
+          
+          else if(parm[2]=='=') opt=atoi(&parm[3]);
+          *parm=0;
+        }
+        if(!strcmp(parm,"-o")&&i<argc-1) {
+            *argv[i++]=0;destname=convert_path(argv[i]);
+            flags|=OUTPUTSET;argv[i]="";continue;
+        }
+        if(!strncmp(parm,"-o=",3)){
+            destname=convert_path(parm+3);
+            flags|=OUTPUTSET;*parm=0;continue;
+        }
+        if(parm[0]=='-'&&parm[1]=='l'){
+            size_t l=strlen(userlibs);
+            if((l+strlen(parm)-2+strlen(ul)+1)>=USERLIBS){puts("Userlibs too long");exit(EXIT_FAILURE);}
+            userlibs[l]=' ';
+            sprintf(userlibs+l+1,ul,parm+2);
+            *parm=0;continue;
+        }
+        if(parm[0]=='-'&&parm[1]=='L'){
+            size_t l=strlen(userlibs);
+            if((l+strlen(parm)+1)>=USERLIBS){puts("Userlibs too long");exit(EXIT_FAILURE);}
+            userlibs[l]=' ';
+            sprintf(userlibs+l+1,"%s",parm);
+            *parm=0;continue;
+        }
+        len+=strlen(parm)+10;
+#ifdef ATARI
+        if(vbccenv)
+          len+=strlen(vbccenv)+5;
+#endif
+    }
+    if(!db&&*nodb){
+      if(strlen(userlibs)+2+strlen(nodb)>=USERLIBS){
+        puts("Userlibs too long");exit(EXIT_FAILURE);
+      }
+      strcat(userlibs," ");
+      strcat(userlibs,nodb);
+    }
+    if(staticmode&&*staticflag){
+      size_t ulen=strlen(userlibs);
+      size_t slen=strlen(staticflag);
+      if(ulen+2+slen>=USERLIBS){
+        puts("Userlibs too long");exit(EXIT_FAILURE);
+      }
+      memmove(userlibs+slen+1,userlibs,ulen+1);
+      memcpy(userlibs,staticflag,slen);
+      userlibs[slen]=' ';
+    }
+    if(flags&VERBOSE){
+      printf("vc frontend for vbcc (c) in 1995-2020 by Volker Barthelmann\n");
+#ifdef SPECIAL_COPYRIGHT
+      printf("%s\n",SPECIAL_COPYRIGHT);
+#endif
+    }
+    if(!(flags&7)) flags|=OBJ+1;
+    tfl=flags&7;
+    if((flags&WPO)&&tfl!=OBJ){
+      flags&=~WPO;
+      flags|=CROSSMODULE;
+    }
+    if(scname==empty) flags&=~SCHEDULER;
+    if(flags&VERYVERBOSE){
+      ppname=ppv;ccname=ccv;asname=asv;ldname=ldv;
+      rmname=rmv;l2name=l2v;scname=scv;
+    }
+    if(flags&NOSTDLIB){ldname=l2name;}
+    /*  Nummer sicher...    */
+    len+=strlen(ppname)+strlen(ccname)+strlen(asname)+
+         strlen(rmname)+strlen(scname)+strlen(userlibs)+NAMEBUF+100;
+    if(!(command=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+    if(!(oldfile=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+    if(!(options=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+    if(!(ppopts=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+    *options=0;*ppopts=0;
+    for(i=1;i<argc+count;i++){
+        if(i<argc) parm=argv[i]; else parm=confp[i-argc];
+        if(*parm=='-'){
+            if(ppname==empty||(parm[1]!='D'&&parm[1]!='I'&&parm[1]!='+')){
+                strcat(options,parm);strcat(options," ");
+            }else{
+                strcat(ppopts,parm);strcat(ppopts," ");
+            }
+        }
+    }
+    if(flags&VERYVERBOSE) printf("flags=%d opt=%ld len=%d\n",flags,opt,len);
+    namebuf[0]='\"'; namebuf2[0]='\"';
+    for(i=1;i<argc+count+((flags&CROSSMODULE)!=0);i++){
+        int t,j;char *file;
+#ifdef AMIGA
+        BPTR lock;
+#endif
+        if(i<argc)
+          parm=argv[i];
+        else if(i<argc+count)
+          parm=confp[i-argc];
+        else
+          parm=cmfiles;
+        if(!parm||(*parm=='-'&&parm!=cmfiles)||!*parm) continue;
+        if(flags&VERYVERBOSE) printf("Argument %d:%s\n",i,parm);
+#ifdef AMIGA
+        if(pm&&parm!=cmfiles)
+            if(MatchFirst((STRPTR)convert_path(parm),ap)){
+                MatchEnd(ap);
+                printf("No match for %s\n",parm);
+                rc=RETURN_WARN;
+                continue;
+            }
+#endif
+        do{
+            if(parm==cmfiles){
+                file=parm;
+                t=CCSRC;
+            }else{
+#ifdef AMIGA
+#ifdef __amigaos4__
+                if(pm) file=(char *)ap->ap_Buffer; else file=parm;
+#else
+                if(pm) file=(char *)&ap->ap_Buf[0]; else file=parm;
+#endif
+#else
+                file=convert_path(parm);
+#endif
+                t=typ(file);
+                strcpy(namebuf+1,file);
+                strcat(namebuf,"\"");
+                file=namebuf;
+            }
+            if(flags&VERYVERBOSE) printf("File %s=%d\n",file,t);
+            if(!cmname&&(flags&CROSSMODULE)&&t<=CCSRC){
+                cmname=malloc(NAMEBUF);
+                if(!cmname){printf(nomem);exit(EXIT_FAILURE);}
+                if(tfl==OBJ){
+                    strcpy(cmname,file);
+                }else{
+                    cmname[0]='\"';
+                    tmpnam(cmname+1);
+		    strcat(cmname,".");
+                }
+            }
+            for(j=t;j<tfl;j++){
+                if(j==OBJ){
+                    if(j==t) add_name(file,&first_obj,&last_obj);
+                    continue;
+                }
+                strcpy(oldfile,file);
+                if(file==cmfiles){
+                    file=cmoutput;
+                }else{
+                    if(j==t&&j!=tfl-1&&!(flags&(NOTMPFILE|KEEPSCRATCH))){
+                        file=namebuf2;
+                        tmpnam(file+1);
+			strcat(file,".");
+                    }
+                    if(j==tfl-1||(flags&WPO)) file=namebuf;
+                }
+                if(j==PPSRC){
+                    file=add_suffix(file,".i");
+                    if(tfl==CCSRC&&(flags&OUTPUTSET)) file=destname;
+                    sprintf(command,ppname,ppopts,oldfile,file);
+                    if((tfl)!=CCSRC) add_name(file,&first_scratch,&last_scratch);
+                }
+                /* MUST come before CCSRC-handling! */
+                if(j==SCSRC){
+                    /*if(final) file=cmname;*/
+                    file=add_suffix(file,".asm");
+                    if(tfl==ASSRC&&(flags&OUTPUTSET)) file=destname;
+                    sprintf(command,scname,oldfile,file);
+                    if(tfl!=ASSRC) add_name(file,&first_scratch,&last_scratch);
+                }
+                if(j==CCSRC){
+                    if(file!=cmoutput){
+                      if(flags&WPO){
+                        if(flags&OUTPUTSET)
+                          file=destname;
+                        else
+                          file=add_suffix(file,".o");
+                      }else if(flags&SCHEDULER){
+                        file=add_suffix(file,".scs");
+                      }else{
+                        if(++j==tfl-1) file=namebuf;
+                        file=add_suffix(file,".asm");
+                      }
+                      if(tfl==j+1&&(flags&OUTPUTSET)) file=destname;
+                      if(flags&CROSSMODULE){
+#ifdef USECMDFILE
+                        if(!cmdfile){
+                          char *s;
+                          s=tmpnam(0);
+                          cmfiles=malloc(strlen(s)+16);
+                          if(!cmfiles){printf(nomem);exit(EXIT_FAILURE);}
+                          sprintf(cmfiles,"-cmd= \"%s\"",s);
+                          cmdfile=fopen(s,"w");
+                          if(!cmdfile){printf("Could not open <%s>!\n",s);exit(EXIT_FAILURE);}
+                          add_name(s,&first_scratch,&last_scratch);
+                        }
+                        fputs(oldfile,cmdfile);
+                        fputs("\n",cmdfile);
+#else
+                        if(!cmfiles){
+                          cmfiles=malloc(strlen(oldfile)+3);
+                          if(!cmfiles){printf(nomem);exit(EXIT_FAILURE);}
+                          strcpy(cmfiles,oldfile);
+                        }else{
+                          cmfiles=realloc(cmfiles,strlen(cmfiles)+strlen(oldfile)+3);
+                          if(!cmfiles){printf(nomem);exit(EXIT_FAILURE);}
+                          strcat(cmfiles," ");strcat(cmfiles,oldfile);
+                        }
+#endif
+                        if(!cmoutput){
+                          cmoutput=malloc(strlen(file)+1);
+                          if(!cmoutput){printf(nomem);exit(EXIT_FAILURE);}
+                          strcpy(cmoutput,file);
+                        }
+                        break;
+                      }
+                    }
+                    if(flags&CROSSMODULE){
+#ifdef USECMDFILE
+                      fclose(cmdfile);
+                      cmdfile=0;
+#endif
+                      final=1;
+                    }
+                    if((flags&(CROSSMODULE|SCHEDULER))==CROSSMODULE) j++;
+                    sprintf(command,ccname,oldfile,file,options,opt);
+                    if(flags&WPO){
+                      strcat(command," -wpo");
+                      j=OBJ;
+                    }else{
+                      if(tfl!=j+1) add_name(file,&first_scratch,&last_scratch);
+                    }
+		    if(deps&&tfl==OBJ&&(flags&OUTPUTSET)){
+		      strcat(command," -depobj=");
+		      strcat(command,destname);
+		    }
+                }
+                if(j==ASSRC){
+                    if(final) file=cmname;
+                    file=add_suffix(file,".o");
+                    if(tfl==OBJ&&(flags&OUTPUTSET)) file=destname;
+                    sprintf(command,asname,oldfile,file);
+                    add_name(file,&first_obj,&last_obj);
+                    if((tfl)!=OBJ) add_name(file,&first_scratch,&last_scratch);
+                }
+                if(flags&VERBOSE) printf("%s\n",command);
+#ifdef AMIGA
+#if !defined(__amigaos4__) && !defined(__MORPHOS__)
+                if(DOSBase->dl_lib.lib_Version>=36){
+#else
+                if(1){
+#endif
+                    if(SystemTags(command,NP_Priority,-2,TAG_DONE)){
+                        printf("%s failed\n",command);
+                        if(pm) MatchEnd(ap);
+                        raus(EXIT_FAILURE);
+                    }
+                }else
+#endif
+                if(runcmd(command)){printf("%s failed\n",command);raus(EXIT_FAILURE);}
+            }
+#ifdef AMIGA
+        }while(pm&&!MatchNext(ap));
+        if(pm) MatchEnd(ap);
+#else
+        }while(0);
+#endif
+    }
+    if((tfl)>OBJ){
+    /*  Zu Executable linken    */
+        struct NameList *p;
+        FILE *objfile=0;
+        char *tfname;
+        objects=malloc(linklen);
+        if(!objects){printf(nomem);raus(EXIT_FAILURE);}
+        linklen+=strlen(ldname)+strlen(destname)+strlen(userlibs)+10;
+#ifdef ATARI
+        if(vbccenv) linklen+=strlen(vbccenv)+5;
+#endif
+        if(flags&VERYVERBOSE) printf("linklen=%d\n",linklen);
+        if(!(linkcmd=malloc(linklen))){printf(nomem);raus(EXIT_FAILURE);}
+        p=first_obj;
+        if(linklen>=MAXCLEN){
+            tfname=tmpnam(0);
+            sprintf(objects,cf,tfname);
+            if(!(objfile=fopen(tfname,"w"))){
+                printf("Could not open <%s>!\n",tfname);
+                raus(EXIT_FAILURE);
+            }
+        }else *objects=0;
+        while(p){
+            if(p->obj){
+                if(linklen>=MAXCLEN){
+                    fputs(p->obj,objfile);
+                    fputs("\n",objfile);
+                }else{
+                    strcat(objects,p->obj);strcat(objects," ");
+                }
+            }
+            p=p->next;
+        }
+        if(objfile) fclose(objfile);
+        if(*objects){
+            sprintf(linkcmd,ldname,objects,userlibs,destname);
+            if(flags&VERBOSE) printf("%s\n",linkcmd);
+            /*  hier wird objfile bei Fehler nicht geloescht    */
+            if(runcmd(linkcmd)){printf("%s failed\n",linkcmd);raus(EXIT_FAILURE);}
+#ifdef AMIGA
+            if(flags&VERBOSE){
+                BPTR l;
+                if(l=Lock((STRPTR)destname,-2)){
+                    if(Examine(l,&fib)) printf("Size of executable: %lu bytes\n",(unsigned long)fib.fib_Size);
+                    UnLock(l);
+                }
+            }
+#endif
+        }else puts("No objects to link");
+        if(objfile) remove(tfname);
+    }
+    if(!(flags&KEEPSCRATCH)) del_scratch(first_scratch);
+    raus(rc);
+}
diff --git a/ic.c b/ic.c
new file mode 100644
index 0000000..4e76920
--- /dev/null
+++ b/ic.c
@@ -0,0 +1,2802 @@
+/*  $VER: vbcc (ic.c) $Revision: 1.65 $  */
+
+#include "vbc.h"
+#include "opt.h"
+
+#define RNOSAVE 32 /* register does not have to be saved across call */
+#define RHALF   64 /* half of a register pair was already allocated */
+
+static char FILE_[]=__FILE__;
+
+static IC *first_pushed;
+static unsigned int opushed;
+static int volatile_convert;
+
+int do_arith(np,IC *,np,obj *);
+static obj *postop_obj;
+static int postop_type;
+np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2);
+
+static void handle_reglist(regargs_list *,obj *);
+
+static void fix_pushic(IC **pushic,IC *new)
+{
+  IC *p=last_ic;
+  while(p&&p->code==FREEREG) p=p->prev;
+  if(new==*pushic&&new!=p){
+    if(DEBUG&1){
+      printf("pushic converted to:\n");
+      pric2(stdout,p);
+    }
+    *pushic=p;
+  }
+}
+
+#if HAVE_LIBCALLS
+/* avoid calling use_libcall with illegal operands */
+static char *use_libcall_wrap(int c,int t,int t2)
+{
+  if(optflags&2)
+    return 0;
+
+  if(c==PMULT) c=MULT;
+  if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST)
+    return use_libcall(c,t,t2);
+  return 0;
+}
+#endif
+
+void gen_test(obj *o,int t,int branch,int label)
+/*  Generiert ein test o, branch label und passt auf, dass      */
+/*  kein TEST const generiert wird.                             */
+{
+  IC *new;
+  if(o->flags&KONST){
+    eval_const(&o->val,t);
+    if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+      if(branch==BEQ) branch=BRA; else branch=0;
+    }else{
+      if(branch==BNE) branch=BRA; else branch=0;
+    }
+  }else{
+#if HAVE_LIBCALLS
+    static node n={TEST},nn={REINTERPRET};
+    static type nt,it={INT};
+    char *libname;
+    n.left=&nn;
+    n.ntyp=&it;
+    nn.ntyp=&nt;
+    nt.flags=t;
+    n.o=nn.o=*o;
+    if(libname=use_libcall_wrap(TEST,t,0)){
+      new=new_IC();
+      new->code=TEST;
+      new->q2.flags=new->z.flags=0;
+      new->typf=INT;
+      new->q1=gen_libcall(libname,&nn,&nt,0,0)->o;
+      add_IC(new);
+    }else{
+#endif
+      new=new_IC();
+      new->code=TEST;
+      new->q2.flags=new->z.flags=0;
+      new->typf=t;
+      new->q1=*o;
+      add_IC(new);
+#if HAVE_LIBCALLS
+    }
+#endif
+  }
+  if(branch){
+    new=new_IC();
+    new->code=branch;
+    new->typf=label;
+    add_IC(new);
+  }
+}
+
+/* remove a freereg if a scratch register is needed more than once */
+static void keep_reg(int r)
+{
+  IC *n;
+  if(nocode) return;
+  n=last_ic;
+  while(n){
+    if(n->code==CALL&&regscratch[r]){
+      IC *ret;
+      regs[r]=1;
+      savescratch(MOVEFROMREG,n->prev,0,&n->q1);
+      ret=n->next;
+      while(ret->code==ALLOCREG||ret->code==FREEREG)
+        ret=ret->next;
+      if(ret->code==GETRETURN){
+        if((ret->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ret->z.reg==r) 
+          ret->z.flags&=~REG;
+      }else
+        ret=ret->prev;
+      savescratch(MOVETOREG,ret,0,&n->q1);
+    }
+    if(n->code==FREEREG&&n->q1.reg==r){
+      remove_IC(n);
+      if(!nocode)
+        regs[r]=1;
+      break;
+    }
+    n=n->prev;
+  }
+}
+
+/* Generate code to insert a bitfield */
+void insert_bitfield(obj *dest,obj *src,obj *val,int bfs,int bfo,int t,int isclear)
+{
+  /*FIXME: shortcut beachten? */
+  IC *new;
+  obj tmp1,tmp2,tmp3;
+  int vmerk;
+  bfo=bflayout(bfo,bfs,t);
+  if((dest->flags&REG)&&!regs[dest->reg])
+    keep_reg(dest->reg);
+  new=new_IC();
+  new->code=AND;
+  new->typf=t;
+  new->q1=*src;
+  new->q1.flags&=~SCRATCH;
+  new->q2.flags=KONST;
+  gval.vmax=zmsub(zmlshift(l2zm(1L),l2zm((int)bfs)),l2zm(1L));
+  eval_const(&gval,MAXINT);
+  insert_const(&new->q2.val,t);
+  get_scratch(&new->z,t,0,0);
+  tmp1=new->z;
+  if((new->q1.flags&(KONST|DREFOBJ))==KONST){
+    calc(AND,new->typf,&new->q1.val,&new->q2.val,&new->q1.val,0);
+    new->code=ASSIGN;
+    new->q2.flags=0;
+    new->q2.val.vmax=sizetab[new->typf&NQ];
+  }
+  *val=tmp1;
+  vmerk=val->flags;
+  tmp1.flags&=~SCRATCH;
+  add_IC(new);
+  if(bfo!=0){
+    new=new_IC();
+    new->code=LSHIFT;
+    new->typf=t;
+    new->typf2=INT;
+    new->q1=tmp1;
+    new->q2.flags=KONST;
+    new->q2.val.vint=zm2zi(l2zm((long)bfo));
+    get_scratch(&new->z,t,0,0);
+    tmp3=new->z;
+    add_IC(new);
+  }else{
+    tmp3=tmp1;
+  }
+  if(!isclear){
+    new=new_IC();
+    new->code=AND;
+    new->typf=t;
+    new->q1=*dest;
+    new->q1.flags&=~SCRATCH;
+    new->q2.flags=KONST;
+    gval.vmax=zmkompl(zmlshift(zmsub(zmlshift(l2zm(1L),l2zm((int)bfs)),l2zm(1L)),l2zm((long)bfo)));
+    eval_const(&gval,MAXINT);
+    insert_const(&new->q2.val,t);
+    get_scratch(&new->z,t,0,0);
+    tmp2=new->z;
+    add_IC(new);
+  }
+  new=new_IC();
+  new->code=OR;
+  new->typf=t;
+  if(isclear)
+    new->q1=*dest;
+  else
+    new->q1=tmp2;
+  new->q2=tmp3;
+  new->z=*dest;
+  add_IC(new);
+  if(dest->flags&(REG|SCRATCH)) free_reg(dest->reg);
+  val->flags=vmerk;
+}
+
+void inline_memcpy(np z,np q,zmax size)
+/*  fuegt ein ASSIGN-IC ein, das memcpy(z,q,size) entspricht    */
+{
+    IC *new=new_IC();
+    if(!ISPOINTER(z->ntyp->flags)) {error(39);return;}
+    if(!ISPOINTER(q->ntyp->flags)) {error(39);return;}
+
+    if(z->flags==ADDRESS||z->flags==ADDRESSA||z->flags==ADDRESSS){
+      gen_IC(z,0,0);
+      new->z=z->left->o;
+      if(z->flags!=ADDRESSS&&z->left->flags==IDENTIFIER&&is_vlength(z->left->ntyp)){
+	/* variable length array */
+	new->z.flags|=DREFOBJ;
+	new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+      }
+    }else{
+      gen_IC(z,0,0);
+      if(z->o.flags&DREFOBJ){
+        IC *n2=new_IC();
+        n2->code=ASSIGN;
+        n2->typf=q->ntyp->flags;
+        n2->q1=z->o;
+        get_scratch(&n2->z,z->ntyp->flags,z->ntyp->next->flags,z->ntyp);
+        n2->q2.flags=0;
+        n2->q2.val.vmax=sizetab[POINTER_TYPE(z->ntyp->next)];
+        new->z=n2->z;
+        add_IC(n2);
+      }else{
+        new->z=z->o;
+      }
+      if(new->z.flags&VARADR){
+	new->z.flags&=~VARADR; 
+      }else{
+	new->z.flags|=DREFOBJ;
+	new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+      }
+    }
+    if(z->ntyp->next->flags&VOLATILE){
+      if(new->z.flags&DREFOBJ)
+	new->z.dtyp|=PVOLATILE;
+    }
+    if(q->flags==ADDRESS||q->flags==ADDRESSA||q->flags==ADDRESSS){
+      gen_IC(q,0,0);
+      new->q1=q->left->o;
+      if(q->flags!=ADDRESSS&&q->left->flags==IDENTIFIER&&is_vlength(q->left->ntyp)){
+	/* variable length array */
+	new->q1.flags|=DREFOBJ;
+	new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+      }
+    }else{    
+      gen_IC(q,0,0);
+      if(q->o.flags&DREFOBJ){
+        IC *n2=new_IC();
+        n2->code=ASSIGN;
+        n2->typf=q->ntyp->flags;
+        n2->q1=q->o;
+        get_scratch(&n2->z,q->ntyp->flags,q->ntyp->next->flags,q->ntyp);
+        n2->q2.flags=0;
+        n2->q2.val.vmax=sizetab[POINTER_TYPE(q->ntyp->next)];
+
+        new->q1=n2->z;
+        add_IC(n2);
+      }else{
+        new->q1=q->o;
+      }
+      if(new->q1.flags&VARADR){
+	new->q1.flags&=~VARADR;
+      }else{
+	new->q1.flags|=DREFOBJ;
+	new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+      }
+    }
+    if(q->ntyp->next->flags&VOLATILE){
+      if(new->q1.flags&DREFOBJ)
+	new->q1.dtyp|=PVOLATILE;
+    }
+    new->code=ASSIGN;
+    new->typf=UNSIGNED|CHAR;
+    new->q2.flags=0;
+    new->q2.val.vmax=size;
+
+    if(!zmeqto(size,Z0))
+      add_IC(new);
+}
+
+void add_IC(IC *new)
+/*  fuegt ein IC ein                                            */
+{
+    int code;
+    if(!new) return;
+    if(nocode) {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      /*free(new);*/ /* building a list to free later would be nice... */
+      return;
+    }
+    new->next=0;
+    new->q1.am=new->q2.am=new->z.am=0;
+    new->line=line; new->file=filename;
+    code=new->code;
+    if(code>=BEQ&&code<=BRA) new->q1.flags=new->q2.flags=new->z.flags=0;
+    if(code==ALLOCREG||code==FREEREG||code==SAVEREGS||code==RESTOREREGS) new->typf=0;
+    if(DEBUG&64){ pric(stdout,first_ic);printf("new\n");pric2(stdout,new);printf("-\n");}
+    if(new->q1.flags&VAR){
+        if(!new->q1.v) 
+	  ierror(0);
+        new->q1.v->flags|=USEDASSOURCE;
+        if(code==ADDRESS||(new->q1.flags&VARADR))
+	  if(!is_vlength(new->q1.v->vtyp))
+	    new->q1.v->flags|=USEDASADR;
+        new->q1.v->priority+=currentpri;
+    }
+    if(new->q2.flags&VAR){
+        if(!new->q2.v) ierror(0);
+        new->q2.v->flags|=USEDASSOURCE;
+        if(code==ADDRESS||(new->q2.flags&VARADR))
+   	  if(!is_vlength(new->q2.v->vtyp))
+	    new->q2.v->flags|=USEDASADR;
+        new->q2.v->priority+=currentpri;
+    }
+    if(new->z.flags&VAR){
+        if(!new->z.v) ierror(0);
+        if(new->z.flags&DREFOBJ)
+	  new->z.v->flags|=USEDASSOURCE;
+	else
+	  new->z.v->flags|=USEDASDEST;
+        new->z.v->priority+=currentpri;
+    }
+    if(block_vla[nesting]){
+      /* special handling for blocks with variable-length arrays */
+      llist *p;
+      if(new->code==LABEL){
+	p=mymalloc(LSIZE);
+	p->label=new->typf;
+	p->next=vladeflabels[nesting];
+	vladeflabels[nesting]=p;
+      }else if(0&&new->code==BRA&&!(new->flags&LOOP_COND_TRUE)){
+	p=mymalloc(LSIZE);
+	p->label=new->typf;
+	p->next=vlajmplabels[nesting];
+	vlajmplabels[nesting]=p;
+	p=vladeflabels[nesting];
+	while(p){
+	  if(p->label==new->typf)
+	    break;
+	  p=p->next;
+	}
+	if(!p){ 
+	  /* label not declared in this block so far;
+	     re-adjust stack, but store the position - label may be
+	     declared later in the same block and adjustement must be
+	     removed */
+	  vlaadjust_list *vl;
+	  IC *first;
+	  first=last_ic;
+	  freevl();
+	  first=first->next;
+	  vl=mymalloc(sizeof(*vl));
+	  vl->branch=new;
+	  vl->first=first;
+	  vl->next=vlaadjusts[nesting];
+	  vlaadjusts[nesting]=vl;
+	}
+      }
+    }
+    if(/*(c_flags_val[0].l&2)&&*/code==LABEL){
+    /*  entfernt Spruenge zu direkt folgenden Labels    */
+        IC *p=last_ic;
+        while(p){
+            if(p->typf==new->typf&&p->code>=BEQ&&p->code<=BRA){
+                IC *n;
+		if(p->code!=BRA){
+		  IC *cmp=p->prev;
+		  while(cmp&&cmp->code==FREEREG) cmp=cmp->prev;
+		  if(cmp->code==TEST){
+		    if(is_volatile_obj(&cmp->q1))
+		      break;
+		    else{
+		      if(DEBUG&1) printf("preceding test removed\n");
+		      remove_IC(cmp);
+		    }
+		  }else if(cmp->code==COMPARE){
+		    if(is_volatile_obj(&cmp->q1)||is_volatile_obj(&cmp->q2))
+		      break;
+		    else{
+		      if(DEBUG&1) printf("preceding compare removed\n");
+		      remove_IC(cmp);
+		    }
+		  }else
+		    break;
+		}
+		if(vlaadjusts[nesting]){
+		  /* remove it from vlaadjusts-lists, if necessary */
+		  vlaadjust_list *vl=vlaadjusts[nesting];
+		  while(vl){
+		    if(vl->branch==p){
+		      IC *np=vl->branch->prev;
+		      while(np!=vl->first->prev){
+			if(!np) ierror(0);
+			np->code=NOP;
+			np->q1.flags=np->q2.flags=np->z.flags=0;
+			np=np->prev;
+		      }
+		      vl->branch=0;
+		    }
+		    vl=vl->next;
+		  }
+		}
+                if(DEBUG&1) printf("%s l%d deleted\n",ename[p->code],p->typf);
+                n=p->next;
+                remove_IC(p);
+                p=n;
+            }else{
+                if(p->code!=LABEL) break;
+                p=p->prev;
+            }
+        }
+    }
+    if(last_ic){
+        if(code==ASSIGN){
+            if((last_ic->z.flags&(REG|SCRATCH|DREFOBJ))==(REG|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.reg==new->q1.reg/*&&last_ic->code!=CALL*/){
+                if(USEQ2ASZ||!(last_ic->q2.flags&REG)||!(new->z.flags&REG)||last_ic->q2.reg!=new->z.reg){
+                    if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+                    /*  verbindet op a,b->reg,move reg->c zu op a,b->c  */
+                    /*  hier fehlt aber noch Registerfreigabe           */
+                        last_ic->z=new->z;
+                        if(DEBUG&1) printf("move and op combined\n");
+                        if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
+                            free_reg(new->q1.reg);
+                        free(new);
+                        return;
+                    }
+                }
+            }
+            if((last_ic->z.flags&(VAR|SCRATCH|DREFOBJ))==(VAR|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.v==new->q1.v/*&&last_ic->code!=CALL*/){
+                if(USEQ2ASZ||!(last_ic->q2.flags&REG)||!(new->z.flags&REG)||last_ic->q2.reg!=new->z.reg){
+                    if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+                    /*  verbindet op a,b->scratch,move scratch->c zu op a,b->c  */
+                    /*  hier fehlt aber noch Registerfreigabe           */
+                        last_ic->z=new->z;
+                        if(DEBUG&1) printf("move and op combined(2)\n");
+/*                        if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
+                            free_reg(new->q1.reg);*/
+                        free(new);
+                        return;
+                    }
+                }
+            }
+
+        }
+        if(last_ic->code==BRA){
+            if(!dontdelete&&code!=LABEL&&code!=ALLOCREG&&code!=FREEREG){
+            /*  loescht alles nach bra bis ein Label kommt  */
+            /*  momentan noch nicht perfekt, da es bei alloc/freereg stoppt */
+                free(new);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+                if(DEBUG&1) printf("Unreachable Statement deleted\n");
+                return;
+            }
+            if(last_ic->prev&&code==LABEL){
+            /*  ersetzt bcc l1;bra l2;l1 durch b!cc l2      */
+                if(last_ic->prev->code>=BEQ&&last_ic->prev->code<=BGT&&new->typf==last_ic->prev->typf){
+		  if(last_ic->next) pric2(stdout,last_ic->next);
+                    if(DEBUG&1) printf("%s l%d;%s l%d; substituted\n",ename[last_ic->prev->code],last_ic->prev->typf,ename[last_ic->code],last_ic->typf);
+                    if(last_ic->prev->code&1) 
+		      last_ic->prev->code--;
+		    else
+		      last_ic->prev->code++;
+                    last_ic->prev->typf=last_ic->typf;
+                    last_ic=last_ic->prev;
+		    free(last_ic->next);
+                    last_ic->next=new;new->prev=last_ic;
+                    last_ic=new;
+                    return;
+                }
+            }
+        }
+/*        }*/
+        new->prev=last_ic;
+        last_ic->next=new;
+        last_ic=new;
+    }else{
+        last_ic=new;first_ic=new;new->prev=0;
+    }
+    ic_count++;
+
+#if HAVE_POF2OPT
+    if(((new->code==MULT)||((new->code==DIV||new->code==MOD)&&(new->typf&UNSIGNED)))&&(new->q2.flags&KONST)&&ISINT(new->typf)){
+      /*  ersetzt mul etc. mit Zweierpotenzen     */
+      long ln;
+      eval_const(&new->q2.val,new->typf);
+      if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	if(ln=get_pof2(vumax)){
+	  if(new->code==MOD){
+	    vmax=zmsub(vmax,l2zm(1L));
+	    new->code=AND;
+	  }else{
+	    if(new->code==DIV) new->code=RSHIFT; else new->code=LSHIFT;
+	    vmax=l2zm(ln-1);
+	  }
+	  gval.vmax=vmax;
+	  eval_const(&gval,MAXINT);
+	  insert_const(&new->q2.val,new->typf);
+	  new->typf2=new->typf;
+	}
+      }
+    }
+#endif
+
+    /*  Merken, on Fliesskomma benutzt wurde    */
+    if(code!=LABEL&&(code<BEQ||code>BRA)){
+        if(ISFLOAT(new->typf)) float_used=1;
+        if(code==CONVERT&&ISFLOAT(new->typf2)) float_used=1;
+    }
+    if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(!(new->z.flags&REG)||new->q1.reg!=new->z.reg))
+        free_reg(new->q1.reg);
+    if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(!(new->z.flags&REG)||new->q2.reg!=new->z.reg))
+        free_reg(new->q2.reg);
+}
+
+np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2)
+/* generate call to a library function (emulate operation) */
+{
+  np new; 
+  argument_list *al=0,*t;
+  new=new_node();
+  new->flags=CALL;
+  new->right=0;
+  new->left=new_node();
+  new->left->flags=IDENTIFIER;
+  new->left->left=new->left->right=0;
+  new->left->identifier=add_identifier(fname,strlen(fname));
+  new->left->ntyp=0;
+  new->left->sidefx=0;
+  new->left->val.vmax=l2zm(0L); 
+  new->alist=0;
+  if(arg1){
+    al=mymalloc(sizeof(*al));
+    if(postop_obj){
+      al->arg=new_node();
+      al->arg->o=*postop_obj;
+      al->arg->ntyp=new_typ();
+      al->arg->ntyp->flags=postop_type;
+      al->arg->flags=REINTERPRET;
+    }else
+      al->arg=arg1;
+    al->next=0;
+    if(t1){
+      np cnv=new_node();
+      cnv->flags=CAST;
+      cnv->left=arg1;
+      cnv->right=0;
+      cnv->ntyp=t1;
+      al->arg=cnv;
+    }
+  }
+  if(arg2){
+    t=mymalloc(sizeof(*t));
+    t->arg=arg2;
+    t->next=0;
+    al->next=t;
+    if(t2){
+      np cnv=new_node();
+      cnv->flags=CAST;
+      cnv->left=arg2;
+      cnv->right=0;
+      cnv->ntyp=t2;
+      t->arg=cnv;
+    }
+  }
+  new->alist=al;
+  /* Kann man type_expr nochmal auf die Argumente anwenden? */
+  if(t1||t2)
+    no_cast_free=1;
+  if(!type_expression(new,0))
+    ierror(0); 
+  no_cast_free=0;
+  gen_IC(new,0,0);
+  return new;
+}
+
+
+void gen_IC(np p,int ltrue,int lfalse)
+/*  Erzeugt eine IC-Liste aus einer expression      */
+{
+    IC *new; regargs_list *rl;
+    if(!p) return;
+
+    if(p->flags==STRING){
+        Var *v=0;
+	if(merge_strings){
+	  for(v=first_var[0];v;v=v->next){
+	    if(v->vtyp->flags==ARRAY&&(v->vtyp->next->flags&STRINGCONST)&&zmleq(p->ntyp->size,v->vtyp->size)){
+	      zmax i;const_list *cl1=p->cl,*cl2=v->clist;
+	      for(i=Z0;!zmleq(p->ntyp->size,i)&&cl1&&cl2;cl1=cl1->next,cl2=cl2->next,i=zmadd(i,Z1)){
+		if(!zumeqto(zuc2zum(cl1->other->val.vuchar),zuc2zum(cl2->other->val.vuchar)))
+		  break;
+	      }
+	      if(zmleq(p->ntyp->size,i)) break;
+	    }
+	  }
+	}
+	if(!v){
+	  p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,p->cl);
+	  p->o.v->flags|=DEFINED;
+	}else
+	  p->o.v=v;
+        p->o.flags=VAR;
+        p->o.reg=0;
+        p->o.val=p->val;
+        return;
+    }
+    if(p->flags==LITERAL){
+      int sc;
+      if(nesting==0||(is_const(p->ntyp)&&zmeqto(p->val.vmax,l2zm(0L))))
+	sc=STATIC;
+      else
+	sc=AUTO;
+      p->o.v=add_var(empty,clone_typ(p->ntyp),sc,p->cl);
+      p->o.v->flags|=DEFINED;
+      p->o.flags=VAR;
+      p->o.reg=0;
+      p->o.val.vmax=l2zm(0L);
+      if(sc==AUTO)
+	init_local_compound(p->o.v);
+      return;
+    }
+    if(p->flags==IDENTIFIER){
+/*        p->o.v=find_var(p->identifier,0);*/
+        p->o.flags=VAR;
+        p->o.reg=0;
+        p->o.val=p->val;
+        return;
+    }
+    if(p->flags==CEXPR||p->flags==PCEXPR){
+        if(p->left){
+            if(p->left->flags==POSTINC) p->left->flags=PREINC;
+            if(p->left->flags==POSTDEC) p->left->flags=PREDEC;
+            gen_IC(p->left,0,0);
+            if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+        }
+        if(p->right){
+            if(p->right->flags==POSTINC) p->right->flags=PREINC;
+            if(p->right->flags==POSTDEC) p->right->flags=PREDEC;
+            gen_IC(p->right,0,0);
+            if((p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->right->o.reg);
+        }
+        p->o.flags=KONST;
+        p->o.val=p->val;
+        p->o.reg=0;
+        return;
+    }
+    if(p->flags==KOMMA){
+        if(p->left->sidefx){
+            gen_IC(p->left,0,0);
+            if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+        }else if(!(p->left->ntyp->flags&VOLATILE)) 
+	  error(129);
+        gen_IC(p->right,0,0);
+        p->o=p->right->o;
+        return;
+    }
+    if(p->flags==REINTERPRET){
+      if(p->left){
+	gen_IC(p->left,0,0);
+	p->o=p->left->o;
+      }
+      /* if no left, do nothing, use just object */
+      return;
+    }
+    if(p->flags==CAST){
+      gen_IC(p->left,0,0);
+      if((p->ntyp->flags&NQ)==VOID){
+	if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+	p->o.flags=0;
+      }else{
+	if(ISPOINTER(p->ntyp->flags)&&(p->ntyp->next->flags&VOLATILE))
+	  volatile_convert=1;
+	convert(p->left,p->ntyp->flags);
+	if(volatile_convert){
+	  if((p->left->o.flags&VAR)&&p->left->o.v->vtyp->next)
+	    p->left->o.v->vtyp->next->flags|=VOLATILE;
+	  volatile_convert=0;
+	}
+	p->o=p->left->o;
+      }
+      return;
+    }
+    if(p->flags==FIRSTELEMENT){
+        gen_IC(p->left,0,0);
+        p->o=p->left->o;
+        return;
+    }
+
+#if HAVE_POF2OPT
+    if(((p->flags==MULT||p->flags==PMULT)||((p->flags==DIV||p->flags==MOD)&&(p->ntyp->flags&UNSIGNED)))&&(p->right->flags==CEXPR||p->right->flags==PCEXPR)&&ISINT(p->ntyp->flags)){
+      /*  ersetzt mul etc. mit Zweierpotenzen     */
+      long ln;
+      eval_constn(p->right);
+      if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	if(ln=get_pof2(vumax)){
+	  if(p->flags==MOD){
+	    vmax=zmsub(vmax,l2zm(1L));
+	    p->flags=AND;
+	  }else{
+	    if(p->flags==DIV) p->flags=RSHIFT; else p->flags=LSHIFT;
+	    vmax=l2zm(ln-1);
+	  }
+	  gval.vmax=vmax;
+	  eval_const(&gval,MAXINT);
+	  insert_constn(p->right);
+	}
+      }
+    }
+#endif
+
+#if HAVE_LIBCALLS
+    if(!(optflags&2)){
+      char *libname;
+      if(libname=use_libcall_wrap(p->flags,p->ntyp->flags,0)){
+	np lc;type *t1,*t2;
+	if(p->flags==LSHIFT||p->flags==RSHIFT){
+	  t1=clone_typ(p->ntyp);
+	  t2=new_typ();
+	  t2->flags=INT;
+	}else{
+	  if(p->right){
+	    t1=arith_typ(p->left->ntyp,p->right->ntyp);
+	    t2=clone_typ(t1);
+	  }else{
+	    t1=arith_typ(p->left->ntyp,p->left->ntyp);
+	    t2=0;
+	  }
+	}
+	lc=gen_libcall(libname,p->left,t1,p->right,t2);
+	*p=*lc;
+	free(lc);
+	return;
+      }
+    }
+#endif
+    new=new_IC();
+    new->typf=p->ntyp->flags;
+    new->q1.reg=new->q2.reg=new->z.reg=0;
+    new->q1.flags=new->q2.flags=new->z.flags=0;
+    if((p->flags>=LSHIFT&&p->flags<=MOD)||(p->flags>=OR&&p->flags<=AND)||p->flags==PMULT){
+      do_arith(p,new,0,0);
+      return;
+    }
+    if(p->flags==CONTENT){
+        gen_IC(p->left,0,0);
+        if(p->left->o.flags&VARADR){
+            free(new);
+            p->o=p->left->o;
+            p->o.flags&=~VARADR;
+            return;
+        }
+        if(!(p->left->o.flags&DREFOBJ)){
+            free(new);
+            p->o=p->left->o;
+            p->o.flags|=DREFOBJ;
+	    p->o.dtyp=p->left->ntyp->flags;
+        }else{
+          if((p->left->o.flags&SCRATCH)&&p->left->o.dtyp==POINTER_TYPE(p->ntyp)){
+            new->z=p->left->o;
+            new->z.flags&=~DREFOBJ;
+          }else{
+            get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags,p->left->ntyp);
+          }
+          new->code=ASSIGN;new->typf=POINTER_TYPE(p->ntyp);
+          new->q1=p->left->o;
+          new->q2.val.vmax=sizetab[new->typf&NQ];
+          p->o=new->z;
+          add_IC(new);
+          p->o.flags|=DREFOBJ;
+	  p->o.dtyp=POINTER_TYPE(p->ntyp);
+        }
+	if(p->left->ntyp->next->flags&VOLATILE) p->o.dtyp|=PVOLATILE;
+        return;
+    }
+    if(p->flags==ASSIGN){
+      if(p->left->flags==BITFIELD){
+        gen_IC(p->right,0,0);
+        gen_IC(p->left->left,0,0);
+        convert(p->right,p->ntyp->flags);
+        insert_bitfield(&p->left->left->o,&p->right->o,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags&NU,0);
+        return;
+      }
+      new->code=ASSIGN;
+      gen_IC(p->right,0,0);
+      gen_IC(p->left,0,0);
+      convert(p->right,p->ntyp->flags);
+      new->q1=p->right->o;
+      new->z=p->left->o;
+      new->q2.val.vmax=szof(p->left->ntyp);
+      p->o=new->z;
+      if(!ISSCALAR(p->ntyp->flags))
+	new->typf2=zm2l(falign(p->ntyp));
+      add_IC(new);
+      return;
+    }
+    if(p->flags==ASSIGNOP){
+    /*  das hier ist nicht besonders schoen */
+      obj o,q;IC *n;int f;char *libname;
+      np lc;
+      if(p->right->right==0){
+        /*  sowas wie a+=0 wurde wegoptimiert   */
+	free(new);
+	p->o=p->left->o;
+	return;
+      }
+#if HAVE_LIBCALLS
+      if(libname=use_libcall_wrap(p->right->flags,p->right->ntyp->flags,(p->right->flags==LSHIFT||p->right->flags==RSHIFT)?INT:0)){
+	type *t1,*t2;
+	np a1;
+	gen_IC(p->left,0,0);
+	a1=new_node();
+	a1->o=p->left->o;
+	a1->flags=REINTERPRET;
+	a1->o.flags&=~SCRATCH;
+	a1->ntyp=clone_typ(p->left->ntyp);
+	t1=clone_typ(p->right->ntyp);
+	if(p->right->flags==LSHIFT||p->right->flags==RSHIFT){
+	  t2=new_typ();
+	  t2->flags=INT;
+	}else
+	  t2=clone_typ(t1);
+	lc=gen_libcall(libname,a1/*p->right->left*/,t1,p->right->right,t2);
+	/**p->right=*lc;*/
+	o=p->left->o;
+	free(a1);
+	/*p->left=0;*/
+	/*free(lc);*/
+      }else
+#endif
+	{
+	  lc=0;
+	  f=do_arith(p->right,new,p->left,&o);
+	  if(!f) ierror(0);
+	  if(f>1) ierror(0);
+	}
+      if((o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&!regs[o.reg])
+        keep_reg(o.reg);
+      if(lc)
+	convert(lc,p->ntyp->flags);
+      else
+	convert(p->right,p->ntyp->flags);
+      if(p->left&&p->left->flags==BITFIELD){
+	if(lc) ierror(0);
+        insert_bitfield(&p->left->left->o,&p->right->o,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags&NU,0);
+        if((p->right->o.flags&(REG|SCRATCH))==(REG|SCRATCH)&&regs[p->right->o.reg])
+          free_reg(p->right->o.reg);
+        return;
+      }
+      new=new_IC();
+      new->typf=p->ntyp->flags;
+      new->q2.flags=0;
+      new->code=ASSIGN;
+      if(lc){
+	new->q1=lc->o;
+	/*free(lc);*/
+      }else
+	new->q1=p->right->o;
+      new->z=o;
+      new->q2.val.vmax=szof(p->ntyp);
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    if(p->flags==MINUS||p->flags==KOMPLEMENT){
+      new->code=p->flags;
+      gen_IC(p->left,0,0);
+      convert(p->left,p->ntyp->flags);
+      if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->left->o.reg,p->ntyp->flags,0)){
+	new->z=p->left->o;
+	new->z.flags&=~DREFOBJ;
+      }else{
+	get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+      }
+      new->q1=p->left->o;
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    if(p->flags==ADDRESS||p->flags==ADDRESSA||p->flags==ADDRESSS){
+      if(p->flags!=ADDRESSS&&p->left->flags==IDENTIFIER&&is_vlength(p->left->ntyp)){
+	gen_IC(p->left,0,0);
+	if(!(p->left->o.flags&VAR))
+	  ierror(0);
+	free(new);
+	p->o=p->left->o;
+	return;
+      }
+      new->code=ADDRESS;
+      new->typf=p->left->ntyp->flags;
+      new->typf2=POINTER_TYPE(p->left->ntyp);
+      gen_IC(p->left,0,0);
+      if(p->left->o.flags&VAR) p->left->o.v->flags|=(USEDASSOURCE|USEDASDEST);
+      if(p->left->o.flags&DREFOBJ){
+	free(new);
+	p->o=p->left->o;
+	p->o.flags&=~DREFOBJ;
+	return;
+      }
+      if((p->left->o.flags&VAR)&&!(p->left->o.flags&VARADR)
+	 &&(p->left->o.v->storage_class==EXTERN||p->left->o.v->storage_class==STATIC)){
+	free(new);
+	p->o=p->left->o;
+	p->o.flags|=VARADR;
+	return;
+      }
+      new->q1=p->left->o;
+      get_scratch(&new->z,POINTER_TYPE(p->ntyp->next),p->ntyp->next->flags,0);
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    if(p->flags==LAND||p->flags==LOR){
+        int l1,l2,l3,l4;
+/*        printf("%s true=%d false=%d\n",ename[p->flags],ltrue,lfalse);*/
+
+	if(ISVECTOR(p->ntyp->flags)){
+	  do_arith(p,new,0,0);
+	  return;
+	}
+
+        l1=++label;
+	if(!ltrue) {l2=++label;l3=++label;l4=++label;}
+        if(!ltrue){
+	  if(p->flags==LAND)
+	    gen_IC(p->left,l1,l3);
+	  else 
+	    gen_IC(p->left,l3,l1);
+        }else{
+	  if(p->flags==LAND) 
+	    gen_IC(p->left,l1,lfalse);
+	  else 
+	    gen_IC(p->left,ltrue,l1);
+        }
+        if(p->left->o.flags!=0){
+            if(p->flags==LAND)
+                gen_test(&p->left->o,p->left->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+            else
+                gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+        }
+        gen_label(l1);
+        if(!ltrue){
+	  if(p->flags==LAND) 
+	    gen_IC(p->right,l2,l3);
+	  else
+	    gen_IC(p->right,l3,l2);
+        }else
+	  gen_IC(p->right,ltrue,lfalse);
+        if(p->right->o.flags!=0){
+            if(p->flags==LAND)
+                gen_test(&p->right->o,p->right->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+            else
+                gen_test(&p->right->o,p->right->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+        }
+        if(!ltrue){
+            gen_label(l2);
+            if(p->flags==LAND) gen_cond(&p->o,0,l3,l4); else gen_cond(&p->o,1,l3,l4);
+        }else{
+            new=new_IC();
+            new->code=BRA;
+            if(p->flags==LAND) new->typf=ltrue; else new->typf=lfalse;
+            add_IC(new);
+        }
+        if(ltrue) p->o.flags=0;
+        return;
+    }
+    if(p->flags==NEGATION){
+        int l1,l2,l3;
+	if(ISVECTOR(p->ntyp->flags)){
+	  gen_IC(p->left,0,0);
+	  if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->left->o.reg,p->ntyp->flags,0)){
+	    new->z=p->left->o;
+	    new->z.flags&=~DREFOBJ;
+	  }else{
+	    get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+	  }
+	  new->typf=p->left->ntyp->flags;
+	  new->q1=p->left->o;
+	  p->o=new->z;
+	  new->code=NEGATION;
+	  add_IC(new);
+	  return;
+	}
+        if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+        if(ltrue)
+	  gen_IC(p->left,lfalse,ltrue);
+	else
+	  gen_IC(p->left,l1,l3);
+        if(!p->left->o.flags){
+	  free(new);p->o.flags=0;
+        }else{
+            gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l1:lfalse));
+        }
+        if(ltrue){
+            new=new_IC();
+            new->code=BRA;
+            if(!ltrue) new->typf=l2; else new->typf=ltrue;
+            add_IC(new);
+            p->o.flags=0;
+        }else{
+            gen_label(l3);
+            gen_cond(&p->o,0,l1,l2);
+        }
+        return;
+    }
+    if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
+      int l1,l2,l3,tl,tr;
+      type *at=0;
+      char *libname;
+      if(ISVECTOR(p->ntyp->flags)){
+	do_arith(p,new,0,0);
+	return;
+      }
+      if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+      if(p->left->flags==CEXPR){
+        /*  Konstanten nach rechts  */
+	np merk;merk=p->left;p->left=p->right;p->right=merk;
+	if(p->flags==LESS) p->flags=GREATER;
+	else if(p->flags==LESSEQ) p->flags=GREATEREQ;
+	else if(p->flags==GREATER) p->flags=LESS;
+	else if(p->flags==GREATEREQ) p->flags=LESSEQ;
+      }
+#if HAVE_LIBCALLS
+      at=arith_typ(p->left->ntyp,p->right->ntyp);
+      if(libname=use_libcall_wrap(COMPARE,at->flags,0)){
+	new->q1=gen_libcall(libname,p->left,at,p->right,clone_typ(at))->o;
+	new->code=COMPARE;
+	new->typf=LIBCALL_CMPTYPE;
+	new->q2.flags=KONST;
+	gval.vmax=Z0;
+	eval_const(&gval,MAXINT);
+	insert_const(&new->q2.val,LIBCALL_CMPTYPE);
+      }else{
+#endif
+        new->code=COMPARE;
+        tl=p->left->ntyp->flags&NU;tr=p->right->ntyp->flags&NU;
+        if(p->right->flags==CEXPR&&ISINT(tr)&&ISINT(tl)&&zm2l(sizetab[tl&NQ])<=zm2l(sizetab[tr&NQ])&&((tl&NQ)>=INT||shortcut(COMPARE,tl))){
+	  int negativ;
+	  eval_constn(p->right);
+	  if(zmleq(vmax,l2zm(0L))) negativ=1; else negativ=0;
+	  if((tl&UNSIGNED)||(tr&UNSIGNED)) negativ=0;
+	  if((!negativ||zmleq(t_min(tl),vmax))&&(negativ||zumleq(vumax,t_max(tl)))){
+	    if((tl&UNSIGNED)||!(tr&UNSIGNED)||p->flags==EQUAL||p->flags==INEQUAL){
+	      convert(p->right,tl);
+	      tr=tl;
+	    }
+	  }
+        }
+        if(ISARITH(tl)&&(tl!=tr||!shortcut(COMPARE,tl))){
+	  type *t;
+	  t=arith_typ(p->left->ntyp,p->right->ntyp);
+	  new->typf=t->flags;
+	  freetyp(t);
+        }else{
+	  new->typf=p->left->ntyp->flags;
+        }
+        gen_IC(p->left,0,0);
+        convert(p->left,new->typf);
+        gen_IC(p->right,0,0);
+        convert(p->right,new->typf);
+        new->q1=p->left->o;
+        new->q2=p->right->o;
+        new->z.flags=0;
+	if(p->flags==EQUAL||p->flags==INEQUAL){
+	  /* generate TEST, if possible */
+	  if(new->q2.flags&KONST){
+	    eval_const(&new->q2.val,new->typf);
+	    if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+	      new->code=TEST;
+	      new->q2.flags=0;
+	    }
+	  }
+	}
+#if HAVE_LIBCALLS
+      }
+#endif
+      freetyp(at);
+      add_IC(new);
+      new=new_IC();
+      if(p->flags==EQUAL) new->code=BEQ;
+      if(p->flags==INEQUAL) new->code=BNE;
+      if(p->flags==LESS) new->code=BLT;
+      if(p->flags==LESSEQ) new->code=BLE;
+      if(p->flags==GREATER) new->code=BGT;
+      if(p->flags==GREATEREQ) new->code=BGE;
+      if(ltrue) new->typf=ltrue; else new->typf=l1;
+      add_IC(new);
+      if(ltrue){
+	new=new_IC();
+	new->code=BRA;
+	new->typf=lfalse;
+	add_IC(new);
+	p->o.flags=0;
+      }else{
+	gen_label(l3);
+	gen_cond(&p->o,1,l1,l2);
+      }
+      return;
+    }
+    if(p->flags==CALL){
+        int r=0,radrpush=0;
+	obj *op,cfunc,ret_obj;
+	zmax sz;
+        int mregs[MAXR+1];
+	IC *callic;
+#ifdef ORDERED_PUSH
+        IC *merk_fp,*lp;
+	unsigned int merk_opushed=opushed;
+#endif
+        if(p->left->flags==ADDRESS&&p->left->left->flags==IDENTIFIER){
+            Var *v;
+            gen_IC(p->left,0,0); r=1;
+            v=p->left->o.v;
+            if(v->fi&&v->fi->first_ic&&!cross_module&&(c_flags_val[0].l&4096)){
+            /*  function call inlining  */
+                argument_list *al;
+                Var *vp,**argl1,**argl2;
+                IC *ip;int lc;
+                int arg_cnt=0,i;
+                if(DEBUG&1024){
+                    printf("inlining call to <%s>\n",v->identifier);
+                    for(vp=v->fi->vars;vp;vp=vp->next)
+                        printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);
+                }
+                for(vp=v->fi->vars;vp;vp=vp->next){
+		  /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+		  if((zmeqto(vp->offset,l2zm(0L))||vp->reg)&&*vp->identifier&&(vp->storage_class==AUTO||vp->storage_class==REGISTER)) arg_cnt++;
+                }
+
+                /*  Argumente in die ersten Parametervariablen kopieren */
+                argl1=mymalloc(arg_cnt*sizeof(Var *));
+                argl2=mymalloc(arg_cnt*sizeof(Var *));
+
+                al=p->alist;vp=v->fi->vars;i=0;
+                while(al){
+		    /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+		    while(vp&&(!*vp->identifier||(!zmeqto(vp->offset,l2zm(0L))&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next;
+                    if(!vp){ error(39); break; }
+                    if(i>=arg_cnt) ierror(0);
+                    if(DEBUG&1024) printf("arg: %s(%ld)\n",vp->identifier,zm2l(vp->offset));
+                    argl1[i]=vp;
+                    argl2[i]=add_var(empty,clone_typ(vp->vtyp),vp->storage_class,0);
+                    if(!al->arg) ierror(0);
+                    gen_IC(al->arg,0,0);
+                    convert(al->arg,vp->vtyp->flags);
+                    new=new_IC();
+                    new->code=ASSIGN;
+                    new->q1=al->arg->o;
+                    new->q2.flags=0;
+                    new->q2.val.vmax=szof(vp->vtyp);
+                    new->z.flags=VAR;
+                    new->z.val.vmax=l2zm(0L);
+                    new->z.v=argl2[i];
+                    new->typf=vp->vtyp->flags;
+		    new->typf2=falign(vp->vtyp);
+                    add_IC(new);
+                    i++;
+                    al=al->next;
+                    vp=vp->next;
+                }
+                if(i<arg_cnt){ error(83); arg_cnt=i;}
+
+                /*  Kopien der Variablen erzeugen   */
+                for(vp=v->fi->vars;vp;vp=vp->next){
+                    vp->inline_copy=0;
+                }
+                for(i=0;i<arg_cnt;i++){
+                    if(argl1[i]){
+                        if(!argl2[i]) ierror(0);
+                        argl1[i]->inline_copy=argl2[i];
+                    }
+                }
+
+                /*  Rueckgabewert   */
+                if((p->ntyp->flags&NQ)!=VOID){
+                    p->o.flags=SCRATCH|VAR;
+                    p->o.reg=0;p->o.val.vmax=l2zm(0L);
+                    p->o.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+                }else{
+                    p->o.flags=0;
+                }
+
+                free(argl1);
+                free(argl2);
+
+                /*  Code einfuegen und Labels umschreiben   */
+                ip=v->fi->first_ic;lc=0;
+                while(ip){
+                    Var *iv;
+                    int c;
+                    new=new_IC();
+		    *new=*ip;
+		    ip->copy=new;
+                    c=ip->code;
+                    /*  evtl. ist ein IC praktisch ein SETRETURN, falls das */
+                    /*  Rueckgabeziel ueber Parameterzeiger angespr. wird   */
+                    if(ip->z.flags&VAR){
+                      iv=ip->z.v;
+                      if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+                        if(!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))){
+                          new->z=p->o;
+                        }else{
+                          if(!iv->inline_copy){
+                            iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+                            iv->inline_copy->reg=iv->reg;
+                          }
+                          new->z.v=iv->inline_copy;
+                        }/*else if(iv->inline_copy) ierror(0);*/
+                      }
+                    }
+                    /*  Kopien aller auto/register Variablen erzeugen   */
+                    if(ip->q1.flags&VAR){
+                      iv=ip->q1.v;
+                      if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+                        if(!iv->inline_copy){
+                          iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+                          iv->inline_copy->reg=iv->reg;
+                        }
+                        new->q1.v=iv->inline_copy;
+                      }/*else if(iv->inline_copy) ierror(0);*/
+                    }
+                    if(ip->q2.flags&VAR){
+                      iv=ip->q2.v;
+                      if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+                        if(!iv->inline_copy){
+                          iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+                          iv->inline_copy->reg=iv->reg;
+                        }
+                        new->q2.v=iv->inline_copy;
+                      }/*else if(iv->inline_copy) ierror(0);*/
+                    }
+                    if(c==CALL){
+		      int i;
+		      function_calls+=currentpri;
+		      new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+		      for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy;
+		    }
+                    if(c==LABEL||(c>=BEQ&&c<=BRA)){
+                        if(new->typf>lc) lc=new->typf;
+                        new->typf+=label;
+                    }
+                    if(c==SETRETURN){
+                        new->code=ASSIGN;
+                        new->z=p->o;
+                    }
+		    add_IC(new);
+                    ip=ip->next;
+                }
+                label+=lc;
+                return;
+            }
+            /*  einige spezielle Inline-Funktionen; das setzt voraus, dass  */
+            /*  diese in den Headerfiles passend deklariert werden          */
+            if(v->storage_class==EXTERN){
+	        if((optflags&2)&&(!strcmp(v->identifier,"strlen")||!strcmp(v->identifier,"__asm_strlen"))&&p->alist&&p->alist->arg){
+                    np n=p->alist->arg;
+                    if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+                        const_list *cl;zumax len=ul2zum(0UL);
+                        cl=n->left->cl;
+                        while(cl){
+			  if(zmeqto(l2zm(0L),zc2zm(cl->other->val.vchar))) break;
+			  len=zumadd(len,ul2zum(1UL));
+			  cl=cl->next;
+                        }
+                        p->o.val.vumax=len;
+                        eval_const(&p->o.val,UNSIGNED|MAXINT);
+                        insert_constn(p);
+                        insert_const(&p->o.val,p->ntyp->flags);
+                        p->flags=CEXPR;
+                        p->o.flags=KONST;
+                        return;
+                    }
+                }
+
+                if(inline_memcpy_sz>0&&(optflags&2)){
+		    if((!strcmp(v->identifier,"strcpy")||!strcmp(v->identifier,"__asm_strcpy"))&&p->alist&&p->alist->next&&p->alist->next->arg){
+                        np n=p->alist->next->arg;
+                        if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+                            const_list *cl;zmax len=l2zm(0L);
+                            cl=n->left->cl;
+                            while(cl){
+                                len=zmadd(len,l2zm(1L));
+                                if(zmeqto(zc2zm(cl->other->val.vchar),l2zm(0L))) break;
+                                cl=cl->next;
+                            }
+                            if(zmleq(len,l2zm((long)inline_memcpy_sz))){
+                                inline_memcpy(p->alist->arg,n,len);
+                                p->o=p->alist->arg->o;
+                                return;
+                            }
+                        }
+                    }
+                    if(!strcmp(v->identifier,"memcpy")||!strcmp(v->identifier,"__asm_memcpy")){
+                        if(p->alist&&p->alist->next&&p->alist->next->next
+                           &&p->alist->next->next->arg
+                           &&p->alist->next->next->arg->flags==CEXPR){
+                            eval_constn(p->alist->next->next->arg);
+                            if(zmleq(vmax,l2zm((long)inline_memcpy_sz))){
+                                inline_memcpy(p->alist->arg,p->alist->next->arg,vmax);
+                                p->o=p->alist->arg->o;
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        rl=0;
+        if(!(optflags&2)){
+          int r;
+          for(r=1;r<=MAXR;r++){mregs[r]=regs[r];regs[r]&=~(RNOSAVE|RHALF);}
+        }else{
+	  gen_IC(p->left,0,0);
+	}
+#ifdef ORDERED_PUSH
+        merk_fp=first_pushed;
+        first_pushed=0;
+        lp=last_ic;
+#endif
+#ifdef HAVE_REGPARMS
+        if(!ffreturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){
+          IC *new2;static type ptyp={0};
+	  treg_handle reg_handle=empty_reg_handle;
+	  int reg;
+	  ptyp.next=p->ntyp;
+	  ptyp.flags=POINTER_TYPE(p->ntyp);
+	  reg=reg_parm(&reg_handle,&ptyp,0,p->left->ntyp->next);
+	  if(reg){
+	    new2=new_IC();
+	    new2->code=ADDRESS;
+	    new2->typf=p->ntyp->flags;
+	    new2->typf2=POINTER_TYPE(p->ntyp);
+	    new2->q1.flags=VAR;
+	    new2->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+	    new2->q1.val.vmax=l2zm(0L);
+	    op=&new2->q1;
+	    new2->q2.flags=0;
+	    get_scratch(&new2->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+	    ret_obj=new2->z;
+	    add_IC(new2);
+	    sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,&reg_handle,&ret_obj,p->ntyp,reg,p->left->ntyp);
+	    if(optflags&2)
+	      handle_reglist(rl,&ret_obj);
+	  }else{
+	    sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,&reg_handle,0,p->ntyp,reg,p->left->ntyp);
+	    radrpush=1;
+	    if(optflags&2)
+	      handle_reglist(rl,0);
+	  }
+	}else{
+	  treg_handle reg_handle=empty_reg_handle;
+	  sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,&reg_handle,0,0,-1,p->left->ntyp);
+	  if(optflags&2)
+	    handle_reglist(rl,0);
+	}
+#else
+        sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl);
+	if(optflags&2)
+	  handle_reglist(rl,0);
+#endif
+        if(!r&&!(optflags&2)) gen_IC(p->left,0,0);
+        if(!(p->left->o.flags&DREFOBJ)){
+            free(new);
+            p->o=p->left->o;
+            if(p->o.flags&VARADR){
+	      p->o.flags&=~VARADR;
+	    }else{
+	      p->o.flags|=DREFOBJ;
+	      p->o.dtyp=p->left->ntyp->flags;
+	    }
+        }else{
+            if(p->left->o.flags&VARADR){
+                free(new);
+                p->o=p->left->o;
+                p->o.flags&=~VARADR;
+            }else{
+                if((p->left->o.flags&SCRATCH)&&p->ntyp->flags==p->left->ntyp->flags){
+		  new->z=p->left->o;
+		  new->z.flags&=~DREFOBJ;
+                }else{
+		  get_scratch(&new->z,p->left->ntyp->flags,FUNKT,p->left->ntyp);
+                }
+                new->code=ASSIGN;
+		new->typf=p->left->ntyp->flags;
+                new->q1=p->left->o;
+                new->q2.val.vmax=sizetab[new->typf&NQ];
+                new->q2.flags=0;
+                p->o=new->z;
+                add_IC(new);
+                p->o.flags|=DREFOBJ;
+		p->o.dtyp=p->left->ntyp->flags;
+            }
+        }
+/*            p->left->o.flags-=DREFOBJ|VARADR; Was sollte das??    */
+
+#if 0
+        if(optflags&2){
+            while(rl){
+                regargs_list *m;
+                new=new_IC();
+                new->code=NOP;
+                new->q1.flags=VAR;
+                new->q1.v=rl->v;
+                new->q1.val.vmax=l2zm(0L);
+                new->typf=0;
+                new->q2.flags=new->z.flags=0;
+                add_IC(new);
+                m=rl->next;free(rl);rl=m;
+            }
+        }
+#endif
+
+        /*  gegebenenfalls Adresse des Ziels auf den Stack  */
+#ifdef HAVE_REGPARMS
+	if(radrpush)
+#else
+        if(!ffreturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID)
+#endif
+	{
+#if defined(ORDERED_PUSH) && defined(HAVE_REGPARMS)
+	  ierror(0);
+#endif
+	  new=new_IC();
+	  new->code=ADDRESS;
+	  new->typf=p->ntyp->flags;
+	  new->typf2=POINTER_TYPE(p->ntyp);
+	  new->q1.flags=VAR;
+	  new->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+	  new->q1.val.vmax=l2zm(0L);
+	  op=&new->q1;
+	  new->q2.flags=0;
+	  get_scratch(&new->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+	  ret_obj=new->z;
+	  add_IC(new);
+	  new=new_IC();
+	  new->code=PUSH;
+	  new->typf=POINTER_TYPE(p->ntyp);
+	  new->q1=ret_obj;
+	  new->q2.flags=new->z.flags=0;
+	  new->q2.val.vmax=sizetab[new->typf&NQ];
+	  new->z.val.vmax=new->q2.val.vmax;
+	  add_IC(new);
+	  sz=zmadd(sz,sizetab[new->typf&NQ]);
+        }
+
+        /*  Scratchregister evtl. sichern   */
+	cfunc=p->o;
+        if(!nocode)
+	  savescratch(MOVEFROMREG,last_ic,0,&cfunc);
+        function_calls+=currentpri;
+        new=new_IC();
+        new->code=CALL;
+	callic=new;
+	if(p->alist){
+	  /* insert list of argument ICs */
+	  int i=0;
+	  argument_list *a=p->alist;
+	  while(a){i++;a=a->next;}
+	  new->arg_cnt=i;
+	  new->arg_list=mymalloc(sizeof(*new->arg_list)*i);
+	  for(a=p->alist,i=0;a;a=a->next,i++) new->arg_list[i]=a->pushic;
+	}else{
+	  new->arg_cnt=0;
+	  new->arg_list=0;
+	}
+        new->typf=FUNKT;
+        new->q1=p->o;
+        new->q2.flags=new->z.flags=0;
+        new->q2.val.vmax=sz; /*  Groesse der Parameter auf dem Stack */
+        add_IC(new);
+
+	//pric2(stdout,new);
+
+        if(optflags&2){
+            while(rl){
+                regargs_list *m;
+                new=new_IC();
+                new->code=NOP;
+                new->q1.flags=VAR;
+                new->q1.v=rl->v;
+                new->q1.val.vmax=l2zm(0L);
+                new->typf=0;
+                new->q2.flags=new->z.flags=0;
+                add_IC(new);
+                m=rl->next;free(rl);rl=m;
+            }
+        }
+
+        r=0;
+        if((p->ntyp->flags&NQ)!=VOID){
+            new=new_IC();
+            new->code=GETRETURN;
+            new->q1.flags=new->q2.flags=0;
+            new->q1.reg=ffreturn(p->ntyp);
+            new->q2.val.vmax=szof(p->ntyp);
+            new->typf=p->ntyp->flags;
+            if(ffreturn(p->ntyp)){
+              int t=p->ntyp->flags&NQ;
+              if(ISSTRUCT(t)||ISUNION(t)){
+                new->z.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+                new->z.flags=VAR;
+                new->z.val.vmax=l2zm(0L);
+              }else{
+                if(optflags&2){
+                  get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+                }else{
+                  /* Suche geeignetes Register, um Rueckgabewert zu speichern. */
+                  regargs_list *l2;
+                  int r;
+                  r=new->q1.reg;
+                  if(regs[r]||!regok(r,p->ntyp->flags,0)||(reg_pair(r,&rp)&&(regs[rp.r1]||regs[rp.r2]))){
+                    r=0;
+                  }else{
+                    for(l2=rl;l2;l2=l2->next){
+                      if(l2->v&&abs(l2->reg)==r) {r=0;break;}
+                    }
+                  }
+                  if(r==0){
+                    for(r=1;r<=MAXR;r++){
+                      if(!regs[r]&&regok(r,p->ntyp->flags,0)&&(!reg_pair(r,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+                        for(l2=rl;l2;l2=l2->next){
+                          if(l2->v&&abs(l2->reg)==r) break;
+                        }
+                        if(l2) continue;
+                        break;
+                      }
+                    }
+                  }
+                  if(r>=1&&r<=MAXR){
+                    alloc_hardreg(r);
+                    new->z.flags=(REG|SCRATCH);
+                    new->z.reg=r;
+                  }else{
+                    get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+                  }
+                }
+              }
+            } else
+              new->z=*op;
+            if((new->z.flags&(REG|DREFOBJ))==REG) r=new->z.reg;
+            p->o=new->z;
+            add_IC(new);
+        }else{
+            p->o.flags=0;
+        }
+        /*  Scratchregister evtl. wiederherstellen  */
+        if(!nocode)
+	  savescratch(MOVETOREG,last_ic,r,&cfunc);
+        if(!(optflags&2)){
+          int r;
+          for(r=1;r<=MAXR;r++){
+            if(regs[r])
+              regs[r]|=(mregs[r]&RNOSAVE);
+          }
+        }
+        /*  Evtl. gespeicherte Registerargumente wiederherstellen.  */
+        while(rl){
+            regargs_list *m;
+            if(rl->v){
+	      int r;
+	      for(r=MAXR;r>=1;r--){
+		if(regs[r]&&reg_pair(r,&rp)&&(rp.r1==abs(rl->reg)||rp.r2==abs(rl->reg)))
+		  break;
+	      }
+	      if(r<=1) r=abs(rl->reg);
+	      new=new_IC();
+	      new->code=MOVETOREG;
+	      new->typf=0;
+	      new->q1.flags=VAR|DONTREGISTERIZE;
+	      new->q1.v=rl->v;
+	      new->q1.val.vmax=l2zm(0L);
+	      new->z.flags=REG;
+	      if(rl->rsaved)
+		new->z.reg=rl->rsaved;
+	      else
+		new->z.reg=abs(r);
+	      new->q2.flags=0;
+	      new->q2.val.vmax=regsize[r];
+	      add_IC(new);
+	      if(rl->rsaved)
+		free_reg(abs(rl->reg));
+            }else{
+	      free_reg(abs(rl->reg));
+	    }
+            m=rl->next;free(rl);rl=m;
+        }
+#ifdef ORDERED_PUSH
+        /* If arguments have been pushed nested we have to copy them and */
+        /* push them later. */
+        if(merk_fp&&opushed!=merk_opushed){
+          IC *p,*m=0,*np;
+          if(!lp) ierror(0);
+          for(p=merk_fp;p;){
+            np=p->next;
+            if(p->code==PUSH){
+              new=new_IC();
+              *new=*p;
+	      /* be careful about the address because of arg_list! */
+	      if(p->prev) p->prev->next=new;
+	      new->prev=p->prev;
+	      if(p->next) p->next->prev=new;
+	      new->next=p->next;
+	      if(p==last_ic) last_ic=new;
+	      if(p==first_ic) first_ic=new;
+              if(new->q1.flags&&!(p->flags&ORDERED_PUSH_COPY)){
+                new->code=ASSIGN;
+                new->z.flags=VAR;
+                new->z.val.vmax=l2zm(0L);
+		/* typ allocated in push_args and not used there */
+		/*		if(!p->ityp) ierror(0);*/
+		new->z.v=add_tmp_var(clone_typ(p->ityp)); /*FIXME??*/
+                p->q1=new->z;
+		/*		p->ityp=0;*/
+              }else{
+                remove_IC(new);
+              }
+	      p->next=p->prev=0;
+	      p->flags|=ORDERED_PUSH_COPY;
+              add_IC(p);
+              if(!m&&!nocode) m=p;
+            }
+            if(p==lp) break;
+            p=np;
+          }
+          if(!m) ierror(0);
+          first_pushed=m;
+        }else
+          first_pushed=merk_fp;
+#endif
+        return;
+    }
+    if(p->flags>=PREINC&&p->flags<=POSTDEC){
+        obj o;
+#if HAVE_LIBCALLS
+	char *libname;
+	node tn={ADD},one={CEXPR};
+#endif
+        gen_IC(p->left,0,0);
+        if((p->flags==POSTINC||p->flags==POSTDEC)){
+	  /*new=new_IC();*/
+            new->code=ASSIGN;
+            new->typf=p->ntyp->flags;
+            new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+            new->q1=p->left->o;
+	    postop_obj=&new->q1;
+	    postop_type=new->typf;
+            new->q1.flags&=~SCRATCH;
+            get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+            new->q2.flags=0;
+            o=new->z;
+            add_IC(new);
+            new=new_IC();
+        }else
+	  o=p->left->o;
+#if HAVE_LIBCALLS
+	if(p->flags==PREDEC||p->flags==POSTDEC)
+	  tn.flags=SUB;
+	tn.left=p->left;
+	tn.right=&one;
+	tn.ntyp=p->ntyp;
+	one.flags=CEXPR;
+	one.ntyp=p->ntyp;
+	gval.vmax=l2zm(1L);
+	eval_const(&gval,MAXINT);
+	insert_const(&one.val,p->ntyp->flags&NU);
+	if(libname=use_libcall_wrap(tn.flags,tn.ntyp->flags,0)){
+	  np lc;
+	  lc=gen_libcall(libname,p->left,0,&one,0);
+	  new=new_IC();
+	  new->code=ASSIGN;
+	  new->typf=p->ntyp->flags;
+	  new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+	  new->q1=lc->o;
+	  new->q1.flags&=~SCRATCH;
+	  new->z=p->left->o;
+	  add_IC(new);
+	  new=new_IC();
+	  free(lc);
+	}else
+#endif
+        if(ISPOINTER(p->left->ntyp->flags)){
+            if(p->flags==PREINC||p->flags==POSTINC)
+	      new->code=ADDI2P; 
+	    else
+	      new->code=SUBIFP;
+            vmax=szof(p->left->ntyp->next);
+            new->q2.val.vint=zm2zi(vmax);
+            new->typf=INT;
+	    new->typf2=p->left->ntyp->flags;
+            new->q1=p->left->o;
+            new->z=p->left->o;
+            new->q2.flags=KONST;
+            add_IC(new);
+        }else{
+            if(p->flags==PREINC||p->flags==POSTINC)
+	      new->code=ADD;
+	    else 
+	      new->code=SUB;
+            new->typf=p->ntyp->flags;
+            new->q1=p->left->o;
+            new->z=p->left->o;
+            new->q2.flags=KONST;
+	    gval.vint=zm2zi(l2zm(1L));
+	    eval_const(&gval,INT);
+	    insert_const(&new->q2.val,new->typf);
+            add_IC(new);
+        }
+        if(p->left->flags==BITFIELD){
+          insert_bitfield(&p->left->left->o,&new->z,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags,0);
+          if(p->flags!=POSTINC&&p->flags!=POSTDEC){
+            o=p->o;
+          }else{
+            if((p->o.flags&(REG|SCRATCH))==(REG|SCRATCH))
+              free_reg(p->o.reg);
+          }
+        }
+        if(p->flags==POSTINC||p->flags==POSTDEC||p->left->flags==BITFIELD){
+          if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) 
+            free_reg(p->left->o.reg);
+        }
+
+	postop_obj=0;
+        p->o=o;
+        return;
+    }
+    if(p->flags==COND){
+        int ltrue,lfalse,lout;
+        ltrue=++label;lfalse=++label;lout=++label;
+        gen_IC(p->left,ltrue,lfalse);
+        if(!p->left->o.flags){
+            free(new);
+        }else{
+            if(p->left->flags!=CEXPR){
+                gen_test(&p->left->o,p->left->ntyp->flags,BEQ,lfalse);
+            }else{
+                eval_constn(p->left);
+                if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+                    gen_IC(p->right->right,0,0);
+                    p->o=p->right->right->o;
+                }else{
+                    gen_IC(p->right->left,0,0);
+                    p->o=p->right->left->o;
+                }
+                return;
+            }
+        }
+        gen_label(ltrue);
+        gen_IC(p->right->left,0,0);
+        if((p->ntyp->flags&NQ)!=VOID){
+            convert(p->right->left,p->ntyp->flags);
+            if((p->right->left->o.flags&(SCRATCH|DREFOBJ))==SCRATCH){
+                p->o=p->right->left->o;
+            }else{
+                get_scratch(&p->o,p->ntyp->flags,0,p->ntyp);
+                new=new_IC();
+                new->code=ASSIGN;
+                new->q1=p->right->left->o;
+                new->z=p->o;
+                new->q2.flags=0;
+                new->q2.val.vmax=szof(p->ntyp);
+                new->typf=p->ntyp->flags;
+                p->o=new->z;
+                add_IC(new);
+            }
+        }else
+	  p->o.flags=0;
+        new=new_IC();
+        new->code=BRA;
+        new->typf=lout;
+        add_IC(new);
+        gen_label(lfalse);
+        gen_IC(p->right->right,0,0);
+        if((p->ntyp->flags&NQ)!=VOID){
+            convert(p->right->right,p->ntyp->flags);
+            new=new_IC();
+            new->code=ASSIGN;
+            new->q1=p->right->right->o;
+            new->z=p->o;
+            new->q2.flags=0;
+            new->q2.val.vmax=szof(p->ntyp);
+            new->typf=p->ntyp->flags;
+            add_IC(new);
+        }
+        gen_label(lout);
+        return;
+    }
+    if(p->flags==BITFIELD){
+      int lsc,rsc,bfo;
+      obj tmp;
+      bfo=bflayout(p->bfo,p->bfs,p->ntyp->flags);
+      lsc=zm2l(zmmult(sizetab[p->ntyp->flags&NQ],char_bit))-p->bfs-bfo;
+      rsc=lsc+bfo;
+      gen_IC(p->left,0,0);
+      new->code=LSHIFT;
+      new->typf=p->ntyp->flags;
+      new->typf2=INT;
+      new->q1=p->left->o;
+      new->q2.flags=KONST;
+      new->q2.val.vint=zm2zi(l2zm((long)lsc));
+      get_scratch(&new->z,new->typf,0,0);
+      tmp=new->z;
+      add_IC(new);
+      new=new_IC();
+      new->code=RSHIFT;
+      new->typf=p->ntyp->flags;
+      new->typf2=INT;
+      new->q1=tmp;
+      new->q2.flags=KONST;
+      new->q2.val.vint=zm2zi(l2zm((long)rsc));
+      new->z=tmp;
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    printf("Operation: %d=%s\n",p->flags,ename[p->flags]);
+    ierror(0);
+    free(new);
+    p->o.flags=0;
+}
+
+static void handle_reglist(regargs_list *nrl,obj *radr)
+{
+  IC *new;
+  /*  Letztes Argument; jetzt in Register laden.  */
+#ifdef HAVE_REGPARMS
+  int didradr=0;
+#endif
+  while(nrl){
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=nrl->v->vtyp->flags/*|VOLATILE*/;
+    new->q1.flags=VAR;
+    new->q1.v=nrl->v;
+    new->q1.val.vmax=l2zm(0L);
+    new->q2.flags=0;
+    new->q2.val.vmax=szof(nrl->v->vtyp);
+    new->z.flags=VAR;
+    new->z.val.vmax=l2zm(0L);
+    new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0);
+    new->z.v->reg=nrl->reg;
+    new->z.v->vtyp->flags|=VOLATILE;
+    nrl->v=new->z.v;
+    add_IC(new);
+    
+#ifdef HAVE_REGPARMS
+    if(radr&&!didradr){
+      didradr=1;
+    }else{
+#endif
+      nrl->al->pushic=new;
+      fix_pushic(&nrl->al->pushic,new);
+#ifdef HAVE_REGPARMS
+    }
+#endif
+    nrl=nrl->next;
+  }
+}
+
+#ifdef HAVE_REGPARMS
+zmax push_args(argument_list *al,struct_declaration *sd,int n,regargs_list **rl,treg_handle *reg_handle,obj *radr,type *rtype,int rreg,type *fkt)
+#else
+zmax push_args(argument_list *al,struct_declaration *sd,int n,regargs_list **rl)
+#endif
+/*  Legt die Argumente eines Funktionsaufrufs in umgekehrter Reihenfolge    */
+/*  auf den Stack. Es wird Integer-Erweiterung vorgenommen und float wird   */
+/*  nach double konvertiert, falls kein Prototype da ist.                   */
+{
+    int t,reg,regpush,evaluated=0;type *ft;
+    IC *new;regargs_list *nrl;zmax sz,rsz,of;obj *arg;
+#ifdef HAVE_REGPARMS
+    int stdreg;
+    if(!al&&!radr) return(0);
+    if(radr){
+      stdreg=rreg;
+    }else{
+      if(n<sd->count){
+        stdreg=reg_parm(reg_handle,(*sd->sl)[n].styp,0,fkt->next);
+      }else{
+        if(sd->count)
+          stdreg=reg_parm(reg_handle,al->arg->ntyp,1,fkt->next);
+        else{
+	  if(short_push&&ISINT(al->arg->ntyp->flags)){
+	    static type t;
+	    t.flags=int_erw(al->arg->ntyp->flags);
+	    stdreg=reg_parm(reg_handle,&t,0,fkt->next);
+	  }else{
+	    stdreg=reg_parm(reg_handle,al->arg->ntyp,0,fkt->next);
+	  }
+	}
+      }
+    }
+    reg=stdreg;
+#else
+    if(!al) return(0);
+    reg=0;
+#endif
+#ifdef HAVE_REGPARMS
+    if(!radr){
+#endif
+      if(!al->arg) ierror(0);
+      if(!sd) ierror(0);
+      if(n<sd->count){
+        ft=clone_typ((*sd->sl)[n].styp);sz=szof(ft);
+	t=ft->flags;
+        reg=(*sd->sl)[n].reg;
+      }else{
+        ft=clone_typ(al->arg->ntyp);sz=szof(ft);
+	t=ft->flags;
+      }
+      if(ISINT(t)){
+	if(n>=sd->count||!short_push)
+	  t=int_erw(t);
+	ft->flags=t;
+	sz=sizetab[t&NQ];
+      }
+      if((t&NQ)==FLOAT&&n>=sd->count) {t=DOUBLE;ft->flags=t;sz=sizetab[t&NQ];}
+#ifdef HAVE_REGPARMS
+    }else{
+      ft=new_typ();
+      ft->flags=t=POINTER_TYPE(rtype);
+      ft->next=clone_typ(rtype);
+      sz=sizetab[t&NQ];
+    }
+#endif
+    if(reg<0) {reg=-reg;regpush=1;} else regpush=0;
+    rsz=sz;
+    sz=zmmult(zmdiv(zmadd(sz,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+#ifdef ORDERED_PUSH
+    if(reg==0||regpush){
+      new=new_IC();
+#ifdef HAVE_REGPARMS
+      if(!radr&&!evaluated){
+#endif
+        gen_IC(al->arg,0,0);
+        convert(al->arg,t);
+        evaluated=1;
+        new->q1=al->arg->o;
+	al->pushic=new;
+#ifdef HAVE_REGPARMS
+      }else
+        new->q1=*radr;
+#endif
+      /*  Parameteruebergabe ueber Stack. */
+      new->code=PUSH;
+      new->typf=t;
+      new->ityp=ft;
+      new->q2.flags=new->z.flags=0;
+      new->q2.val.vmax=sz;
+      new->z.val.vmax=rsz;
+      if(regpush){
+        if(c_flags[26]&USEDFLAG){
+          new->q1.am=new->q2.am=new->z.am=0;
+          new->line=line; new->file=filename;
+          insert_IC(last_ic,new);
+        }else{
+          new->q1.flags=0;
+          add_IC(new);
+	  if(al) fix_pushic(&al->pushic,new);
+        }
+      }else{
+        add_IC(new);
+	if(al) fix_pushic(&al->pushic,new);
+      }
+      opushed++;
+      if(!first_pushed&&!nocode) first_pushed=new;
+      if(al&&!al->next&&!regpush) return sz;
+    }
+#endif
+#ifdef HAVE_REGPARMS
+    if(radr){
+      if(al) of=push_args(al,sd,0,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+    }else{
+      if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+    }
+#else
+    if(al->next) of=push_args(al->next,sd,n+1,rl); else of=l2zm(0L);
+#endif
+#ifdef ORDERED_PUSH
+    if(reg==0) return zmadd(of,sz);
+#endif
+
+    if(regpush) of=zmadd(of,sz);
+
+#ifdef HAVE_REGPARMS
+    if(radr){
+      arg=radr;
+    }else{
+      if(!evaluated){
+        gen_IC(al->arg,0,0);
+        convert(al->arg,t);
+        evaluated=1;
+      }
+      arg=&al->arg->o;
+    }
+#else
+    if(!evaluated){
+      gen_IC(al->arg,0,0);
+      convert(al->arg,t);
+      evaluated=1;
+    }
+    arg=&al->arg->o;
+#endif
+#ifndef ORDERED_PUSH
+    if(reg==0||regpush){
+        /*  Parameteruebergabe ueber Stack. */
+        new=new_IC();
+        new->code=PUSH;
+        new->typf=t;
+        new->q1=*arg;
+        if(regpush&&!(c_flags[26]&USEDFLAG)) new->q1.flags=0;
+        new->q2.flags=new->z.flags=0;
+        new->q2.val.vmax=sz;
+	new->z.val.vmax=rsz;
+        add_IC(new);
+	al->pushic=new;
+	fix_pushic(&al->pushic,new);
+        if(!regpush) return(zmadd(of,sz));
+    }
+#endif
+    if(reg){
+        /*  Parameteruebergabe in Register. */
+        Var *v=0; type *t2;
+	int rsaved=0;
+        if(optflags&2){
+        /*  Version fuer Optimizer. */
+            t2=new_typ();
+            t2->flags=t;
+            if(ISPOINTER(t)){
+                t2->next=new_typ();
+                t2->next->flags=VOID;
+            }
+            v=add_var(empty,t2,AUTO,0);
+            new=new_IC();
+            new->code=ASSIGN;
+            new->typf=t;
+            new->q1=*arg;
+            new->q2.flags=0;
+            new->q2.val.vmax=sizetab[t&NQ];
+            new->z.flags=VAR;
+            new->z.v=v;
+            new->z.val.vmax=l2zm(0L);
+            add_IC(new);
+            nrl=mymalloc(sizeof(*nrl));
+            nrl->next=*rl;
+            nrl->reg=reg;
+            nrl->v=v;
+	    nrl->al=al;
+            *rl=nrl;
+            return of;
+        }else{
+        /*  Nicht-optimierende Version. */
+
+	  if(DEBUG&16){
+	    printf("reg[%s]=%d ",regnames[reg],regs[reg]);
+	    if(reg_pair(reg,&rp))
+	      printf("reg[%s]=%d reg[%s]=%d ",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]);
+	    printf("\n");
+	  }
+	  if(reg_pair(reg,&rp)&&(arg->flags&(REG|SCRATCH))==(REG|SCRATCH)&&(arg->reg==rp.r1||arg->reg==rp.r2)){
+	    /* rx->reg_pair(rx,ry): make a copy */
+	    new=new_IC();
+	    new->code=ASSIGN;
+	    new->typf=t;
+	    new->q1=*arg;
+	    new->q2.flags=0;
+	    new->q2.val.vmax=sizetab[t&NQ];
+	    scratch_var(&new->z,t,0);
+	    add_IC(new);
+	    *arg=new->z;
+	    free_reg(arg->reg);
+	  }
+	  if(!regs[reg]&&(!reg_pair(reg,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))&&!nocode){
+	    new=new_IC();
+	    new->code=ALLOCREG;
+	    new->typf=0;
+	    new->q1.flags=REG;
+	    new->q1.reg=reg;
+	    new->q2.flags=new->z.flags=0;
+	    add_IC(new);
+	    regs[reg]=(1|RNOSAVE);regused[reg]++;
+	    if(DEBUG&16) printf("allocated %s (1)\n",regnames[reg]);
+	    if(reg_pair(reg,&rp)){
+	      regs[rp.r1]=1|RNOSAVE;regused[rp.r1]++;
+	      regs[rp.r2]=1|RNOSAVE;regused[rp.r2]++;
+	    }
+	  }else if(!regs[reg]&&reg_pair(reg,&rp)&&(regs[rp.r1]||regs[rp.r2])&&!nocode){
+	    int r=0;
+	    regargs_list *p;
+
+	    new=new_IC();
+	    new->code=ALLOCREG;
+	    new->typf=0;
+	    new->q1.flags=REG;
+	    new->q2.flags=new->z.flags=0;
+	    if(regs[rp.r1]){
+	      new->q1.reg=rp.r2;
+	      r=rp.r1;
+	      regs[r]|=RHALF;
+	    }else{
+	      new->q1.reg=rp.r1;
+	      r=rp.r2;
+	      regs[r]|=RHALF;
+	    }
+	    regs[new->q1.reg]=(1|RNOSAVE);regused[new->q1.reg]++;
+	    regs[reg]=(1|RNOSAVE);regused[reg]++;
+	    add_IC(new);
+	    if(DEBUG&16) printf("allocated %s (half)\n",regnames[new->q1.reg]);
+	    rsaved=r;
+	    /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+	    for(p=*rl;p;p=p->next){
+	      int ri;
+	      if(p->v&&(ri=abs(p->reg))){
+		if(ri==r) break;
+		if(reg_pair(ri,&rp)&&(rp.r1==r||rp.r2==r)) break;
+	      }
+	    }
+	    
+	    if(r&&!p){
+	      t2=clone_typ(regtype[r]);
+	      v=add_var(empty,t2,AUTO,0);
+	      v->flags|=USEDASADR;
+	      new=new_IC();
+	      new->code=MOVEFROMREG;
+	      new->typf=0;
+	      new->q1.flags=REG;
+	      new->q1.reg=r;
+	      new->q2.flags=0;
+	      new->q2.val.vmax=regsize[r];
+	      new->z.flags=VAR|DONTREGISTERIZE;
+	      new->z.v=v;
+	      new->z.val.vmax=l2zm(0L);
+	      add_IC(new);
+	    }
+	  }else{
+	    if((arg->flags&(REG|SCRATCH))!=(REG|SCRATCH)||arg->reg!=reg){
+	      int r=0;
+              regargs_list *p;
+
+	      /* register pairs */
+	      if(reg_pair(reg,&rp)){
+		if(regs[reg]||regs[rp.r1]||regs[rp.r2]) 
+		  r=reg;
+	      }else{
+		for(r=MAXR;r>=1;r--){
+		  if(regs[r]&&reg_pair(r,&rp)&&(rp.r1==reg||rp.r2==reg))
+		    break;
+		}
+		if(r<1) r=reg;
+	      }
+
+
+              /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+              for(p=*rl;p;p=p->next){
+                int ri;
+                if(p->v&&(ri=abs(p->reg))){
+                  if(ri==r||(reg_pair(r,&rp)&&(rp.r1==ri||rp.r2==ri))) {break;}
+                  if(reg_pair(ri,&rp)&&(rp.r1==r||rp.r2==r)) {break;}
+                }
+              }
+
+              if(r&&!p){
+                t2=clone_typ(regtype[r]);
+                v=add_var(empty,t2,AUTO,0);
+                v->flags|=USEDASADR;
+                new=new_IC();
+                new->code=MOVEFROMREG;
+                new->typf=0;
+                new->q1.flags=REG;
+                new->q1.reg=r;
+                new->q2.flags=0;
+                new->q2.val.vmax=regsize[r];
+                new->z.flags=VAR|DONTREGISTERIZE;
+                new->z.v=v;
+                new->z.val.vmax=l2zm(0L);
+                add_IC(new);
+              }
+	    }else{
+	      regs[reg]|=RNOSAVE;
+	    }
+	  }
+	  new=new_IC();
+#ifdef HAVE_REGPARMS
+	    if(!radr){
+	      al->pushic=new;
+	    }
+#else
+	    al->pushic=new;
+#endif
+	    new->code=ASSIGN;
+	    new->typf=t;
+            new->q1=*arg;
+            /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+            if((new->q1.flags&REG)){
+              regargs_list *p;
+              for(p=*rl;p;p=p->next){
+		int r;
+                if(p->v&&(r=abs(p->reg))){
+		  if(new->q1.reg==r||(reg_pair(new->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+		  /*FIXME: andersrum bei LITTLEENDIAN?? */
+		  if(reg_pair(r,&rp)&&rp.r1==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+		  if(reg_pair(r,&rp)&&rp.r2==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=regsize[rp.r1];break;}
+
+		}
+              }
+              if(p&&new->q1.v){
+		if(!(new->q1.flags&DREFOBJ)&&must_convert(new->typf,regtype[new->q1.reg]->flags,0)){
+		  new->code=CONVERT;
+		  new->typf2=regtype[new->q1.reg]->flags;
+		}
+                new->q1.flags&=~REG;
+                new->q1.flags|=VAR;
+                /*new->q1.val.vmax=l2zm(0L);*/
+              }
+            }
+            new->q2.flags=new->z.flags=0;
+            new->q2.val.vmax=sizetab[t&NQ];
+            new->z.flags=REG;
+            new->z.reg=reg;
+            add_IC(new);
+	    if(al) fix_pushic(&al->pushic,new);
+            nrl=mymalloc(sizeof(*nrl));
+            nrl->next=*rl;
+            nrl->reg=reg;
+            nrl->v=v;
+	    nrl->rsaved=rsaved; /* if only part of a pair was saved */
+	    rsaved=0;
+            *rl=nrl;
+            return of;
+        }
+    }
+}
+
+void convert(np p,int f)
+/*  konvertiert das Objekt in p->o in bestimmten Typ    */
+/* wenn volatile_convert gesetzt ist, wird immer IC erzeugt */
+{
+  IC *new;
+  int o=p->ntyp->flags;
+  int to,tn,mc,dr;
+  static node n,nn;
+  static type nt;
+  char *libname;
+  if((f&NQ)==VOID) return;
+
+  if(p->flags==CEXPR||p->flags==PCEXPR){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    eval_constn(p);
+    p->ntyp->flags=f;
+    insert_constn(p);
+    p->o.val=p->val;
+    return;
+  }
+  if((AVOID_FLOAT_TO_UNSIGNED&&ISFLOAT(o)&&(f&UNSIGNED))||
+     (AVOID_UNSIGNED_TO_FLOAT&&ISFLOAT(f)&&(o&UNSIGNED))){
+    union atyps val;
+    int l1,l2,it;
+    Var *tmp;
+    np t;
+    type *ttyp;
+    if(f&UNSIGNED)
+      it=f&NQ;
+    else
+      it=o&NQ;
+    ttyp=clone_typ(p->ntyp);
+    ttyp->flags=f;
+    tmp=add_tmp_var(ttyp);
+    new=new_IC();
+    new->code=COMPARE;
+    new->typf=o;
+    new->q1=p->o;
+    new->q1.flags&=~SCRATCH;
+    new->q2.flags=KONST;
+    new->q2.val.vumax=t_max[it];
+    eval_const(&new->q2.val,MAXINT|UNSIGNED);
+    insert_const(&new->q2.val,o);
+    val=new->q2.val;
+    add_IC(new);
+    new=new_IC();
+    new->code=BLE;
+    l1=++label;
+    new->typf=l1;
+    add_IC(new);
+    new=new_IC();
+    new->code=SUB;
+    new->typf=o;
+    new->q1=p->o;
+    new->q1.flags&=~SCRATCH;
+    new->q2.flags=KONST;
+    new->q2.val=val;
+    new->z.flags=VAR;
+    get_scratch(&new->z,o,0,0);
+    t=new_node();
+    t->ntyp=clone_typ(p->ntyp);
+    t->ntyp->flags&=~UNSIGNED;
+    t->o=new->z;
+    add_IC(new);
+    convert(t,f&NQ);
+    new=new_IC();
+    new->code=ADD;
+    new->typf=f;
+    new->q1=t->o;
+    new->q1.flags&=~SCRATCH;
+    freetyp(t->ntyp);
+    free(t);
+    new->q2.flags=KONST;
+    new->q2.val.vumax=t_max[it];
+    eval_const(&new->q2.val,MAXINT|UNSIGNED);
+    insert_const(&new->q2.val,f);
+    new->z.flags=VAR;
+    new->z.v=tmp;
+    new->z.val.vmax=l2zm(0L);
+    add_IC(new);
+    new=new_IC();
+    new->code=BRA;
+    l2=++label;
+    new->typf=l2;
+    add_IC(new);
+    new=new_IC();
+    new->code=LABEL;
+    new->typf=l1;
+    add_IC(new);
+    p->ntyp->flags&=~UNSIGNED;
+    convert(p,f&NQ);
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=f;
+    new->q1=p->o;
+    new->z.flags=VAR;
+    new->z.v=tmp;
+    new->z.val.vmax=l2zm(0L);
+    new->q2.val.vmax=sizetab[f&NQ];
+    p->o=new->z;
+    p->ntyp->flags=f;
+    add_IC(new);
+    new=new_IC();
+    new->code=LABEL;
+    new->typf=l2;
+    add_IC(new);
+    return;
+  }
+  if(ISVECTOR(f)&&ISSCALAR(o)){
+    o=VECTYPE(f);
+    convert(p,o);
+  }
+  if(!volatile_convert&&((o&(NU&~UNSIGNED))==(f&(NU&~UNSIGNED))||(!(mc=must_convert(o,f,const_expr))&&(const_expr||!(optflags&2))))){
+    p->ntyp->flags=f;
+    if(!ISPOINTER(f)&&!ISARRAY(f)){freetyp(p->ntyp->next);p->ntyp->next=0;}
+    return;
+  }
+  /* do not create direct converts between float and small types
+     if the backend does not like that */
+  if(ISFLOAT(o)&&ISINT(f)&&(f&NQ)<MIN_FLOAT_TO_INT_TYPE)
+    tn=MIN_FLOAT_TO_INT_TYPE|(f&UNSIGNED);
+  else
+    tn=f;
+  libname=0;
+  if(ISFLOAT(f)&&ISINT(o)&&(o&NQ)<MIN_INT_TO_FLOAT_TYPE){
+#if HAVE_LIBCALLS
+    if((libname=use_libcall_wrap(CONVERT,tn,o))&&mc){
+      to=o;
+      libname=use_libcall_wrap(CONVERT,tn,MIN_INT_TO_FLOAT_TYPE|(o&UNSIGNED));
+      if(!libname) ierror(0);
+    }else
+#endif
+    {
+      to=MIN_INT_TO_FLOAT_TYPE|(o&UNSIGNED);
+      convert(p,to);
+    }
+  }else{
+    to=o;
+  }
+#if HAVE_LIBCALLS
+  n.flags=CONVERT;
+  n.ntyp=&nt;
+  nt.flags=f;
+  n.left=&nn;
+  nn.ntyp=p->ntyp;
+  if((libname||(libname=use_libcall_wrap(CONVERT,tn,to)))&&mc){
+    node *n=new_node();
+    n->flags=REINTERPRET;
+    n->o=p->o;
+    n->ntyp=p->ntyp;
+    p->o=gen_libcall(libname,n,p->ntyp,0,0)->o;
+  }else{
+#endif
+    new=new_IC();
+    new->q1=p->o;
+    new->q2.flags=0;
+    new->code=CONVERT;
+    new->typf2=to;
+    new->typf=tn;
+    if((p->o.flags&(SCRATCH|REG))!=(SCRATCH|REG)||!regok(p->o.reg,tn,0)){
+      get_scratch(&new->z,tn,0,0);
+    }else{
+      new->z=p->o;new->z.flags&=~DREFOBJ;
+    }
+    p->o=new->z;
+    /* hmm... */
+    if(!mc&&libname){
+      new->code=ASSIGN;
+      new->q2.val.vmax=sizetab[tn&NQ];
+    }
+    add_IC(new);
+#if HAVE_LIBCALLS
+  }
+#endif
+  if(f!=tn){
+    p->ntyp->flags=tn;
+    convert(p,f);
+  }
+}
+
+void alloc_hardreg(int r)
+/*  Belegt Register r.  */
+{
+  IC *new;
+  if(nocode) return;
+  if(DEBUG&16) printf("allocated %s\n",regnames[r]);
+  regs[r]=1;regused[r]++;
+  new=new_IC();
+  new->code=ALLOCREG;
+  new->typf=0;
+  new->q1.flags=REG;
+  new->q1.reg=r;
+  new->q2.flags=new->z.flags=0;
+  add_IC(new);
+  if(reg_pair(r,&rp)){
+    regs[rp.r1]=1;regused[rp.r1]++;
+    regs[rp.r2]=1;regused[rp.r2]++;
+  }
+}
+
+int allocreg(int f,int mode)
+/*  Fordert Register fuer Typ f an.                     */
+{
+  int i,r=0,prio=-1;
+  if(nocode) return(1);
+  for(i=1;i<=MAXR;i++){
+    if(!regs[i]&&reg_prio[i]>prio&&regok(i,f,mode)&&(!reg_pair(i,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+      r=i;
+      prio=reg_prio[i];
+    }
+  }
+  if(r){
+    if(DEBUG&16) printf("alloc %s\n",regnames[r]);
+    alloc_hardreg(r);
+    return r;
+  }
+  if(DEBUG&1) printf("Couldn't allocate register for type %d\n",f);
+  return 0;
+}
+void free_reg(int r)
+/*  Gibt Register r frei                                */
+{
+    IC *new;
+    if(!r||nocode) return;
+    if(regs[r]==0&&!cross_module)
+      {printf("Register %d(%s):\n",r,regnames[r]);ierror(0);}
+    if(DEBUG&16) printf("freed %s\n",regnames[r]);
+    new=new_IC();
+    new->code=FREEREG;
+    new->typf=0;
+    new->q1.flags=REG;
+    new->q1.reg=r;
+    new->q2.flags=new->z.flags=0;
+    regs[r]=0;
+    if(reg_pair(r,&rp)){
+      if(regs[rp.r1]&RHALF){
+	if(DEBUG&16) printf("keep %s\n",regnames[rp.r1]);
+	regs[rp.r1]&=~RHALF;
+	new->q1.reg=rp.r2;
+      }else
+	regs[rp.r1]=0;
+      if(regs[rp.r2]&RHALF){
+	if(DEBUG&16) printf("keep %s\n",regnames[rp.r2]);
+	regs[rp.r2]&=~RHALF;
+	new->q1.reg=rp.r1;
+      }else
+	regs[rp.r2]=0;
+    }
+    add_IC(new);
+}
+void gen_label(int l)
+/*  Erzeugt ein Label                                   */
+{
+    IC *new;
+    new=new_IC();
+    new->code=LABEL;
+    new->typf=l;
+    new->q1.flags=new->q2.flags=new->z.flags=0;
+    add_IC(new);
+}
+void gen_cond(obj *p,int m,int l1,int l2)
+/*  Generiert code, der 0 oder 1 in Register schreibt. Schreibt obj nach p. */
+{
+    IC *new;
+    obj omerk;
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=INT;
+    new->q1.flags=KONST;
+    new->q2.flags=0;
+    new->q2.val.vmax=sizetab[INT];
+    if(!m) vmax=l2zm(1L); else vmax=l2zm(0L);
+    new->q1.val.vint=zm2zi(vmax);
+    get_scratch(&new->z,INT,0,0);
+    omerk=new->z;
+    add_IC(new);
+    new=new_IC();
+    new->code=BRA;
+    new->typf=l2;
+    add_IC(new);
+    gen_label(l1);
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=INT;
+    new->q1.flags=KONST;
+    new->q2.flags=0;
+    new->q2.val.vmax=sizetab[INT];
+    if(!m) vmax=l2zm(0L); else vmax=l2zm(1L);
+    new->q1.val.vint=zm2zi(vmax);
+    new->z=omerk;
+/*    new->z.reg=r;
+    new->z.flags=SCRATCH|REG;*/
+    add_IC(new);
+    gen_label(l2);
+    *p=omerk;
+}
+void scratch_var(obj *o,int t,type *typ)
+/*  liefert eine temporaere Variable                            */
+/*  nicht effizient, aber wer hat schon so wenig Register...    */
+{
+  type *nt;
+  if(!ISSCALAR(t)&&!ISVECTOR(t)){
+    if(!typ) ierror(0);
+    nt=clone_typ(typ);
+  }else{
+    nt=new_typ();
+    nt->flags=t;
+    if(ISPOINTER(t)){
+      nt->next=new_typ();
+      nt->next->flags=VOID;
+    }
+  }
+  o->flags=SCRATCH|VAR;o->reg=0;
+  o->v=add_var(empty,nt,AUTO,0);
+  o->val.vmax=l2zm(0L);
+}
+void get_scratch(obj *o,int t1,int t2,type *typ)
+/*  liefert ein Scratchregister oder eine Scratchvariable       */
+{
+    if(!(optflags&2)&&(o->reg=allocreg(t1,t2))){
+        o->flags=SCRATCH|REG;
+    }else{
+        scratch_var(o,t1,typ);
+    }
+}
+int do_arith(np p,IC *new,np dest,obj *o)
+/*  erzeugt IC new fuer einen arithmetischen Knoten und speichert das   */
+/*  Resultat vom Unterknoten dest in o (fuer a op= b)               */
+/*  liefert 0, wenn dest nicht gefunden                             */
+{
+    int f=0,mflags;
+    new->code=p->flags;
+    if(new->code==PMULT) new->code=MULT;
+    gen_IC(p->left,0,0);
+    if(dest&&p->left==dest){
+      *o=p->left->o;f++;
+      if(p->left->flags==BITFIELD){
+        *o=p->left->left->o;
+        if((o->flags&(REG|SCRATCH))==(REG|SCRATCH))
+          keep_reg(o->reg);
+      }
+    }
+    gen_IC(p->right,0,0);
+    if(dest&&p->right==dest) {*o=p->right->o;f++;}
+    if(dest){
+      mflags=dest->o.flags;
+      if(p->left->flags!=BITFIELD) 
+        dest->o.flags&=(~SCRATCH);
+    }
+
+    if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){
+    /*  Subtrahieren zweier Pointer                                 */
+      int dt=PTRDIFF_T(p->left->ntyp->flags);
+      if(p->flags!=SUB) ierror(0);
+      new->typf=dt;
+      new->typf2=p->left->ntyp->flags;
+      new->code=SUBPFP;
+      new->q1=p->left->o;
+      new->q2=p->right->o;
+      if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->left->o.reg,dt,0)){
+	new->z=p->left->o;
+	new->z.flags&=~DREFOBJ;
+      }else{
+	if(USEQ2ASZ&&(p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->right->o.reg,dt,0)){
+	  new->z=p->right->o;
+	  new->z.flags&=(~DREFOBJ);
+	}else{
+	  get_scratch(&new->z,dt,0,0);
+	}
+      }
+      p->o=new->z;
+      add_IC(new);
+      if(!zmleq(szof(p->left->ntyp->next),l2zm(1L))){
+	long ln;
+	new=new_IC();
+	new->q1=p->o;
+	new->q2.flags=KONST;
+	gval.vmax=szof(p->left->ntyp->next);
+	eval_const(&gval,MAXINT);
+	if(ln=get_pof2(vumax)){
+	  /* Division immer ohne Rest, daher shift möglich */
+	  /* TODO: Haben wir Targets ohne arith. shift right? */
+	  gval.vmax=l2zm(ln-1);
+	  eval_const(&gval,MAXINT);
+	  insert_const(&new->q2.val,INT);
+	  new->typf2=INT;
+	  new->code=RSHIFT;
+	}else{
+	  insert_const(&new->q2.val,dt);
+	  new->code=DIV;
+	}
+	new->z=p->o;
+	new->typf=dt;
+	add_IC(new);
+      }
+      if(dest) dest->o.flags=mflags;
+      return f;
+    }
+    if((p->flags==ADD||p->flags==SUB)&&(ISPOINTER(p->left->ntyp->flags)||ISPOINTER(p->right->ntyp->flags))){
+      /*  Addieren und Subtrahieren eines Integers zu einem Pointer   */
+      if(p->flags==ADD){
+	new->code=ADDI2P;
+	if(!ISPOINTER(p->left->ntyp->flags)){
+	  np tmp=p->left;
+	  p->left=p->right;
+	  p->right=tmp;
+	}
+      }else
+	new->code=SUBIFP;
+      new->typf=p->right->ntyp->flags;
+      new->typf2=p->ntyp->flags;
+      new->q1=p->left->o;
+      /*  kleinere Typen als MINADDI2P erst in diesen wandeln */
+      if(new->typf&UNSIGNED){
+	if((new->typf&NQ)<(MINADDUI2P&NQ)){convert(p->right,MINADDUI2P);new->typf=MINADDUI2P;}
+      }else{
+	if((new->typf&NQ)<MINADDI2P){convert(p->right,MINADDI2P);new->typf=MINADDI2P;}
+      }
+      /*  groessere Typen als MAXADDI2P erst in diesen wandeln */
+      if(new->typf&UNSIGNED){
+	if((new->typf&NQ)>(MAXADDI2P&NQ)){convert(p->right,MAXADDUI2P);new->typf=MAXADDUI2P;}      
+      }else{
+	if((new->typf&NQ)>MAXADDI2P){convert(p->right,MAXADDI2P);new->typf=MAXADDI2P;}      
+      }
+      if((p->left->o.flags&VARADR)&&(p->right->o.flags&KONST)){
+	eval_const(&p->right->o.val,p->right->ntyp->flags);
+	p->o=p->left->o;
+	p->o.val.vmax=zmadd(vmax,p->left->o.val.vmax);
+	free(new);
+	return f;
+      }
+      new->q2=p->right->o;
+      if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(new->q1.reg,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags)){
+	new->z=p->left->o;
+	new->z.flags&=(~DREFOBJ);
+      }else{
+	/*get_scratch(&new->z,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags,0);*/
+	get_scratch(&new->z,p->ntyp->flags,p->ntyp->next->flags,0);
+      }
+      p->o=new->z;
+      add_IC(new);
+      if(dest) dest->o.flags=mflags;
+      return f;
+    }
+    if(!ISVECTOR(p->ntyp->flags)||!ISVECTOR(p->left->ntyp->flags))
+      convert(p->left,p->ntyp->flags);
+    if(p->flags==LSHIFT||p->flags==RSHIFT){
+      if(shortcut(p->flags,p->left->ntyp->flags&NU)){
+	convert(p->right,p->right->ntyp->flags);
+	new->typf2=p->right->ntyp->flags;
+      }else{
+	convert(p->right,INT);
+	new->typf2=INT;
+      }
+#if 0
+      type *st;
+      st=clone_typ(p->right->ntyp);
+      /*st->flags=int_erw(st->flags);*/
+      st->flags=INT;
+      convert(p->right,st->flags);
+      new->typf2=st->flags;
+      freetyp(st);
+#endif
+    }else{
+      if(!ISVECTOR(p->ntyp->flags)||!ISVECTOR(p->right->ntyp->flags))
+	convert(p->right,p->ntyp->flags);
+    }
+    new->q1=p->left->o;
+    new->q2=p->right->o;
+    if(ISVECTOR(p->ntyp->flags)){
+      new->typf=p->left->ntyp->flags;
+      new->typf2=p->ntyp->flags;
+    }else
+      new->typf=p->ntyp->flags;
+    /*  Bei dest!=0, d.h. ASSIGNOP, darf q1 nicht als Ziel benuzt werden!  */
+    if(!dest&&(new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(new->q1.reg,p->ntyp->flags,0)){
+      new->z=new->q1;
+      new->z.flags&=~DREFOBJ;
+    }else{
+      if((new->q2.flags&SCRATCH)&&regok(new->q2.reg,p->ntyp->flags,0)){
+	if((p->flags>=OR&&p->flags<=AND)||p->flags==ADD||p->flags==MULT||p->flags==PMULT){
+	  /*  bei kommutativen Operatoren vertauschen     */
+	  new->z=new->q2;
+	  new->q2=new->q1;
+	  new->q1=new->z;
+	  new->z.flags&=~DREFOBJ;
+	}else{
+	  if(USEQ2ASZ){
+	    new->z=new->q2;
+	    new->z.flags&=~DREFOBJ;
+	  }else{
+	    get_scratch(&new->z,new->typf,0,0);
+	  }
+	}
+      }else{
+	get_scratch(&new->z,new->typf,0,0);
+      }
+    }
+    p->o=new->z;
+    add_IC(new);
+    if(dest){
+      dest->o.flags=mflags;
+      /*
+      if((dest->o.flags&REG)&&!regs[dest->o.reg])
+        keep_reg(dest->o.reg);
+      */
+    }
+
+    return f;
+}
+void savescratch(int code,IC *p,int dontsave,obj *o)
+/*  speichert Scratchregister bzw. stellt sie wieder her (je nach code  */
+/*  entweder MOVEFROMREG oder MOVETOREG)                                */
+{
+  int i,s,e,b,ds1,ds2;IC *new;
+  if(code==MOVETOREG){ s=1;e=MAXR+1;b=1;} else {s=MAXR;e=0;b=-1;}
+  if(reg_pair(dontsave,&rp)){
+    ds1=rp.r1;
+    ds2=rp.r2;
+  }else
+    ds1=ds2=0;
+  for(i=s;i!=e;i+=b){
+    int mustsave=0;
+    if((o->flags&(VAR|DREFOBJ))==VAR&&o->v->fi&&(o->v->fi->flags&ALL_REGS))
+      mustsave=BTST(o->v->fi->regs_modified,i);
+    else
+      mustsave=regscratch[i];
+    if(regsa[i]) mustsave=0;
+    if(mustsave) simple_scratch[i]=1;
+    if(regs[i]&&!(regs[i]&RNOSAVE)&&mustsave&&i!=dontsave&&i!=ds1&&i!=ds2&&!reg_pair(i,&rp)){
+      if(!regsbuf[i]){
+	type *t;
+	if(code!=MOVEFROMREG) continue;
+	t=clone_typ(regtype[i]);
+	regsbuf[i]=add_var(empty,t,AUTO,0);
+	regsbuf[i]->flags|=USEDASADR;
+	regbnesting[i]=nesting;
+      }
+      new=new_IC();
+      new->typf=new->q2.flags=0;
+      new->line=0;new->file=0;
+      new->code=code;
+      if(code==MOVEFROMREG){
+	new->q1.flags=REG;new->q1.reg=i;
+	new->z.flags=VAR|DONTREGISTERIZE;new->z.v=regsbuf[i];
+	new->z.val.vmax=l2zm(0L);
+      }else{
+	new->z.flags=REG;new->z.reg=i;
+	new->q1.flags=VAR|DONTREGISTERIZE;new->q1.v=regsbuf[i];
+	new->q1.val.vmax=l2zm(0L);
+      }
+      new->use_cnt=new->change_cnt=0;
+      new->use_list=new->change_list=0;
+      insert_IC(p,new);
+    }
+  }
+}
+
diff --git a/icn.c b/icn.c
new file mode 100755
index 0000000..4e4feab
--- /dev/null
+++ b/icn.c
@@ -0,0 +1,2104 @@
+/*  $VER: vbcc (ic.c) V0.8  */
+
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+static struct IC *first_pushed;
+static unsigned int opushed;
+
+static int volatile_convert;
+
+int do_arith(np,struct IC *,np,struct obj *);
+
+static void handle_reglist(struct regargs_list *,struct obj *);
+
+void gen_test(struct obj *o,int t,int branch,int label)
+/*  Generiert ein test o, branch label und passt auf, dass      */
+/*  kein TEST const generiert wird.                             */
+{
+    struct IC *new;
+    if(o->flags&KONST){
+        eval_const(&o->val,t);
+        if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+            if(branch==BEQ) branch=BRA; else branch=0;
+        }else{
+            if(branch==BNE) branch=BRA; else branch=0;
+        }
+    }else{
+        new=new_IC();
+        new->code=TEST;
+        new->q2.flags=new->z.flags=0;
+        new->typf=t;
+        new->q1=*o;
+        add_IC(new);
+    }
+    if(branch){
+        new=new_IC();
+        new->code=branch;
+        new->typf=label;
+        add_IC(new);
+    }
+}
+
+void inline_memcpy(np z,np q,zmax size)
+/*  fuegt ein ASSIGN-IC ein, das memcpy(z,q,size) entspricht    */
+{
+    struct IC *new=new_IC();
+    if(!ISPOINTER(z->ntyp->flags)) ierror(0);
+    if(!ISPOINTER(q->ntyp->flags)) ierror(0);
+
+    if(z->flags==ADDRESS||z->flags==ADDRESSA||z->flags==ADDRESSS){
+      gen_IC(z,0,0);
+      new->z=z->left->o;
+      if(z->flags!=ADDRESSS&&z->left->flags==IDENTIFIER&&is_vlength(z->left->ntyp)){
+	/* variable length array */
+	new->z.flags|=DREFOBJ;
+	new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+      }
+    }else{
+      gen_IC(z,0,0);
+      if(z->o.flags&DREFOBJ){
+        struct IC *n2=new_IC();
+        n2->code=ASSIGN;
+        n2->typf=q->ntyp->flags;
+        n2->q1=z->o;
+        get_scratch(&n2->z,z->ntyp->flags,z->ntyp->next->flags,z->ntyp);
+        n2->q2.flags=0;
+        n2->q2.val.vmax=sizetab[POINTER_TYPE(z->ntyp->next)];
+        new->z=n2->z;
+        add_IC(n2);
+      }else{
+        new->z=z->o;
+      }
+      if(new->z.flags&VARADR){
+	new->z.flags&=~VARADR; 
+      }else{
+	new->z.flags|=DREFOBJ;
+	new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+      }
+    }
+    if(q->flags==ADDRESS||q->flags==ADDRESSA||q->flags==ADDRESSS){
+      gen_IC(q,0,0);
+      new->q1=q->left->o;
+      if(q->flags!=ADDRESSS&&q->left->flags==IDENTIFIER&&is_vlength(q->left->ntyp)){
+	/* variable length array */
+	new->q1.flags|=DREFOBJ;
+	new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+      }
+    }else{    
+      gen_IC(q,0,0);
+      if(q->o.flags&DREFOBJ){
+        struct IC *n2=new_IC();
+        n2->code=ASSIGN;
+        n2->typf=q->ntyp->flags;
+        n2->q1=q->o;
+        get_scratch(&n2->z,q->ntyp->flags,q->ntyp->next->flags,q->ntyp);
+        n2->q2.flags=0;
+        n2->q2.val.vmax=sizetab[POINTER_TYPE(q->ntyp->next)];
+
+        new->q1=n2->z;
+        add_IC(n2);
+      }else{
+        new->q1=q->o;
+      }
+      if(new->q1.flags&VARADR){
+	new->q1.flags&=~VARADR;
+      }else{
+	new->q1.flags|=DREFOBJ;
+	new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+      }
+    }
+    new->code=ASSIGN;
+    new->typf=UNSIGNED|CHAR;
+    new->q2.flags=0;
+    new->q2.val.vmax=size;
+    add_IC(new);
+}
+
+void add_IC(struct IC *new)
+/*  fuegt ein IC ein                                            */
+{
+    int code;
+    if(!new) return;
+    if(nocode) {
+#ifdef HAVE_MISRA
+		misra_neu(52,14,1,-1);
+#endif
+		free(new);return;}
+    new->next=0;
+    new->q1.am=new->q2.am=new->z.am=0;
+    new->line=line; new->file=filename;
+    code=new->code;
+    if(code>=BEQ&&code<=BRA) new->q1.flags=new->q2.flags=new->z.flags=0;
+    if(code==ALLOCREG||code==FREEREG||code==SAVEREGS||code==RESTOREREGS) new->typf=0;
+    if(DEBUG&64){ pric(stdout,first_ic);printf("new\n");pric2(stdout,new);printf("-\n");}
+    if(new->q1.flags&VAR){
+        if(!new->q1.v) ierror(0);
+        new->q1.v->flags|=USEDASSOURCE;
+        if(code==ADDRESS||(new->q1.flags&VARADR))
+	  if(!is_vlength(new->q1.v->vtyp))
+	    new->q1.v->flags|=USEDASADR;
+        new->q1.v->priority+=currentpri;
+    }
+    if(new->q2.flags&VAR){
+        if(!new->q2.v) ierror(0);
+        new->q2.v->flags|=USEDASSOURCE;
+        if(code==ADDRESS||(new->q2.flags&VARADR))
+   	  if(!is_vlength(new->q2.v->vtyp))
+	    new->q2.v->flags|=USEDASADR;
+        new->q2.v->priority+=currentpri;
+    }
+    if(new->z.flags&VAR){
+        if(!new->z.v) ierror(0);
+        if(new->z.flags&DREFOBJ)
+	  new->z.v->flags|=USEDASSOURCE;
+	else
+	  new->z.v->flags|=USEDASDEST;
+        new->z.v->priority+=currentpri;
+    }
+    if(block_vla[nesting]){
+      /* special handling for blocks with variable-length arrays */
+      struct llist *p;
+      if(new->code==LABEL){
+	p=mymalloc(LSIZE);
+	p->label=new->typf;
+	p->next=vladeflabels[nesting];
+	vladeflabels[nesting]=p;
+      }else if(0&&new->code==BRA&&!(new->flags&LOOP_COND_TRUE)){
+	p=mymalloc(LSIZE);
+	p->label=new->typf;
+	p->next=vlajmplabels[nesting];
+	vlajmplabels[nesting]=p;
+	p=vladeflabels[nesting];
+	while(p){
+	  if(p->label==new->typf)
+	    break;
+	  p=p->next;
+	}
+	if(!p){ 
+	  /* label not declared in this block so far;
+	     re-adjust stack, but store the position - label may be
+	     declared later in the same block and adjustement must be
+	     removed */
+	  struct vlaadjust_list *vl;
+	  struct IC *first;
+	  first=last_ic;
+	  freevl();
+	  first=first->next;
+	  vl=mymalloc(sizeof(*vl));
+	  vl->branch=new;
+	  vl->first=first;
+	  vl->next=vlaadjusts[nesting];
+	  vlaadjusts[nesting]=vl;
+	}
+      }
+    }
+    if(/*(c_flags_val[0].l&2)&&*/code==LABEL){
+    /*  entfernt Spruenge zu direkt folgenden Labels    */
+        struct IC *p=last_ic;
+        while(p){
+            if(p->typf==new->typf&&p->code>=BEQ&&p->code<=BRA){
+                struct IC *n;
+		if(p->code!=BRA){
+		  struct IC *cmp=p->prev;
+		  while(cmp&&cmp->code==FREEREG) cmp=cmp->prev;
+		  if(cmp->code==TEST){
+		    if(is_volatile_obj(&cmp->q1))
+		      break;
+		    else{
+		      if(DEBUG&1) printf("preceding test removed\n");
+		      remove_IC(cmp);
+		    }
+		  }else if(cmp->code==COMPARE){
+		    if(is_volatile_obj(&cmp->q1)||is_volatile_obj(&cmp->q2))
+		      break;
+		    else{
+		      if(DEBUG&1) printf("preceding compare removed\n");
+		      remove_IC(cmp);
+		    }
+		  }else
+		    break;
+		}
+		if(vlaadjusts[nesting]){
+		  /* remove it from vlaadjusts-lists, if necessary */
+		  struct vlaadjust_list *vl=vlaadjusts[nesting];
+		  while(vl){
+		    if(vl->branch==p){
+		      struct IC *np=vl->branch->prev;
+		      while(np!=vl->first->prev){
+			if(!np) ierror(0);
+			np->code=NOP;
+			np->q1.flags=np->q2.flags=np->z.flags=0;
+			np=np->prev;
+		      }
+		      vl->branch=0;
+		    }
+		    vl=vl->next;
+		  }
+		}
+                if(DEBUG&1) printf("%s l%d deleted\n",ename[p->code],p->typf);
+                n=p->next;
+                remove_IC(p);
+                p=n;
+            }else{
+                if(p->code!=LABEL) break;
+                p=p->prev;
+            }
+        }
+    }
+    if(last_ic){
+        if(code==ASSIGN){
+            if((last_ic->z.flags&(REG|SCRATCH|DREFOBJ))==(REG|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.reg==new->q1.reg/*&&last_ic->code!=CALL*/){
+                if(USEQ2ASZ||!(last_ic->q2.flags&REG)||!(new->z.flags&REG)||last_ic->q2.reg!=new->z.reg){
+                    if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+                    /*  verbindet op a,b->reg,move reg->c zu op a,b->c  */
+                    /*  hier fehlt aber noch Registerfreigabe           */
+                        last_ic->z=new->z;
+                        if(DEBUG&1) printf("move and op combined\n");
+                        if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
+                            free_reg(new->q1.reg);
+                        free(new);
+                        return;
+                    }
+                }
+            }
+            if((last_ic->z.flags&(VAR|SCRATCH|DREFOBJ))==(VAR|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.v==new->q1.v/*&&last_ic->code!=CALL*/){
+                if(USEQ2ASZ||!(last_ic->q2.flags&REG)||!(new->z.flags&REG)||last_ic->q2.reg!=new->z.reg){
+                    if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+                    /*  verbindet op a,b->scratch,move scratch->c zu op a,b->c  */
+                    /*  hier fehlt aber noch Registerfreigabe           */
+                        last_ic->z=new->z;
+                        if(DEBUG&1) printf("move and op combined(2)\n");
+/*                        if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
+                            free_reg(new->q1.reg);*/
+                        free(new);
+                        return;
+                    }
+                }
+            }
+
+        }
+        if(last_ic->code==BRA){
+            if(code!=LABEL&&code!=ALLOCREG&&code!=FREEREG){
+            /*  loescht alles nach bra bis ein Label kommt  */
+            /*  momentan noch nicht perfekt, da es bei alloc/freereg stoppt */
+                free(new);
+#ifdef HAVE_MISRA
+		misra_neu(52,14,1,-1);
+#endif
+                if(DEBUG&1) printf("Unreachable Statement deleted\n");
+                return;
+            }
+            if(last_ic->prev&&code==LABEL){
+            /*  ersetzt bcc l1;bra l2;l1 durch b!cc l2      */
+                if(last_ic->prev->code>=BEQ&&last_ic->prev->code<=BGT&&new->typf==last_ic->prev->typf){
+		  if(last_ic->next) pric2(stdout,last_ic->next);
+                    if(DEBUG&1) printf("%s l%d;%s l%d; substituted\n",ename[last_ic->prev->code],last_ic->prev->typf,ename[last_ic->code],last_ic->typf);
+                    if(last_ic->prev->code&1) 
+		      last_ic->prev->code--;
+		    else
+		      last_ic->prev->code++;
+                    last_ic->prev->typf=last_ic->typf;
+                    last_ic=last_ic->prev;
+		    free(last_ic->next);
+                    last_ic->next=new;new->prev=last_ic;
+                    last_ic=new;
+                    return;
+                }
+            }
+        }
+/*        }*/
+        new->prev=last_ic;
+        last_ic->next=new;
+        last_ic=new;
+    }else{
+        last_ic=new;first_ic=new;new->prev=0;
+    }
+    ic_count++;
+    /*  Merken, on Fliesskomma benutzt wurde    */
+    if(code!=LABEL&&(code<BEQ||code>BRA)){
+        if(ISFLOAT(new->typf)) float_used=1;
+        if(code==CONVERT&&ISFLOAT(new->typf2)) float_used=1;
+    }
+    if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
+        free_reg(new->q1.reg);
+    if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q2.reg!=new->z.reg||!(new->z.flags&REG)))
+        free_reg(new->q2.reg);
+}
+
+np gen_libcall(char *fname,np arg1,struct Typ *t1,np arg2,struct Typ *t2)
+/* generate call to a library function (emulate operation) */
+{
+  np new; 
+  struct argument_list *al=0,*t;
+  new=mymalloc(NODES);
+  new->flags=CALL;
+  new->right=0;
+  new->left=mymalloc(NODES);
+  new->left->flags=IDENTIFIER;
+  new->left->left=new->left->right=0;
+  new->left->identifier=add_identifier(fname,strlen(fname));
+  new->left->ntyp=0;
+  new->left->sidefx=0;
+  new->left->val.vmax=l2zm(0L); 
+  new->alist=0;
+  if(arg1){
+    al=mymalloc(sizeof(*al));
+    al->arg=arg1;
+    al->next=0;
+    if(t1){
+      np cnv=mymalloc(NODES);
+      cnv->flags=CAST;
+      cnv->left=arg1;
+
+      cnv->right=0;
+      cnv->ntyp=t1;
+      al->arg=cnv;
+    }
+  }
+  if(arg2){
+    t=mymalloc(sizeof(*t));
+    t->arg=arg2;
+    t->next=0;
+    al->next=t;
+    if(t2){
+      np cnv=mymalloc(NODES);
+      cnv->flags=CAST;
+      cnv->left=arg2;
+      cnv->right=0;
+      cnv->ntyp=t2;
+      t->arg=cnv;
+    }
+  }
+  new->alist=al;
+  /* Kann man type_expr nochmal auf die Argumente anwenden? */
+  if(!type_expression(new))
+    ierror(0); 
+  gen_IC(new,0,0);
+  return new;
+}
+
+
+void gen_IC(np p,int ltrue,int lfalse)
+/*  Erzeugt eine IC-Liste aus einer expression      */
+{
+    struct IC *new; struct regargs_list *rl;
+    if(!p) return;
+    if(p->flags==STRING){
+    /*  hier fehlt noch die Verwaltung der String-Inhalte   */
+        p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,p->cl);
+        p->o.v->flags|=DEFINED;
+        p->o.flags=VAR;
+        p->o.reg=0;
+        p->o.val=p->val;
+        return;
+    }
+    if(p->flags==IDENTIFIER){
+/*        p->o.v=find_var(p->identifier,0);*/
+        p->o.flags=VAR;
+        p->o.reg=0;
+        p->o.val=p->val;
+        return;
+    }
+    if(p->flags==CEXPR||p->flags==PCEXPR){
+        if(p->left){
+            if(p->left->flags==POSTINC) p->left->flags=PREINC;
+            if(p->left->flags==POSTDEC) p->left->flags=PREDEC;
+            gen_IC(p->left,0,0);
+            if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+        }
+        if(p->right){
+            if(p->right->flags==POSTINC) p->right->flags=PREINC;
+            if(p->right->flags==POSTDEC) p->right->flags=PREDEC;
+            gen_IC(p->right,0,0);
+            if((p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->right->o.reg);
+        }
+        p->o.flags=KONST;
+        p->o.val=p->val;
+        p->o.reg=0;
+        return;
+    }
+    if(p->flags==KOMMA){
+        if(p->left->sidefx){
+            gen_IC(p->left,0,0);
+            if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+        }else if(!(p->left->ntyp->flags&VOLATILE)) 
+	  error(129);
+        gen_IC(p->right,0,0);
+        p->o=p->right->o;
+        return;
+    }
+    if(p->flags==CAST){
+        gen_IC(p->left,0,0);
+        if((p->ntyp->flags&NQ)==VOID){
+            if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+            p->o.flags=0;
+        }else{
+	  if(ISPOINTER(p->ntyp->flags)&&(p->ntyp->next->flags&VOLATILE))
+	    volatile_convert=1;
+	  convert(p->left,p->ntyp->flags);
+	  if(volatile_convert){
+	    if(!(p->left->o.flags&VAR))
+	      ierror(0);
+	    if(!p->left->o.v->vtyp->next)
+	      ierror(0);
+	    p->left->o.v->vtyp->next->flags|=VOLATILE;
+	    volatile_convert=0;
+	  }
+	  p->o=p->left->o;
+        }
+        return;
+    }
+    if(p->flags==FIRSTELEMENT){
+        gen_IC(p->left,0,0);
+        p->o=p->left->o;
+        return;
+    }
+#if HAVE_LIBCALLS
+    { char *libname;
+    if(libname=use_libcall(p)){
+      np lc;struct Typ *t1,*t2;
+      if(p->flags==LSHIFT||p->flags==RSHIFT){
+	t1=clone_typ(p->ntyp);
+	t2=new_typ();
+	t2->flags=INT;
+      }else{
+	t1=arith_typ(p->left->ntyp,p->right->ntyp);
+	t2=clone_typ(t1);
+      }
+      lc=gen_libcall(libname,p->left,t1,p->right,t2);
+      *p=*lc;
+      free(lc);
+      return;
+    }
+    }
+#endif
+    new=new_IC();
+    new->typf=p->ntyp->flags;
+    new->q1.reg=new->q2.reg=new->z.reg=0;
+    new->q1.flags=new->q2.flags=new->z.flags=0;
+    if((p->flags>=LSHIFT&&p->flags<=MOD)||(p->flags>=OR&&p->flags<=AND)||p->flags==PMULT){
+      do_arith(p,new,0,0);
+      return;
+    }
+    if(p->flags==CONTENT){
+        gen_IC(p->left,0,0);
+        if(p->left->o.flags&VARADR){
+            free(new);
+            p->o=p->left->o;
+            p->o.flags&=~VARADR;
+            return;
+        }
+        if(!(p->left->o.flags&DREFOBJ)){
+            free(new);
+            p->o=p->left->o;
+            p->o.flags|=DREFOBJ;
+	    p->o.dtyp=p->left->ntyp->flags;
+        }else{
+          if((p->left->o.flags&SCRATCH)&&p->left->o.dtyp==POINTER_TYPE(p->ntyp)){
+            new->z=p->left->o;
+            new->z.flags&=~DREFOBJ;
+          }else{
+            get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags,p->left->ntyp);
+          }
+          new->code=ASSIGN;new->typf=POINTER_TYPE(p->ntyp);
+          new->q1=p->left->o;
+          new->q2.val.vmax=sizetab[new->typf];
+          p->o=new->z;
+          add_IC(new);
+          p->o.flags|=DREFOBJ;
+	  p->o.dtyp=POINTER_TYPE(p->ntyp);
+        }
+        return;
+    }
+    if(p->flags==ASSIGN){
+        new->code=ASSIGN;
+        gen_IC(p->right,0,0);
+        gen_IC(p->left,0,0);
+        convert(p->right,p->ntyp->flags);
+        new->q1=p->right->o;
+        new->z=p->left->o;
+        new->q2.val.vmax=szof(p->left->ntyp);
+        p->o=new->z;
+        add_IC(new);
+        return;
+    }
+    if(p->flags==ASSIGNOP){
+    /*  das hier ist nicht besonders schoen */
+      struct obj o,q;struct IC *n;int f;char *libname;
+      if(p->right->right==0){
+        /*  sowas wie a+=0 wurde wegoptimiert   */
+	free(new);
+	p->o=p->left->o;
+	return;
+      }
+#if HAVE_LIBCALLS
+      if(libname=use_libcall(p->right)){
+	np lc;struct Typ *t1,*t2;
+	t1=clone_typ(p->ntyp);
+	if(p->right->flags==LSHIFT||p->right->flags==RSHIFT){
+	  t2=new_typ();
+	  t2->flags=INT;
+	}else
+	  t2=clone_typ(p->ntyp);
+	lc=gen_libcall(libname,p->right->left,t1,p->right->right,t2);
+	*p->right=*lc;
+	o=p->left->o;
+	p->left=0;
+	free(lc);
+      }else
+#endif
+	{
+	  f=do_arith(p->right,new,p->left,&o);
+	  if(!f) ierror(0);
+	  if(f>1) ierror(0);
+	}
+      if(!nocode&&(o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&!regs[o.reg]){
+	/*  ueberfluessiges FREEREG entfernen   */
+	n=last_ic;
+	while(n){
+	  if(!nocode&&n->code==CALL&&regscratch[o.reg]){
+	    struct IC *ret;
+	    regs[o.reg]=1;
+	    savescratch(MOVEFROMREG,n->prev,0,&n->q1);
+	    ret=n->next;
+	    while(ret->code==ALLOCREG||ret->code==FREEREG)
+	      ret=ret->next;
+	    if(ret->code==GETRETURN){
+	      if((ret->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ret->z.reg==o.reg) ret->z.flags&=~REG;
+	    }else
+	      ret=ret->prev;
+	    savescratch(MOVETOREG,ret,0,&n->q1);
+	  }
+	  if(n->code==FREEREG&&n->q1.reg==o.reg){
+	    remove_IC(n);if(!nocode) regs[o.reg]=1;
+	    break;
+	  }
+	  n=n->prev;
+	}
+      }
+      convert(p->right,p->ntyp->flags);
+      new=new_IC();
+      new->typf=p->ntyp->flags;
+      new->q2.flags=0;
+      new->code=ASSIGN;
+      new->q1=p->right->o;
+      new->z=o;
+      new->q2.val.vmax=szof(p->ntyp);
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    if(p->flags==MINUS||p->flags==KOMPLEMENT){
+      new->code=p->flags;
+      gen_IC(p->left,0,0);
+      convert(p->left,p->ntyp->flags);
+      if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->left->o.reg,p->ntyp->flags,0)){
+	new->z=p->left->o;
+	new->z.flags&=~DREFOBJ;
+      }else{
+	get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+      }
+      new->q1=p->left->o;
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    if(p->flags==ADDRESS||p->flags==ADDRESSA||p->flags==ADDRESSS){
+      if(p->flags!=ADDRESSS&&p->left->flags==IDENTIFIER&&is_vlength(p->left->ntyp)){
+	gen_IC(p->left,0,0);
+	if(!(p->left->o.flags&VAR))
+	  ierror(0);
+	free(new);
+	p->o=p->left->o;
+	return;
+      }
+      new->code=ADDRESS;
+      new->typf=p->left->ntyp->flags;
+      new->typf2=POINTER_TYPE(p->left->ntyp);
+      gen_IC(p->left,0,0);
+      if(p->left->o.flags&VAR) p->left->o.v->flags|=(USEDASSOURCE|USEDASDEST);
+      if(p->left->o.flags&DREFOBJ){
+	free(new);
+	p->o=p->left->o;
+	p->o.flags&=~DREFOBJ;
+	return;
+      }
+      if((p->left->o.flags&VAR)&&!(p->left->o.flags&VARADR)
+	 &&(p->left->o.v->storage_class==EXTERN||p->left->o.v->storage_class==STATIC)){
+	free(new);
+	p->o=p->left->o;
+	p->o.flags|=VARADR;
+	return;
+      }
+      new->q1=p->left->o;
+      get_scratch(&new->z,POINTER_TYPE(p->ntyp->next),p->ntyp->next->flags,0);
+      p->o=new->z;
+      add_IC(new);
+      return;
+    }
+    if(p->flags==LAND||p->flags==LOR){
+        int l1,l2,l3,l4;
+/*        printf("%s true=%d false=%d\n",ename[p->flags],ltrue,lfalse);*/
+        l1=++label;
+	if(!ltrue) {l2=++label;l3=++label;l4=++label;}
+        if(!ltrue){
+	  if(p->flags==LAND)
+	    gen_IC(p->left,l1,l3);
+	  else 
+	    gen_IC(p->left,l3,l1);
+        }else{
+	  if(p->flags==LAND) 
+	    gen_IC(p->left,l1,lfalse);
+	  else 
+	    gen_IC(p->left,ltrue,l1);
+        }
+        if(p->left->o.flags!=0){
+            if(p->flags==LAND)
+                gen_test(&p->left->o,p->left->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+            else
+                gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+        }
+        gen_label(l1);
+        if(!ltrue){
+	  if(p->flags==LAND) 
+	    gen_IC(p->right,l2,l3);
+	  else
+	    gen_IC(p->right,l3,l2);
+        }else
+	  gen_IC(p->right,ltrue,lfalse);
+        if(p->right->o.flags!=0){
+            if(p->flags==LAND)
+                gen_test(&p->right->o,p->right->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+            else
+                gen_test(&p->right->o,p->right->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+        }
+        if(!ltrue){
+            gen_label(l2);
+            if(p->flags==LAND) gen_cond(&p->o,0,l3,l4); else gen_cond(&p->o,1,l3,l4);
+        }else{
+            new=new_IC();
+            new->code=BRA;
+            if(p->flags==LAND) new->typf=ltrue; else new->typf=lfalse;
+            add_IC(new);
+        }
+        if(ltrue) p->o.flags=0;
+        return;
+    }
+    if(p->flags==NEGATION){
+        int l1,l2,l3;
+        if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+        if(ltrue)
+	  gen_IC(p->left,lfalse,ltrue);
+	else
+	  gen_IC(p->left,l1,l3);
+        if(!p->left->o.flags){
+	  free(new);p->o.flags=0;
+        }else{
+            gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l1:lfalse));
+        }
+        if(ltrue){
+            new=new_IC();
+            new->code=BRA;
+            if(!ltrue) new->typf=l2; else new->typf=ltrue;
+            add_IC(new);
+            p->o.flags=0;
+        }else{
+            gen_label(l3);
+            gen_cond(&p->o,0,l1,l2);
+        }
+        return;
+    }
+    if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
+        int l1,l2,l3,tl,tr;
+        if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+        if(p->left->flags==CEXPR){
+        /*  Konstanten nach rechts  */
+            np merk;merk=p->left;p->left=p->right;p->right=merk;
+            if(p->flags==LESS) p->flags=GREATER;
+            else if(p->flags==LESSEQ) p->flags=GREATEREQ;
+            else if(p->flags==GREATER) p->flags=LESS;
+            else if(p->flags==GREATEREQ) p->flags=LESSEQ;
+        }
+        new->code=COMPARE;
+        tl=p->left->ntyp->flags&NU;tr=p->right->ntyp->flags&NU;
+        if(p->right->flags==CEXPR&&ISINT(tr)&&ISINT(tl)){
+            int negativ;
+            eval_constn(p->right);
+            if(zmleq(vmax,l2zm(0L))) negativ=1; else negativ=0;
+            if((tl&UNSIGNED)||(tr&UNSIGNED)) negativ=0;
+            if((!negativ||zmleq(t_min(tl),vmax))&&(negativ||zumleq(vumax,t_max(tl)))){
+                convert(p->right,tl);
+                tr=tl;
+            }
+        }
+        if(ISARITH(tl)&&(tl!=tr||!shortcut(COMPARE,tl))){
+            struct Typ *t;
+            t=arith_typ(p->left->ntyp,p->right->ntyp);
+            new->typf=t->flags;
+            freetyp(t);
+        }else{
+            new->typf=p->left->ntyp->flags;
+        }
+        gen_IC(p->left,0,0);
+        convert(p->left,new->typf);
+        gen_IC(p->right,0,0);
+        convert(p->right,new->typf);
+        new->q1=p->left->o;
+        new->q2=p->right->o;
+        new->z.flags=0;
+	if(p->flags==EQUAL||p->flags==INEQUAL){
+	  /* generate TEST, if possible */
+	  if(new->q2.flags&KONST){
+	    eval_const(&new->q2.val,new->typf);
+	    if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+	      new->code=TEST;
+	      new->q2.flags=0;
+	    }
+	  }
+	}
+        add_IC(new);
+        new=new_IC();
+        if(p->flags==EQUAL) new->code=BEQ;
+        if(p->flags==INEQUAL) new->code=BNE;
+        if(p->flags==LESS) new->code=BLT;
+        if(p->flags==LESSEQ) new->code=BLE;
+        if(p->flags==GREATER) new->code=BGT;
+        if(p->flags==GREATEREQ) new->code=BGE;
+        if(ltrue) new->typf=ltrue; else new->typf=l1;
+        add_IC(new);
+        if(ltrue){
+            new=new_IC();
+            new->code=BRA;
+            new->typf=lfalse;
+            add_IC(new);
+            p->o.flags=0;
+        }else{
+            gen_label(l3);
+            gen_cond(&p->o,1,l1,l2);
+        }
+        return;
+    }
+    if(p->flags==CALL){
+        int r=0;struct obj *op,cfunc,ret_obj;zmax sz;
+        int mregs[MAXR+1];
+	struct IC *callic;
+#ifdef ORDERED_PUSH
+        struct IC *merk_fp,*lp;
+	unsigned int merk_opushed=opushed;
+#endif
+        if(p->left->flags==ADDRESS&&p->left->left->flags==IDENTIFIER){
+            struct Var *v;
+            gen_IC(p->left,0,0); r=1;
+            v=p->left->o.v;
+            if(v->fi&&v->fi->first_ic&&!cross_module&&(c_flags_val[0].l&4096)){
+            /*  function call inlining  */
+                struct argument_list *al;
+                struct Var *vp,**argl1,**argl2;
+                struct IC *ip;int lc;
+                int arg_cnt=0,i;
+                if(DEBUG&1024){
+                    printf("inlining call to <%s>\n",v->identifier);
+                    for(vp=v->fi->vars;vp;vp=vp->next)
+                        printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);
+                }
+                for(vp=v->fi->vars;vp;vp=vp->next){
+		  /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+		  if((zmeqto(vp->offset,l2zm(0L))||vp->reg)&&*vp->identifier&&(vp->storage_class==AUTO||vp->storage_class==REGISTER)) arg_cnt++;
+                }
+
+                /*  Argumente in die ersten Parametervariablen kopieren */
+                argl1=mymalloc(arg_cnt*sizeof(struct Var *));
+                argl2=mymalloc(arg_cnt*sizeof(struct Var *));
+
+                al=p->alist;vp=v->fi->vars;i=0;
+                while(al){
+		    /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+		    while(vp&&(!*vp->identifier||(!zmeqto(vp->offset,l2zm(0L))&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next;
+                    if(!vp){ error(39); break; }
+                    if(i>=arg_cnt) ierror(0);
+                    if(DEBUG&1024) printf("arg: %s(%ld)\n",vp->identifier,zm2l(vp->offset));
+                    argl1[i]=vp;
+                    argl2[i]=add_var(empty,clone_typ(vp->vtyp),vp->storage_class,0);
+                    if(!al->arg) ierror(0);
+                    gen_IC(al->arg,0,0);
+                    convert(al->arg,vp->vtyp->flags);
+                    new=new_IC();
+                    new->code=ASSIGN;
+                    new->q1=al->arg->o;
+                    new->q2.flags=0;
+                    new->q2.val.vmax=szof(vp->vtyp);
+                    new->z.flags=VAR;
+                    new->z.val.vmax=l2zm(0L);
+                    new->z.v=argl2[i];
+                    new->typf=vp->vtyp->flags;
+                    add_IC(new);
+                    i++;
+                    al=al->next;
+                    vp=vp->next;
+                }
+                if(i<arg_cnt){ error(83); arg_cnt=i;}
+
+                /*  Kopien der Variablen erzeugen   */
+                for(vp=v->fi->vars;vp;vp=vp->next){
+                    vp->inline_copy=0;
+                }
+                for(i=0;i<arg_cnt;i++){
+                    if(argl1[i]){
+                        if(!argl2[i]) ierror(0);
+                        argl1[i]->inline_copy=argl2[i];
+                    }
+                }
+
+                /*  Rueckgabewert   */
+                if((p->ntyp->flags&NQ)!=VOID){
+                    p->o.flags=SCRATCH|VAR;
+                    p->o.reg=0;p->o.val.vmax=l2zm(0L);
+                    p->o.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+                }else{
+                    p->o.flags=0;
+                }
+
+                free(argl1);
+                free(argl2);
+
+                /*  Code einfuegen und Labels umschreiben   */
+                ip=v->fi->first_ic;lc=0;
+                while(ip){
+                    struct Var *iv;
+                    int c;
+                    new=new_IC();
+		    *new=*ip;
+		    ip->copy=new;
+                    c=ip->code;
+                    /*  evtl. ist ein IC praktisch ein SETRETURN, falls das */
+                    /*  Rueckgabeziel ueber Parameterzeiger angespr. wird   */
+                    if(ip->z.flags&VAR){
+                      iv=ip->z.v;
+                      if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+                        if(!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))){
+                          new->z=p->o;
+                        }else{
+                          if(!iv->inline_copy){
+                            iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+                            iv->inline_copy->reg=iv->reg;
+                          }
+                          new->z.v=iv->inline_copy;
+                        }/*else if(iv->inline_copy) ierror(0);*/
+                      }
+                    }
+                    /*  Kopien aller auto/register Variablen erzeugen   */
+                    if(ip->q1.flags&VAR){
+                      iv=ip->q1.v;
+                      if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+                        if(!iv->inline_copy){
+                          iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+                          iv->inline_copy->reg=iv->reg;
+                        }
+                        new->q1.v=iv->inline_copy;
+                      }/*else if(iv->inline_copy) ierror(0);*/
+                    }
+                    if(ip->q2.flags&VAR){
+                      iv=ip->q2.v;
+                      if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+                        if(!iv->inline_copy){
+                          iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+                          iv->inline_copy->reg=iv->reg;
+                        }
+                        new->q2.v=iv->inline_copy;
+                      }/*else if(iv->inline_copy) ierror(0);*/
+                    }
+                    if(c==CALL){
+		      int i;
+		      function_calls+=currentpri;
+		      new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+		      for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy;
+		    }
+                    if(c==LABEL||(c>=BEQ&&c<=BRA)){
+                        if(new->typf>lc) lc=new->typf;
+                        new->typf+=label;
+                    }
+                    if(c==SETRETURN){
+                        new->code=ASSIGN;
+                        new->z=p->o;
+                    }
+		    add_IC(new);
+                    ip=ip->next;
+                }
+                label+=lc;
+                return;
+            }
+            /*  einige spezielle Inline-Funktionen; das setzt voraus, dass  */
+            /*  diese in den Headerfiles passend deklariert werden          */
+            if(v->storage_class==EXTERN){
+	        if((optflags&2)&&!strcmp(v->identifier,"strlen")&&p->alist&&p->alist->arg){
+                    np n=p->alist->arg;
+                    if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+                        struct const_list *cl;zumax len=ul2zum(0UL);
+                        cl=n->left->cl;
+                        while(cl){
+			  if(zmeqto(l2zm(0L),zc2zm(cl->other->val.vchar))) break;
+			  len=zumadd(len,ul2zum(1UL));
+			  cl=cl->next;
+                        }
+                        p->o.val.vumax=len;
+                        eval_const(&p->o.val,UNSIGNED|MAXINT);
+                        insert_constn(p);
+                        insert_const(&p->o.val,p->ntyp->flags);
+                        p->flags=CEXPR;
+                        p->o.flags=KONST;
+                        return;
+                    }
+                }
+
+                if(INLINEMEMCPY>0&&(optflags&2)){
+                    if(!strcmp(v->identifier,"strcpy")&&p->alist&&p->alist->next&&p->alist->next->arg){
+                        np n=p->alist->next->arg;
+                        if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+                            struct const_list *cl;zmax len=l2zm(0L);
+                            cl=n->left->cl;
+                            while(cl){
+                                len=zmadd(len,l2zm(1L));
+                                if(zmeqto(zc2zm(cl->other->val.vchar),l2zm(0L))) break;
+                                cl=cl->next;
+                            }
+                            if(zmleq(len,l2zm((long)INLINEMEMCPY))){
+                                inline_memcpy(p->alist->arg,n,len);
+                                p->o=p->alist->arg->o;
+                                return;
+                            }
+                        }
+                    }
+                    if(!strcmp(v->identifier,"memcpy")){
+                        if(p->alist&&p->alist->next&&p->alist->next->next
+                           &&p->alist->next->next->arg
+                           &&p->alist->next->next->arg->flags==CEXPR){
+                            eval_constn(p->alist->next->next->arg);
+                            if(zmleq(vmax,l2zm((long)INLINEMEMCPY))){
+                                inline_memcpy(p->alist->arg,p->alist->next->arg,vmax);
+                                p->o=p->alist->arg->o;
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        rl=0;
+        if(!(optflags&2)){
+          int r;
+          for(r=1;r<=MAXR;r++){mregs[r]=regs[r];regs[r]&=~32;}
+        }
+#ifdef ORDERED_PUSH
+        merk_fp=first_pushed;
+        first_pushed=0;
+        lp=last_ic;
+#endif
+#ifdef HAVE_REGPARMS
+        if(!freturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){
+          struct IC *new2;static struct Typ ptyp={0};
+	  struct reg_handle reg_handle=empty_reg_handle;
+	  int reg;
+          new2=new_IC();
+          new2->code=ADDRESS;
+          new2->typf=p->ntyp->flags;
+	  new2->typf2=POINTER_TYPE(p->ntyp);
+          new2->q1.flags=VAR;
+          new2->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+          new2->q1.val.vmax=l2zm(0L);
+          op=&new2->q1;
+          new2->q2.flags=0;
+          get_scratch(&new2->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+          ret_obj=new2->z;
+          add_IC(new2);
+	  ptyp.next=p->ntyp;
+	  ptyp.flags=POINTER_TYPE(p->ntyp);
+	  reg=reg_parm(&reg_handle,&ptyp,0,p->left->ntyp);
+	  if(!reg) ierror(0);
+	  sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,&reg_handle,&ret_obj,p->ntyp,reg,p->left->ntyp);
+	  if(optflags&2)
+	    handle_reglist(rl,&ret_obj);
+	}else{
+	  struct reg_handle reg_handle=empty_reg_handle;
+	  sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,&reg_handle,0,0,-1,p->left->ntyp);
+	  if(optflags&2)
+	    handle_reglist(rl,0);
+	}
+#else
+        sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl);
+	if(optflags&2)
+	  handle_reglist(rl,0);
+#endif
+        if(!r) gen_IC(p->left,0,0);
+        if(!(p->left->o.flags&DREFOBJ)){
+            free(new);
+            p->o=p->left->o;
+            if(p->o.flags&VARADR){
+	      p->o.flags&=~VARADR;
+	    }else{
+	      p->o.flags|=DREFOBJ;
+	      p->o.dtyp=p->left->ntyp->flags;
+	    }
+        }else{
+            if(p->left->o.flags&VARADR){
+                free(new);
+                p->o=p->left->o;
+                p->o.flags&=~VARADR;
+            }else{
+                if((p->left->o.flags&SCRATCH)&&p->ntyp->flags==p->left->ntyp->flags){
+		  new->z=p->left->o;
+		  new->z.flags&=~DREFOBJ;
+                }else{
+		  get_scratch(&new->z,p->left->ntyp->flags,FUNKT,p->left->ntyp);
+                }
+                new->code=ASSIGN;
+		new->typf=p->left->ntyp->flags;
+                new->q1=p->left->o;
+                new->q2.val.vmax=sizetab[new->typf];
+                new->q2.flags=0;
+                p->o=new->z;
+                add_IC(new);
+                p->o.flags|=DREFOBJ;
+		p->o.dtyp=p->left->ntyp->flags;
+            }
+        }
+/*            p->left->o.flags-=DREFOBJ|VARADR; Was sollte das??    */
+
+#if 0
+        if(optflags&2){
+            while(rl){
+                struct regargs_list *m;
+                new=new_IC();
+                new->code=NOP;
+                new->q1.flags=VAR;
+                new->q1.v=rl->v;
+                new->q1.val.vmax=l2zm(0L);
+                new->typf=0;
+                new->q2.flags=new->z.flags=0;
+                add_IC(new);
+                m=rl->next;free(rl);rl=m;
+            }
+        }
+#endif
+
+#ifndef HAVE_REGPARMS
+        /*  gegebenenfalls Adresse des Ziels auf den Stack  */
+        if(!freturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){
+#ifdef ORDERED_PUSH
+            ierror(0);
+#endif
+            new=new_IC();
+            new->code=ADDRESS;
+            new->typf=p->ntyp->flags;
+	    new->typf2=POINTER_TYPE(p->ntyp->next);
+            new->q1.flags=VAR;
+            new->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+            new->q1.val.vmax=l2zm(0L);
+            op=&new->q1;
+            new->q2.flags=0;
+            get_scratch(&new->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+            ret_obj=new->z;
+            add_IC(new);
+            new=new_IC();
+            new->code=PUSH;
+            new->typf=POINTER_TYPE(p->ntyp);
+            new->q1=ret_obj;
+            new->q2.flags=new->z.flags=0;
+            new->q2.val.vmax=sizetab[new->typf];
+	    new->z.val.vmax=new->q2.val.vmax;
+            add_IC(new);
+            sz=zmadd(sz,sizetab[new->typf]);
+        }
+#endif
+
+        /*  Scratchregister evtl. sichern   */
+	cfunc=p->o;
+        if(!nocode)
+	  savescratch(MOVEFROMREG,last_ic,0,&cfunc);
+        function_calls+=currentpri;
+        new=new_IC();
+        new->code=CALL;
+	callic=new;
+	if(p->alist){
+	  /* insert list of argument ICs */
+	  int i=0;
+	  struct argument_list *a=p->alist;
+	  while(a){i++;a=a->next;}
+	  new->arg_cnt=i;
+	  new->arg_list=mymalloc(sizeof(*new->arg_list)*i);
+	  for(a=p->alist,i=0;a;a=a->next,i++) new->arg_list[i]=a->pushic;
+	}else{
+	  new->arg_cnt=0;
+	  new->arg_list=0;
+	}
+        new->typf=FUNKT;
+        new->q1=p->o;
+        new->q2.flags=new->z.flags=0;
+        new->q2.val.vmax=sz; /*  Groesse der Parameter auf dem Stack */
+        add_IC(new);
+
+        if(optflags&2){
+            while(rl){
+                struct regargs_list *m;
+                new=new_IC();
+                new->code=NOP;
+                new->q1.flags=VAR;
+                new->q1.v=rl->v;
+                new->q1.val.vmax=l2zm(0L);
+                new->typf=0;
+                new->q2.flags=new->z.flags=0;
+                add_IC(new);
+                m=rl->next;free(rl);rl=m;
+            }
+        }
+
+        r=0;
+        if((p->ntyp->flags&NQ)!=VOID){
+            new=new_IC();
+            new->code=GETRETURN;
+            new->q1.flags=new->q2.flags=0;
+            new->q1.reg=freturn(p->ntyp);
+            new->q2.val.vmax=szof(p->ntyp);
+            new->typf=p->ntyp->flags;
+            if(freturn(p->ntyp)){
+              int t=p->ntyp->flags&NQ;
+              if(ISSTRUCT(t)||ISUNION(t)){
+                new->z.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+                new->z.flags=VAR;
+                new->z.val.vmax=l2zm(0L);
+              }else{
+                if(optflags&2){
+                  get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+                }else{
+                  /* Suche geeignetes Register, um Rueckgabewert zu speichern. */
+                  struct regargs_list *l2;
+                  int r;
+                  r=new->q1.reg;
+                  if(regs[r]||!regok(r,p->ntyp->flags,0)||(reg_pair(r,&rp)&&(regs[rp.r1]||regs[rp.r2]))){
+                    r=0;
+                  }else{
+                    for(l2=rl;l2;l2=l2->next){
+                      if(l2->v&&abs(l2->reg)==r) {r=0;break;}
+                    }
+                  }
+                  if(r==0){
+                    for(r=1;r<=MAXR;r++){
+                      if(!regs[r]&&regok(r,p->ntyp->flags,0)&&(!reg_pair(r,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+                        for(l2=rl;l2;l2=l2->next){
+                          if(l2->v&&abs(l2->reg)==r) break;
+                        }
+                        if(l2) continue;
+                        break;
+                      }
+                    }
+                  }
+                  if(r>=1&&r<=MAXR){
+                    alloc_hardreg(r);
+                    new->z.flags=(REG|SCRATCH);
+                    new->z.reg=r;
+                  }else{
+                    get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+                  }
+                }
+              }
+            } else
+              new->z=*op;
+            if((new->z.flags&(REG|DREFOBJ))==REG) r=new->z.reg;
+            p->o=new->z;
+            add_IC(new);
+        }else{
+            p->o.flags=0;
+        }
+        /*  Scratchregister evtl. wiederherstellen  */
+        if(!nocode)
+	  savescratch(MOVETOREG,last_ic,r,&cfunc);
+        if(!(optflags&2)){
+          int r;
+          for(r=1;r<=MAXR;r++){
+            if(regs[r])
+              regs[r]|=(mregs[r]&32);
+          }
+        }
+        /*  Evtl. gespeicherte Registerargumente wiederherstellen.  */
+        while(rl){
+            struct regargs_list *m;
+            if(rl->v){
+	      int r;
+	      for(r=MAXR;r>=1;r--){
+		if(regs[r]&&reg_pair(r,&rp)&&(rp.r1==abs(rl->reg)||rp.r2==abs(rl->reg)))
+		  break;
+	      }
+	      if(r<=1) r=abs(rl->reg);
+	      new=new_IC();
+	      new->code=MOVETOREG;
+	      new->typf=0;
+	      new->q1.flags=VAR|DONTREGISTERIZE;
+	      new->q1.v=rl->v;
+	      new->q1.val.vmax=l2zm(0L);
+	      new->z.flags=REG;
+	      new->z.reg=abs(r);
+	      new->q2.flags=0;
+	      new->q2.val.vmax=regsize[r];
+	      add_IC(new);
+            }else{
+                new=new_IC();
+                new->code=FREEREG;
+                new->typf=0;
+                new->q1.flags=REG;
+                new->q2.flags=new->z.flags=0;
+                new->q1.reg=abs(rl->reg);
+                add_IC(new);
+                regs[abs(rl->reg)]=0;
+            }
+            m=rl->next;free(rl);rl=m;
+        }
+#ifdef ORDERED_PUSH
+        /* If arguments have been pushed nested we have to copy them and */
+        /* push them later. */
+        if(merk_fp&&opushed!=merk_opushed){
+          struct IC *p,*m=0,*np;
+          if(!lp) ierror(0);
+          for(p=merk_fp;p;){
+            np=p->next;
+            if(p->code==PUSH){
+              new=new_IC();
+              *new=*p;
+	      /* be careful about the address because of arg_list! */
+	      if(p->prev) p->prev->next=new;
+	      new->prev=p->prev;
+	      if(p->next) p->next->prev=new;
+	      new->next=p->next;
+	      if(p==last_ic) last_ic=new;
+	      if(p==first_ic) first_ic=new;
+              if(new->q1.flags){
+                new->code=ASSIGN;
+                new->z.flags=VAR;
+                new->z.val.vmax=l2zm(0L);
+		/* typ allocated in push_args and not used there */
+		/*		if(!p->ityp) ierror(0);*/
+		new->z.v=add_tmp_var(clone_typ(p->ityp)); /*FIXME??*/
+                p->q1=new->z;
+		/*		p->ityp=0;*/
+              }else{
+                remove_IC(new);
+              }
+	      p->next=p->prev=0;
+              add_IC(p);
+              if(!m) m=p;
+            }
+            if(p==lp) break;
+            p=np;
+          }
+          if(!m) ierror(0);
+          first_pushed=m;
+        }else
+          first_pushed=merk_fp;
+#endif
+        return;
+    }
+    if(p->flags>=PREINC&&p->flags<=POSTDEC){
+        struct obj o;
+#if HAVE_LIBCALLS
+	char *libname;
+	struct node tn={ADD},one={CEXPR};
+#endif
+        gen_IC(p->left,0,0);
+        if(p->flags==POSTINC||p->flags==POSTDEC){
+	  /*new=new_IC();*/
+            new->code=ASSIGN;
+            new->typf=p->ntyp->flags;
+            new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+            new->q1=p->left->o;
+            new->q1.flags&=~SCRATCH;
+            get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+            new->q2.flags=0;
+            o=new->z;
+            add_IC(new);
+            new=new_IC();
+        }else
+	  o=p->left->o;
+#if HAVE_LIBCALLS
+	if(p->flags==PREDEC||p->flags==POSTDEC)
+	  tn.flags=SUB;
+	tn.left=p->left;
+	tn.right=&one;
+	tn.ntyp=p->ntyp;
+	one.flags=CEXPR;
+	one.ntyp=p->ntyp;
+	gval.vmax=l2zm(1L);
+	eval_const(&gval,MAXINT);
+	insert_const(&one.val,p->ntyp->flags&NU);
+	if(libname=use_libcall(&tn)){
+	  np lc;
+	  lc=gen_libcall(libname,p->left,0,&one,0);
+	  new=new_IC();
+	  new->code=ASSIGN;
+	  new->typf=p->ntyp->flags;
+	  new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+	  new->q1=lc->o;
+	  new->q1.flags&=~SCRATCH;
+	  new->z=p->left->o;
+	  add_IC(new);
+	  new=new_IC();
+	  free(lc);
+	}else
+#endif
+        if(ISPOINTER(p->left->ntyp->flags)){
+            if(p->flags==PREINC||p->flags==POSTINC)
+	      new->code=ADDI2P; 
+	    else
+	      new->code=SUBIFP;
+            vmax=szof(p->left->ntyp->next);
+            new->q2.val.vint=zm2zi(vmax);
+            new->typf=INT;
+	    new->typf2=p->left->ntyp->flags;
+            new->q1=p->left->o;
+            new->z=p->left->o;
+            new->q2.flags=KONST;
+            add_IC(new);
+        }else{
+            if(p->flags==PREINC||p->flags==POSTINC)
+	      new->code=ADD;
+	    else 
+	      new->code=SUB;
+            new->typf=p->ntyp->flags;
+            new->q1=p->left->o;
+            new->z=p->left->o;
+            new->q2.flags=KONST;
+	    gval.vint=zm2zi(l2zm(1L));
+	    eval_const(&gval,INT);
+	    insert_const(&new->q2.val,new->typf);
+            add_IC(new);
+        }
+        if(p->flags==POSTINC||p->flags==POSTDEC){
+            if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) 
+	      free_reg(p->left->o.reg);
+        }
+        p->o=o;
+        return;
+    }
+    if(p->flags==COND){
+        int ltrue,lfalse,lout;
+        ltrue=++label;lfalse=++label;lout=++label;
+        gen_IC(p->left,ltrue,lfalse);
+        if(!p->left->o.flags){
+            free(new);
+        }else{
+            if(p->left->flags!=CEXPR){
+                gen_test(&p->left->o,p->left->ntyp->flags,BEQ,lfalse);
+            }else{
+                eval_constn(p->left);
+                if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+                    gen_IC(p->right->right,0,0);
+                    p->o=p->right->right->o;
+                }else{
+                    gen_IC(p->right->left,0,0);
+                    p->o=p->right->left->o;
+                }
+                return;
+            }
+        }
+        gen_label(ltrue);
+        gen_IC(p->right->left,0,0);
+        if((p->ntyp->flags&NQ)!=VOID){
+            convert(p->right->left,p->ntyp->flags);
+            if((p->right->left->o.flags&(SCRATCH|DREFOBJ))==SCRATCH){
+                p->o=p->right->left->o;
+            }else{
+                get_scratch(&p->o,p->ntyp->flags,0,p->ntyp);
+                new=new_IC();
+                new->code=ASSIGN;
+                new->q1=p->right->left->o;
+                new->z=p->o;
+                new->q2.flags=0;
+                new->q2.val.vmax=szof(p->ntyp);
+                new->typf=p->ntyp->flags;
+                p->o=new->z;
+                add_IC(new);
+            }
+        }else
+	  p->o.flags=0;
+        new=new_IC();
+        new->code=BRA;
+        new->typf=lout;
+        add_IC(new);
+        gen_label(lfalse);
+        gen_IC(p->right->right,0,0);
+        if((p->ntyp->flags&NQ)!=VOID){
+            convert(p->right->right,p->ntyp->flags);
+            new=new_IC();
+            new->code=ASSIGN;
+            new->q1=p->right->right->o;
+            new->z=p->o;
+            new->q2.flags=0;
+            new->q2.val.vmax=szof(p->ntyp);
+            new->typf=p->ntyp->flags;
+            add_IC(new);
+        }
+        gen_label(lout);
+        return;
+    }
+    printf("Operation: %d=%s\n",p->flags,ename[p->flags]);
+    ierror(0);
+    free(new);
+    p->o.flags=0;
+}
+
+static void handle_reglist(struct regargs_list *nrl,struct obj *radr)
+{
+  struct IC *new;
+  /*  Letztes Argument; jetzt in Register laden.  */
+#ifdef HAVE_REGPARMS
+  int didradr=0;
+#endif
+  while(nrl){
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=nrl->v->vtyp->flags/*|VOLATILE*/;
+    new->q1.flags=VAR;
+    new->q1.v=nrl->v;
+    new->q1.val.vmax=l2zm(0L);
+    new->q2.flags=0;
+    new->q2.val.vmax=szof(nrl->v->vtyp);
+    new->z.flags=VAR;
+    new->z.val.vmax=l2zm(0L);
+    new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0);
+    new->z.v->reg=nrl->reg;
+    new->z.v->vtyp->flags|=VOLATILE;
+    nrl->v=new->z.v;
+    add_IC(new);
+    
+#ifdef HAVE_REGPARMS
+    if(radr&&!didradr){
+      didradr=1;
+    }else{
+#endif
+      nrl->al->pushic=new;
+#ifdef HAVE_REGPARMS
+    }
+#endif
+    nrl=nrl->next;
+  }
+}
+
+#ifdef HAVE_REGPARMS
+zmax push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl,struct reg_handle *reg_handle,struct obj *radr,struct Typ *rtype,int rreg,struct Typ *fkt)
+#else
+zmax push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl)
+#endif
+/*  Legt die Argumente eines Funktionsaufrufs in umgekehrter Reihenfolge    */
+/*  auf den Stack. Es wird Integer-Erweiterung vorgenommen und float wird   */
+/*  nach double konvertiert, falls kein Prototype da ist.                   */
+{
+    int t,reg,regpush,evaluated=0;struct Typ *ft;
+    struct IC *new;struct regargs_list *nrl;zmax sz,rsz,of;struct obj *arg;
+#ifdef HAVE_REGPARMS
+    int stdreg;
+    if(!al&&!radr) return(0);
+    if(radr){
+      stdreg=rreg;
+    }else{
+      if(n<sd->count){
+        stdreg=reg_parm(reg_handle,(*sd->sl)[n].styp,0,fkt);
+      }else{
+        if(sd->count)
+          stdreg=reg_parm(reg_handle,al->arg->ntyp,1,fkt);
+        else
+          stdreg=reg_parm(reg_handle,al->arg->ntyp,0,fkt);
+      }
+    }
+    reg=stdreg;
+#else
+    if(!al) return(0);
+    reg=0;
+#endif
+#ifdef HAVE_REGPARMS
+    if(!radr){
+#endif
+      if(!al->arg) ierror(0);
+      if(!sd) ierror(0);
+      if(n<sd->count){
+        ft=clone_typ((*sd->sl)[n].styp);sz=szof(ft);
+	t=ft->flags;
+        reg=(*sd->sl)[n].reg;
+      }else{
+        ft=clone_typ(al->arg->ntyp);sz=szof(ft);
+	t=ft->flags;
+      }
+      if(ISINT(t)) {t=int_erw(t);ft->flags=t;sz=sizetab[t&NQ];}
+      if((t&NQ)==FLOAT&&n>=sd->count) {t=DOUBLE;ft->flags=t;sz=sizetab[t];}
+#ifdef HAVE_REGPARMS
+    }else{
+      ft=new_typ();
+      ft->flags=t=POINTER_TYPE(rtype);
+      ft->next=clone_typ(rtype);
+      sz=sizetab[t];
+    }
+#endif
+    if(reg<0) {reg=-reg;regpush=1;} else regpush=0;
+    rsz=sz;
+    sz=zmmult(zmdiv(zmadd(sz,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+#ifdef ORDERED_PUSH
+    if(reg==0||regpush){
+      new=new_IC();
+      if(!radr&&!evaluated){
+        gen_IC(al->arg,0,0);
+        convert(al->arg,t);
+        evaluated=1;
+        new->q1=al->arg->o;
+	al->pushic=new;
+      }else
+        new->q1=*radr;
+      /*  Parameteruebergabe ueber Stack. */
+      new->code=PUSH;
+      new->typf=t;
+      new->ityp=ft;
+      new->q2.flags=new->z.flags=0;
+      new->q2.val.vmax=sz;
+      new->z.val.vmax=rsz;
+      if(regpush){
+        if(c_flags[26]&USEDFLAG){
+          new->q1.am=new->q2.am=new->z.am=0;
+          new->line=line; new->file=filename;
+          insert_IC(last_ic,new);
+        }else{
+          new->q1.flags=0;
+          add_IC(new);
+        }
+      }else{
+        add_IC(new);
+      }
+      opushed++;
+      if(!first_pushed) first_pushed=new;
+      if(al&&!al->next&&!regpush) return sz;
+    }
+#endif
+#ifdef HAVE_REGPARMS
+    if(radr){
+      if(al) of=push_args(al,sd,0,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+    }else{
+      if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+    }
+#else
+    if(al->next) of=push_args(al->next,sd,n+1,rl); else of=l2zm(0L);
+#endif
+#ifdef ORDERED_PUSH
+    if(reg==0) return zmadd(of,sz);
+#endif
+
+    if(regpush) of=zmadd(of,sz);
+
+#ifdef HAVE_REGPARMS
+    if(radr){
+      arg=radr;
+    }else{
+      if(!evaluated){
+        gen_IC(al->arg,0,0);
+        convert(al->arg,t);
+        evaluated=1;
+      }
+      arg=&al->arg->o;
+    }
+#else
+    if(!evaluated){
+      gen_IC(al->arg,0,0);
+      convert(al->arg,t);
+      evaluated=1;
+    }
+    arg=&al->arg->o;
+#endif
+#ifndef ORDERED_PUSH
+    if(reg==0||regpush){
+        /*  Parameteruebergabe ueber Stack. */
+        new=new_IC();
+        new->code=PUSH;
+        new->typf=t;
+        new->q1=*arg;
+        if(regpush&&!(c_flags[26]&USEDFLAG)) new->q1.flags=0;
+        new->q2.flags=new->z.flags=0;
+        new->q2.val.vmax=sz;
+	new->z.val.vmax=rsz;
+        add_IC(new);
+	al->pushic=new;
+        if(!regpush) return(zmadd(of,sz));
+    }
+#endif
+    if(reg){
+        /*  Parameteruebergabe in Register. */
+        struct Var *v=0; struct Typ *t2;
+        if(optflags&2){
+        /*  Version fuer Optimizer. */
+            t2=new_typ();
+            t2->flags=t;
+            if(ISPOINTER(t)){
+                t2->next=new_typ();
+                t2->next->flags=VOID;
+            }
+            v=add_var(empty,t2,AUTO,0);
+            new=new_IC();
+            new->code=ASSIGN;
+            new->typf=t;
+            new->q1=*arg;
+            new->q2.flags=0;
+            new->q2.val.vmax=sizetab[t&NQ];
+            new->z.flags=VAR;
+            new->z.v=v;
+            new->z.val.vmax=l2zm(0L);
+            add_IC(new);
+            nrl=mymalloc(sizeof(*nrl));
+            nrl->next=*rl;
+            nrl->reg=reg;
+            nrl->v=v;
+	    nrl->al=al;
+            *rl=nrl;
+            return of;
+        }else{
+        /*  Nicht-optimierende Version. */
+            if(!regs[reg]&&(!reg_pair(reg,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+                new=new_IC();
+                new->code=ALLOCREG;
+                new->typf=0;
+                new->q1.flags=REG;
+                new->q1.reg=reg;
+                new->q2.flags=new->z.flags=0;
+                add_IC(new);
+                regs[reg]=33;regused[reg]++;
+		if(reg_pair(reg,&rp)){
+		  regs[rp.r1]=33;regused[rp.r1]++;
+		  regs[rp.r2]=33;regused[rp.r2]++;
+		}
+            }else{
+                if(arg->flags!=(REG|SCRATCH)||arg->reg!=reg){
+		  int r=0;
+		  /* register pairs */
+		  if(reg_pair(reg,&rp)){
+		    if(regs[reg]||regs[rp.r1]||regs[rp.r2]) 
+		      r=reg;
+		  }else{
+		    for(r=MAXR;r>=1;r--){
+		      if(regs[r]&&reg_pair(r,&rp)&&(rp.r1==reg||rp.r2==reg))
+			break;
+		    }
+		    if(r<1) r=reg;
+		  }
+		  t2=clone_typ(regtype[r]);
+		  v=add_var(empty,t2,AUTO,0);
+		  v->flags|=USEDASADR;
+		  new=new_IC();
+		  new->code=MOVEFROMREG;
+		  new->typf=0;
+		  new->q1.flags=REG;
+		  new->q1.reg=r;
+		  new->q2.flags=0;
+		  new->q2.val.vmax=regsize[r];
+		  new->z.flags=VAR|DONTREGISTERIZE;
+		  new->z.v=v;
+		  new->z.val.vmax=l2zm(0L);
+		  add_IC(new);
+                }else
+		  regs[reg]|=32;
+            }
+            new=new_IC();
+#ifdef HAVE_REGPARMS
+	    if(!radr){
+	      al->pushic=new;
+	    }
+#else
+	    al->pushic=new;
+#endif
+	    new->code=ASSIGN;
+	    new->typf=t;
+            new->q1=*arg;
+            /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+            if((new->q1.flags&REG)){
+              struct regargs_list *p;
+              for(p=*rl;p;p=p->next){
+		int r;
+                if(p->v&&(r=abs(p->reg))){
+		  if(new->q1.reg==r||(reg_pair(new->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+		  /*FIXME: andersrum bei LITTLEENDIAN?? */
+		  if(reg_pair(r,&rp)&&rp.r1==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+		  if(reg_pair(r,&rp)&&rp.r2==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=regsize[rp.r1];break;}
+
+		}
+              }
+              if(p&&new->q1.v){
+		if(must_convert(new->typf,regtype[new->q1.reg]->flags,0)){
+		  new->code=CONVERT;
+		  new->typf2=regtype[new->q1.reg]->flags;
+		}
+                new->q1.flags&=~REG;
+                new->q1.flags|=VAR;
+                /*new->q1.val.vmax=l2zm(0L);*/
+              }
+            }
+            new->q2.flags=new->z.flags=0;
+            new->q2.val.vmax=sizetab[t&NQ];
+            new->z.flags=REG;
+            new->z.reg=reg;
+            add_IC(new);
+            nrl=mymalloc(sizeof(*nrl));
+            nrl->next=*rl;
+            nrl->reg=reg;
+            nrl->v=v;
+            *rl=nrl;
+            return of;
+        }
+    }
+}
+
+void convert(np p,int f)
+/*  konvertiert das Objekt in p->o in bestimmten Typ    */
+/* wenn volatile_convert gesetzt ist, wird immer IC erzeugt */
+{
+  struct IC *new;
+  int o=p->ntyp->flags;
+  if((f&NQ)==VOID) return;
+  if(p->flags==CEXPR||p->flags==PCEXPR){
+#ifdef HAVE_MISRA
+    if((o&NU)<(f&NU))
+      misra_neu(18,0,0,-1);
+#endif
+    eval_constn(p);
+    p->ntyp->flags=f;
+    insert_constn(p);
+    p->o.val=p->val;
+    return;
+  }
+  if(!volatile_convert&&((o&NU)==(f&NU)||(!must_convert(o,f,const_expr)&&(const_expr||!(optflags&2))))){
+    p->ntyp->flags=f;
+    if(!ISPOINTER(f)&&!ISARRAY(f)){freetyp(p->ntyp->next);p->ntyp->next=0;}
+    return;
+  }
+  new=new_IC();
+  new->q1=p->o;
+  new->q2.flags=0;
+  new->code=CONVERT;
+  new->typf2=o;
+  new->typf=f;
+  if((p->o.flags&(SCRATCH|REG))!=(SCRATCH|REG)||!regok(p->o.reg,f,0)){
+    get_scratch(&new->z,f,0,0);
+    p->o=new->z;
+    add_IC(new);
+  }else{
+    new->z=p->o;new->z.flags&=~DREFOBJ;
+    p->o=new->z;
+    add_IC(new);
+  }
+}
+
+void alloc_hardreg(int r)
+/*  Belegt Register r.  */
+{
+  struct IC *new;
+  if(nocode) return;
+  if(DEBUG&16) printf("allocated %s\n",regnames[r]);
+  regs[r]=1;regused[r]++;
+  new=new_IC();
+  new->code=ALLOCREG;
+  new->typf=0;
+  new->q1.flags=REG;
+  new->q1.reg=r;
+  new->q2.flags=new->z.flags=0;
+  add_IC(new);
+  if(reg_pair(r,&rp)){
+    regs[rp.r1]=1;regused[rp.r1]++;
+    regs[rp.r2]=1;regused[rp.r2]++;
+  }
+}
+
+int allocreg(int f,int mode)
+/*  Fordert Register fuer Typ f an.                     */
+{
+  int i,r=0,prio=-1;
+  if(nocode) return(1);
+  for(i=1;i<=MAXR;i++){
+    if(!regs[i]&&reg_prio[i]>prio&&regok(i,f,mode)&&(!reg_pair(i,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+      r=i;
+      prio=reg_prio[i];
+    }
+  }
+  if(r){
+    if(DEBUG&16) printf("alloc %s\n",regnames[r]);
+    alloc_hardreg(r);
+    return r;
+  }
+  if(DEBUG&1) printf("Couldn't allocate register for type %d\n",f);
+  return 0;
+}
+void free_reg(int r)
+/*  Gibt Register r frei                                */
+/*  Eintrag eines IC fehlt noch                         */
+{
+    struct IC *new;
+    if(!r||nocode) return;
+    if(regs[r]==0)
+      {printf("Register %d(%s):\n",r,regnames[r]);ierror(0);}
+    if(DEBUG&16) printf("freed %s\n",regnames[r]);
+    new=new_IC();
+    new->code=FREEREG;
+    new->typf=0;
+    new->q1.flags=REG;
+    new->q1.reg=r;
+    new->q2.flags=new->z.flags=0;
+    add_IC(new);
+    regs[r]=0;
+    if(reg_pair(r,&rp)){
+      regs[rp.r1]=0;
+      regs[rp.r2]=0;
+    }
+}
+void gen_label(int l)
+/*  Erzeugt ein Label                                   */
+{
+    struct IC *new;
+    new=new_IC();
+    new->code=LABEL;
+    new->typf=l;
+    new->q1.flags=new->q2.flags=new->z.flags=0;
+    add_IC(new);
+}
+void gen_cond(struct obj *p,int m,int l1,int l2)
+/*  Generiert code, der 0 oder 1 in Register schreibt. Schreibt obj nach p. */
+{
+    struct IC *new;
+    struct obj omerk;
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=INT;
+    new->q1.flags=KONST;
+    new->q2.flags=0;
+    new->q2.val.vmax=sizetab[INT];
+    if(!m) vmax=l2zm(1L); else vmax=l2zm(0L);
+    new->q1.val.vint=zm2zi(vmax);
+    get_scratch(&new->z,INT,0,0);
+    omerk=new->z;
+    add_IC(new);
+    new=new_IC();
+    new->code=BRA;
+    new->typf=l2;
+    add_IC(new);
+    gen_label(l1);
+    new=new_IC();
+    new->code=ASSIGN;
+    new->typf=INT;
+    new->q1.flags=KONST;
+    new->q2.flags=0;
+    new->q2.val.vmax=sizetab[INT];
+    if(!m) vmax=l2zm(0L); else vmax=l2zm(1L);
+    new->q1.val.vint=zm2zi(vmax);
+    new->z=omerk;
+/*    new->z.reg=r;
+    new->z.flags=SCRATCH|REG;*/
+    add_IC(new);
+    gen_label(l2);
+    *p=omerk;
+}
+void scratch_var(struct obj *o,int t,struct Typ *typ)
+/*  liefert eine temporaere Variable                            */
+/*  nicht effizient, aber wer hat schon so wenig Register...    */
+{
+  struct Typ *nt;
+  if(!ISSCALAR(t)){
+    if(!typ) ierror(0);
+    nt=clone_typ(typ);
+  }else{
+    nt=new_typ();
+    nt->flags=t;
+    if(ISPOINTER(t)){
+      nt->next=new_typ();
+      nt->next->flags=VOID;
+    }
+  }
+  o->flags=SCRATCH|VAR;o->reg=0;
+  o->v=add_var(empty,nt,AUTO,0);
+  o->val.vmax=l2zm(0L);
+}
+void get_scratch(struct obj *o,int t1,int t2,struct Typ *typ)
+/*  liefert ein Scratchregister oder eine Scratchvariable       */
+{
+    if(!(optflags&2)&&(o->reg=allocreg(t1,t2))){
+        o->flags=SCRATCH|REG;
+    }else{
+        scratch_var(o,t1,typ);
+    }
+}
+int do_arith(np p,struct IC *new,np dest,struct obj *o)
+/*  erzeugt IC new fuer einen arithmetischen Knoten und speichert das   */
+/*  Resultat vom Unterknoten dest in o (fuer a op= b)               */
+/*  liefert 0, wenn dest nicht gefunden                             */
+{
+    int f=0,mflags;
+    new->code=p->flags;
+    if(new->code==PMULT) new->code=MULT;
+    gen_IC(p->left,0,0);
+    if(dest&&p->left==dest) {*o=p->left->o;f++;}
+    gen_IC(p->right,0,0);
+    if(dest&&p->right==dest) {*o=p->right->o;f++;}
+    if(dest){mflags=dest->o.flags;dest->o.flags&=(~SCRATCH);}
+
+    if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){
+    /*  Subtrahieren zweier Pointer                                 */
+      int dt=PTRDIFF_T(p->left->ntyp->flags);
+      if(p->flags!=SUB) ierror(0);
+      new->typf=dt;
+      new->typf2=p->left->ntyp->flags;
+      new->code=SUBPFP;
+      new->q1=p->left->o;
+      new->q2=p->right->o;
+      if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->left->o.reg,dt,0)){
+	new->z=p->left->o;
+	new->z.flags&=~DREFOBJ;
+      }else{
+	if(USEQ2ASZ&&(p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(p->right->o.reg,dt,0)){
+	  new->z=p->right->o;
+	  new->z.flags&=(~DREFOBJ);
+	}else{
+	  get_scratch(&new->z,dt,0,0);
+	}
+      }
+      p->o=new->z;
+      add_IC(new);
+      if(!zmleq(szof(p->left->ntyp->next),l2zm(1L))){
+	new=new_IC();
+	new->code=DIV;
+	new->q1=p->o;
+	new->q2.flags=KONST;
+	gval.vmax=szof(p->left->ntyp->next);
+	eval_const(&gval,MAXINT);
+	insert_const(&new->q2.val,dt);
+	new->z=p->o;
+	new->typf=dt;
+	add_IC(new);
+      }
+      if(dest) dest->o.flags=mflags;
+      return f;
+    }
+    if((p->flags==ADD||p->flags==SUB)&&ISPOINTER(p->ntyp->flags)){
+      /*  Addieren und Subtrahieren eines Integers zu einem Pointer   */
+      if(p->flags==ADD){
+	new->code=ADDI2P;
+	if(!ISPOINTER(p->left->ntyp->flags)){
+	  np tmp=p->left;
+	  p->left=p->right;
+	  p->right=tmp;
+	}
+      }else
+	new->code=SUBIFP;
+      new->typf=p->right->ntyp->flags;
+      new->typf2=p->ntyp->flags;
+      new->q1=p->left->o;
+      /*  kleinere Typen als MINADDI2P erst in diesen wandeln */
+      if((new->typf&NQ)<MINADDI2P){convert(p->right,MINADDI2P);new->typf=MINADDI2P;}
+      /*  groessere Typen als MAXADDI2P erst in diesen wandeln */
+      if((new->typf&NQ)>MAXADDI2P){convert(p->right,MAXADDI2P);new->typf=MAXADDI2P;}      
+      if((p->left->o.flags&VARADR)&&(p->right->o.flags&KONST)){
+	eval_const(&p->right->o.val,p->right->ntyp->flags);
+	p->o=p->left->o;
+	p->o.val.vmax=zmadd(vmax,p->left->o.val.vmax);
+	free(new);
+	return f;
+      }
+      new->q2=p->right->o;
+      if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(new->q1.reg,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags)){
+	new->z=p->left->o;
+	new->z.flags&=(~DREFOBJ);
+      }else{
+	get_scratch(&new->z,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags,0);
+      }
+      p->o=new->z;
+      add_IC(new);
+      if(dest) dest->o.flags=mflags;
+      return f;
+    }
+    convert(p->left,p->ntyp->flags);
+    if(p->flags==LSHIFT||p->flags==RSHIFT){
+      struct Typ *st=clone_typ(p->right->ntyp);
+      /*st->flags=int_erw(st->flags);*/
+      st->flags=INT;
+      convert(p->right,st->flags);
+      new->typf2=st->flags;
+      freetyp(st);
+    }else
+      convert(p->right,p->ntyp->flags);
+    new->q1=p->left->o;
+    new->q2=p->right->o;
+    new->typf=p->ntyp->flags;
+    /*  Bei dest!=0, d.h. ASSIGNOP, darf q1 nicht als Ziel benuzt werden!  */
+    if(!dest&&(new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regok(new->q1.reg,p->ntyp->flags,0)){
+      new->z=new->q1;
+      new->z.flags&=~DREFOBJ;
+    }else{
+      if((new->q2.flags&SCRATCH)&&regok(new->q2.reg,p->ntyp->flags,0)){
+	if((p->flags>=OR&&p->flags<=AND)||p->flags==ADD||p->flags==MULT||p->flags==PMULT){
+	  /*  bei kommutativen Operatoren vertauschen     */
+	  new->z=new->q2;
+	  new->q2=new->q1;
+	  new->q1=new->z;
+	  new->z.flags&=~DREFOBJ;
+	}else{
+	  if(USEQ2ASZ){
+	    new->z=new->q2;
+	    new->z.flags&=~DREFOBJ;
+	  }else{
+	    get_scratch(&new->z,new->typf,0,0);
+	  }
+	}
+      }else{
+	get_scratch(&new->z,new->typf,0,0);
+      }
+    }
+    p->o=new->z;
+    add_IC(new);
+    if(dest) dest->o.flags=mflags;
+    return f;
+}
+void savescratch(int code,struct IC *p,int dontsave,struct obj *o)
+/*  speichert Scratchregister bzw. stellt sie wieder her (je nach code  */
+/*  entweder MOVEFROMREG oder MOVETOREG)                                */
+{
+  int i,s,e,b,ds1,ds2;struct IC *new;
+  if(code==MOVETOREG){ s=1;e=MAXR+1;b=1;} else {s=MAXR;e=0;b=-1;}
+  if(reg_pair(dontsave,&rp)){
+    ds1=rp.r1;
+    ds2=rp.r2;
+  }else
+    ds1=ds2=0;
+  for(i=s;i!=e;i+=b){
+    int mustsave=0;
+    if((o->flags&(VAR|DREFOBJ))==VAR&&o->v->fi&&(o->v->fi->flags&ALL_REGS))
+      mustsave=BTST(o->v->fi->regs_modified,i);
+    else
+      mustsave=regscratch[i];
+    if(regsa[i]) mustsave=0;
+    if(mustsave) simple_scratch[i]=1;
+    if(regs[i]&&!(regs[i]&32)&&mustsave&&i!=dontsave&&i!=ds1&&i!=ds2&&!reg_pair(i,&rp)){
+      if(!regsbuf[i]){
+	struct Typ *t;
+	if(code!=MOVEFROMREG) continue;
+	t=clone_typ(regtype[i]);
+	regsbuf[i]=add_var(empty,t,AUTO,0);
+	regsbuf[i]->flags|=USEDASADR;
+	regbnesting[i]=nesting;
+      }
+      new=new_IC();
+      new->typf=new->q2.flags=0;
+      new->line=0;new->file=0;
+      new->code=code;
+      if(code==MOVEFROMREG){
+	new->q1.flags=REG;new->q1.reg=i;
+	new->z.flags=VAR|DONTREGISTERIZE;new->z.v=regsbuf[i];
+	new->z.val.vmax=l2zm(0L);
+      }else{
+	new->z.flags=REG;new->z.reg=i;
+	new->q1.flags=VAR|DONTREGISTERIZE;new->q1.v=regsbuf[i];
+	new->q1.val.vmax=l2zm(0L);
+      }
+      new->use_cnt=new->change_cnt=0;
+      new->use_list=new->change_list=0;
+      insert_IC(p,new);
+    }
+  }
+}
+
diff --git a/loop.c b/loop.c
new file mode 100644
index 0000000..b0190c6
--- /dev/null
+++ b/loop.c
@@ -0,0 +1,2077 @@
+/*  $VER: vbcc (loop.c) $Revision: 1.19 $    */
+/*  schleifenorientierte Optimierungen  */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+#define MOVE_IC 1
+#define MOVE_COMP 2
+
+/*  Liste, in die ICs eingetragen werden, die aus Schleifen */
+/*  gezogen werden sollen.                                  */
+typedef struct movlist{
+  struct movlist *next;
+  IC *IC;
+  flowgraph *target_fg;
+  int flags;
+} movlist;
+
+movlist *first_mov,*last_mov;
+
+int report_weird_code,report_suspicious_loops;
+
+static int only_shorten;
+
+/*  Bitvektoren fuer schleifeninvariante ICs    */
+bvtype *invariant,*inloop,*moved,*moved_completely;
+bvtype *fg_tmp;
+bvtype *not_movable;
+size_t bsize;
+
+
+/*  Liste, in die ICs fuer strength-reduction eingetragen   */
+/*  werden.                                                 */
+typedef struct srlist{
+  struct srlist *next;
+  IC *ind_var;
+  IC *IC;
+  flowgraph *target_fg;
+  /*  Hilfsvariable, falls eine aequivalente Operation schon reduziert    */
+  /*  wurde.                                                              */
+  Var *hv;
+} srlist ;
+
+srlist *first_sr,*last_sr;
+
+/*  Liste, in die Daten fuer loop-unrolling eingetragen werden. */
+typedef struct urlist{
+  int flags;
+  long total,unroll;
+  IC *cmp,*branch,*ind;
+  flowgraph *start,*head;
+  struct urlist *next;
+} urlist;
+
+urlist *first_ur;
+
+#define UNROLL_COMPLETELY 1
+#define UNROLL_MODULO 2
+#define UNROLL_INVARIANT 4
+#define UNROLL_REVERSE 8
+#define UNROLL_SHORTEN 16
+#define IND_ONLY_COUNTS 32
+#define MULTIPLE_EXITS 64
+
+/*  Hier werden Induktionsvariablen vermerkt    */
+IC **ind_vars;
+
+static flowgraph *first_fg;
+
+#ifdef ALEX_REG
+void IncrementLoopDepth(flowgraph* fg,int start,int end)
+     /* erhoeht loop_depth in den Bloecken [start,end] */
+{
+  if ( (fg->index >= start) && (fg->index <= end) )
+    {
+      fg->loop_depth++;
+    }
+  if (fg->normalout)
+    IncrementLoopDepth(fg->normalout,start,end);
+}
+#endif
+
+#if !HAVE_DECIDE_REVERSE
+int decide_reverse(zmax v)
+{
+  if(optspeed||zmeqto(v,l2zm(1L)))
+    return 1;
+  return 0;
+}
+#endif
+
+int loops(flowgraph *fg,int footers)
+/*  kennzeichnet Schleifen im Flussgraph; wenn footers!=0 werden darf eine  */
+/*  Schleife nur einen gemeinsamen Austrittspunkt haben                     */
+{
+  int i,start,end,c=0;flowlist *lp;flowgraph *g,*loopend;
+  if(DEBUG&1024) printf("searching loops\n");
+  g=fg;
+  while(g){
+    start=g->index;
+    end=-1;
+    for(lp=g->in;lp;lp=lp->next){
+      if(!lp->graph) continue;
+      if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+	i=lp->graph->index;
+	if(i>=start&&i>end){ end=i;loopend=lp->graph; }
+      }
+    }
+    if(end>=0){
+      /*  Schleife oder etwas aehnliches  */
+      flowgraph *p=g;
+      if(DEBUG&1024) printf("found possible loop from blocks %d to %d\n",start,end);
+      if(1/*goto_used*/){
+	if(DEBUG&1024) printf("have to check...\n");
+	do{
+	  if(!p||p->index>end) break;
+
+	  /*  testen, ob aus der Schleife gesprungen wird */
+	  if(p->branchout&&footers){
+	    i=p->branchout->index;
+	    if(i<start){
+	      end=-1;
+	      break;
+	    }
+	    if(i>end&&(DEBUG&1024)){
+	      puts("jump out of loop");
+	      if(p->branchout!=loopend->normalout){
+		puts("no break");
+		if(p->branchout->start->typf!=return_label) puts("no return");
+	      }
+	    }
+	    if(i>end&&p->branchout!=loopend->normalout&&p->branchout->start->typf!=return_label){
+	      /*  Sprung zu anderem als dem normalen Austritt oder return */
+	      end=-1;
+	      break;
+	    }
+	  }
+	  /*  testen, ob in die Schleife gesprungen wird  */
+	  if(p!=g){
+	    for(lp=p->in;lp;lp=lp->next){
+	      if(!lp->graph) continue;
+	      if(lp->graph->branchout==p){
+		i=lp->graph->index;
+		if(i<start){
+		  if(report_weird_code){error(175);report_weird_code=0;}
+		  end=-1;
+		  break;
+		}
+		if(i>end){
+		  end=-1;
+		  break;
+		}
+	      }
+	    }
+	  }
+	  if(p->index==end) break;
+	  p=p->normalout;
+	}while(end>=0);
+      }else{
+	if(DEBUG&1024) printf("must be a loop, because there was no goto\n");
+      }
+    }
+    if(end>=0){
+      if(DEBUG&1024) printf("confirmed that it is a loop\n");
+      g->loopend=loopend;
+      c++;
+#ifdef ALEX_REG
+      IncrementLoopDepth(fg,start,end);
+#endif
+    }
+    g=g->normalout;
+  }
+  return c;
+}
+
+flowgraph *create_loop_headers(flowgraph *fg,int av)
+/*  Fuegt vor jede Schleife einen Kopf-Block ein, wenn noetig.  */
+/*  Wenn av!=0 werden aktive Variablen korrekt uebertragen und  */
+/*  diverse Registerlisten uebernommen und index=-1 gesetzt.    */
+/*  Kann einen Block mehrmals in der ->in Liste eintragen       */
+{
+  flowgraph *g,*last,*new,*rg=fg;
+  IC *lic,*lastic;
+  if(DEBUG&1024) printf("creating loop-headers\n");
+  g=fg;last=0;lastic=0;
+  while(g){
+    new=0;
+    if(g->loopend){
+      if(!last){
+	flowlist *lp;
+	new=new_flowgraph();
+	rg=new;
+	new->in=0;
+	lic=new_IC();
+	lic->code=LABEL;
+	lic->typf=++label;
+	lic->q1.flags=lic->q2.flags=lic->z.flags=0;
+	lic->q1.am=lic->q2.am=lic->z.am=0;
+	new->start=new->end=lic;
+	lic->next=first_ic;
+	lic->prev=0;
+	first_ic->prev=lic;
+	first_ic=lic;
+	lp=mymalloc(sizeof(flowlist));
+	lp->graph=new;
+	lp->next=g->in;
+	g->in=lp;
+      }else{
+	flowlist *lp,*nl,**ls;
+	new=new_flowgraph();
+	last->normalout=new;
+	lic=new_IC();
+	new->start=new->end=lic;
+	lic->code=LABEL;
+	lic->typf=++label;
+	lic->q1.flags=lic->q2.flags=lic->z.flags=0;
+	lic->q1.am=lic->q2.am=lic->z.am=0;
+	if(lastic) lastic->next=lic;
+	else   first_ic=lic;
+	lic->prev=lastic;
+	g->start->prev=lic;
+	lic->next=g->start;
+	lp=g->in;ls=&new->in;
+	while(lp){
+	  if(lp->graph&&lp->graph->index<g->index){
+	    /*  Eintritt von oben soll in den Kopf  */
+	    nl=mymalloc(sizeof(flowlist));
+	    nl->graph=lp->graph;
+	    nl->next=0;
+	    (*ls)=nl;
+	    ls=&nl->next;
+	    if(lp->graph->branchout==g){
+	      IC *p=lp->graph->end;
+	      if(DEBUG&1024) printf("changing branch\n");
+	      while(p&&p->code==FREEREG) p=p->prev;
+	      if(!p||p->code<BEQ||p->code>BRA) ierror(0);
+	      p->typf=lic->typf;
+	      lp->graph->branchout=new;
+	    }
+	    lp->graph=new;
+	  }
+	  lp=lp->next;
+	}
+	if(!new->in) ierror(0);
+      }
+      if(new){
+	if(DEBUG&1024) printf("must insert loop-header before block %d\n",g->index);
+	basic_blocks++;
+	new->branchout=0;
+	new->loopend=0;
+	if(av)
+	  new->index=-1;
+	else
+	  new->index=basic_blocks;
+	new->normalout=g;
+	new->calls=0;
+	new->loop_calls=0;
+	new->rd_in=new->rd_out=new->rd_kill=new->rd_gen=0;
+	new->ae_in=new->ae_out=new->ae_kill=new->ae_gen=0;
+	new->cp_in=new->cp_out=new->cp_kill=new->cp_gen=0;
+	if(!av){
+	  new->av_in=new->av_out=new->av_kill=new->av_gen=0;
+	}else{
+	  new->av_in=mymalloc(vsize);
+	  new->av_out=mymalloc(vsize);
+	  new->av_gen=mymalloc(vsize);
+	  new->av_kill=mymalloc(vsize);
+	  memset(new->av_gen,0,vsize);
+	  memset(new->av_kill,0,vsize);
+	  memcpy(new->av_out,g->av_in,vsize);
+	  memcpy(new->av_in,g->av_in,vsize);
+	  memcpy(&new->regv,&g->regv,sizeof(new->regv));
+	  memcpy(&new->regused,&g->regused,sizeof(new->regused));
+	}
+      }
+    }
+    last=g;if(last->end) lastic=last->end;
+    g=g->normalout;
+  }
+  return rg;
+}
+flowgraph *create_loop_footers(flowgraph *fg,int av)
+/*  Fuegt hinter jede Schleife einen Fuss-Block ein, wenn noetig.   */
+/*  Wenn av!=0 werden aktive Variablen korrekt uebertragen und      */
+/*  diverse Registerlisten uebernommen und index auf -2 gesetzt.    */
+{
+  flowgraph *g,*loopend,*out,*new;
+  IC *lic;
+  if(DEBUG&1024) printf("creating loop-footers\n");
+  g=fg;
+  while(g){
+    new=0;
+    loopend=g->loopend;
+    if(loopend){
+      flowlist *lp,*nl,**ls;
+      out=loopend->normalout;
+      new=new_flowgraph();
+      new->normalout=out;
+      loopend->normalout=new;
+      lic=new_IC();
+      lic->line=0;
+      lic->file=0;
+      new->start=new->end=lic;
+      lic->code=LABEL;
+      lic->typf=++label;
+      lic->q1.flags=lic->q2.flags=lic->z.flags=0;
+      lic->q1.am=lic->q2.am=lic->z.am=0;
+      lic->use_cnt=lic->change_cnt=0;
+      lic->use_list=lic->change_list=0;
+      if(out) lp=out->in; else {lp=0;new->in=0;}
+      ls=&new->in;
+      while(lp){
+	if(lp->graph&&lp->graph->index<=loopend->index&&lp->graph->index>=g->index){
+	  /*  Austritt aus Schleife soll in den Fuss  */
+	  nl=mymalloc(sizeof(flowlist));
+	  nl->graph=lp->graph;
+	  nl->next=0;
+	  (*ls)=nl;
+	  ls=&nl->next;
+	  if(lp->graph->branchout==out){
+	    IC *p=lp->graph->end;
+	    if(DEBUG&1024) printf("changing branch\n");
+	    while(p&&p->code==FREEREG) p=p->prev;
+	    if(!p||p->code<BEQ||p->code>BRA) ierror(0);
+	    p->typf=lic->typf;
+	    lp->graph->branchout=new;
+	  }
+	  lp->graph=new;
+	}
+	lp=lp->next;
+      }
+      if(out&&!new->in) ierror(0);
+      if(DEBUG&1024) printf("must insert loop-footer after block %d\n",loopend->index);
+      basic_blocks++;
+      new->branchout=0;
+      new->loopend=0;
+      if(av)
+	new->index=-2;
+      else
+	new->index=basic_blocks;
+      new->normalout=out;
+      new->calls=0;
+      new->loop_calls=0;
+      new->rd_in=new->rd_out=new->rd_kill=new->rd_gen=0;
+      new->ae_in=new->ae_out=new->ae_kill=new->ae_gen=0;
+      new->cp_in=new->cp_out=new->cp_kill=new->cp_gen=0;
+      if(!av){
+	new->av_in=new->av_out=new->av_kill=new->av_gen=0;
+      }else{
+	new->av_in=mymalloc(vsize);
+	new->av_out=mymalloc(vsize);
+	new->av_kill=mymalloc(vsize);
+	new->av_gen=mymalloc(vsize);
+	memset(new->av_gen,0,vsize);
+	memset(new->av_kill,0,vsize);
+	if(out){
+	  memcpy(new->av_out,out->av_in,vsize);
+	  memcpy(new->av_in,out->av_in,vsize);
+	}else{
+	  memcpy(new->av_out,av_globals,vsize);
+	  bvunite(new->av_out,av_statics,vsize);
+	  memcpy(new->av_in,new->av_out,vsize);
+	}
+	memcpy(&new->regv,&g->regv,sizeof(new->regv));
+	memcpy(&new->regused,&g->regused,sizeof(new->regused));
+      }
+      insert_IC_fg(new,loopend->end,lic);
+    }
+    g=g->normalout;
+  }
+  return fg;
+}
+void add_movable(IC *p,flowgraph *fg,int flags)
+/*  Fuegt IC p, das aus der Schleife in Block fg mit Flags flags    */
+/*  verschoben werden darf in eine Liste.                           */
+{
+  movlist *new=mymalloc(sizeof(*new));
+  new->IC=p;
+  new->target_fg=fg;
+  new->flags=flags;
+  new->next=0;
+  if(last_mov){
+    last_mov->next=new;
+    last_mov=new;
+  }else{
+    first_mov=last_mov=new;
+  }
+  BSET(moved,p->defindex);
+  if(flags==MOVE_IC) BSET(moved_completely,p->defindex);
+}
+int move_to_head(void)
+/*  Geht die Liste mit verschiebbaren ICs durch und schiebt die ICs */
+/*  in den Vorkopf der Schleife. Ausserdem wird die Liste           */
+/*  freigegeben.                                                    */
+/*  Der Rueckgabewert hat Bit 1 gesetzt, wenn ICs ganz verschoben   */
+/*  wurden und Bit 2, falls eine Berechnung mit Hilfsvariable vor   */
+/*  die Schleife gezogen wurde.                                     */
+{
+  IC **fglist; /* Letztes IC vor jedem Block   */
+  flowgraph *g;IC *p;movlist *m;
+  int changed=0;
+
+  if(!first_mov) return 0;
+
+  if(DEBUG&1024) printf("moving the ICs out of the loop\n");
+
+  fglist=mymalloc((basic_blocks+1)*sizeof(*fglist));
+  p=0;
+  for(g=first_fg;g;g=g->normalout){
+    if(g->index>basic_blocks) ierror(0);
+    if(g->end) p=g->end;
+    fglist[g->index]=p;
+  }
+  while(first_mov){
+    p=first_mov->IC;
+    g=first_mov->target_fg;
+    if(first_mov->flags==MOVE_IC){
+      if(DEBUG&1024) {printf("moving IC out of loop:\n");pric2(stdout,p);}
+      if(!p->prev||!p->next) ierror(0);
+      p->next->prev=p->prev;
+      p->prev->next=p->next;
+      insert_IC_fg(g,fglist[g->index],p);
+      fglist[g->index]=p;
+      changed|=1;
+    }else if(1){
+      type *t=new_typ();
+      IC *new=new_IC();
+      Var *v;
+      if(DEBUG&1024) {printf("moving computation out of loop:\n");pric2(stdout,p);}
+      t->flags=ztyp(p);
+      if(p->code==COMPARE||p->code==TEST) t->flags=0;
+      if(ISPOINTER(t->flags)){
+	t->next=new_typ();
+	t->next->flags=VOID;
+      }
+      v=add_tmp_var(t);
+      *new=*p;
+      new->z.flags=VAR;
+      new->z.v=v;
+      new->z.val.vmax=l2zm(0L);
+
+      /*  Die neue Operation benutzt maximal, was die andere benutzte */
+      /*  und aendert nur die Hilfsvariable.                          */
+      if(have_alias){
+	new->use_cnt=p->use_cnt;
+	new->use_list=mymalloc(new->use_cnt*VLS);
+	memcpy(new->use_list,p->use_list,new->use_cnt*VLS);
+	new->change_cnt=1;
+	new->change_list=mymalloc(VLS);
+	new->change_list[0].v=v;
+	new->change_list[0].flags=0;
+      }
+      insert_IC_fg(g,fglist[g->index],new);
+      fglist[g->index]=new;
+      p->code=ASSIGN;
+      p->typf=t->flags;
+      p->q1.flags=VAR;
+      p->q1.v=v;
+      p->q1.val.vmax=l2zm(0L);
+      p->q2.flags=0;
+      p->q2.val.vmax=szof(t);
+      /*  Die Operation in der Schleife benutzt nun zusaetzlich   */
+      /*  noch die Hilfsvariable.                                 */
+      if(have_alias){
+	void *m=p->use_list;
+	p->use_cnt++;
+	p->use_list=mymalloc(p->use_cnt*VLS);
+	memcpy(&p->use_list[1],m,(p->use_cnt-1)*VLS);
+	free(m);
+	p->use_list[0].v=v;
+	p->use_list[0].flags=0;
+      }
+      changed|=2;
+    }
+    m=first_mov->next;
+    free(first_mov);
+    first_mov=m;
+  }
+  if(DEBUG&1024) print_flowgraph(first_fg);
+  free(fglist);
+  return changed;
+}
+void calc_movable(flowgraph *start,flowgraph *end)
+/*  Berechnet, welche Definitionen nicht aus der Schleife start-end     */
+/*  verschoben werden duerfen. Eine Def. p von z darf nur verschoben    */
+/*  werden, wenn keine andere Def. von p existiert und alle             */
+/*  Verwendungen von z nur von p erreicht werden.                       */
+/*  Benutzt rd_defs.                                                    */
+{
+  flowgraph *g;IC *p;
+  int i,j,k,d;
+  bvtype *changed_vars;
+  if(DEBUG&1024) printf("calculating not_movable for blocks %d to %d\n",start->index,end->index);
+  if(0/*!(optflags&1024)*/){
+    memset(not_movable,UCHAR_MAX,dsize);
+    return;
+  }
+  memset(not_movable,0,dsize);
+  changed_vars=mymalloc(vsize);
+  memset(changed_vars,0,vsize);
+  for(i=0;i<vcount-rcount;i++){
+    if(vilist[i]->vtyp->flags&VOLATILE) BSET(changed_vars,i);
+    if(i<rcount){
+      if(!vilist[i]->vtyp->next||(vilist[i]->vtyp->next->flags&VOLATILE)) BSET(changed_vars,i+vcount-rcount);
+    }
+  }
+  for(g=start;g;g=g->normalout){
+    if(!g->rd_in) ierror(0);
+    memcpy(rd_defs,g->rd_in,dsize);
+    for(p=g->start;p;p=p->next){
+      for(j=0;j<p->change_cnt;j++){
+	i=p->change_list[j].v->index;
+	if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+	if(i>=vcount) continue;
+	if(BTST(changed_vars,i)||is_volatile_ic(p)){
+	  bvunite(not_movable,var_defs[i],dsize);
+	}else{
+	  BSET(changed_vars,i);
+	}
+      }
+      for(k=0;k<p->use_cnt;k++){
+	i=p->use_list[k].v->index;
+	if(p->use_list[k].flags&DREFOBJ) i+=vcount-rcount;
+	if(i>=vcount) continue;
+	for(d=-1,j=1;j<=dcount;j++){
+	  if(BTST(rd_defs,j)&&BTST(var_defs[i],j)){
+	    if(d>=0){  /*  mehr als eine Def.  */
+	      bvunite(not_movable,var_defs[i],dsize);
+	      d=-1;break;
+	    }else d=j;
+	  }
+	  if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))){
+	    bvunite(not_movable,var_defs[i],dsize);
+	    d=-1;break;
+	  }
+	}
+      }
+      /*  Das hier, um rd_defs zu aktualisieren.  */
+      rd_change(p);
+      if(p==g->end) break;
+    }
+    if(g==end) break;
+  }
+  free(changed_vars);
+}
+/*  Testet, ob Variable nur in der Schleife benutzt wird.               */
+/* could be improved */
+int used_in_loop_only(flowgraph *start,flowgraph *end,obj *o)
+{
+  Var *v;flowgraph *g;IC *p;
+  if((o->flags&(VAR|DREFOBJ))!=VAR) return 0;
+  v=o->v;
+  if((v->flags&USEDASADR)||v->nesting==0||v->storage_class==EXTERN||v->storage_class==STATIC)
+    return 0;
+  for(g=first_fg;g;g=g->normalout){
+    if(g==start) g=end->normalout;
+    if(!g) break;
+    for(p=g->start;p;p=p->next){
+      if((p->q1.flags&VAR)&&p->q1.v==v) return 0;
+      if((p->q2.flags&VAR)&&p->q2.v==v) return 0;
+      if((p->z.flags&VAR)&&p->z.v==v) return 0;
+      if(p==g->end) break;
+    }
+    if(g==end) break;
+  }
+  return 1;
+}
+
+/*  Testet, ob z immer ausgefuehrt wird, falls start in fg ausgefuehrt  */
+/*  wird. fg_tmp ist ein Bitvektor, um zu merken, welche Bloecke sicher */
+/*  zu z fuehren. Das ganze fuer die Schleife start-end.                */
+/*  Wenn ignorecall!=0 ist, wird angenommen, dass jeder CALL            */
+/*  zurueckkehrt (das ist nuetzlich fuer loop-unrolling).               */
+int always_reached(flowgraph *start,flowgraph *end,flowgraph *fg,IC *z,int ignorecall)
+{
+  bvtype *bmk=fg_tmp;
+  IC *p;flowgraph *g;
+  int changed;
+  
+  for(p=z;p;p=p->prev){
+    if(!ignorecall&&p->code==CALL) return 0;
+    if(p==fg->start) break;
+  }
+  
+  if(fg==start) return 1;
+  
+  memset(bmk,0,bsize);
+  BSET(bmk,fg->index);
+  
+  do{
+    changed=0;
+    for(g=start;g;g=g->normalout){
+      if(!BTST(bmk,g->index)){
+	flowgraph *n=g->normalout;
+	flowgraph *b=g->branchout;
+	if(n||b){
+	  if((!b||BTST(bmk,b->index))&&
+	     (!n||(g->end&&g->end->code==BRA)||BTST(bmk,n->index))){
+	    for(p=g->end;p;p=p->prev){
+	      if(!ignorecall&&p->code==CALL) break;
+	      if(p==g->start){
+		if(g==start) return 1;
+		changed=1; BSET(bmk,g->index);
+		break;
+	      }
+	    }
+	  }
+	}
+      }
+      if(g==end) break;
+    }
+  }while(changed);
+  return 0;
+}
+
+/*  Ermittelt, ob Variable vindex schleifeninvariant unter den Bedingungen  */
+/*  rd_defs, inloop und invariant ist.                                      */
+/*  Definition ignore wird nicht beachtet. Wenn ignore auf eine gueltige    */
+/*  Definition gesetzt wird, kann man somit auf Induktionsvariablen testen  */
+/*  (das Ergebnis sagt dann, ob das die einzige Definition in der Schleife  */
+/*  ist).                                                                   */
+int def_invariant(int vindex,int ignore)
+{
+  int i,k,j,d=0;
+  /*printf("def_inv(%d)=%s(%ld)\n",vindex,vilist[vindex]->identifier,zm2l(vilist[vindex]->offset));*/
+  for(j=1;j<=dcount;j++){
+    if(j!=ignore&&BTST(rd_defs,j)){
+      if(BTST(var_defs[vindex],j)&&BTST(inloop,j)){
+	/*  Mehr als eine moegliche Def. innerhalb der Schleife oder    */
+	/*  eine invariante Def. in der Schleife => nicht invariant.    */
+	if(d) return 0;
+	if(!BTST(moved_completely,j)) return 0;
+	d=1;
+      }
+    }  
+    if(BTST(rd_defs,UNDEF(j))){
+      if(BTST(var_defs[vindex],UNDEF(j))&&BTST(inloop,UNDEF(j))){
+	/*  Mehr als eine moegliche Def. innerhalb der Schleife oder    */
+	/*  eine invariante Def. in der Schleife => nicht invariant.    */
+	if(d) return 0;
+	if(!BTST(moved_completely,UNDEF(j))) return 0;
+	d=1;
+      }
+    }      
+  }
+  return 1;
+#if 0
+  if(!BTST(rd_defs,vindex+dcount+1)){
+    memcpy(rd_tmp,rd_defs,dsize);
+    bvintersect(rd_tmp,var_defs[vindex],dsize);
+    for(j=1;j<=dcount;j++){
+      if(j!=ignore&&BTST(rd_tmp,j)&&BTST(inloop,j)){
+	/*  Mehr als eine moegliche Def. innerhalb der Schleife oder    */
+	/*  eine invariante Def. in der Schleife => nicht invariant.    */
+	if(d) return 0;
+	if(!BTST(moved_completely,j)) return 0;
+	d=1;
+      }
+    }
+  }else{
+    for(j=1;j<=dcount;j++){
+      if(j!=ignore&&BTST(rd_defs,j)&&BTST(inloop,j)){
+	IC *p=dlist[j];
+	for(k=0;k<p->change_cnt;k++){
+	  i=p->change_list[k].v->index;
+	  if(p->change_list[k].flags&DREFOBJ) i+=vcount-rcount;
+	  if(i==vindex) break;
+	}
+	if(k>=p->change_cnt) continue;
+	/*  Mehr als eine moegliche Def. innerhalb der Schleife oder    */
+	/*  eine invariante Def. in der Schleife => nicht invariant.    */
+	if(d) return 0;
+	if(!BTST(moved_completely,j)) return 0;
+	d=1;
+      }
+    }
+  }
+  return 1;
+#endif
+}
+
+void frequency_reduction(flowgraph *start,flowgraph *end,flowgraph *head)
+/*  Schleifeninvariante ICs finden und in eine Liste eintragen, falls   */
+/*  sie vor die Schleife gezogen werden koennen.                        */
+{
+  IC *p;flowgraph *g;
+  int i,changed;
+
+  if(head&&start->loopend){
+    end=start->loopend;
+
+    if(DEBUG&1024){
+      printf("searching for loop-invariant code in loop from block %d to %d\n",start->index,end->index);
+      printf("head_fg=%d\n",head->index);
+    }
+    calc_movable(start,end);
+    /*  erstmal kein IC invariant   */
+    memset(invariant,0,dsize);
+
+    /*  kennzeichnen, welche ICs in der Schleife liegen */
+    memset(inloop,0,dsize);
+    for(g=start;g;g=g->normalout){
+      for(p=g->start;p;p=p->next){
+	if(p->defindex) BSET(inloop,p->defindex);
+	if(p==g->end) break;
+      }
+      if(g==end) break;
+    }
+
+    do{
+      changed=0;
+      if(DEBUG&1024) printf("loop-invariant pass\n");
+
+      /*  Schleifeninvariante ICs suchen  */
+
+      for(g=start;g;g=g->normalout){
+	memcpy(rd_defs,g->rd_in,dsize);
+	for(p=g->start;p;p=p->next){
+	  int k1,k2;
+	  /*  testen, ob IC neu als invariant markiert werden kann    */
+	  if(p->defindex&&p->code!=CALL&&p->code!=GETRETURN&&!BTST(invariant,p->defindex)){
+	    if(!BTST(inloop,p->defindex)) ierror(0);
+	    if(p->code==ADDRESS||!p->q1.flags||(p->q1.flags&(KONST|DREFOBJ))==KONST||(p->q1.flags&VARADR)){
+	      k1=1;
+	    }else{
+	      if(!(p->q1.flags&VAR)){
+		k1=0;
+	      }else{
+		i=p->q1.v->index;
+		if(p->q1.flags&DREFOBJ){
+		  i+=vcount-rcount;
+		  if(p->q1.dtyp&(VOLATILE|PVOLATILE))
+		    k1=0;
+		  else
+		    k1=def_invariant(i,-1);
+		}else
+		  k1=def_invariant(i,-1);
+	      }
+	    }
+	    if(k1){
+	      if(!p->q2.flags||(p->q2.flags&(KONST|DREFOBJ))==KONST||(p->q2.flags&VARADR)){
+		k2=1;
+	      }else{
+		if(!(p->q2.flags&VAR)){
+		  k2=0;
+		}else{
+		  i=p->q2.v->index;
+		  if(p->q2.flags&DREFOBJ){
+		    i+=vcount-rcount;
+		    if(p->q2.dtyp&(VOLATILE|PVOLATILE))
+		      k2=0;
+		    else
+		      k2=def_invariant(i,-1);
+		  }else
+		    k2=def_invariant(i,-1);
+		}
+	      }
+	    }
+	    if(k1&&k2&&!(ztyp(p)&VOLATILE)&&!(q1typ(p)&VOLATILE)){
+	      if(DEBUG&1024){ printf("found loop-invariant IC:\n");pric2(stdout,p);}
+	      if(!BTST(moved,p->defindex)&&(always_reached(start,end,g,p,0)||(!dangerous_IC(p)&&used_in_loop_only(start,end,&p->z)))){
+		if(p->z.flags&DREFOBJ){
+		  if(p->z.flags&KONST)
+		    k1=0;
+		  else
+		    k1=def_invariant(p->z.v->index,-1);
+		}else
+		  k1=1;
+		/*if(DEBUG&1024) printf("always reached or used only in loop\n");*/
+		if(k1&&!BTST(not_movable,p->defindex)&&!(ztyp(p)&VOLATILE)&&(!(p->z.flags&VAR)||!p->z.v->reg)){
+		  /*if(DEBUG&1024) printf("movable\n");*/
+		  add_movable(p,head,MOVE_IC);
+		}else{
+		  if(p->code==ADDRESS||(ISSCALAR(p->typf)&&(p->q2.flags||(p->q1.flags&DREFOBJ)))){
+		    /*if(DEBUG&1024) printf("move computation out of loop\n");*/
+		    if(!(disable&256))
+		      add_movable(p,head,MOVE_COMP);
+		  }
+		}
+	      }else{
+		/*  Wenn IC immer erreicht wird oder ungefaehrlich  */
+		/*  ist, kann man zumindest die Operation           */
+		/*  rausziehen, falls das lohnt.                    */
+		if(!BTST(moved,p->defindex)&&(!dangerous_IC(p)&&ISSCALAR(p->typf)&&(p->q2.flags||(p->q1.flags&DREFOBJ)||p->code==ADDRESS))){
+		  /*if(DEBUG&1024) printf("move computation out of loop\n");*/
+		  if(!(disable&256))
+		    add_movable(p,head,MOVE_COMP);
+		}
+	      }
+	      BSET(invariant,p->defindex);
+	      changed=1;
+	    }
+	  }
+
+	  /*  Das hier, um rd_defs zu aktualisieren.  */
+	  rd_change(p);
+
+	  if(p==g->end) break;
+	}
+	if(g==end) break;
+      }
+    }while(changed);
+
+  }
+  return;
+}
+void add_sr(IC *p,flowgraph *fg,int i_var)
+/*  Fuegt IC p, das aus der Schleife in Block fg lineare Fkt. der   */
+/*  Induktionsvariable i_var ist, in Liste ein.                     */
+/*  Funktioniert als Stack. Da mit aeusseren Schleifen angefangen   */
+/*  wird, werden ICs zuerst in inneren Schleifen reduziert. Da ein  */
+/*  IC nur einmal reduziert wird, sollte dadurch das Problem eines  */
+/*  ICs, das potentiell in mehreren Schleifen reduziert werden      */
+/*  koennte, geloest werden.                                        */
+{
+  srlist *new=mymalloc(sizeof(*new));
+  if(DEBUG&1024) printf("all:%p\n",(void*)new);
+  new->IC=p;
+  new->target_fg=fg;
+  new->ind_var=ind_vars[i_var];
+  new->next=first_sr;
+  new->hv=0;
+  first_sr=new;
+#if 0
+  if(last_sr){
+    last_sr->next=new;
+    last_sr=new;
+  }else{
+    first_sr=last_sr=new;
+  }
+#endif
+}
+int do_sr(int donothing)
+/*  Durchlaufe die Liste aller strength-reduction-Kandidaten und    */
+/*  ersetze sie durch neue Induktionsvariablen. Dabei aufpassen,    */
+/*  falls ein IC schon von frequency-reduction bearbeitet wurde.    */
+/*  Ausserdem wird die Liste freigegeben.                           */
+{
+  IC **fglist; /* Letztes IC vor jedem Block   */
+  IC *p;
+  flowgraph *g;
+  srlist *mf;
+  int changed=0;
+
+  if(!first_sr) return 0;
+
+  if(DEBUG&1024) printf("performing strength-reductions\n");
+
+  fglist=mymalloc((basic_blocks+1)*sizeof(*fglist));
+  p=0;
+  for(g=first_fg;g;g=g->normalout){
+    if(g->index>basic_blocks) ierror(0);
+    if(g->end) p=g->end;
+    fglist[g->index]=p;
+  }
+
+  while(first_sr){
+    Var *niv,*nstep;
+    type *t1,*t2;
+    IC *iv_ic,*new,*m;
+    int i,c;
+    p=first_sr->IC;
+    i=p->defindex;
+    /*  Falls IC noch nicht verschoben und noch nicht reduziert wurde.  */
+    if(!donothing&&!BTST(moved,i)&&p->code!=ASSIGN){
+      if(first_sr->hv){
+	/*  Es wurde schon eine aequivalente Operation reduziert, wir   */
+	/*  koennen also dieselbe Hilfsvariable benutzen.               */
+	p->code=ASSIGN;
+	p->q1.flags=VAR;
+	p->q1.v=first_sr->hv;
+	p->q1.val.vmax=l2zm(0L);
+	p->q2.flags=0;
+	p->q2.val.vmax=szof(p->z.v->vtyp);
+        p->typf=p->z.v->vtyp->flags;
+	/*  Hilfsvariable wird jetzt auch benutzt.  */
+	if(have_alias){
+	  void *m=p->use_list;
+	  p->use_cnt++;
+	  p->use_list=mymalloc(p->use_cnt*VLS);
+	  memcpy(&p->use_list[1],m,(p->use_cnt-1)*VLS);
+	  free(m);
+	  p->use_list[0].v=first_sr->hv;
+	  p->use_list[0].flags=0;
+	}
+      }else{
+	int minus=0,q1t,q2t;
+	if(DEBUG&1024){ printf("performing strength-reduction on IC:\n");pric2(stdout,p);}
+	c=p->code;
+	g=first_sr->target_fg;
+	iv_ic=first_sr->ind_var;
+	/*  Merken, wenn IC von der Form SUB x,ind_var->z   */
+	if((c==SUB||c==SUBIFP)&&!compare_objs(&p->q2,&iv_ic->z,iv_ic->typf))
+	  minus=1;
+	t1=new_typ();
+	t1->flags=p->typf;
+	if(c==ADDI2P||c==SUBIFP){
+	  t1->flags=p->typf2;
+	  t1->next=new_typ();
+	  t1->next->flags=VOID;
+	}
+	niv=add_tmp_var(t1);
+	/*  Suchen, ob es noch aequivalente Operationen gibt.   */
+	/*  Noch sehr ineffizient...                            */
+	q1t=q1typ(p);q2t=q2typ(p);
+	for(mf=first_sr->next;mf;mf=mf->next){
+	  if(mf->target_fg==g&&mf->ind_var==iv_ic){
+	    m=mf->IC;
+	    if(c==m->code&&p->typf==m->typf&&
+	       !compare_objs(&p->q1,&m->q1,q1t)&&
+	       !compare_objs(&p->q2,&m->q2,q2t)){
+	      if(mf->hv) ierror(0);
+	      mf->hv=niv;
+	      if(DEBUG&1024){ printf("equivalent operation\n");pric2(stdout,m);}
+	    }
+	  }
+	}
+	/*  Initialisierung der Hilfsinduktionsvariablen    */
+	new=new_IC();
+	*new=*p;
+	new->z.flags=VAR;
+	new->z.v=niv;
+	new->z.val.vmax=l2zm(0L);
+	/*  IC benutzt dasselbe wie p und aendert nur niv.  */
+	if(have_alias){
+	  new->change_cnt=1;
+	  new->change_list=mymalloc(VLS);
+	  new->change_list[0].v=niv;
+	  new->change_list[0].flags=0;
+	  new->use_cnt=p->use_cnt;
+	  new->use_list=mymalloc(new->use_cnt*VLS);
+	  memcpy(new->use_list,p->use_list,new->use_cnt*VLS);
+	}
+	insert_IC_fg(g,fglist[g->index],new);
+	fglist[g->index]=m=new;
+	/*  Ersetzen der Operation durch die Hilfsvariable  */
+	p->code=ASSIGN;
+	p->typf=t1->flags;
+	p->q1=m->z;
+	p->q2.flags=0;
+	p->q2.val.vmax=szof(t1);
+	/*  Benutzt jetzt auch Hilfsvariable.               */
+	if(have_alias){
+	  void *mr=p->use_list;
+	  p->use_cnt++;
+	  p->use_list=mymalloc(p->use_cnt*VLS);
+	  memcpy(&p->use_list[1],mr,(p->use_cnt-1)*VLS);
+	  free(mr);
+	  p->use_list[0].v=niv;
+	  p->use_list[0].flags=0;
+	}
+	/*  Berechnen der Schrittweite fuer Hilfsvariable   */
+	if(c==MULT||c==LSHIFT){
+	  int styp;
+	  t2=new_typ();
+	  t2->flags=iv_ic->typf;
+	  nstep=add_tmp_var(t2);
+	  new=new_IC();
+	  new->line=iv_ic->line;
+	  new->file=iv_ic->file;
+	  new->code=MULT;
+	  new->typf=p->typf;
+	  new->z.flags=VAR;
+	  new->z.v=nstep;
+	  new->z.val.vmax=l2zm(0L);
+	  if(!compare_objs(&m->q1,&iv_ic->z,iv_ic->typf)){
+	    new->q1=m->q2;
+	    styp=q2typ(m);
+	  }else{
+	    new->q1=m->q1;
+	    styp=m->typf;
+	  }
+	  if(!compare_objs(&iv_ic->q1,&iv_ic->z,iv_ic->typf)) new->q2=iv_ic->q2;
+	  else new->q2=iv_ic->q1;
+	  if(c==LSHIFT){
+	    if((new->q1.flags&(KONST|DREFOBJ))!=KONST) ierror(0);
+	    eval_const(&new->q1.val,styp);
+	    gval.vmax=zmlshift(Z1,vmax);
+	    eval_const(&gval,MAXINT);
+	    insert_const(&new->q1.val,new->typf);
+	  }
+	  /*  Benutzt dasselbe wie iv_ic und m.   */
+	  if(have_alias){
+	    new->use_cnt=iv_ic->use_cnt+m->use_cnt;
+	    new->use_list=mymalloc(new->use_cnt*VLS);
+	    memcpy(new->use_list,iv_ic->use_list,iv_ic->use_cnt*VLS);
+	    memcpy(&new->use_list[iv_ic->use_cnt],m->use_list,m->use_cnt*VLS);
+	    new->change_cnt=1;
+	    new->change_list=mymalloc(VLS);
+	    new->change_list[0].v=nstep;
+	    new->change_list[0].flags=0;
+	  }
+	  insert_IC_fg(g,fglist[g->index],new);
+	  fglist[g->index]=m=new;
+	}
+	/*  Erhoehen der Hilfsvariable um Schrittweite      */
+	new=new_IC();
+	new->line=iv_ic->line;
+	new->file=iv_ic->file;
+
+	new->code=iv_ic->code;
+	if(minus){
+	  switch(new->code){
+	  case ADD:     new->code=SUB; break;
+	  case SUB:     new->code=ADD; break;
+	  case ADDI2P:  new->code=SUBIFP; break;
+	  case SUBIFP:  new->code=ADDI2P; break;
+	  }
+	}
+	if(ISPOINTER(t1->flags)){
+	  if(new->code==ADD) new->code=ADDI2P;
+	  if(new->code==SUB) new->code=SUBIFP;
+	  new->typf=t1->flags;
+	}
+	new->typf=iv_ic->typf;
+	new->q1.flags=VAR;
+	new->q1.v=niv;
+	new->typf2=niv->vtyp->flags;
+	new->q1.val.vmax=l2zm(0L);
+	new->z=new->q1;
+	if(c==MULT||c==LSHIFT){
+	  new->q2=m->z;
+	}else{
+	  if(!compare_objs(&iv_ic->q1,&iv_ic->z,iv_ic->typf)) new->q2=iv_ic->q2;
+	  else new->q2=iv_ic->q1;
+	}
+	if(have_alias){
+	  new->use_cnt=iv_ic->use_cnt+m->use_cnt;
+	  new->use_list=mymalloc(new->use_cnt*VLS);
+	  memcpy(new->use_list,iv_ic->use_list,iv_ic->use_cnt*VLS);
+	  memcpy(&new->use_list[iv_ic->use_cnt],m->use_list,m->use_cnt*VLS);
+	  new->change_cnt=1;
+	  new->change_list=mymalloc(VLS);
+	  new->change_list[0].v=niv;
+	  new->change_list[0].flags=0;
+	}
+	/*  Flussgraph muss nur bei den Schleifenkoepfen ok sein.   */
+	insert_IC(iv_ic,new);
+	changed|=2;
+      }
+    }
+
+    mf=first_sr->next;
+    free(first_sr);
+    first_sr=mf;
+  }
+  free(fglist);
+  return changed;
+}
+void strength_reduction(flowgraph *start,flowgraph *end,flowgraph *head)
+/*  Ersetzen von Operationen mit einer Induktionsvariablen und einem    */
+/*  schleifeninvarianten Operanden durch eine zusaetzliche              */
+/*  Hilfsinduktionsvariable.                                            */
+{
+  flowgraph *g;IC *p;
+  int i;
+  if(DEBUG&1024) printf("performing strength_reduction on blocks %d to %d\n",start->index,end->index);
+  for(i=0;i<vcount;i++) ind_vars[i]=0;
+  /*  Nach Induktionsvariablen suchen.    */
+  for(g=start;g;g=g->normalout){
+    memcpy(rd_defs,g->rd_in,dsize);
+    for(p=g->start;p;p=p->next){
+      int c=p->code;
+      if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
+	/* TODO: what is possible/useful with floating point induction variables? */
+	if(!compare_objs(&p->q1,&p->z,p->typf)&&!ISFLOAT(p->typf)){
+	  if(DEBUG&1024){printf("possible induction:\n");pric2(stdout,p);}
+	  if(p->q2.flags&VAR){
+	    i=p->q2.v->index;
+	    if(p->q2.flags&DREFOBJ) i+=vcount-rcount;
+	  }
+	  if((p->z.flags&VAR)&&((p->q2.flags&(VAR|VARADR))!=VAR||def_invariant(i,-1))){
+	    i=p->z.v->index;
+	    if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+	    if(def_invariant(i,p->defindex)){
+	      if(DEBUG&1024) {printf("found basic induction var:\n");pric2(stdout,p);}
+	      ind_vars[i]=p;
+	    }
+	  }
+	}
+	if(USEQ2ASZ&&c!=SUB&&c!=SUBIFP&&!compare_objs(&p->q2,&p->z,p->typf)){
+	  if(DEBUG&1024){printf("possible induction:\n");pric2(stdout,p);}
+	  if(p->q1.flags&VAR){
+	    i=p->q1.v->index;
+	    if(p->q1.flags&DREFOBJ) i+=vcount-rcount;
+	  }
+	  if((p->q1.flags&(VAR|VARADR))!=VAR||def_invariant(i,-1)){
+	    i=p->z.v->index;
+	    if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+	    if(def_invariant(i,p->defindex)){
+	      if(DEBUG&1024) {printf("found basic induction var:\n");pric2(stdout,p);}
+	      ind_vars[i]=p;
+	    }
+	  }
+	}
+      }
+
+      /*  Das hier, um rd_defs zu aktualisieren.  */
+      rd_change(p);
+
+      if(p==g->end) break;
+    }
+    if(g==end) break;
+  }
+
+  if(disable&1024) return;
+
+  /*  Nach reduzierbaren Operationen suchen   */
+  for(g=start;g;g=g->normalout){
+    memcpy(rd_defs,g->rd_in,dsize);
+    for(p=g->start;p;p=p->next){
+      if(((p->code==MULT||p->code==LSHIFT)||((p->code==ADD||p->code==SUB||p->code==ADDI2P||p->code==SUBIFP)&&!(disable&512)))&&
+	 ((!ISFLOAT(p->typf))||fp_assoc)&&!(p->flags&EFF_IC) ){
+	int k1,k2,iv;
+	if((p->q1.flags&(VAR|VARADR))==VAR){
+	  i=p->q1.v->index;
+	  if(p->q1.flags&DREFOBJ) i+=vcount-rcount;
+	  if(ind_vars[i]){
+	    k1=1;iv=i;
+	  }else if(def_invariant(i,-1))
+	    k1=2;
+	  else
+	    k1=0;
+	}else
+	  k1=2;
+	if((p->q2.flags&(VAR|VARADR))==VAR){
+	  i=p->q2.v->index;
+	  if(p->q2.flags&DREFOBJ) i+=vcount-rcount;
+	  if(ind_vars[i]){
+	    k2=1;iv=i;
+	  }else if(def_invariant(i,-1))
+	    k2=2;
+	  else
+	    k2=0;
+	}else
+	  k2=2;
+	if(p->code==LSHIFT&&(p->q2.flags&(KONST|DREFOBJ))!=KONST)
+	  k2=0;
+	if(p->z.flags&VAR){
+	  /*  Aufpassen, dass eine Induktion nicht selbst reduziert   */
+	  /*  wird.                                                   */
+	  i=p->z.v->index;
+	  if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+	  if(ind_vars[i]) k1=0;
+	}
+	if(k1+k2==3){
+	  /*                    if(DEBUG&1024) {printf("could perform strength-reduction on:\n");pric2(stdout,p);}*/
+	  add_sr(p,head,iv);
+	}
+      }
+      /*  Das hier, um rd_defs zu aktualisieren.  */
+      rd_change(p);
+
+      if(p==g->end) break;
+    }
+    if(g==end) break;
+  }
+}
+void copy_code(IC *start,IC *end,IC *dest,int n,IC *ignore)
+/*  Kopiert Code von start bis end n-mal hinter dest. Generiert         */
+/*  entsprechend neue Labels. Allerdings wird der Flussgraph und        */
+/*  aliasing-info nicht angepasst und muss danach neu generiert werden. */
+/*  IC ignore wird nicht kopiert.                                       */
+{
+  int firstl=0,lastl=0,*larray,i,j;
+  IC *p,*new,*current;
+  if(DEBUG&1024) printf("copy_code %d times\n",n);
+  /*  Feststellen, welche Labels in der Schleife definiert werden.    */
+  for(p=start;p;p=p->next){
+    if(p->code==LABEL){
+      if(firstl==0||firstl>p->typf) firstl=p->typf;
+      if(lastl ==0|| lastl<p->typf) lastl =p->typf;
+    }
+    if(p==end) break;
+  }
+  if(DEBUG&1024) printf("firstl=%d, lastl=%d\n",firstl,lastl);
+  larray=mymalloc((lastl-firstl+1)*sizeof(*larray));
+  for(i=0;i<=lastl-firstl;i++) larray[i]=0;
+  for(p=start;p;p=p->next){
+    if(p->code==LABEL) larray[p->typf-firstl]=1;
+    if(p==end) break;
+  }
+  current=dest;
+  /*  Hauptschleife.  */
+  for(i=0;i<n;i++){
+    /*  Neue Labels erzeugen.   */
+    for(j=0;j<=lastl-firstl;j++)
+      if(larray[j]) larray[j]=++label;
+    /*  Code kopieren (rueckwaerts).    */
+    for(p=start;p;p=p->next){
+      if(p!=ignore){
+	new=new_IC();
+	*new=*p;
+	p->copy=new;
+	/*  Fuer free_alias.    */
+	new->change_cnt=new->use_cnt=0;
+	new->change_list=new->use_list=0;
+	/*  Evtl. Label anpassen.   */
+	if(p->code>=LABEL&&p->code<=BRA){
+	  if(p->typf>=firstl&&p->typf<=lastl&&larray[p->typf-firstl])
+	    new->typf=larray[p->typf-firstl];
+	}
+	if(p->code==CALL){
+	  int i;
+	  new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+	  for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=p->arg_list[i]->copy;
+	  new->call_list=mymalloc(new->call_cnt*sizeof(*new->call_list));
+	  memcpy(new->call_list,p->call_list,new->call_cnt*sizeof(*new->call_list));
+	}
+	insert_IC(current,new);
+	current=new;
+      }
+      if(p==end) break;
+    }
+  }
+  free(larray);
+}
+void add_ur(int flags,long total,long unroll,flowgraph *start,flowgraph *head,IC *cmp,IC *branch,IC *ind)
+/*  Fuegt Daten fuer loop-unrolling in Stack ein.                       */
+{
+  urlist *new=mymalloc(sizeof(urlist));
+  if(DEBUG&1024) printf("add_ur, flags=%d\n",flags);
+  new->flags=flags;
+  new->total=total;
+  new->unroll=unroll;
+  new->start=start;
+  new->head=head;
+  new->cmp=cmp;
+  new->branch=branch;
+  new->ind=ind;
+  new->next=first_ur;
+  first_ur=new;
+}
+
+static int decide_shorten(int t,flowgraph *start,IC *ind,IC *cmp)
+{
+  IC *p;
+  Var *oiv=ind->z.v;
+  int cnt=0;
+  for(p=start->start;p;p=p->next){
+    if(p==ind) continue;
+    if(p==cmp) break;
+    if((p->q1.flags&VAR)&&p->q1.v==oiv){
+      if(!(p->code==CONVERT&&!compare_objs(&p->q1,&ind->q1,p->typf)&&(p->typf&NQ)==(t&NQ)))
+	cnt++;
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==oiv){
+      if(!((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q2,&ind->q1,p->typf)&&(p->typf&NQ)>=MINADDI2P))
+	cnt++;
+    }
+    if((p->z.flags&VAR)&&p->z.v==oiv) cnt++;
+  }
+  return cnt==0;
+}
+
+static int do_shorten()
+{
+  int changed=0; urlist *m;
+  for(m=first_ur;m;m=m->next){
+    if(m->flags&UNROLL_SHORTEN){
+      /* use shorter induction variable */
+      type st={CHAR};
+      int cnt=0;
+      Var *niv,*oiv;IC *new,*p,*cmp=m->cmp,*ind=m->ind;
+      if(DEBUG&1024) printf("shorten induction variable to %s %s\n",(m->total&UNSIGNED)?"unsigned":"signed",typname[m->total&NQ]);
+      st.flags=m->total;
+      niv=add_tmp_var(clone_typ(&st));
+      new=new_IC();
+      new->code=CONVERT;
+      new->q1=ind->z;
+      new->z.flags=VAR;
+      new->z.val.vmax=Z0;
+      new->z.v=niv;
+      new->typf2=ind->typf;
+      new->typf=st.flags;
+      insert_IC(m->head->end,new);
+      ind->q1=new->z;
+      ind->z=new->z;
+      ind->typf=st.flags;
+      cmp->q1=new->z;
+      eval_const(&cmp->q2.val,cmp->typf);
+      cmp->typf=st.flags;
+      insert_const(&cmp->q2.val,cmp->typf);
+      oiv=new->q1.v;
+      /* replace uses of the old induction variable that do not need conversions */
+      for(p=m->start->start;p;p=p->next){
+	if(p==cmp) break;
+	if((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q2,&new->q1,p->typf)&&(p->typf&NQ)>=MINADDI2P){
+	  if(DEBUG&1024){
+	    printf("replace use of large induction variable (ADDI2P):\n");
+	    pric2(stdout,p);
+	  }
+	  p->q2=new->z;
+	  p->typf=new->typf;
+	}
+	if(p->code==CONVERT&&!compare_objs(&p->q1,&new->q1,p->typf)&&(p->typf&NQ)==(new->typf&NQ)){
+	  if(DEBUG&1024){
+	    printf("replace use of large induction variable (CONVERT):\n");
+	    pric2(stdout,p);
+	  }
+	  p->q1=new->z;
+	  p->code=ASSIGN;
+	  p->q2.val.vmax=sizetab[p->typf&NQ];
+	}
+	if((p->q1.flags&VAR)&&p->q1.v==oiv) cnt++;
+	if((p->q2.flags&VAR)&&p->q2.v==oiv) cnt++;
+	if((p->z.flags&VAR)&&p->z.v==oiv) cnt++;
+      }
+      p=new_IC();
+      p->code=CONVERT;
+      p->q1=new->z;
+      p->z=new->q1;
+      p->typf=new->typf2;
+      p->typf2=new->typf;
+      if(cnt||(m->flags&MULTIPLE_EXITS))
+	insert_IC(ind,p);
+      else
+	insert_IC(m->branch,p);
+
+      m->flags=0;
+      changed|=2;
+    }
+  }
+  return changed;
+}
+
+int do_unroll(int donothing)
+/*  Fuehrt loop-unrolling durch. Wenn donothing!=0, wird die Liste nur  */
+/*  freigegeben.                                                        */
+{
+  int changed=0; urlist *m;
+  IC *div;
+  while(m=first_ur){
+    int flags=m->flags;
+    long total=m->total,unroll=m->unroll;
+    flowgraph *start=m->start,*head=m->head;
+    IC *cmp=m->cmp,*branch=m->branch,*ind=m->ind;
+    if(donothing) flags=0;
+    if(flags&UNROLL_COMPLETELY){
+      /*  Schleife komplett ausrollen.    */
+      if(DEBUG&1024) printf("unroll loop completely\n");
+      copy_code(start->start->next,cmp->prev,start->start,total-1,0);
+      if(DEBUG&1024) printf("removing loop branch\n");
+      remove_IC(branch);
+      if(!cmp->z.flags){
+	remove_IC(cmp);
+	if(DEBUG&1024) printf("removing loop compare\n");
+      }
+      changed|=1;
+    }
+
+    if(flags&UNROLL_MODULO){
+      /*  Schleife teilweise ausrollen.   */
+      if(DEBUG&1024) printf("unroll loop partially, n=%ld,r=%ld\n",unroll,total%unroll);
+      if(unroll>1){
+	if((flags&(IND_ONLY_COUNTS|MULTIPLE_EXITS))==IND_ONLY_COUNTS){
+	  IC *new=new_IC();
+	  copy_code(start->start->next,cmp->prev,head->start,total%unroll,ind);
+	  *new=*ind;
+	  new->use_cnt=new->change_cnt=0;
+	  new->use_list=new->change_list=0;
+	  if(!(ind->q2.flags&KONST)) ierror(0);
+	  eval_const(&ind->q2.val,ind->typf);
+	  if(ind->typf&UNSIGNED){
+	    gval.vumax=zummult(vumax,ul2zum((unsigned long)(total%unroll)));
+	    eval_const(&gval,(UNSIGNED|MAXINT));
+	  }else{
+	    gval.vumax=zummult(vumax,ul2zum((unsigned long)(total%unroll)));
+	    eval_const(&gval,MAXINT);
+	  }
+	  insert_const(&new->q2.val,ind->typf);
+	  insert_IC(head->end,new);
+	  copy_code(start->start->next,cmp->prev,start->start,unroll-1,ind);
+	  eval_const(&ind->q2.val,ind->typf);
+	  if(ind->typf&UNSIGNED){
+	    gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+	    eval_const(&gval,(UNSIGNED|MAXINT));
+	  }else{
+	    gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+	    eval_const(&gval,MAXINT);
+	  }
+	  insert_const(&ind->q2.val,ind->typf);		
+	  changed|=1;
+	}else{
+	  copy_code(start->start->next,cmp->prev,head->start,total%unroll,0);
+	  copy_code(start->start->next,cmp->prev,start->start,unroll-1,0);
+	  changed|=1;
+	}
+      }
+    }
+    if(flags&UNROLL_INVARIANT){
+      IC *new,*mc,*mn; Var *v; int out=++label,code;
+      long i; type *t;static type tptrdiff={0};
+      IC tmp;
+      if(DEBUG&1024) printf("unrolling non-constant loop\n");
+      if(ISPOINTER(cmp->typf)){
+	tptrdiff.flags=PTRDIFF_T(cmp->typf);
+	t=&tptrdiff;
+      }else{
+	if(cmp->q1.flags&VAR)
+	  t=cmp->q1.v->vtyp;
+	else
+	  t=cmp->q2.v->vtyp;
+      }
+      v=add_tmp_var(clone_typ(t));
+      /*  branch dient hier teilweise als leere Schablone.    */
+      /*  Label an Schleifenausgang setzen.   */
+      new=new_IC(); 
+      *new=*branch;
+      new->q1.flags=0;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=LABEL;
+      new->typf=out;
+      insert_IC(branch,new);
+      /*  Test vor die unroll-Variante.   */
+      new=new_IC(); *new=*branch;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      if(branch->code==BLT) new->code=BGE;
+      if(branch->code==BLE) new->code=BGT;
+      if(branch->code==BGT) new->code=BLE;
+      if(branch->code==BGE) new->code=BLT;
+      if(branch->code==BEQ) ierror(0);
+      if(branch->code==BNE) ierror(0);
+      code=branch->code;
+      mc=new;
+      new->typf=out;
+      insert_IC(head->start,new);
+      new=new_IC(); *new=*cmp;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      insert_IC(head->start,new);
+      /*  Einsprungpunkte fuer die Modulos.   */
+      label+=unroll;
+      for(i=1;i<unroll;i++){
+	copy_code(start->start->next,cmp->prev,head->start,1,0);
+	new=new_IC(); *new=*branch;
+	new->q1.flags=0;
+	new->change_cnt=new->use_cnt=0;
+	new->change_list=new->use_list=0;
+	new->code=LABEL;
+	new->typf=out+i;
+	insert_IC(head->start,new);
+      }
+      /*  Testen, welches Modulo. */
+      for(i=unroll-2;i>=0;i--){
+	new=new_IC(); *new=*branch;
+	new->change_cnt=new->use_cnt=0;
+	new->change_list=new->use_list=0;
+	new->code=BEQ;
+	if(i>0) new->typf=out+i;
+	else new->typf=start->start->typf;
+	insert_IC(head->start,new);
+	new=new_IC(); *new=*branch;
+	new->change_cnt=new->use_cnt=0;
+	new->change_list=new->use_list=0;
+	if(SWITCHSUBS) gval.vint=zm2zi(l2zm(1L));
+	else       gval.vint=zm2zi(l2zm(i));
+	eval_const(&gval,INT);
+	new->q1.flags=VAR;
+	new->q1.v=v;
+	new->q1.val.vmax=l2zm(0L);
+	new->typf=t->flags;
+	if(SWITCHSUBS||i==0){
+	  new->code=TEST;
+	  insert_IC(head->start,new);
+	  if(i>0){
+	    new=new_IC();
+	    *new=*head->start->next;
+	    new->change_cnt=new->use_cnt=0;
+	    new->change_list=new->use_list=0;
+	    new->code=SUB;
+	    new->z=new->q1;
+	    new->q2.flags=KONST;
+	    insert_const(&new->q2.val,new->typf&NU);
+	    insert_IC(head->start,new);
+	  }
+	}else{
+	  new->code=COMPARE;
+	  new->q2.flags=KONST;
+	  insert_const(&new->q2.val,new->typf&NU);
+	  insert_IC(head->start,new);
+	}
+      }
+      /*  Durchlaeufe modulo unroll berechnen.    */
+      new=new_IC(); *new=*branch;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=AND;
+      new->typf=t->flags;
+      new->q1.flags=VAR;
+      new->q1.v=v;
+      new->q1.val.vmax=l2zm(0L);
+      new->z=new->q1;
+      new->q2.flags=KONST;
+      gval.vmax=l2zm(unroll-1);
+      eval_const(&gval,MAXINT);
+      insert_const(&new->q2.val,new->typf);
+      insert_IC(head->start,new);
+      new=new_IC();
+      *new=*ind;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=DIV;
+      div=new;
+      new->q1=head->start->next->z;
+      new->z=new->q1;
+      insert_IC(head->start,new);
+      tmp=*new;
+      fix_shortop(head,new);
+      new=new_IC();
+      *new=tmp;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=ADD;
+      insert_IC(head->start,new);
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      if(code==BLT||code==BGT){
+	new=new_IC();
+	*new=*head->start->next;
+	new->change_cnt=new->use_cnt=0;
+	new->change_list=new->use_list=0;
+	new->code=SUB;
+	gval.vmax=l2zm(1L);
+	eval_const(&gval,MAXINT);
+	insert_const(&new->q2.val,new->typf);
+	insert_IC(head->start,new);
+      }
+      new=new_IC();
+      *new=tmp;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=SUB;
+      if(t==&tptrdiff)
+	new->code=SUBPFP;
+
+      if(!compare_objs(&ind->z,&cmp->q1,new->typf)){
+	if(code==BLT||code==BLE){
+	  new->q1=cmp->q2;new->q2=ind->z;
+	}else{
+	  new->q2=cmp->q2;new->q1=ind->z;
+	}
+      }else{
+	if(code==BLT||code==BLE){
+	  new->q1=cmp->q1;new->q2=ind->z;
+	}else{
+	  new->q2=cmp->q1;new->q1=ind->z;
+	}
+      }
+#if 0
+      if(ind->code==SUB){
+	obj o;
+	o=new->q1;new->q1=new->q2;new->q2=o;
+      }
+#endif
+      if(!new->q1.flags){
+	if(!new->q2.flags) ierror(0);
+	new->q1.flags=KONST;
+	gval.vmax=l2zm(0L);
+	eval_const(&gval,new->typf);
+	insert_const(&new->q1.val,new->typf);
+      }
+      if(!new->q2.flags){
+	if(!new->q1.flags) ierror(0);
+	new->q2.flags=KONST;
+	gval.vmax=l2zm(0L);
+	eval_const(&gval,new->typf);
+
+	insert_const(&new->q2.val,new->typf);
+      }
+      insert_IC(head->start,new);
+      new=new_IC();
+      *new=*mc;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->typf=out+1;
+      insert_IC(head->start,new);
+      new=new_IC();
+      *new=*cmp; new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      insert_IC(head->start,new);
+      if((flags&(IND_ONLY_COUNTS|MULTIPLE_EXITS))==IND_ONLY_COUNTS){
+	if(!(ind->q2.flags&KONST)) ierror(0);
+	copy_code(start->start->next,cmp->prev,start->start,unroll-1,ind);
+	eval_const(&ind->q2.val,ind->typf);
+	if(ind->typf&UNSIGNED){
+	  gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+	  eval_const(&gval,(UNSIGNED|MAXINT));
+	}else{
+	  gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+	  eval_const(&gval,MAXINT);
+	}
+	insert_const(&ind->q2.val,ind->typf);		
+	changed|=2;
+      }else{
+	copy_code(start->start->next,cmp->prev,start->start,unroll-1,0);
+	changed|=2;
+      }
+      div->typf|=UNSIGNED;
+    }
+    if(flags&UNROLL_REVERSE){
+      IC *new,*mc; Var *v; int out=++label,code;
+      long i; type *t;static type tptrdiff={0};
+      IC tmp;
+      if(DEBUG&1024) printf("reversing loop\n");
+      if(ISPOINTER(cmp->typf)){
+	tptrdiff.flags=PTRDIFF_T(cmp->typf);
+	t=&tptrdiff;
+      }else{
+	if(cmp->q1.flags&VAR)
+	  t=cmp->q1.v->vtyp;
+	else
+	  t=cmp->q2.v->vtyp;
+      }
+      v=add_tmp_var(clone_typ(t));
+      new=new_IC();
+      *new=*ind;
+      new->code=SUB;
+      new->typf=t->flags;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->q1.flags=VAR;
+      new->q1.v=v;
+      new->q1.val.vmax=l2zm(0L);
+      new->z=new->q1;
+      new->q2.flags=KONST;
+      gval.vmax=l2zm(1L);
+      eval_const(&gval,MAXINT);
+      insert_const(&new->q2.val,new->typf);
+      insert_IC(cmp->prev,new);
+      code=branch->code;
+#if HAVE_WANTBNE
+      branch->code=BNE;
+#else
+      branch->code=BGT;
+#endif
+      /*  Durchlaeufe berechnen.    */
+      new=new_IC();
+      *new=*ind;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=DIV;
+      div=new;
+      new->q1.flags=VAR;
+      new->q1.v=v;
+      new->q1.val.vmax=l2zm(0L);
+      new->z=new->q1;
+      insert_IC(head->start,new);
+      tmp=*new;
+      fix_shortop(head,new);
+      new=new_IC();
+      *new=tmp;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=ADD;
+      insert_IC(head->start,new);
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      if(code==BLT||code==BGT||code==BNE){
+	IC *a=head->start->next;
+	gval.vmax=l2zm(1L);
+	eval_const(&gval,MAXINT);
+	insert_const(&gval,a->typf);
+	calc(SUB,a->typf,&a->q2.val,&gval,&a->q2.val,0);
+      }
+      new=new_IC();
+      *new=tmp;
+      new->change_cnt=new->use_cnt=0;
+      new->change_list=new->use_list=0;
+      new->code=SUB;
+      if(t==&tptrdiff)
+	new->code=SUBPFP;
+
+      if(!compare_objs(&ind->z,&cmp->q1,new->typf)){
+	if(code==BLT||code==BLE||(code==BNE&&(ind->code==ADD||ind->code==ADDI2P))){
+	  new->q1=cmp->q2;new->q2=ind->z;
+	}else{
+	  new->q2=cmp->q2;new->q1=ind->z;
+	}
+      }else{
+	if(code==BLT||code==BLE||(code==BNE&&(ind->code==ADD||ind->code==ADDI2P))){
+	  new->q1=cmp->q1;new->q2=ind->z;
+	}else{
+	  new->q2=cmp->q1;new->q1=ind->z;
+	}
+      }
+#if 0
+      if(ind->code==SUB){
+	obj o;
+	o=new->q1;new->q1=new->q2;new->q2=o;
+      }
+#endif
+      if(!new->q1.flags||!new->q2.flags) ierror(0);
+      insert_IC(head->start,new);
+      cmp->code=TEST;
+      cmp->q1.flags=VAR;
+      cmp->q1.v=v;
+      cmp->q1.val.vmax=l2zm(0L);
+      cmp->q2.flags=0;
+      div->typf|=UNSIGNED;
+      changed|=2;
+    }
+    first_ur=m->next;
+    free(m);
+  }
+  return changed;
+}
+
+void unroll(flowgraph *start,flowgraph *head)
+/*  Versucht loop-unrolling.                                            */
+{
+  flowlist *lp;flowgraph *end,*g;IC *p,*m,*branch,*cmp;
+  obj *o,*e,*cc; union atyps init_val,end_val,step_val;
+  bvtype *tmp;
+  long dist,step,ic_cnt,n,small_type;
+  int bflag=0,t=0,i,flags=0; /* 1: sub, 2: init_val gefunden  */
+  int ind_only_counts,multiple_exits,cfl;
+  end=start->loopend;
+  if(DEBUG&1024) printf("checking for possible unrolling from %d to %d\n",start->index,end->index);
+  if(end->end->code==BRA){
+    if(DEBUG&1024) printf("loop ends with BRA\n");
+    return;
+  }
+  for(lp=start->in;lp;lp=lp->next)
+    if(lp->graph->index>start->index&&lp->graph->index<=end->index&&lp->graph!=end) return;
+  if(DEBUG&1024) printf("only one backward-branch\n");
+  e=0; p=end->end; cfl=0;
+  do{
+    if(p->code>=BEQ&&p->code<BRA){ branch=p;bflag=p->code;cc=&p->q1; cfl=1;}
+    if(p->code==TEST){
+      if(!cfl) return;
+      if(compare_objs(cc,&p->z,p->typf)) return;
+      o=&p->q1;t=p->typf;cmp=p;
+      end_val.vmax=l2zm(0L); eval_const(&end_val,MAXINT);
+      insert_const(&end_val,t);
+      break;
+    }
+    if(p->code==COMPARE){
+      if(!cfl) return;
+      if(compare_objs(cc,&p->z,p->typf)) return;
+      cmp=p;
+      if(p->q1.flags&VAR){
+	if(ind_vars[p->q1.v->index]){
+	  o=&p->q1;t=p->typf;
+	  e=&p->q2;
+	  break;
+	}
+      }
+      if(p->q2.flags&VAR){
+	if(ind_vars[p->q2.v->index]){
+	  o=&p->q2;t=p->typf;
+	  e=&p->q1;
+	  if(bflag==BLT) bflag=BGT;
+	  if(bflag==BLE) bflag=BGE;
+	  if(bflag==BGT) bflag=BLT;
+	  if(bflag==BGE) bflag=BLE;
+	  break;
+	}
+      }
+      return;
+    }
+    if(p==end->start) return;
+    p=p->prev;
+  }while(p);
+  if(!e||(e->flags&KONST)){
+    if(e) end_val=e->val;
+    if(DEBUG&1024) printf("end condition is constant\n");
+  }else{
+    if(!(e->flags&VAR)) return;
+    i=e->v->index;
+    if(e->flags&DREFOBJ) i+=vcount-rcount;
+    if(DEBUG&1024) printf("testing end-condition\n");
+    memcpy(rd_defs,end->rd_in,dsize);
+    for(m=end->start;m;m=m->next){
+      if(m==cmp){
+	if(DEBUG&1024) pric2(stdout,m);
+	if(!def_invariant(i,-1)) return;
+	if(DEBUG&1024) printf("end condition loop-invariant\n");
+	break;
+      }
+      rd_change(m);
+      if(m==end->end) ierror(0);
+    }
+  }
+  if((o->flags&(VAR|DREFOBJ))!=VAR) return;
+  p=ind_vars[o->v->index];
+  if(!p) return;
+  if(compare_objs(o,&p->z,t)) return;
+  if(DEBUG&1024) printf("loop condition only dependant on induction var\n");
+  if(!(p->q2.flags&KONST)) return;
+  if(DEBUG&1024) printf("induction is constant\n");
+  ind_only_counts=IND_ONLY_COUNTS;
+  multiple_exits=0;
+  for(ic_cnt=0,g=start;g;g=g->normalout){
+    for(m=g->start;m;m=m->next){
+      if(m!=p&&m!=cmp&&ind_only_counts){
+	int i;
+	for(i=0;i<m->use_cnt;i++){
+	  if(m->use_list[i].v==p->q1.v){
+	    if(DEBUG&1024){printf("use of ind_var:");pric2(stdout,m);}
+	    ind_only_counts=0;break;
+	  }
+	}
+      }
+      if(m==p&&!always_reached(start,end,g,p,1)) return;
+      ic_cnt++;
+      if(m==g->end) break;
+    }
+    if(g==end) break;
+    if(!multiple_exits&&g->branchout&&(g->branchout->index<start->index||g->branchout->index>end->index))
+      multiple_exits=MULTIPLE_EXITS;
+  }
+  ic_cnt-=2;  /*  Branch und Test */
+  if(DEBUG&1024) printf("induction always reached\n");
+  if(ind_only_counts&&(DEBUG&1024)) printf("induction variable only used as counter\n");
+  if(multiple_exits&&(DEBUG&1024)) printf("loop has multiple exits\n");
+  if(DEBUG&1024) printf("ICs in loop: %ld\n",ic_cnt);
+  step_val=p->q2.val;
+  if(p->code==SUB) flags|=1;
+  if(start->start->code==LABEL&&(start->start->flags&LOOP_COND_TRUE)&&e&&ind_only_counts){
+    if(e->flags&KONST)
+      eval_const(&e->val,t);
+    if(!(e->flags&KONST)||!zmeqto(vmax,l2zm(0L))||!zumeqto(vumax,ul2zum(0UL))||!zldeqto(vldouble,d2zld(0.0))){
+      int bc=branch->code;
+      eval_const(&step_val,t);
+      if((!(flags&1)&&(bc==BLT||bc==BLE))
+	 ||((flags&1)&&(bc==BGT||bc==BGE))
+	 ||(bc==BNE&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL)))){
+	if((t&UNSIGNED)||zmleq(l2zm(0L),vmax)){
+	  if(decide_reverse(vmax)){
+	    add_ur(UNROLL_REVERSE|ind_only_counts|multiple_exits,0,1,start,head,cmp,branch,p);
+	    return;
+	  }
+	}
+      }
+    }
+  }
+  if(!e||(e->flags&KONST)){
+    IC tmpic;
+    i=p->z.v->index;
+    if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+    memcpy(rd_defs,head->rd_out,dsize);
+    tmpic=*p;
+    if(propagate(&tmpic,&tmpic.z,1,1)){
+      init_val=tmpic.z.val;
+    }else{
+      goto inv;
+    }
+    if(DEBUG&1024){
+      printf("loop number determinable\n");
+      printf("init_val: ");printval(stdout,&init_val,t);
+      printf("\nend_val: ");printval(stdout,&end_val,t);
+      printf("\nstep_val: ");printval(stdout,&step_val,t);
+      printf("\nflags=%d bflag=%d\n",flags,bflag);
+    }
+    /*  Nur integers als Induktionsvariablen.   */
+    if(!ISINT(t)) goto inv;
+    /*  Distanz und Step werden als long behandelt, deshalb pruefen, ob */
+    /*  alles im Bereich des garantierten Mindestwerte fuer long.       */
+    /*  Wenn man hier die Arithmetik der Zielmaschine benutzen wuerde,  */
+    /*  koennte man theoretisch mehr Faelle erkennen, aber das waere    */
+    /*  recht popelig und man muss sehr aufpassen.                      */
+    if(t&UNSIGNED){
+      eval_const(&step_val,t);
+      if(!zumleq(vumax,l2zm(2147483647))) return;
+      step=zum2ul(vumax);
+      if(flags&1) step=-step;
+      eval_const(&end_val,t);
+      if(!zumleq(vumax,l2zm(2147483647))) goto inv;
+      dist=zum2ul(vumax);
+      eval_const(&init_val,t);
+      if(!zumleq(vumax,l2zm(2147483647))) goto inv;
+      dist-=zum2ul(vumax);
+    }else{
+      eval_const(&step_val,t);
+      if(!zmleq(vmax,l2zm(2147483647))) return;
+      if(zmleq(vmax,l2zm(-2147483647))) return; /*  eins weniger als moeglich waere */
+      step=zm2l(vmax);
+      if(flags&1) step=-step;
+      eval_const(&end_val,t);
+      if(!zmleq(vmax,l2zm(2147483647/2))) goto inv;
+      if(zmleq(vmax,l2zm(-2147483647/2))) goto inv; /*  eins weniger als moeglich waere */
+      dist=zm2l(vmax);
+      eval_const(&init_val,t);
+      if(!zmleq(vmax,l2zm(2147483647/2))) goto inv;
+      if(zmleq(vmax,l2zm(-2147483647/2))) goto inv; /*  eins weniger als moeglich waere */
+      dist-=zm2l(vmax);
+    }
+    if(DEBUG&1024) printf("dist=%ld, step=%ld\n",dist,step);
+    if(step==0) ierror(0);
+    /*  Die Faelle kann man noch genauer untersuchen, ob die Schleife   */
+    /*  evtl. nur einmal durchlaufen wird o.ae.                         */
+    if(step<0&&dist>=0){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+    if(step>0&&dist<=0){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+    if(bflag==BEQ){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+    /*  Aufpassen, ob das Schleifenende bei BNE auch getroffen wird.    */
+    if(bflag==BNE){
+      if(dist%step){
+	if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+	return;
+      }
+    }
+    if(bflag==BLT||bflag==BGT||bflag==BNE){
+      if(step>0) dist--; else dist++;
+    }
+    if(dist/step<0) ierror(0);
+    if(DEBUG&1024) printf("loop is executed %ld times\n",dist/step+1);
+    if(start->start->code!=LABEL) ierror(0);
+
+    /* determine smallest type for induction variable */
+    small_type=(UNSIGNED|CHAR);
+    eval_const(&init_val,t);
+    if(!(t&UNSIGNED)&&!zmleq(Z0,vmax)){
+      small_type&=~UNSIGNED;
+      while((small_type&NQ)<(t&NQ)&&(!zmleq(t_min(small_type),vmax)||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+	small_type++;
+    }else{
+      while((small_type&NQ)<(t&NQ)&&(!zumleq(vumax,t_max(small_type))||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+	small_type++;
+    }
+    eval_const(&end_val,t);
+    if(!(t&UNSIGNED)&&!zmleq(Z0,vmax)){
+      small_type&=~UNSIGNED;
+      while((small_type&NQ)<(t&NQ)&&(!zmleq(t_min(small_type),vmax)||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+	small_type++;
+    }else{
+      while((small_type&NQ)<(t&NQ)&&(!zumleq(vumax,t_max(small_type))||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+	small_type++;
+    }
+    if(zmleq(sizetab[t&NQ],sizetab[small_type&NQ]))
+      small_type=0;
+    if(small_type&&(DEBUG&1024)) printf("induction variable can be done in %s %s\n",(small_type&UNSIGNED)?"unsigned":"signed",typname[small_type&NQ]);
+    if(range_opt&&small_type&&decide_shorten(small_type,start,p,cmp)){
+      add_ur(UNROLL_SHORTEN|ind_only_counts|multiple_exits,small_type,small_type,start,head,cmp,branch,p);
+    }else if(dist/step+1==1||ic_cnt*(dist/step+1)<=unroll_size){
+      /*  Schleife komplett ausrollen.    */
+      add_ur(UNROLL_COMPLETELY|ind_only_counts|multiple_exits,dist/step+1,dist/step+1,start,head,cmp,branch,p);
+    }else{
+      /*  Schleife teilweise ausrollen.   */
+      n=(unroll_size-ic_cnt-2)/(2*ic_cnt);
+      if(n>0)
+	add_ur(UNROLL_MODULO|ind_only_counts|multiple_exits,dist/step+1,n,start,head,cmp,branch,p);
+    }
+    return;
+  }
+ inv:
+  /*  Anzahl der Schleifendurchlaeufe kann beim Eintritt in die   */
+  /*  Schleife zur Laufzeit berechnet werden.                     */
+  if(!(p->q2.flags&KONST)) return;
+  if(t&UNSIGNED){
+    eval_const(&step_val,t);
+    if(!zumleq(vumax,l2zm(2147483647))) return;
+    step=zum2ul(vumax);
+    if(flags&1) step=-step;
+  }else{
+    eval_const(&step_val,t);
+    if(!zmleq(vmax,l2zm(2147483647))) return;
+    if(zmleq(vmax,l2zm(0))) return; /* gibt Probleme */
+    step=zm2l(vmax);
+    if(flags&1) step=-step;
+  }
+  if(!compare_objs(&cmp->q1,&p->z,t)){
+    if(step>0&&(branch->code==BGT||branch->code==BGE)){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+    if(step<0&&(branch->code==BLT||branch->code==BLE)){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+  }else{
+    if(step<0&&(branch->code==BGT||branch->code==BGE)){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+    if(step>0&&(branch->code==BLT||branch->code==BLE)){
+      if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+      return;
+    }
+  }
+  if(!unroll_all) return;
+  if(bflag!=BEQ&&bflag!=BNE){
+    if(unroll_size>=8*ic_cnt+8)
+      add_ur(UNROLL_INVARIANT|ind_only_counts|multiple_exits,0,8,start,head,cmp,branch,p);
+    else if(unroll_size>=4*ic_cnt+4)
+      add_ur(UNROLL_INVARIANT|ind_only_counts|multiple_exits,0,4,start,head,cmp,branch,p);
+    else if(unroll_size>=4*ic_cnt+2)
+      add_ur(UNROLL_INVARIANT|ind_only_counts|multiple_exits,0,2,start,head,cmp,branch,p);
+    return;
+  }
+}
+
+int loop_optimizations(flowgraph *fg)
+/*  steuert Optimierungen in Schleifen  */
+{
+  int changed=0,i;
+  flowgraph *g,*last;
+  if(DEBUG&1024) print_flowgraph(fg);
+  if(loops(fg,0)==0) return 0;
+  if(DEBUG&1024) print_flowgraph(fg);
+  first_fg=fg=create_loop_headers(fg,0);
+  if(DEBUG&1024) print_flowgraph(fg);
+  num_defs();
+
+  /*bsize=(basic_blocks+CHAR_BIT)/CHAR_BIT;*/
+  bsize=BVSIZE(basic_blocks+1);
+  fg_tmp=mymalloc(bsize);
+  ind_vars=mymalloc(vcount*sizeof(*ind_vars));
+  invariant=mymalloc(dsize);
+  inloop=mymalloc(dsize);
+  rd_defs=mymalloc(dsize);
+  reaching_definitions(fg);
+  if(DEBUG&1024) print_flowgraph(fg);
+  moved=mymalloc(dsize);
+  memset(moved,0,dsize);
+  moved_completely=mymalloc(dsize);
+  memset(moved_completely,0,dsize);
+  not_movable=mymalloc(dsize);
+
+  first_mov=last_mov=0;
+  first_sr=last_sr=0;
+
+  for(last=0,g=fg;g;g=g->normalout){
+    if(g->loopend){
+      frequency_reduction(g,g->loopend,last);
+      strength_reduction(g,g->loopend,last);
+      if(optflags&2048) unroll(g,last);
+    }
+    last=g;
+  }
+
+  free(rd_matrix);
+  free(var_defs);
+  free(defs_kill);
+  free(defs_gen);
+  free(dlist);
+  free(rd_defs);
+  free(invariant);
+  free(inloop);
+  changed|=move_to_head();
+  if(DEBUG&1024) puts("done");
+  if(range_opt)
+    changed|=do_shorten();
+  changed|=do_sr(changed);
+  if(DEBUG&1024) puts("done");
+  changed|=do_unroll(changed);
+  if(DEBUG&1024) puts("done");
+  free(moved);
+  free(not_movable);
+  free(moved_completely);
+  if(DEBUG&1024) puts("4");
+  if(changed&2){
+    if(DEBUG&1024) printf("must repeat num_vars\n");
+    free(vilist);
+    free(av_globals);free(av_statics);
+    free(av_drefs);free(av_address);
+    num_vars();
+  }
+
+  free(ind_vars);
+  free(fg_tmp);
+
+  return changed;
+}
+
diff --git a/machines/6502/compress.c b/machines/6502/compress.c
new file mode 100644
index 0000000..9295229
--- /dev/null
+++ b/machines/6502/compress.c
@@ -0,0 +1,127 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "vcpr.h"
+
+
+const char tg_copyright[]="6502 code compressor V0.1 (c) 2020 by Volker Barthelmann";
+
+char *inst[]={
+  "lda","ldx","sta","stx","ldy","sty","ldz","stz","ldq","stq",
+  "adc","sbc","and","ora","eor","adcq","sbcq","andq","oraq","eorq",
+  "bne","beq","bcc","bcs","bvs","bvc","bpl","bmi","bra",
+  "clc","sec",
+  /*"pla","pha",*/
+  "txa","tax","tya","tay","tza","taz",
+  "inc","dec","dex","inx","iny","dey","inz","dez","inw","dew","push",
+  /*"rts","rti",*/"jsr","jmp",
+  "cmp","cpx","cpy",
+  "asl","lsr","ror","rol","asw","aslq","lsrq","asr","asrq"
+};
+
+int minsave=5;
+
+void parse_line(char *s,line *p)
+{
+  int l,i;
+  static int secok=0;
+  char buf[16],buf2[16],*e;
+
+  if(sscanf(s," %8s %8s",buf,buf2)==2&&!strcmp(buf,"section")){
+    if(!strcmp(buf2,"text"))
+      secok=1;
+    else
+      secok=0;
+    p->flags=BARRIER;
+    return;
+  }
+
+  if(sscanf(s,"l%d:",&l)==1){
+    p->flags|=LABDEF;
+    p->l1=l;
+    p->size=0;
+    if(!secok) p->flags|=BARRIER;
+    return;
+  }
+
+  if(!secok){
+    p->flags|=BARRIER;
+    return;
+  }
+
+  if(!isspace((unsigned char)*s)){
+    p->flags=BARRIER;
+    return;
+  }
+  while(isspace((unsigned char)*s))
+    s++;
+  for(e=s;isalpha((unsigned char)*e);e++);
+
+  for(i=0;i<sizeof(inst)/sizeof(inst[0]);i++){
+    if(!strncmp(s,inst[i],e-s)){
+      int quad=0;
+      if(e[-1]=='q') quad=2;
+      while(isspace((unsigned char)*e)) e++;
+      if(*e==0){
+	p->size=1;
+	return;
+      }
+      if(*e=='[') p->size++;
+      p->size=2;
+      p->size+=quad;
+      if(sscanf(e,"l%d",&l)==1){
+	p->flags|=LABUSE;
+	p->l1=l;
+      }
+      if(*s=='b'||!strncmp(s,"jmp",3)){
+	p->flags|=BRANCH;
+      }
+      return;
+    }
+  }
+  p->flags=BARRIER;
+}
+
+static int nlab;
+
+#define SECTION "\tsection\ttext\n"
+
+void add_header(line *after)
+{
+  nlab=new_label();
+  line *new;
+  new=new_line();
+  new->flags=LABDEF;
+  new->l1=nlab;
+  new->code=mymalloc(16); /* TODO */
+  sprintf(new->code,"x%d:\n",nlab);
+  insert_line(after,new);
+  new=new_line();
+  new->flags=BARRIER;
+  new->code=mymalloc(strlen(SECTION)+1);
+  strcpy(new->code,SECTION);
+  insert_line(after,new);
+}
+
+void add_ret(line *after)
+{
+  line *new=new_line();
+  new->size=1;
+  new->flags=BARRIER;
+  new->code=mymalloc(8); /*TODO*/
+  strcpy(new->code,"\trts\n");
+  insert_line(after,new);
+}
+
+void add_jsr(line *after)
+{
+  line *new=new_line();
+  new->flags=LABUSE;
+  new->size=3;
+  new->l1=nlab;
+  new->code=mymalloc(24); /* TODO */
+  sprintf(new->code,"\tjsr\tx%d\n",nlab);
+  insert_line(after,new);
+}
diff --git a/machines/6502/machine.c b/machines/6502/machine.c
new file mode 100755
index 0000000..c8e14b6
--- /dev/null
+++ b/machines/6502/machine.c
@@ -0,0 +1,6029 @@
+/*  6502 backend for vbcc
+    (c) Volker Barthelmann 2020
+
+*/                                                                             
+
+#include "supp.h"
+#include "vbc.h"
+
+#include <math.h>
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc 6502 code-generator V0.5 (c) in 2022 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+		    VALFLAG,0,0,
+		    0,0,
+		    VALFLAG,VALFLAG,0,0,
+		    VALFLAG,0,0,0,
+		    0,0,0,
+		    0,0,0,0,0,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"std-syntax","no-rax",
+			   "volatile-regs","ieee","no-peephole",
+			   "cbmascii","softstack",
+			   "reg-args","int-args","mainargs","no-bank-vars",
+			   "common-banknr","btmp-zpage","oldfp","large",
+			   "glob-acc","avoid-bank-switch","manual-banking",
+			   "atascii","65c02","nox","mega65","ce02","c02",
+			   "div-bug","m65io"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__zpage","__nocpr",0};
+
+#define INTERRUPT 1
+#define ZPAGE 2
+#define NOCOMPRESS 4
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define STDSYNTAX  (g_flags[0]&USEDFLAG)
+#define NORAX      (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define IEEE       (g_flags[3]&USEDFLAG)
+#define NOPEEP     (g_flags[4]&USEDFLAG)
+#define CBMASCII   (g_flags[5]&USEDFLAG)
+#define SOFTSTACK  (g_flags[6]&USEDFLAG)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:8)
+#define MAINARGS   (g_flags[9]&USEDFLAG)
+#define NOBANKVARS (g_flags[10]&USEDFLAG)
+#define COMMONBANK ((g_flags[11]&USEDFLAG)?g_flags_val[11].l:0)
+#define BIGZPAGE   (g_flags[12]&USEDFLAG)
+#define OLDFP      (g_flags[13]&USEDFLAG)
+#define LARGE      (g_flags[14]&USEDFLAG)
+#define GLOBACC    (g_flags[15]&USEDFLAG)
+#define NOSWITCH   (g_flags[16]&USEDFLAG)
+#define NOBANKING  (g_flags[17]&USEDFLAG)
+#define ATASCII    (g_flags[18]&USEDFLAG)
+#define C02        (g_flags[19]&USEDFLAG)
+#define NOX        (g_flags[20]&USEDFLAG)
+#define MEGA65     (g_flags[21]&USEDFLAG)
+#define CE02       (g_flags[22]&USEDFLAG)
+#define C02ALT     (g_flags[23]&USEDFLAG)
+#define DIVBUG     (g_flags[24]&USEDFLAG)
+#define M65IO      (g_flags[25]&USEDFLAG)
+
+
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define PLA (-1)
+#define JMPIND (-2)
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isacc(x) (isreg(x)&&(p->x.reg==ra||p->x.reg==rax))
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define iszpage(o) (((o)->flags&(REG|DREFOBJ))==REG||(((o)->flags&(VAR|DREFOBJ))==VAR&&(o)->v->tattr&ZPAGE))
+
+#define isptr(r) ((r)>=FIRST_PAIR&&(r)<=LAST_PAIR)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"ora","eor","and"};
+static char *arithmetics[]={"slw","srw","adc","sbc","mullw","divw","mod"};
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,2,4,8,4,4,4,0,2,3,3,0,0,0,1,0};
+static char *mregnames[MAXR+1+4];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","int","long","long long",
+                 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+                 "array","struct","union","enum","function"};
+
+
+/* used to initialize regtyp[] */
+static struct Typ ityp={INT},ctyp={CHAR},ftyp={FLOAT},lltyp={LLONG};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__6502__",
+		       "__SIZE_T_INT",
+		       "__bank(x)=__vattr(\"bank(\"#x\")\")",
+                       "__far=__attr(\"far\")",
+                       "__near=__attr(\"near\")",
+                       "__huge=__attr(\"huge\")",
+		       0};
+
+/* special registers */
+static int ra=1, rx=2, ry=3, sp1=4,sp2=5,sp=6,fp,fp1,fp2;
+static int t4=LAST_GPR,t3=LAST_GPR-1,t2=LAST_GPR-2,t1=LAST_GPR-3;
+static int rax=7;
+static int yval;
+#define NOVAL 1000
+
+#define REGDUMMY1 MAXR+1
+#define REGDUMMY2 MAXR+2
+#define REGDUMMY3 MAXR+3
+
+static int t1,t2,f1,f2; /*tODO: remove*/
+
+static int pushedacc,pushedx,nopeep,cbmascii,atascii,ieee;
+static int storedacc,storedx;
+static int c02,m65,ce02,zzero,noy;
+static int divbug;
+static int m65io;
+static int manbank;
+static char *jmpinst;
+static int pass;
+static int libsave;
+static struct rpair rp2;
+static int cbank;
+static Var bankv;
+static int bankvoffset;
+static int bankcnum;
+static obj zstore;
+static int zstoreflag;
+static int hasretval;
+
+#define SECLEN 128
+char *use_sec;
+int use_bank=-1;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* perhaps provide version with 8bit int? */
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSHORT(t) ((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==POINTER)
+#define ISFPOINTER(t) ((t&NQ)==FPOINTER)
+#define ISLONG(t) ((t&NQ)==LONG)
+#define ISLLONG(t) ((t&NQ)==LLONG)
+
+#define ISIDX(r) (r==rx)
+#define ISRIDX(op) (isreg(op)&&ISIDX(p->op.reg))
+#define ISPREG(op) (isreg(op)&&isptr(p->op.reg))
+
+#define LONGM65(c) ((c)==ASSIGN||(c)==PUSH||(c)==GETRETURN||(c)==SETRETURN||((c)>=LSHIFT&&(c)<=MOD)||((c)>=OR&&(c)<=AND))
+
+/* am */
+#define IMM_IND 1
+#define GPR_IND 2
+#define ABS_IND 3
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\tsection\ttext",
+  *dataname="\tsection\tdata",
+  *bssname="\tsection\tbss",
+  *rodataname="\tsection\trodata";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+
+static long localsize,rsavesize,rscnt,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+#define bank(x) bankx((x),manbank)
+#define sbank(x) bankx((x),0)
+
+static int bankx(Var *v,int nobank)
+{
+  char *s=v->vattr;
+  int n,r;
+  if(!nobank&&s&&(s=strstr(s,"bank("))){
+    if(sscanf(s+5,"%i",&n)==1)
+      return n;
+  }
+  return -1;
+}
+
+static void ebank(FILE *f,int b)
+{
+  if(b>=0) emit(f,"%d",b);
+  emit(f,"\n");
+}
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize-off-zm2l(maxalign);
+  }
+
+  off+=argsize;
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(v->tattr&ZPAGE){
+    emit(f,"\tsection\tzpage\n");
+  }else{
+    if(!v->vattr) return 0;
+    sec=strstr(v->vattr,"section(");
+    if(!sec) return 0;
+    sec+=strlen("section(");
+    emit(f,"\tsection\t");
+    while(*sec&&*sec!=')') emit_char(f,*sec++);
+    emit(f,"\n");
+  }
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+
+
+#define chk_coll(x) do{if((x)==r||(x)==r1||(x)==r2) return 0;	\
+    if(reg_pair((x),&rp)&&(rp.r1==r||rp.r2==r)) return 0;}while(0)
+
+static int scratch(IC *p,int r,int isnext)
+{
+  int r1,r2;
+  if(!p) return 1;
+  if(reg_pair(r,&rp)){
+    r1=rp.r1;
+    r2=rp.r2;
+  }else{
+    r1=0;
+    r2=0;
+  }
+  if(!isnext&&isreg(z)&&p->z.reg==r){
+    if(!(p->q2.flags&REG))
+      return 1;
+    if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)
+      return 0;
+    if(reg_pair(p->q2.reg,&rp))
+      if(rp.r1==r||rp.r2==r)
+	return 0;
+    return 1;
+  }
+  while(p){
+    if(p->code==LABEL||p->code==CALL)
+      return 0;
+    if(p->code>=BEQ&&p->code<=BRA)
+      return 0;
+    if(p->code==FREEREG||p->code==ALLOCREG){
+      if(p->q1.reg==r)
+	return 1;
+      if(reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))
+	return 1;
+    }
+    if(p->q1.am){
+      chk_coll(p->q1.am->base);
+      if(p->q1.am->flags!=IMM_IND) chk_coll(p->q1.am->idx);
+    }
+    if(p->q2.am){
+      chk_coll(p->q2.am->base);
+      if(p->q2.am->flags!=IMM_IND) chk_coll(p->q2.am->idx);
+    }
+    if(p->z.am){
+      chk_coll(p->z.am->base);
+      if(p->z.am->flags!=IMM_IND) chk_coll(p->z.am->idx);
+    }
+    if(p->q1.flags&REG) chk_coll(p->q1.reg);
+    if(p->q2.flags&REG) chk_coll(p->q2.reg);
+    if(p->z.flags&REG){
+      if(p->z.flags&DREFOBJ)
+	chk_coll(p->z.reg);
+      else{
+	if(p->z.reg==r)
+	  return 1;
+	if(reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r))
+	  return 1;
+      }
+    }
+
+    p=p->next;
+  }
+  return 1;
+}
+
+static int rsavecur;
+static int in_isr;
+
+static int get_reg(FILE *f,IC *p,int t)
+{
+  int r,r1,r2,pass,flag;
+
+  for(pass=0;pass<5;pass++){
+    for(r=MAXR;r>sp;r--){
+      if(reg_pair(r,&rp)){
+	r1=rp.r1;
+	r2=rp.r2;
+      }else{
+	r1=0;
+	r2=0;
+      }
+      if((pass==0||pass==3)&&(!regscratch[r]||in_isr))
+	continue;
+      if(pass<3){
+	if(regs[r]) continue;
+	if(r1&&(regs[r1]||regs[r2])) continue;
+      }
+      if(pass==2&&!(regs[r]&4))
+	continue;
+      if(p->q1.flags&REG){
+	if(p->q1.reg==r||p->q1.reg==r1||p->q1.reg==r2) continue;
+	if(r1==0&&reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r)) continue;
+      }
+      if(p->q2.flags&REG){
+	if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2) continue;
+	if(r1==0&&reg_pair(p->q2.reg,&rp)&&(rp.r1==r||rp.r2==r)) continue;
+      }
+      if(p->z.flags&REG){
+	if(p->z.reg==r||p->z.reg==r1||p->z.reg==r2) continue;
+	if(r1==0&&reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r)) continue;
+      }
+      if(regok(r,t,1)){
+	flag=8;
+	if(regs[r]){
+	  flag|=2;
+	  if(p->code==COMPARE||p->code==TEST)
+	    ierror(0);
+	  if(regs[ra]){
+	    emit(f,"\ttay\n");
+	    yval=NOVAL;
+	  }
+	  if(r1){
+	    emit(f,"\tlda\t%s\n",mregnames[r1]);
+	    emit(f,"\tpha\n");
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    emit(f,"\tpha\n");
+	  }else{
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    emit(f,"\tpha\n");
+	  }
+	  if(regs[ra])
+	    emit(f,"\ttya\n");
+	}
+	if(r1){
+	  regs[r1]|=flag;
+	  regs[r2]|=flag;
+	}
+	regs[r]|=flag;
+	regused[r]=1;
+	regused[r1]=1;
+	regused[r2]=1;
+	/*emit(f,"; p=%p r=%s\n",(void*)p,mregnames[r]);*/
+	return r;
+      }
+    }
+  }
+  pric2(stdout,p);
+  ierror(0);
+}
+
+static void get_acc(FILE *f, IC *p,int t)
+{
+  int r;
+  if(isacc(z)) return;
+  t&=NQ;
+  if(ISCHAR(t)){
+    if(1/*!isreg(q1)||(p->q1.reg!=ra&&p->q1.reg!=rax)*/){
+      if((regs[ra]||regs[rax])&&!scratch(p,ra,0)&&!pushedacc){
+	if(storedacc)
+	  pushedacc=storedacc;
+	else if(optsize||(regs[t1]&&regs[t2]&&regs[t3]&&regs[t4])){
+	  emit(f,"\tpha\n");
+	  pushedacc=-1;
+	}else{
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	  pushedacc=r;
+	}
+      }
+    }
+  }else{
+    if(1/*!isreg(q1)||p->q1.reg!=rax*/){
+      if((regs[ra]||regs[rax])&&(!scratch(p,ra,0)||!scratch(p,rax,0))&&!pushedacc){
+	if(!storedacc){
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	  pushedacc=r;
+	}else
+	  pushedacc=storedacc;
+      }
+      if((regs[rx]||regs[rax])&&!scratch(p,rax,0)&&!pushedx){
+	if(!storedx){
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tstx\t%s\n",mregnames[r]);
+	  pushedx=r;
+	}else
+	  pushedx=storedx;
+      }
+    }
+  }
+}
+
+static int cmp_get_acc(FILE *f,IC *p,IC *branch)
+{
+  if(!regs[ra]&&!regs[rax])
+    return 0;
+  if(branch==0&&pushedacc)
+    return 0;
+  if(branch&&isreg(q1)&&(p->q1.reg==ra||p->q1.reg==rax))
+    if(branch->code==BEQ||branch->code==BNE||(p->typf&UNSIGNED))
+      return 0;
+  if(scratch(p,ra,0))
+    return 0;
+  if(!regs[rx]&&!regs[rax]){
+    emit(f,"\ttax\n");
+    pushedacc=rx;
+  }
+  emit(f,"\tpha\n");
+  pushedacc=-1;
+  return pushedacc;
+}
+
+static void reload_acc_opt(FILE *f,IC *p)
+{
+  if(pushedacc==0) return;
+  if(pushedacc>0){
+    while(p){
+      if(p->code!=FREEREG) break;
+      if(p->q1.reg==ra||p->q1.reg==rax){
+	pushedacc=0;
+	return;
+      }
+      p=p->next;
+    }
+  }
+  if(pushedacc==-1)
+    emit(f,"\tpla\n");
+  else if(pushedacc==rx)
+    emit(f,"\ttxa\n");
+  else if(pushedacc==ry)
+    emit(f,"\ttya\n");
+  else if(pushedacc){
+    emit(f,"\tlda\t%s\n",mregnames[pushedacc]);
+    regs[pushedacc]&=~8;
+  }
+  pushedacc=0;
+}
+
+static void reload_acc(FILE *f)
+{
+  reload_acc_opt(f,0);
+}
+
+static void push(int i)
+{
+  pushed-=i;
+  if(pushed<maxpushed)
+    maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+  pushed+=i;
+  if(pushed>0) ierror(0);
+}
+
+static int indirect(obj *o)
+{
+  if(o->am){
+    if(o->am->flags==ABS_IND&&o->am->idx==rx)
+      return 0;
+    else
+      return 1;
+  }
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ)
+    return 1;
+  if((o->flags&(REG|VAR))!=VAR){
+    if((o->flags&REG)&&(o->reg==ra||ISIDX(o->reg)||o->reg==rax))
+      return 1;
+    return 0;
+  }
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+    return 1;
+  return 0;
+}
+
+void convfloat(void)
+{
+}  
+
+void sety(FILE *f,int val)
+{
+  if(yval==val)
+    return;
+  if(val-yval==1)
+    emit(f,"\tiny\n");
+  else if(yval-val==1)
+    emit(f,"\tdey\n");
+  else{
+    emit(f,"\tldy\t#%d\n",val);
+    if(val<0||val>255)
+      ierror(0);
+  }
+  yval=val;
+}
+
+static void cnv_fp(void)
+{
+  double d,mant;
+  int exp;
+  unsigned long t;
+
+  if(ieee){
+    vfloat=zld2zf(vldouble);
+    memcpy((void*)&vmax,(void*)&vfloat,4);
+  }else{
+    d=zld2d(vldouble);
+    mant=frexp(d,&exp);
+    exp=(exp+127)&255;
+    t=((unsigned long)(mant*8388608))&0xffffff;
+    t|=((long)exp)<<24;
+    
+    t=((t&0xff)<<24)|((t&0xff00)<<8)|((t&0xff0000)>>8)|((t&0xff000000)>>24);
+    vmax=l2zm((long)t);
+    if(mant==0&&d==0) vmax=Z0;
+  }
+}
+
+static void emit_ieee(FILE *f,union atyps *p,int t)
+{
+  unsigned char *ip=(unsigned char *)&p->vdouble;
+  emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+  if(t==DOUBLE||t==LDOUBLE)
+    emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+  emit(f,"\n");
+}
+
+static void emit_lobyte(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+       emit(f,"%d",zm2l(vmax));
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",zm2l(vmax)&255);
+    }
+  }else if(o->flags&VARADR){
+    emit(f,"#<(");
+    emit_obj(f,o,t);
+    emit(f,")");
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp))
+      emit(f,"%s",mregnames[o->reg]);
+    else
+      emit(f,"%s",mregnames[rp.r1]);
+  }else{
+    if(zzero&&(o->flags&(DREFOBJ|KONST))==DREFOBJ) noy=1;
+    emit_obj(f,o,t);
+    noy=0;
+  }
+}
+
+static void emit_hibyte(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+1);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>8)&255);
+    }
+  }else if(o->flags&VARADR){
+    emit(f,"#>(");
+    emit_obj(f,o,t);
+    emit(f,")");
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg>=FIRST_BIG&&o->reg<=LAST_BIGP){
+      emit(f,"%s+1",mregnames[o->reg]);
+    }else{
+      if(!reg_pair(o->reg,&rp))
+	ierror(0);
+      emit(f,"%s",mregnames[rp.r2]);
+    }
+  }else{
+    if(o->flags&VARADR)
+      emit(f,"#");
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,Z1);
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,Z1);
+  }
+}
+
+static void emit_byte3(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+2);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>16)&255);
+    }
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    emit(f,"%s+2",mregnames[o->reg]);
+  }else if(o->flags&VARADR){
+    emit(f,"#%d",bank(o->v));
+  }else{
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,l2zm(2L));
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,l2zm(2L));
+  }
+}
+
+static void emit_byte4(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+3);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>24)&255);
+    }
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    emit(f,"%s+3",mregnames[o->reg]);
+  }else{
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,l2zm(3L));
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,l2zm(3L));
+  }
+}
+
+static void ldq_offset(FILE *f,obj *o)
+{
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      emit(f,"\tldz\t#%ld\n",o->am->offset);
+    else if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+      if(o->am->idx==ra)
+	emit(f,"\ttaz\n");
+      else{
+	if(ISIDX(o->am->idx)){
+	  if(o->am->flags==GPR_IND){
+	    emit(f,"\tpha\n");
+	    emit(f,"\tt%sa\n",mregnames[o->am->idx]);
+	    emit(f,"\ttaz\n");
+	    emit(f,"\tpla\n");
+	  }
+	}else
+	  emit(f,"\tldz\t%s\n",mregnames[o->am->idx]);
+      }
+    }else
+      ierror(0);
+  }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    /*if(!zzero)*/ emit(f,"\tldz\t#0\n");
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    emit(f,"\tldz\t#%ld\n",real_offset(o));
+  }
+}
+
+static void do_amload(FILE *f,obj *o)
+{
+  if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+    if(o->am->idx==ra)
+      emit(f,"\ttay\n");
+    else{
+      if(ISIDX(o->am->idx)){
+	if(o->am->flags==GPR_IND){
+	  emit(f,"\tpha\n");
+	  emit(f,"\tt%sa\n",mregnames[o->am->idx]);
+	  emit(f,"\ttay\n");
+	  emit(f,"\tpla\n");
+	}
+      }else{
+	if(o->am->idx==ra)
+	  emit(f,"\ttay\n");
+	else
+	  emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      }
+    }
+  }else
+    ierror(0);
+}
+static void do_lobyte(FILE *f,char *s,obj *o,int type)
+{
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset);
+    else{
+      do_amload(f,o);
+      yval=NOVAL;
+    }
+  }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    if(!zzero) sety(f,0);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o));
+  }
+  emit(f,"\t%s\t",s);
+  emit_lobyte(f,o,type);
+  emit(f,"\n");
+}
+
+static void do_hibyte(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+1);
+    else{
+      do_amload(f,o);
+      if(o->am->flags==GPR_IND){
+	emit(f,"\tiny\n");
+      }else{
+	o->am->offset++;ami=1;
+      }
+      yval=NOVAL;
+    }
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,1);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+1);
+  }
+  emit(f,"\t%s\t",s);
+  emit_hibyte(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset--;
+}
+
+static void do_byte3(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+2);
+    else{
+      do_amload(f,o);
+      if(o->am->flags==GPR_IND){
+	emit(f,"\tiny\n\tiny\n");
+      }else{
+	o->am->offset+=2;ami=1;
+      }
+      yval=NOVAL;
+    }
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,2);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+2);
+  }
+  emit(f,"\t%s\t",s);
+  emit_byte3(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset-=2;
+}
+
+static void do_byte4(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+3);
+    else{
+      do_amload(f,o);
+      if(o->am->flags==GPR_IND){
+	emit(f,"\tiny\n\tiny\n\tiny\n");
+      }else{
+	o->am->offset+=3;ami=1;
+      }
+      yval=NOVAL;
+    }
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,3);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+3);
+  }
+  emit(f,"\t%s\t",s);
+  emit_byte4(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset-=3;
+}
+
+static void load_lobyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==ra||o->reg==rax)
+      return;
+    if(o->reg==rx){
+      emit(f,"\ttxa\n");
+      return;
+    }
+  }
+  do_lobyte(f,"lda",o,t);
+}
+
+static void load_hibyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&REG)&&(o->reg==rx||o->reg==rax))
+    emit(f,"\ttxa\n");
+  else
+    do_hibyte(f,"lda",o,t);
+}
+
+static void store_lobyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==ra||o->reg==rax)
+      return;
+    if(o->reg==rx){
+      emit(f,"\ttax\n");
+      return;
+    }
+  }
+  do_lobyte(f,"sta",o,t);
+}
+
+static void store_hibyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&REG)&&(o->reg==rx||o->reg==rax))
+    emit(f,"\ttax\n");
+  else
+    do_hibyte(f,"sta",o,t);
+}
+
+static void load_acc(FILE *f,obj *o,int type)
+{
+  if((o->flags&REG)&&(o->reg==ra||o->reg==rax))
+    return;
+  if(!ISCHAR(type)){
+    if(indirect(o)){
+      do_hibyte(f,"lda",o,type);
+      emit(f,"\ttax\n");
+    }else
+      do_hibyte(f,"ldx",o,type);
+  }
+  if((o->flags&(REG|DREFOBJ))==REG&&o->reg==rx)
+    emit(f,"\ttxa\n");
+  else
+    do_lobyte(f,"lda",o,type);
+}
+
+static void store_acc(FILE *f,obj *o,int type)
+{
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&((!(o->flags&REG))||!isptr(o->reg))){
+    ierror(0);
+  }
+  if((o->flags&REG)&&(o->reg==ra||o->reg==rax))
+    return;
+  if((o->flags&REG)&&o->reg==rx){
+    emit(f,"\ttax\n");
+    return;
+  }
+  store_lobyte(f,o,type);
+  if(!ISCHAR(type)){
+    if(indirect(o)){
+      /*TODO: save accu */
+      emit(f,"\ttxa\n");
+      store_hibyte(f,o,type);
+    }else
+      do_hibyte(f,"stx",o,type);
+  }
+}
+
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  static obj ro;
+  if(ISIDX(r)&&!indirect(o)){
+    static char ldr[4]="ldr";
+    ldr[2]=mregnames[r][0];
+    do_lobyte(f,ldr,o,type);
+    return;
+  }
+  ro.flags=REG;
+  ro.reg=r;
+  load_lobyte(f,o,type);
+  store_lobyte(f,&ro,type);
+  if(!ISCHAR(type)){
+    load_hibyte(f,o,type);
+    store_hibyte(f,&ro,type);
+  }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  static obj ro;
+  if(ISIDX(r)){
+    if((o->flags&(REG|DREFOBJ))==REG){
+      if(o->reg==r)
+	return;
+      if(o->reg==ra){
+	emit(f,"\tt%sa\n",mregnames[r]);
+	return;
+      }
+    }
+    if(!indirect(o)){
+      static char str[4]="str";
+      str[2]=mregnames[r][0];
+      do_lobyte(f,str,o,type);
+      return;
+    }
+  }
+  ro.flags=REG;
+  ro.reg=r;
+  if(r!=ra&&r!=rax)
+    load_acc(f,&ro,type);
+  store_acc(f,o,type);
+}
+
+static struct fpconstlist {
+  struct fpconstlist *next;
+  int label;
+  int t;
+  union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(t==LDOUBLE) t=DOUBLE;
+  for(p=firstfpc;p;p=p->next){
+    if(t==p->t){
+      eval_const(&p->val,t);
+      if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+      if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+      if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+      if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->t=t;
+  p->label=++label;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+/* generate code to load the address of a local variable into register r */
+static void load_laddr(FILE *f,int r,struct obj *o)
+{
+  long l=real_offset(o);
+  /* assumes acc is available */
+  if(!reg_pair(r,&rp)) ierror(0);
+  emit(f,"\tlda\t%s\n",mregnames[fp]);
+  if(l!=0)
+    emit(f,"\tclc\n");
+  if(l&255)
+    emit(f,"\tadc\t#%ld\n",l&255);
+  emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+  emit(f,"\tlda\t%s\n",mregnames[fp2]);
+  if(l!=0)
+    emit(f,"\tadc\t#%ld\n",(l>>8)&255);
+  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int t)
+{
+  if(o->flags&DREFOBJ){
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER);
+    o->flags|=DREFOBJ;
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t#>%s\n",mregnames[o->reg]);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    emit(f,"\tlda\t#<%s\n",mregnames[o->reg]);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);    
+  }else if(o->flags&VAR){
+    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+      load_laddr(f,r,o);
+    }else{
+      o->flags|=VARADR;
+      load_reg(f,r,o,POINTER);
+      o->flags&=~VARADR;
+    }
+  }else if((o->flags&(KONST|DREFOBJ))==KONST){
+    int l=addfpconst(o,t);
+    if(!ieee) ierror(0);
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t#>%s%d\n",labprefix,l);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    emit(f,"\tlda\t#<%s%d\n",labprefix,l);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);    
+  }else
+    ierror(0);
+}
+
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static void incmem(FILE *f,obj *o,int t,int op,int x)
+{
+  int i,idx=0;
+  char *s;
+  if(ce02&&ISSHORT(t)){
+    if(((o->flags&(REG|DREFOBJ))==REG&&(op==ADD||op==SUB))||
+       (op==LSHIFT&&!indirect(o)&&!o->am)){
+      do{
+	emit(f,"\t%s\t%s\n",op==ADD?"inw":(op==SUB?"dew":"asw"),mregnames[o->reg]);
+      }while(--x);
+      return;
+    }
+  }
+  if((o->flags&(REG|DREFOBJ))==REG&&ISIDX(o->reg)){
+    static char buf[4]="   ";
+    idx=1;s=buf;
+    if(op==ADD){s[0]='i';s[1]='n';}else{s[0]='d';s[1]='e';}
+    s[2]=mregnames[o->reg][0];
+  }else if(op==ADD)
+    s="inc";
+  else if(op==SUB)
+    s="dec";
+  else if(op==LSHIFT)
+    s="asl";
+  else if(op==RSHIFT&&(t&UNSIGNED))
+    s="lsr";
+  else if(op==RSHIFT){
+    s="cmp\t#128\n\tror";
+  }else
+    ierror(0);
+  if(ISCHAR(t)){
+    for(i=0;i<x;i++){
+      if(idx){
+	emit(f,"\t%s\n",s);
+      }else{
+	emit(f,"\t%s\t",s);
+	emit_obj(f,o,t);
+	emit(f,"\n");
+      }
+    }
+  }else{
+    for(i=0;i<x;i++){
+      if(op==SUB){
+	if(m65&&ISLONG(t)){
+	  emit(f,"\tdeq\t");
+	  emit_obj(f,o,t);
+	  emit(f,"\n");
+	}else if(ce02&&iszpage(o)){
+	  emit(f,"\tdew\n");
+	}else{
+	  /* caller mus make sure accu is available */
+	  load_lobyte(f,o,t);
+	  emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	  emit(f,"\tdec\t");
+	  emit_hibyte(f,o,t);
+	  emit(f,"\n");
+	  if(ISLONG(t)){
+	    ierror(0);
+	  }
+	  emit(f,"%s%d:\n",labprefix,label);
+	  emit(f,"\tdec\t");
+	  emit_lobyte(f,o,t);
+	  emit(f,"\n");
+	}
+      }else if(op==ADD){
+	if(!optspeed&&m65&&ISLONG(t)){
+	  emit(f,"\tinq\t");
+	  emit_obj(f,o,t);
+	  emit(f,"\n");
+	}else if(!optspeed&&ce02&&iszpage(o)){
+	  emit(f,"\tinw\t");
+	  emit_lobyte(f,o,t);
+	  emit(f,"\n");
+	  if(ISLONG(t)){
+	    emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	    emit(f,"\tinw\t");
+	    emit_byte3(f,o,t);
+	    emit(f,"\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }
+	}else{
+	  emit(f,"\t%s\t",s);
+	  emit_lobyte(f,o,t);
+	  emit(f,"\n");
+	  emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	  emit(f,"\t%s\t",s);
+	  emit_hibyte(f,o,t);
+	  emit(f,"\n");
+	  if(ISLONG(t)){
+	    emit(f,"\tbne\t%s%d\n",labprefix,label);
+	    emit(f,"\t%s\t",s);
+	    emit_byte3(f,o,t);
+	    emit(f,"\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,label);
+	    emit(f,"\t%s\t",s);
+	    emit_byte4(f,o,t);
+	    emit(f,"\n");
+	  }
+	  emit(f,"%s%d:\n",labprefix,label);
+	}
+      }else if(op==LSHIFT){
+	if(ce02&&!indirect(o)&&!o->am){
+	  emit(f,"\tasw\t");
+	  emit_obj(f,o,t);
+	  emit(f,"\n");
+	}else{
+	  emit(f,"\tasl\t");
+	  emit_lobyte(f,o,t);
+	  emit(f,"\n");
+	  emit(f,"\trol\t");
+	  emit_hibyte(f,o,t);
+	  emit(f,"\n");
+	}
+	if(ISLONG(t)){
+	  do_byte3(f,"rol",o,t);
+	  do_byte4(f,"rol",o,t);
+	}
+      }else if(op==RSHIFT&&(t&UNSIGNED)){
+	/*emit(f,"\tclc\n");
+	  emit(f,"\tror\t");*/
+	if(ISLONG(t)){
+	  do_byte4(f,"lsr",o,t);
+	  do_byte3(f,"ror",o,t);
+	  do_hibyte(f,"ror",o,t);
+	}else
+	  do_hibyte(f,"lsr",o,t);
+	do_lobyte(f,"ror",o,t);
+      }else if(op==RSHIFT){
+	if(ce02){
+	  emit(f,"\tasr\t");
+	}else{
+	  if(ISLONG(t))
+	    do_byte4(f,"lda",o,t);
+	  else
+	    load_hibyte(f,o,t);
+	  emit(f,"\tcmp\t#128\n");
+	  emit(f,"\tror\t");
+	}
+	if(ISLONG(t))
+	  emit_byte4(f,o,t);
+	else
+	  emit_hibyte(f,o,t);
+	emit(f,"\n");
+	if(ISLONG(t)){
+	  do_byte3(f,"ror",o,t);
+	  do_hibyte(f,"ror",o,t);
+	}
+	do_lobyte(f,"ror",o,t);
+      }else{
+	printf("op=%d\n",op);
+	ierror(0);
+      }
+    }
+  }
+}
+
+static void preload_obj(FILE *f,IC *p,obj *o)
+{
+  int r,pa=0,px=0,longm65=0;long of;
+
+  if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+     ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+    emit(f,"; volatile barrier\n");
+
+
+  if(m65){
+    int t;
+    if(o==&p->q1)
+      t=q1typ(p);
+    else{
+      if(o==&p->q2) t=q2typ(p);
+      else if(o==&p->z) t=ztyp(p);
+      else ierror(0);
+      if(ISLONG(t)&&LONGM65(p->code)) longm65=1;
+    }
+  }
+
+  if((o->flags&(VAR|REG))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&(((of=real_offset(o))+zm2l(szof(o->v->vtyp))>255)||longm65)){
+    r=get_reg(f,p,POINTER);
+    if(o->flags&DREFOBJ){
+      if(p->code==GETRETURN&&(p->q1.reg==ra||p->q1.reg==rax)){
+	emit(f,"\tsta\t%s\n",mregnames[t1]);
+	emit(f,"\tstx\t%s\n",mregnames[t2]);
+	pa=px=1;
+      }else
+	get_acc(f,p,INT);
+    }else{
+      if(p->code==GETRETURN&&(p->q1.reg==ra||p->q1.reg==rax)){
+	emit(f,"\tsta\t%s\n",mregnames[t1]);
+	pa=1;
+      }else
+	cmp_get_acc(f,p,0);
+    }
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t%s\n",mregnames[fp1]);
+    emit(f,"\tclc\n");
+    if(of&0xff)
+      emit(f,"\tadc\t#%ld\n",of&0xff);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    emit(f,"\tlda\t%s\n",mregnames[fp2]);
+    if(1/*of&0xff00*/)
+      emit(f,"\tadc\t#%ld\n",(of>>8)&0xff);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    o->flags|=REG;
+    o->reg=r;
+    if(o->flags&DREFOBJ){
+      if(!zzero) sety(f,0);
+      emit(f,"\tlda\t(%s)%s\n",mregnames[r],zzero?"":",y");
+      emit(f,"\ttxa\n");
+      sety(f,1);
+      emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+      emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+      emit(f,"\tstx\t%s\n",mregnames[rp.r1]);
+    }else{
+      o->flags|=DREFOBJ;
+      o->dtyp=POINTER;
+    }
+    if(pa){ emit(f,"\tlda\t%s\n",mregnames[t1]); pa=0;}
+    if(px){ emit(f,"\tldx\t%s\n",mregnames[t2]); px=0;}
+  }
+
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&(!(o->flags&REG)||!isptr(o->reg))&&(!(o->flags&VAR)||!(o->v->tattr&ZPAGE))&&!ISFPOINTER(o->dtyp)){
+    if(p->code==GETRETURN&&(p->q1.reg==ra||p->q1.reg==rax)){
+      emit(f,"\tsta\t%s\n",mregnames[t1]);
+      pa=1;
+    }else
+      cmp_get_acc(f,p,0);
+    r=get_reg(f,p,POINTER);
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER);
+    o->flags|=REG|DREFOBJ;
+    o->reg=r;
+    if(pa){ emit(f,"\tlda\t%s\n",mregnames[t1]); pa=0;}
+  }
+}
+
+static void far_copy(FILE *f,IC *p)
+{
+  int b;long l;
+  get_acc(f,p,INT);
+  if(p->code==PUSH){
+    if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+    emit(f,"\tlda\t%s\n",mregnames[sp]);
+    if(pushed) emit(f,"\tclc\n");
+    if(pushed&0xff) emit(f,"\tadc\t#%d\n",(pushed&0xff));
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+    if(pushed) emit(f,"\tadc\t#%d\n",((pushed>>8)&0xff));
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    pushed+=zm2l(p->q2.val.vmax);
+    emit(f,"\tldx\t#%d\n",bankcnum);
+  }else if(p->z.flags&DREFOBJ){
+    if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+    p->z.flags&=~DREFOBJ;
+    load_lobyte(f,&p->z,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    load_hibyte(f,&p->z,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    if(indirect(&p->z)){
+      do_byte3(f,"lda",&p->z,FPOINTER);
+      emit(f,"\ttax\n");
+    }else
+      do_byte3(f,"ldx",&p->z,FPOINTER);
+  }else{
+    load_address(f,LAST_PAIR,&p->z,POINTER);
+    b=bank(p->z.v);
+    emit(f,"\tldx\t#%d\n",b>=0?b:bankcnum);
+  }
+  if(p->q1.flags&DREFOBJ){
+    if(!reg_pair(LAST_PAIR-1,&rp)) ierror(0);
+    p->q1.flags&=~DREFOBJ;
+    load_lobyte(f,&p->q1,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    load_hibyte(f,&p->q1,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    if(indirect(&p->q1)){
+      do_byte3(f,"lda",&p->q1,FPOINTER);
+      emit(f,"\ttay\n");
+    }else
+      do_byte3(f,"ldy",&p->q1,FPOINTER);
+  }else{
+    load_address(f,LAST_PAIR-1,&p->q1,POINTER);
+    b=bank(p->q1.v);
+    sety(f,b>=0?b:bankcnum);
+  }
+  l=zm2l(p->q2.val.vmax);
+  emit(f,"\tlda\t#%d\n",(l>>8)&0xff);
+  emit(f,"\tsta\t%s__bankcopy_len+1\n",idprefix);
+  emit(f,"\tlda\t#%d\n",(l)&0xff);
+  emit(f,"\tsta\t%s__bankcopy_len\n",idprefix);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  emit(f,"\tjsr\t%s__bankcopy\n",idprefix);
+  yval=NOVAL;
+}
+
+static void load_far(FILE *f,IC *p,obj *o,int t)
+{
+  int pushed=0;
+  if(!(o->flags&DREFOBJ)) ierror(0);
+  o->flags&=~DREFOBJ;
+  t&=NQ;
+  if(zmeqto(sizetab[t],Z0)) return;
+  /*get_acc(f,p,INT);*/
+  if(pushedacc==t3||pushedacc==t4) ierror(0);
+  if(pushedx==t3||pushedx==t4) ierror(0);
+  if(regs[ra]||regs[rax]){
+    if(isacc(q1)||isacc(q2)||!isacc(z)){
+      pushed=1;
+      emit(f,"\tpha\n");
+      if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+    }
+  }
+  load_reg(f,LAST_PAIR,o,POINTER);
+  if(!indirect(o))
+    do_byte3(f,"ldy",o,CHAR);
+  else{
+    do_byte3(f,"lda",o,CHAR);
+    emit(f,"\ttay\n");
+  }
+  emit(f,"\tldx\t#%d\n",bankvoffset);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+  yval=NOVAL;
+  o->flags=VAR;
+  o->v=&bankv;
+  o->val.vmax=l2zm((long)bankvoffset);
+  bankvoffset+=zm2l(sizetab[t]);
+  if(pushed){
+    if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+    emit(f,"\tpla\n");
+  }
+}
+
+static void load_banked(FILE *f,IC *p,obj *o,int t)
+{
+  int pushed=0,m;
+  if(o->flags&DREFOBJ) t=o->dtyp;
+  t&=NQ;
+  if(zmeqto(sizetab[t],Z0)) return;
+  /*get_acc(f,p,INT);*/
+  if(pushedacc==t3||pushedacc==t4) ierror(0);
+  if(pushedx==t3||pushedx==t4) ierror(0);
+  if(regs[ra]||regs[rax]){
+    if(isacc(q1)||isacc(q2)||!isacc(z)){
+      pushed=1;
+      emit(f,"\tpha\n");
+      if(regs[rax]||regs[rx]) emit(f,"\ttxa\n\tpha\n");
+    }
+  }
+  m=o->flags;
+  o->flags&=~DREFOBJ;
+  load_address(f,LAST_PAIR,o,POINTER);
+  o->flags=m;
+  emit(f,"\tldx\t#%d\n",bankvoffset);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  sety(f,bank(o->v));
+  emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+  yval=NOVAL;
+  o->v=&bankv;
+  o->val.vmax=l2zm((long)bankvoffset);
+  bankvoffset+=zm2l(sizetab[t]);
+  if(pushed){
+    if(regs[rax]||regs[rx]) emit(f,"\tpla\n\ttax\n");
+    emit(f,"\tpla\n");
+  }
+}
+
+static void preload(FILE *f,IC *p)
+{
+  int r,mra=regs[ra],mrax=regs[rax];
+  int bq1=-1,bq2=-1,bz=-1,sb=-1,zbuf=0;
+
+  if(((p->q1.flags&DREFOBJ)&&p->q1.am&&(p->q1.am->flags==GPR_IND||p->q1.am->flags==ABS_IND)&&p->q1.am->idx==ra)||
+     ((p->q2.flags&DREFOBJ)&&p->q2.am&&(p->q2.am->flags==GPR_IND||p->q2.am->flags==ABS_IND)&&p->q2.am->idx==ra)||
+     ((p->z.flags&DREFOBJ)&&p->z.am&&(p->z.am->flags==GPR_IND||p->z.am->flags==ABS_IND)&&p->z.am->idx==ra)
+     ){
+    if(pushedacc>0)
+      r=pushedacc;
+    else{
+      r=get_reg(f,p,CHAR);
+      emit(f,"\tsta\t%s\n",mregnames[r]);
+    }
+    pushedacc=r;
+    if((p->q1.flags&DREFOBJ)&&p->q1.am&&(p->q1.am->flags==GPR_IND||p->q1.am->flags==ABS_IND)&&p->q1.am->idx==ra)
+      p->q1.am->idx=r;
+    if((p->q2.flags&DREFOBJ)&&p->q2.am&&(p->q2.am->flags==GPR_IND||p->q2.am->flags==ABS_IND)&&p->q2.am->idx==ra)
+      p->q2.am->idx=r;
+    if((p->z.flags&DREFOBJ)&&p->z.am&&(p->z.am->flags==GPR_IND||p->z.am->flags==ABS_IND)&&p->z.am->idx==ra)
+      p->z.am->idx=r;
+  }
+
+  if(p->code==GETRETURN&&p->q1.reg==ra&&!regs[ra])
+    regs[ra]=1;
+
+  if(p->code==GETRETURN&&p->q1.reg==rax&&!regs[rax])
+    regs[rax]=1;
+
+  bankvoffset=0;
+
+  if(!NOBANKVARS){
+    if((p->q1.flags&(VAR|VARADR))==VAR) bq1=bank(p->q1.v);
+    if((p->q2.flags&(VAR|VARADR))==VAR) bq2=bank(p->q2.v);
+    if((p->z.flags&(VAR|VARADR))==VAR) bz=bank(p->z.v);
+
+    if((p->q1.flags&(VAR|VARADR))==(VAR|VARADR)){
+      r=bank(p->q1.v);
+      /*if(r>=0&&r!=cbank) ierror(0);*/
+    }
+    
+    if((p->code==ASSIGN||p->code==PUSH)&&!zmleq(p->q2.val.vmax,l2zm(4L))){
+      if(p->q1.flags&DREFOBJ) preload_obj(f,p,&p->q1);
+      if(p->z.flags&DREFOBJ) preload_obj(f,p,&p->z);
+      return;
+    }
+
+    if(p->code!=CALL){
+      /* TODO: some optimizations possible */
+      if(bq1>=0&&bq1!=cbank){
+	if(cbank<0&&!NOSWITCH)
+	  sb=bq1;
+	else
+	  load_banked(f,p,&p->q1,q1typ(p));
+      }
+      if(bq2>=0&&bq2!=cbank){
+	if((bq2==sb||(cbank<0&&sb<0))&&!NOSWITCH)
+	  sb=bq2;
+	else
+	  load_banked(f,p,&p->q2,q2typ(p));
+      }
+      if(bz>=0&&bz!=cbank&&(p->z.flags&DREFOBJ)){
+	if((bz==sb||(cbank<0&&sb<0))||!NOSWITCH)
+	  sb=bz;
+	else
+	  load_banked(f,p,&p->z,ztyp(p));
+      }
+      
+      if(sb>=0){
+	if(NOSWITCH) ierror(0);
+	sety(f,sb);
+	emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+	yval=NOVAL;
+      }
+    }
+  }
+
+  if((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp)&&p->code!=CALL) load_far(f,p,&p->q1,q1typ(p));
+  if((p->q2.flags&DREFOBJ)&&ISFPOINTER(p->q2.dtyp)) load_far(f,p,&p->q2,q2typ(p));
+
+  if(isacc(q2)){
+    static obj o;
+    int t=q2typ(p);
+    r=get_reg(f,p,t);
+    o.flags=REG;
+    o.reg=r;
+    store_acc(f,&o,t);
+    p->q2.reg=r;
+    if(!pushedacc){
+      if((t&NQ)==CHAR)
+	storedacc=r;
+      else{
+	if(!reg_pair(r,&rp)) ierror(0);
+	storedacc=rp.r1;
+	storedx=rp.r2;
+      }
+    }
+  }
+
+  if((p->code==ADDI2P||p->code==SUBIFP)&&ISRIDX(q2)){
+    static obj o;
+    if(p->q2.reg==rx){
+      if(pushedx>0) r=pushedx;
+      else if(storedx>0) r=storedx;
+      else r=get_reg(f,p,CHAR);
+    }else
+      r=get_reg(f,p,CHAR);
+    o.flags=REG;
+    o.reg=r;
+    store_reg(f,p->q2.reg,&o,CHAR);
+    p->q2.reg=r;
+    storedx=r;
+  }
+
+  if(p->code!=ADDRESS){
+    preload_obj(f,p,&p->q1);
+    if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+       (p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+       p->q1.v==p->q2.v){
+      p->q2.flags|=REG;
+      p->q2.reg=p->q1.reg;
+    }
+    if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+       (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+       p->q1.v==p->z.v){
+      p->z.flags|=REG;
+      p->z.reg=p->q1.reg;
+    }
+  }
+
+  preload_obj(f,p,&p->q2);
+  if((p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+     (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+     p->q2.v==p->z.v){
+    p->z.flags|=REG;
+    p->z.reg=p->q2.reg;
+  }
+
+
+  if((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp)) zbuf=1;
+  if((p->z.flags&(VAR|DREFOBJ))==VAR){
+    bz=bank(p->z.v);
+    if(bz>=0&&bz!=cbank) zbuf=1;
+  }
+  
+  if(zbuf&&!NOBANKVARS){
+    zstore=p->z;
+    p->z.flags=VAR;
+    p->z.v=&bankv;
+    p->z.val.vmax=l2zm((long)bankvoffset);
+    zstoreflag=1;
+    /*bankvoffset+=zm2l(sizetab[p->typf&NQ]);*/
+  }else{
+    preload_obj(f,p,&p->z);
+
+    if(isreg(z)){
+      r=0;
+      if(p->q1.am&&p->q1.am->base==p->z.reg){
+	r=get_reg(f,p,POINTER);
+	cmp_get_acc(f,p,0);
+	if(!reg_pair(p->q1.am->base,&rp)) ierror(0);
+	if(!reg_pair(r,&rp2)) ierror(0);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	p->q1.am->base=p->q1.reg=r;
+      }else if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg==p->z.reg){
+	r=get_reg(f,p,POINTER);
+	cmp_get_acc(f,p,0);
+	if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	if(!reg_pair(r,&rp2)) ierror(0);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	p->q1.reg=r;
+      }
+      if(p->q2.am&&p->q2.am->base==p->z.reg){
+	if(r==0){
+	  r=get_reg(f,p,POINTER);
+	  cmp_get_acc(f,p,0);
+	  if(!reg_pair(p->q2.am->base,&rp)) ierror(0);
+	  if(!reg_pair(r,&rp2)) ierror(0);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	}
+	p->q2.am->base=p->q2.reg=r;
+      }else if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg){
+	if(r==0){
+	  r=get_reg(f,p,POINTER);
+	  cmp_get_acc(f,p,0);
+	  if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	  if(!reg_pair(r,&rp2)) ierror(0);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	}
+	p->q2.reg=r;
+      }
+    }
+    if(isacc(z)){
+      if(isacc(q2)){
+	if(p->q2.reg==rax){
+	  r=get_reg(f,p,INT);
+	  if(!reg_pair(r,&rp)) ierror(0);
+	  emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tstx\t%s\n",mregnames[rp.r2]);
+	  storedacc=rp.r1;
+	  storedx=rp.r2;
+	}else{
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	  storedacc=r;
+	}
+	p->q2.reg=r;
+	if(isacc(q1))
+	  p->q1.reg=r;
+      }
+    }
+  }     
+ 
+  reload_acc(f);
+
+  regs[ra]=mra;
+  regs[rax]=mrax;
+}
+
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if(o1->flags==o2->flags){
+    if(o1->am){
+      if(o2->am){
+	if(o1->am->flags!=o2->am->flags||o1->am->base!=o2->am->base||
+	   o1->am->idx!=o2->am->idx||o1->am->offset!=o2->am->offset)
+	  return 0;
+	else
+	  return 1;
+      }else
+	return 0;
+    }else if(o2->am)
+      return 0;
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  ierror(0);
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags==IMM_IND)
+      emit(f,"(%s),y ;am(%ld)",mregnames[p->am->base],p->am->offset);
+    else if(p->am->flags==GPR_IND)
+      emit(f,"(%s),y ;am(%s)",mregnames[p->am->base],mregnames[p->am->idx]);
+    else if(p->am->flags==ABS_IND){
+      emit(f,"%ld",p->am->offset);
+      if(p->am->v){
+	Var *v=p->am->v;
+	if(v->storage_class==EXTERN)
+	  emit(f,"+%s%s",idprefix,v->identifier);
+	else
+	  emit(f,"+%s%ld",labprefix,zm2l(v->offset));
+      }
+      if(ISIDX(p->am->idx))
+	emit(f,",%s ;am(%s)",mregnames[p->am->idx],mregnames[p->am->idx]);
+      else
+	emit(f,",y ;am(%s)",mregnames[p->am->idx]);
+    }else
+      ierror(0);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",mregnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"(%s),%s",mregnames[fp],noy==2?"z":"y");
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    if(/*ieee&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)*/ISFLOAT(t))
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    else
+      emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")%s",noy==0?",y":(noy==1?"":",z"));
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2,*free_base,*use;struct AddressingMode *am;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if((c==ADDI2P||c==SUBIFP)&&ISPREG(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&!ISFPOINTER(p->typf2)){
+      int base;zmax of;struct obj *o;IC *dub=0;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(zmleq(Z0,of)&&zmleq(of,l2zm(255L))){
+	r=p->z.reg;
+	if(isreg(q1)&&isptr(p->q1.reg)) base=p->q1.reg; else base=r;
+	o=0;free_base=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2==FREEREG&&p2->q1.reg==p->z.reg) free_base=p2;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    int t,mc;
+	    if((c2==ASSIGN|c2==PUSH)&&(p2->typf&NQ)==CHAR&&!zmeqto(p2->q2.val.vmax,Z1))
+	      mc=1;
+	    else
+	      mc=0;
+	    if(!o&&(c2==ADD||c2==SUB||c2==AND||c2==OR||c2==XOR)&&/*(p2->typf&NQ)==CHAR&&*/!p2->q1.am&&!p2->z.am&&
+	       (p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+	       p2->q1.flags==p2->z.flags&&p2->q1.reg==r&&p2->z.reg==r){
+	      o=&p2->q1;use=p2;
+	      dub=p2;
+	      continue;
+	    }
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o||mc) break;
+	      t=q1typ(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      if(m65&&ISLONG(t)) break;
+	      o=&p2->q1;use=p2;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o||mc) break;
+	      t=q2typ(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      if(m65&&ISLONG(t)) break;
+	      o=&p2->q2;use=p2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o||mc) break;
+	      t=ztyp(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      if(m65&&ISLONG(t)) break;
+	      o=&p2->z;use=p2;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else{
+	      m=p2->z.reg;
+	      if(o==&p->q1||o==&p->q2) break;
+	    }
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=(int)zm2l(of);
+		if(ISPREG(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      if(dub){
+		dub->z=*o;
+		dub->z.am=mymalloc(sizeof(*am));
+		*dub->z.am=*o->am;
+	      }
+	      if(free_base) move_IC(use,free_base);
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(c==ADDI2P&&(p->typf&NU)==(UNSIGNED|CHAR)&&!ISFPOINTER(p->typf2)&&isreg(q2)/*&&p->q2.reg!=ra*/&&ISPREG(z)&&(ISPREG(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx,ind;struct obj *o;IC *free_idx,*dub=0;
+      r=p->z.reg;idx=p->q2.reg;
+      if(ISPREG(q1)) base=p->q1.reg; else base=r;
+      if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST)
+	ind=0;
+      else
+	ind=1;
+      o=0;free_base=free_idx=use=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	if(c2==FREEREG&&p2->q1.reg==p->z.reg) free_base=p2;
+	if(c2==FREEREG&&p2->q1.reg==p->q2.reg) free_idx=p2;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&idx!=r){
+	  if(p2->z.reg==idx) break;
+	  if(reg_pair(p2->z.reg,&rp)){
+	    if(rp.r1==idx) break;
+	    if(rp.r2==idx) break;
+	  }
+	}
+
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	  if(!o&&(c2==ADD||c2==SUB||c2==AND||c2==OR||c2==XOR)&&/*(p2->typf&NQ)==CHAR&&*/!p2->q1.am&&!p2->z.am&&
+	     (p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+	     p2->q1.flags==p2->z.flags&&p2->q1.reg==r&&p2->z.reg==r){
+	    o=&p2->q1;use=p2;
+	    dub=p2;
+	    continue;
+	  }
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(ind&&(q1typ(p2)&NQ)!=CHAR)) break;
+	    if(ieee&&ISFLOAT(q1typ(p2))) break;
+            o=&p2->q1;use=p2;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(ind&&(q2typ(p2)&NQ)!=CHAR)) break;
+	    if(ieee&&ISFLOAT(q2typ(p2))) break;
+            o=&p2->q2;use=p2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ind&&(ztyp(p2)&NQ)!=CHAR)) break;
+	    if(ieee&&ISFLOAT(ztyp(p2))) break;
+            o=&p2->z;use=p2;
+          }
+        }
+	
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+	      am->idx=idx;
+	      if(ind){
+		am->flags=GPR_IND;
+		am->base=base;
+		if(ISPREG(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }else{
+		am->flags=ABS_IND;
+		am->base=0;
+		eval_const(&p->q1.val,MAXINT);
+		am->offset=zm2l(vmax);
+		if(p->q1.flags&VARADR)
+		  am->v=p->q1.v;
+		else
+		  am->v=0;
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }
+	      if(dub){
+		dub->z=*o;
+		dub->z.am=mymalloc(sizeof(*am));
+		*dub->z.am=*o->am;
+	      }
+	      if(free_idx) move_IC(use,free_idx);
+	      if(free_base) move_IC(use,free_base);
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(zstoreflag){
+    int off;
+    if(p->z.flags!=VAR||p->z.v!=&bankv) ierror(0);
+    off=(int)zm2l(p->z.val.vmax);
+    p->z=zstore;
+    get_acc(f,p,INT);
+    if(zstore.flags&DREFOBJ){
+      if(!ISFPOINTER(zstore.dtyp)) ierror(0);
+      zstore.flags&=~DREFOBJ;
+      load_reg(f,LAST_PAIR,&zstore,POINTER);
+      if(indirect(&zstore)){
+	do_byte3(f,"lda",&zstore,FPOINTER);
+	emit(f,"\ttay\n");
+      }else
+	do_byte3(f,"ldy",&zstore,FPOINTER);
+      yval=NOVAL;
+    }else{
+      load_address(f,LAST_PAIR,&zstore,p->typf);
+      r=bank(zstore.v);
+      sety(f,r>=0?r:bankcnum);
+    }
+    emit(f,"\tldx\t#%d\n",off);
+    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+    emit(f,"\tjsr\t%s__bankstore%d\n",idprefix,(int)zm2l(sizetab[p->typf&NQ]));
+    yval=NOVAL;
+    zstoreflag=0;
+  }
+
+  for(r=1;r<=MAXR;r++){
+    if(regs[r]&8)
+      regs[r]&=~8;
+  }
+  for(r=FIRST_GPR;r<=LAST_GPR;r++){
+    int ta=0;
+    if(regs[r]&2){
+      if(regs[ra]&&!pushedacc){
+	emit(f,"\ttay\n");
+	yval=NOVAL;
+	ta=1;
+      }
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s\n",mregnames[r]);
+      regs[r]&=~2;
+    }
+    if(ta)
+      emit(f,"\ttya\n");
+  }
+  if(pushedx){
+    emit(f,"\tldx\t%s\n",mregnames[pushedx]);
+    pushedx=0;
+  }
+
+  reload_acc_opt(f,p->next);
+
+  storedacc=0;
+  storedx=0;
+}
+
+struct cmplist {struct cmplist *next;int from,to,mode;} *first_cmplist;
+
+static void add_cmplist(int from, int to, int mode)
+{
+  struct cmplist *new;
+  new=mymalloc(sizeof(*new));
+  new->next=first_cmplist;
+  new->from=from;
+  new->to=to;
+  new->mode=mode;
+  first_cmplist=new;
+}
+
+static void incsp(FILE *f,long of)
+{
+  if(of==0) return;
+  if(of==1||of==-1){
+    static obj o;
+    o.flags=REG;
+    o.reg=sp;
+    if(of==1)
+      incmem(f,&o,INT,ADD,1);
+    else
+      incmem(f,&o,INT,SUB,1);
+  }else if(of==256){
+    emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+  }else if(of==-256){
+    emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+  }else{
+    long abs;
+    if(of>0){
+      abs=of;
+      emit(f,"\tclc\n");
+    }else{
+      abs=-of;
+      emit(f,"\tsec\n");
+    }
+    if(abs&255){
+      emit(f,"\tlda\t%s\n",mregnames[sp]);
+      if(of>0){
+	emit(f,"\tadc\t#%ld\n",abs&255);
+      }else{
+	emit(f,"\tsbc\t#%ld\n",abs&255);
+      }
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+    }
+    if((abs&0xff00)==0){
+      if(of>0){
+	emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+	emit(f,"%s%d:\n",labprefix,label);
+      }else{
+	emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+	emit(f,"%s%d:\n",labprefix,label);
+      }	
+    }else{
+      emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+      if(of>0)
+	emit(f,"\tadc\t#%ld\n",(abs>>8)&255);
+      else
+	emit(f,"\tsbc\t#%ld\n",(abs>>8)&255);
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  int i,r,of;
+  rsavesize=0;
+  libsave=1;
+  hasretval=0;
+
+  if(!optsize||(v->tattr&NOCOMPRESS)) emit(f,";vcprmin=10000\n");
+  if(vlas) emit(f,"___fo\tset\t%ld\n",(long)argsize);
+  r=0;
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+      if(i!=LAST_GPR-VOL_GPRS+1&&r==0) libsave=0;
+      rsavesize++;
+      r=1;
+    }else{
+      if(i==LAST_GPR-VOL_GPRS+1) libsave=0;
+      r=0;
+    }
+  }
+  rscnt=rsavesize;
+  if(rscnt&&!SOFTSTACK){
+    if(optspeed||rscnt<2)
+      rsavesize=0;
+    else if(!optsize&&rscnt<=5)
+      rsavesize=0;
+  }
+
+  if(!special_section(f,v)){emit(f,codename);ebank(f,sbank(v));if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+  offset=localsize+argsize+rsavesize;
+
+  if(in_isr){
+    emit(f,"\tpha\n");
+    if(c02){
+      emit(f,"\tphx\n");
+      emit(f,"\tphy\n");
+    }else{
+      emit(f,"\ttxa\n");
+      emit(f,"\tpha\n");
+      emit(f,"\ttya\n");
+      emit(f,"\tpha\n");
+    }
+    if(offset||function_calls){
+      emit(f,"\tlda\t%s\n",mregnames[sp]);
+      emit(f,"\tpha\n");
+      emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+      emit(f,"\tpha\n");
+      emit(f,"\tlda\t#<(___isrstack-%ld)\n",offset);
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+      emit(f,"\tlda\t#>(___isrstack-%ld)\n",offset);
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+    }
+  }
+
+  if(MAINARGS&&v->storage_class==EXTERN&&!strcmp(v->identifier,"main")&&v->vtyp->exact->count>1)
+    emit(f,"\tjsr\tinitmainargs\n");
+
+  yval=NOVAL;
+  of=argsize+localsize;
+
+  if(rsavesize>0&&of+rsavesize>255){
+    offset-=rsavesize;
+    incsp(f,-rsavesize);
+    of=0;
+  }else{
+    incsp(f,-offset);
+    offset=0;
+  }
+
+
+  if(!libsave||rscnt!=rsavesize||optspeed||rscnt<=1||(rscnt<=3&&(!optsize)))
+    libsave=0;
+  
+  if(libsave){
+    sety(f,of+rsavesize-1);
+    if(0/*mask_opt*/)
+      emit(f,"\tjsr\t%s__rsave.%d+%ld\n",idprefix,(1<<(rscnt-2)),(rscnt-2)*5);
+    else
+      emit(f,"\tjsr\t%s__rsave%ld\n",idprefix,rscnt);
+    yval=of;
+  }else{
+    int last=0;
+    for(i=FIRST_GPR;i<=LAST_GPR;i++){
+      if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	if(rscnt!=rsavesize){
+	  if(ce02&&last==i-1){
+	    emit(f,"\tphw\t%s\n",mregnames[last]);
+	    last=0;
+	  }else{
+	    if(!ce02){
+	      emit(f,"\tlda\t%s\n",mregnames[i]);
+	      emit(f,"\tpha\n");
+	    }else
+	      last=i;
+	  }
+	}else{
+	  sety(f,of++);
+	  emit(f,"\tlda\t%s\n",mregnames[i]);
+	  emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	}
+      }
+    }
+    if(last){
+      emit(f,"\tlda\t%s\n",mregnames[last]);
+      emit(f,"\tpha\n");
+    }
+  }
+
+
+
+  incsp(f,-offset);
+
+  if(vlas){
+    emit(f,"\tlda\t%s\n",mregnames[sp]);
+    emit(f,"\tsta\t%s\n",mregnames[fp]);
+    emit(f,"\tlda\t%s\n",mregnames[sp2]);
+    emit(f,"\tsta\t%s\n",mregnames[fp2]);
+  }
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  int i,of,ar;
+  struct cmplist *p;
+  offset=localsize+argsize+rsavesize;
+  of=argsize+localsize;
+
+  i=freturn(v->vtyp->next);
+  if(hasretval&&(i==ra||i==rax)) ar=1; else ar=0;
+
+  if(rscnt!=rsavesize){
+    if(ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    for(i=LAST_GPR;i>=FIRST_GPR;i--){
+      if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	emit(f,"\tpla\n");
+	emit(f,"\tsta\t%s\n",mregnames[i]);
+      }
+    }
+  }
+  if(rsavesize>0&&of+rsavesize>255){
+    if(of!=1&&ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    incsp(f,of);
+    offset-=of;
+    of=0;
+  }
+  if(rsavesize>0){
+    if(ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+  }
+  if(rsavesize){
+    if(libsave){
+      sety(f,of+rsavesize-1);
+      if(0/*mask_opt*/)
+	emit(f,"\tjsr\t%s__rload.%d+%ld\n",idprefix,(1<<(rscnt-2)),(rscnt-2)*5);
+      else
+	emit(f,"\tjsr\t%s__rload%ld\n",idprefix,rscnt);
+      yval=of;
+    }else{
+      for(i=FIRST_GPR;i<=LAST_GPR;i++){
+	if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	  sety(f,of++);
+	  emit(f,"\tlda\t(%s),y\n",mregnames[sp]);
+	  emit(f,"\tsta\t%s\n",mregnames[i]);
+	}
+      }
+    }
+  }
+  if(in_isr){
+    if(offset||function_calls){
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+    }
+  }else if(offset==2&&!pushedacc){
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+    reload_acc(f);
+    emit(f,ret);
+    emit(f,"%s%d:\n",labprefix,label-1);
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"%s%d:\n",labprefix,label);
+    emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+  }else{
+    if(offset!=0&&ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    incsp(f,offset);
+  }
+
+  reload_acc(f);
+
+  if(in_isr){
+    if(c02){
+      emit(f,"\tply\n");
+      emit(f,"\tplx\n");
+    }else{
+      emit(f,"\tpla\n");
+      emit(f,"\ttay\n");
+      emit(f,"\tpla\n");
+      emit(f,"\ttax\n");
+    }
+    emit(f,"\tpla\n");
+  }
+  emit(f,ret);
+
+  for(p=first_cmplist;p;){
+    struct cmplist *m;
+    emit(f,"%s%d:\n",labprefix,p->from);
+    if(p->mode==JMPIND){
+      /* indirect call */
+      emit(f,"\tjmp\t(%s)\n",mregnames[p->to]);
+    }else{
+      pushedacc=p->mode;
+      reload_acc(f);
+      emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,p->to);
+    }
+    m=p;
+    p=p->next;
+    free(m);
+  }
+  first_cmplist=0;
+  pushedacc=0;
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(1L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(1);
+
+  if(IEEE){
+    ieee=1;
+    msizetab[DOUBLE]=msizetab[LDOUBLE]=l2zm(8L);
+  }
+
+
+  mregnames[0]=regnames[0]="noreg";
+  mregnames[REGDUMMY1]=mymalloc(MAXI+8);
+  mregnames[REGDUMMY2]=mymalloc(MAXI+8);
+  mregnames[REGDUMMY3]=mymalloc(MAXI+8);
+
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"r%d",i-FIRST_GPR);
+    mregnames[i]=regnames[i];
+    regsize[i]=l2zm(1L);
+    regtype[i]=&ctyp;
+  }
+  for(i=FIRST_PAIR;i<=LAST_PAIR;i++){
+    int sr=(i-FIRST_PAIR)*2+FIRST_GPR;
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+    mregnames[i]=regnames[sr];
+    regsize[i]=l2zm(2L);
+    regtype[i]=&ityp;
+  }
+  for(i=FIRST_BIG;i<=LAST_BIG;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"btmp%d",i-FIRST_BIG);
+    mregnames[i]=regnames[i];
+    regsize[i]=msizetab[FLOAT];
+    regtype[i]=&ftyp;
+    regsa[i]=0;
+    regscratch[i]=1;
+  }
+  for(i=FIRST_BIGP;i<=LAST_BIGP;i++){
+    int sr=(i-FIRST_BIGP)*2+FIRST_BIG;
+    regnames[i]=mymalloc(20);
+    sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+    mregnames[i]=regnames[sr];
+    regsize[i]=msizetab[LLONG];
+    regtype[i]=&lltyp;
+    regsa[i]=0;
+    regscratch[i]=1;
+  }
+
+  mregnames[ra] = regnames[ra] = "a";
+  mregnames[rx] = regnames[rx] = "x";
+  mregnames[ry] = regnames[ry] = "y";
+  regsize[ra]=regsize[rx]=regsize[ry]=l2zm(1L);
+  regtype[ra]=regtype[rx]=regtype[ry]=&ctyp;
+  mregnames[sp]=regnames[sp] = "sp";
+  mregnames[sp1]=regnames[sp1] = "sp";
+  mregnames[sp2]=regnames[sp2] = "sp+1";
+
+  mregnames[rax]=regnames[rax] = "a/x";
+  regsize[rax]=regsize[sp]=l2zm(2L);
+  regtype[rax]=regtype[sp]=&ityp;
+
+  reg_prio[ra]=reg_prio[rax]=100;
+  reg_prio[rx]=50;
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  short_push=1;
+
+  static_cse=0;
+
+  dref_cse=1;
+
+  /*prefer_statics=1; TODO */
+
+
+  if(optsize){
+    clist_copy_stack=2;
+    clist_copy_pointer=2;
+    clist_copy_static=2;
+  }else if(optspeed){
+    clist_copy_stack=64;
+    clist_copy_pointer=64;
+    clist_copy_static=64;
+  }else{
+    clist_copy_stack=8;
+    clist_copy_pointer=8;
+    clist_copy_static=8;
+  }
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[INT]=t_min(SHORT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[INT]=t_max(SHORT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[INT]=t_max(UNSIGNED|SHORT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  regsa[ry]=regsa[sp]=regsa[sp1]=regsa[sp2]=REGSA_NEVER;
+  regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=REGSA_NEVER;
+  regscratch[ra]=regscratch[rx]=regscratch[rax]=1;
+  if(!GLOBACC)
+    regsa[ra]=regsa[rx]=regsa[rax]=REGSA_TEMPS;
+  regsa[rx]=0;
+  regscratch[sp]=regscratch[sp1]=regscratch[sp2]=regscratch[ry]=0;
+  regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=1;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++){
+    regscratch[i]=1;
+    if(i&1)
+      regscratch[FIRST_PAIR+(i-FIRST_GPR)/2]=1;
+  }
+
+  target_macros=marray;
+
+  declare_builtin("__mulint8",CHAR,CHAR,FIRST_GPR,CHAR,FIRST_GPR+1,1,0);
+  declare_builtin("__mulint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__muluint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__modint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__modint16wo",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divuint16wo",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divint16wo",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__moduint16wo",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__modint16wo",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+
+  declare_builtin("__mulint32",LONG,LONG,FIRST_BIG+1,LONG,FIRST_BIG+2,1,0);
+  declare_builtin("__muluint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG+1,UNSIGNED|LONG,FIRST_BIG+2,1,0);
+  declare_builtin("__divint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__modint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__divint32wo",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__divuint32wo",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__modint32wo",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__moduint32wo",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+
+
+
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+  declare_builtin("__sint32toflt32",FLOAT,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32tosint32",LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__sint16toflt32",FLOAT,INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__flt32tosint16",INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+  declare_builtin("__sint32toflt64",DOUBLE,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt64tosint32",LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__sint16toflt64",DOUBLE,INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__flt64tosint16",INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__cmpsflt32",CHAR,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+
+#if 0
+  for(i=1;i<MAXR;i++){
+    printf("%02d %s scratch=%d ",i,regnames[i],regscratch[i]);
+    if(reg_pair(i,&rp))
+      printf("pair(%s,%s)",regnames[rp.r1],regnames[rp.r2]);
+    printf("\n");
+  }
+#endif
+
+  if(NOPEEP) nopeep=1;
+  if(CBMASCII) cbmascii=1;
+  if(ATASCII) atascii=1;
+  if(DIVBUG) divbug=1;
+  if(M65IO) m65io=1;
+  if(NOBANKING) manbank=1;
+  jmpinst="jmp";
+  if(C02||C02ALT){
+    c02=1;zzero=1;
+    jmpinst="bra";
+  }
+  if(CE02){
+    c02=1;ce02=1;
+    jmpinst="bra";
+  }
+  if(MEGA65){
+    m65=1;c02=1;ce02=1;
+    jmpinst="bra";
+  }
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  bankv.storage_class=EXTERN;
+  bankv.identifier="__bankv";
+  bankv.vtyp=new_typ();
+  bankv.vtyp->flags=CHAR;
+
+  bankcnum=COMMONBANK;
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  int typ=t->flags&NQ;
+  if(ISSTRUCT(typ)||ISUNION(typ)||typ==VOID) 
+    return 0;
+  if(OLDFP&&ISFLOAT(typ)) return FIRST_GPR;
+  if(typ==LONG||typ==FLOAT||ISFPOINTER(typ)||(!ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+    return FIRST_BIG;
+  if(typ==LLONG||(ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+    return FIRST_BIGP;
+  if(zmleq(szof(t),l2zm(1L)))
+    return ra;
+  if(zmleq(szof(t),l2zm(2L))) 
+    return rax;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r>=FIRST_PAIR&&r<=LAST_PAIR){
+    p->r1=(r-FIRST_PAIR)*2+FIRST_GPR;
+    p->r2=p->r1+1;
+    return 1;
+  }else if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+    p->r1=(r-FIRST_BIGP)*2+FIRST_BIG;
+    p->r2=p->r1+1;
+    return 1;
+  }else if(r==rax){
+    p->r1=ra;
+    p->r2=rx;
+    return 1;
+  }else if(r==sp){
+    p->r1=sp1;
+    p->r2=sp2;
+    return 1;
+  }
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code,co;
+  if((o->flags&VAR)&&(o->v->tattr&ZPAGE)) return 0;
+  if(indirect(o)) co=5; else co=2;
+
+  /*TODO: adapt this */
+  if(o->flags&VKONST){
+    if(o!=&p->q1||p->q2.flags!=0) return 0;
+    if(r==ra||r==rax) return co;
+    if(r==rx&&(c==ASSIGN||c==PUSH)) return co-1;
+    return 0;
+  }
+
+  if(ISIDX(r)){
+    if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==AND||c==OR||c==XOR){
+      if(o==&p->q2&&c!=ADDI2P) return co-4;
+      if(r==rx&&o==&p->q2&&((p->q1.flags&(VARADR|KONST|VKONST))==0||(p->q1.flags&DREFOBJ)))
+	return co-4;
+      if((c==ADD||c==SUB)&&o==&p->z&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+	eval_const(&p->q2.val,q2typ(p));
+	if(zmeqto(vmax,Z1)&&zumeqto(vumax,ZU1))
+	  return co+2;
+      }
+    }else if(c==ASSIGN||c==CONVERT){
+      if(o==&p->q1&&indirect(&p->z)) return 1;
+      if(o==&p->z&&indirect(&p->q1)) return 1;
+    }else if(c==COMPARE){
+      //if(o==&p->q1&&indirect(&p->q2)) return INT_MIN;
+      //if(o==&p->q2&&indirect(&p->q1)) return INT_MIN;
+    }else if(c==SETRETURN||c==GETRETURN||c==PUSH){
+    }else if(c==TEST){
+    }else
+      return INT_MIN;
+  }
+
+  if(c==ADDI2P&&o==&p->q1&&(p->typf&NU)==CHAR&&(r==rax))
+    return INT_MIN;
+
+
+  if(o->flags&DREFOBJ){
+    if(isptr(r))
+      return co+co+10;
+    if(r==rax)
+      return INT_MIN;
+  }
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return co+2;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return co+2;
+  if((c==ADD||c==SUB)&&o==&p->z&&p->q1.flags==p->z.flags&&p->q1.v==p->z.v&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->q2.val,q2typ(p));
+    if(zmeqto(vmax,Z1)&&zumeqto(vumax,ZU1))
+      return co+1;
+  }
+  if(r==ra)
+    return co+2;
+  if(ISIDX(r))
+    return co+1;
+  if(r==rax)
+    return co+co+4;
+  return co;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  if(r==rax&&NORAX)
+    return 0;
+  if(r==rx&&NOX)
+    return 0;
+  t&=NQ;
+  if(ISCHAR(t))
+    if(r==ra||(ISIDX(r)&&(optflags&2))||(r>=FIRST_GPR&&r<=LAST_GPR))
+      return 1;
+  if(ISSHORT(t)){
+    if(r==rax){
+      if(t==POINTER&&mode<0)
+	return 1;
+      if(t!=POINTER)
+	return 1;
+    }
+    if(r>=FIRST_PAIR&&r<=LAST_PAIR)
+      return 1;
+  }
+  if(r>=FIRST_BIG&&r<=LAST_BIG){
+    if(t==LONG||t==FLOAT||((t==DOUBLE||t==LDOUBLE)&&!ieee))
+      return 1;
+    if(t==FPOINTER)
+      return 1;
+  }
+  if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+    if(t==LLONG||((t==DOUBLE||t==LDOUBLE)&&ieee))
+      return 1;
+  }
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+
+  if(op==tp) return 0;
+  if(ISCHAR(op)&&ISCHAR(tp)) return 0;
+  if(ISSHORT(op)&&ISSHORT(tp)) return 0;
+  if(!ieee&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(STDSYNTAX)
+    emit(f,"\tspace\t%ld\n",zm2l(size));
+  else
+    emit(f,"\treserve\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\talign 1\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag,b=sbank(v);char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(v->tattr&ZPAGE)
+      emit(f,"\tzpage\t%s%ld\n",labprefix,zm2l(v->offset));
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+      if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+    }
+    gen_align(f,falign(v->vtyp));
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t%s\t%s%s\n",(v->flags&NEEDS)?"needs":"global",idprefix,v->identifier);
+    if(v->tattr&ZPAGE)
+      emit(f,"\tzpage\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+	if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+      }
+
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%s:\n",idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if(ISCHAR(t))
+    emit(f,"\tbyte\t");
+  else
+    emit(f,"\tword\t");
+  if(!p->tree){
+    if(ISLONG(t)||ISFLOAT(t)){
+      if(ieee&&ISFLOAT(t)){
+	emit_ieee(f,&p->val,t&NQ);
+      }else{
+	eval_const(&p->val,t&NU);
+	if(ISFLOAT(t)) cnv_fp();
+	gval.vmax=zmand(vmax,l2zm(0xffffL));
+	emitval(f,&gval,MAXINT);
+	emit(f,",");
+	gval.vmax=zmand(zmrshift(vmax,l2zm(16L)),l2zm(0xffffL));
+	emitval(f,&gval,MAXINT);
+      }
+    }else{
+      if(ISFPOINTER(t)){
+	eval_const(&p->val,t&NU);
+	emit(f,"%ld\n",(long)zm2l(vmax)&0xffff);
+	emit(f,"\tbyte\t%d\n",(int)((zm2l(vmax)>>16)&0xff));
+      }else
+	emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+    if(ISFPOINTER(t)){
+      int b;
+      if((p->tree->o.flags&(VAR|VARADR))!=(VAR|VARADR)) ierror(0);
+      b=bank(p->tree->o.v);
+      emit(f,"\n\tbyte\t%d",b>=0?b:bankcnum);
+    }
+  }
+  emit(f,"\n");newobj=0;
+}
+
+static int handle_m65(FILE *f,IC *p)
+{
+  int t=p->typf,c=p->code,noop2=0;
+  if(c==MULT&&(ISSHORT(t)||ISCHAR(t))){
+    get_acc(f,p,INT);
+    load_acc(f,&p->q1,t);
+    if(m65io){
+      emit(f,"\tsta\t$d770\n");
+      if(ISSHORT(t)) emit(f,"\tstx\t$d771\n");
+    }else{
+      emit(f,"\tldz\t#$70\n");
+      emit(f,"\tstz\t___m65mathptr\n");
+      emit(f,"\tstq\t[___m65mathptr]\n");
+    }
+    load_acc(f,&p->q2,t);
+    if(m65io){
+      emit(f,"\tsta\t$d774\n");
+      if(ISSHORT(t)) emit(f,"\tstx\t$d775\n");
+    }
+    if(m65io){
+      emit(f,"\tlda\t$d778\n");
+      if(ISSHORT(t)) emit(f,"\tldx\t$d779\n");
+    }else{
+      emit(f,"\tldz\t#$74\n");
+      emit(f,"\tstz\t___m65mathptr\n");
+      emit(f,"\tstq\t[___m65mathptr]\n");    
+      emit(f,"\tldz\t#4\n");
+      emit(f,"\tldq\t[___m65mathptr],z\n");
+      emit(f,"\tldz\t#0\n");
+    }
+    yval=NOVAL;
+    store_acc(f,&p->z,t);
+    return 1;
+  }
+  if(ISLONG(t)&&LONGM65(c)){
+    int mnoy;
+
+    if(c==ASSIGN&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) return 1;
+    if(c==GETRETURN&&isreg(z)&&p->z.reg==FIRST_BIG) return 1;
+    if(c==SETRETURN&&isreg(q1)&&p->q1.reg==FIRST_BIG) return 1;
+
+    get_acc(f,p,INT);
+
+    if(c==LSHIFT||c==RSHIFT){
+      int r,cnt=-1,mzzero;
+      
+      if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+	eval_const(&p->q2.val,p->typf2);
+	cnt=(int)(zm2l(vmax));
+	cnt&=31;
+      }
+
+      if(cnt==24||cnt==16||cnt==8||(cnt>=0&&(!optsize||cnt<=2))){
+	r=0;
+      }else{
+	if(isreg(q2)&&p->q2.reg>=FIRST_GPR&&scratch(p,r,0)){
+	  r=p->q2.reg;
+	  if(reg_pair(r,&rp)) r=rp.r1;
+	}else{
+	  /* TODO: improve for x or z */
+	  load_lobyte(f,&p->q2,p->typf2);
+	  r=t1;
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	}
+      }
+
+      mzzero=zzero;
+      zzero=0;
+      if(cnt==24||(!optsize&&cnt>=24)){
+	cnt-=24;
+	if(c==LSHIFT){
+	  if(indirect(&p->q1)){
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\ttaz\n");
+	  }else
+	    do_lobyte(f,"ldz",&p->q1,t);
+	  emit(f,"\tlda\t#0\n");
+	  emit(f,"\ttax\n");
+	  emit(f,"\ttay\n");
+	  yval=0;
+	}else if(t&UNSIGNED){
+	  do_byte4(f,"lda",&p->q1,t);
+	  emit(f,"\tldx\t#0\n");
+	  emit(f,"\tldz\t#0\n");
+	  emit(f,"\tldy\t#0\n");
+	  yval=0;
+	}else{
+	  emit(f,"\tldx\t#0\n");
+	  emit(f,"\tldz\t#0\n");
+	  emit(f,"\tldy\t#0\n");
+	  yval=0;
+	  do_byte4(f,"lda",&p->q1,t);
+	  emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	  emit(f,"\tdex\n");
+	  if(yval==0) 
+	    emit(f,"\tdey\n");
+	  emit(f,"\tdez\n");
+	  emit(f,"%s%d:\n",labprefix,label);
+	  if(yval!=0){
+	    emit(f,"\tphx\n");
+	    emit(f,"\tply\n");
+	  }
+	}
+      }else if(cnt==16||(!optsize&&cnt>=16)){
+	cnt-=16;
+	if(c==LSHIFT){
+	  if(indirect(&p->q1)){
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\ttaz\n");
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\ttay\n");
+	  }else{
+	    do_lobyte(f,"ldy",&p->q1,t);
+	    do_hibyte(f,"ldz",&p->q1,t);
+	  }
+	  emit(f,"\tlda\t#0\n");
+	  emit(f,"\ttax\n");
+	}else if(t&UNSIGNED){
+	  if(indirect(&p->q1)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\ttax\n");
+	    do_byte3(f,"lda",&p->q1,t);
+	  }else{
+	    do_byte3(f,"lda",&p->q1,t);
+	    do_byte4(f,"ldx",&p->q1,t);
+	  }
+	  emit(f,"\tldy\t#0\n");
+	  emit(f,"\tldz\t#0\n");
+	}else{
+	  emit(f,"\tldy\t#0\n");
+	  emit(f,"\tldz\t#0\n");
+	  yval=0;
+	  if(indirect(&p->q1)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\ttax\n");
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tcpx\t#0\n");
+	  }else{
+	    do_byte3(f,"lda",&p->q1,t);
+	    do_byte4(f,"ldx",&p->q1,t);
+	  }
+	  emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	  emit(f,"\tdez\n");
+	  if(yval==0)
+	    emit(f,"\tdey\n");
+	  emit(f,"%s%d:\n",labprefix,label);
+	  if(yval!=0){
+	    emit(f,"\tphz\n");
+	    emit(f,"\tply\n");
+	  }
+	}
+      }else if(cnt==8||(!optsize&&cnt>=8)){
+	cnt-=8;
+	if(c==LSHIFT){
+	  if(indirect(&p->q1)){
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\ttaz\n");
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\ttax\n");
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\ttay\n");
+	  }else{
+	    do_lobyte(f,"ldx",&p->q1,t);
+	    do_byte3(f,"ldz",&p->q1,t);
+	    do_hibyte(f,"ldy",&p->q1,t);
+	  }
+	  emit(f,"\tlda\t#0\n");
+	}else if(t&UNSIGNED){
+	  emit(f,"\tldz\t#0\n");
+	  if(indirect(&p->q1)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\tpha\n");
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\ttax\n");
+	    do_hibyte(f,"lda",&p->q1,t);
+	    emit(f,"\tply\n");
+	  }else{
+	    do_hibyte(f,"lda",&p->q1,t);
+	    do_byte3(f,"ldx",&p->q1,t);
+	    do_byte4(f,"ldy",&p->q1,t);
+	  }
+	}else{
+	  emit(f,"\tldz\t#0\n");
+	  if(indirect(&p->q1)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\tpha\n");
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\ttax\n");
+	    do_hibyte(f,"lda",&p->q1,t);
+	    emit(f,"\tply\n");
+	  }else{
+	    do_hibyte(f,"lda",&p->q1,t);
+	    do_byte3(f,"ldx",&p->q1,t);
+	    do_byte4(f,"ldy",&p->q1,t);
+	  }
+	  emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	  emit(f,"\tdez\n");
+	  emit(f,"%s%d:\n",labprefix,label);
+	}
+      }else{
+	mnoy=noy;
+	ldq_offset(f,&p->q1);
+	noy=2;
+	emit(f,"\tldq\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	noy=mnoy;
+      }
+      if(r){
+	emit(f,"\tdec\t%s\n",mregnames[r]);
+	emit(f,"\tbmi\t%s%d\n",labprefix,++label);
+	emit(f,"%s%d:\n",labprefix,++label);
+	emit(f,"\t%s\n",c==LSHIFT?"aslq":((t&UNSIGNED)?"lsrq":"asrq"));
+	emit(f,"\tdec\t%s\n",mregnames[r]);
+	emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	emit(f,"%s%d:\n",labprefix,label-1);
+      }else{
+	while(--cnt>=0)
+	  emit(f,"\t%s\n",c==LSHIFT?"aslq":((t&UNSIGNED)?"lsrq":"asrq"));
+      }
+      yval=NOVAL;
+      mnoy=noy;
+      noy=1;
+      emit(f,"\tstq\t");
+      emit_obj(f,&p->z,t);
+      emit(f,"\n");
+      noy=mnoy;
+      emit(f,"\tldz\t#0\n");
+      zzero=mzzero;
+      return 1;
+    }
+
+    if(c==PUSH){
+      if(pushed){
+	emit(f,"\tlda\t%s\n",mregnames[sp]);
+	emit(f,"\tldx\t%s+1\n",mregnames[sp]);
+	emit(f,"\tclc\n");
+	emit(f,"\tadc\t#%d\n",pushed);
+	emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	emit(f,"\tinx\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	emit(f,"\tsta\t%s\n",mregnames[t1]);
+	emit(f,"\tstx\t%s\n",mregnames[t2]);
+      }
+      pushed+=4;
+    }
+    if((c==MULT||c==DIV)&&!m65io){
+      emit(f,"\tlda\t#$70\n");
+      emit(f,"\tsta\t___m65mathptr\n");
+    }
+    yval=NOVAL;
+    noy=1;
+    if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+      unsigned long v;
+      eval_const(&p->q1.val,q1typ(p));
+      v=zum2ul(vumax);
+      emit(f,"\tlda\t#%d\n",(int)(v&255));v>>=8;
+      emit(f,"\tldx\t#%d\n",(int)(v&255));v>>=8;
+      emit(f,"\tldy\t#%d\n",(int)(v&255));v>>=8;
+      emit(f,"\tldz\t#%d\n",(int)(v&255));
+    }else if(c==GETRETURN){
+      emit(f,"\tldq\t%s\n",mregnames[FIRST_BIG]);
+    }else{
+      noy=2;
+      ldq_offset(f,&p->q1);
+      emit(f,"\tldq\t");
+      /*TODO: VARADR */
+      if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST){
+	emit(f,"%s%d",labprefix,addfpconst(&p->q1,q1typ(p)));
+      }else
+	emit_obj(f,&p->q1,t);
+      emit(f,"\n");
+      noy=1;
+    }
+    if(c==ADD){
+      if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+	eval_const(&p->q2.val,t);
+	if(zmeqto(vmax,Z1)){noop2=1;emit(f,"\tinq\n");}
+	else if(zmeqto(vmax,l2zm(2L))){noop2=1;emit(f,"\tinq\n\tinq\n");}
+	else if(zmeqto(vmax,l2zm(3L))){noop2=1;emit(f,"\tinq\n\tinq\n\tinq\n");}
+	else if(zmeqto(vmax,l2zm(4L))){noop2=1;emit(f,"\tinq\n\tinq\n\tinq\n\tinq\n");}
+      }
+      if(!noop2){
+	emit(f,"\tclc\n");
+	emit(f,"\tadcq\t");
+      }
+    }else if(c==SUB){
+      if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+	eval_const(&p->q2.val,t);
+	if(zmeqto(vmax,Z1)){noop2=1;emit(f,"\tdeq\n");}
+	else if(zmeqto(vmax,l2zm(2L))){noop2=1;emit(f,"\tdeq\n\tdeq\n");}
+	else if(zmeqto(vmax,l2zm(3L))){noop2=1;emit(f,"\tdeq\n\tdeq\n\tdeq\n");}
+	else if(zmeqto(vmax,l2zm(4L))){noop2=1;emit(f,"\tdeq\n\tdeq\n\tdeq\n\tdeq\n");}
+      }
+      if(!noop2){
+	emit(f,"\tsec\n");
+	emit(f,"\tsbcq\t");
+      }
+    }else if(c==OR){
+      emit(f,"\torq\t");
+    }else if(c==AND){
+      emit(f,"\tandq\t");
+    }else if(c==XOR){
+      emit(f,"\teorq\t");
+    }else if(c==MULT||c==DIV){
+      if(m65io){
+	emit(f,"\tstq\t$d770\n");
+      }else{
+	emit(f,"\tstq\t[___m65mathptr]\n");
+	emit(f,"\tlda\t#$74\n");
+	emit(f,"\tsta\t___m65mathptr\n");
+      }
+      noy=2;
+      ldq_offset(f,&p->q2);
+      emit(f,"\tldq\t");
+    }
+    if(c!=ASSIGN&&c!=PUSH&&c!=GETRETURN&&c!=SETRETURN&&!noop2){
+      if((p->q2.flags&VARADR)||(p->q2.flags&(KONST|DREFOBJ))==KONST){
+	emit(f,"%s%d",labprefix,addfpconst(&p->q2,q2typ(p)));
+      }else
+	emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+    }
+    noy=1;
+    if(c==MULT||c==DIV){
+      if(m65io)
+	emit(f,"\tstq\t$d774\n");
+      else
+	emit(f,"\tstq\t[___m65mathptr]\n");
+      if(m65io){
+	if(c==DIV){
+	  /* delay */
+	  emit(f,"\tlda\t$d76c\n");
+	  emit(f,"\tlda\t$d76c\n");
+	  emit(f,"\tlda\t$d76c\n");
+	  emit(f,"\tlda\t$d76c\n");
+	  emit(f,"\tldq\t$d76c\n");
+	}else
+	  emit(f,"\tldq\t$d778\n");
+      }else{
+	if(c==DIV){
+	  emit(f,"\tlda\t#$6c\n");
+	  emit(f,"\tsta\t___m65mathptr\n");
+	  emit(f,"\tldz\t#0\n");
+	  emit(f,"\tlda\t[___m65mathptr],z\n"); /* delay for division */
+	}else
+	  emit(f,"\tldz\t#4\n");
+	emit(f,"\tldq\t[___m65mathptr],z\n");
+      }
+    }
+    emit(f,"\tstq\t");
+    if(c==PUSH)
+      emit(f,"(%s)",pushed==4?mregnames[sp]:mregnames[t1]);
+    else if(c==SETRETURN)
+      emit(f,"%s",mregnames[FIRST_BIG]);
+    else
+      emit_obj(f,&p->z,t);
+    emit(f,"\n");
+    noy=0;
+    if(zzero) 
+      emit(f,"\tldz\t#0\n");
+    else
+      ierror(0);
+    return 1;
+  }
+  return 0;
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *mi;
+  FILE *rf=f;
+  static char *dbgfile;
+  static int dbgline;
+
+  if(vlas){
+    fp=FPVLA_REG;
+    if(!reg_pair(fp,&rp)) ierror(0);
+    fp1=rp.r1;
+    fp2=rp.r2;
+    regused[fp]=regused[fp1]=regused[fp2]=1;
+   }else{
+    fp=sp;
+    fp1=sp1;
+    fp2=sp2;
+  }
+  argsize=0;
+  localsize=offset;
+  if(DEBUG&1) printf("gen_code()\n");
+
+  if(ce02) zzero=1; /* TODO: check what to do */
+
+  cbank=bank(v);
+
+  if(!v->fi) v->fi=new_fi();
+  v->fi->flags|=ALL_REGS;
+
+  for(mi=p;mi;mi=mi->next)
+    switch_IC(mi);
+
+  for(pass=0;pass<2;pass++){
+
+    if(DEBUG&1) printf("pass %d\n",pass);
+
+    if(pass==0){
+      f=0;
+      mi=clone_ic(p);
+    }else
+      f=rf;
+
+    for(c=1;c<=MAXR;c++) regs[c]=0; /*regsa[c];*/
+    maxpushed=0;
+
+    /*FIXME*/
+    if(v->tattr&INTERRUPT){
+      ret="\trti\n";
+      in_isr=1;
+    }else{
+      ret="\trts\n";
+      in_isr=0;
+    }
+
+    if(!nopeep) peephole(pass==0?p:mi);
+
+    function_top(f,v,localsize);
+
+    pushed=0;
+
+    yval=NOVAL;
+
+    dbgfile=0;
+    dbgline=0;
+
+    for(p=pass==0?p:mi;p;pr(f,p),p=p->next){
+
+
+
+      if(DEBUG&1) pric2(stdout,p);
+
+      if(debug_info){
+	if(p->file&&p->line){
+	  if(p->file!=dbgfile||p->line!=dbgline){
+	    dbgfile=p->file;
+	    dbgline=p->line;
+	    emit(f,"; %d \"%s\"\n",dbgline,dbgfile);
+	  }
+	}
+      }
+
+      c=p->code;t=p->typf;
+
+      if(c==NOP) {p->z.flags=0;continue;}
+      if(c==ALLOCREG){
+	regs[p->q1.reg]=1;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regs[rp.r1]=1;
+	  regs[rp.r2]=1;
+	}
+	continue;
+      }
+      if(c==FREEREG){
+	regs[p->q1.reg]=0;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regs[rp.r1]=0;
+	  regs[rp.r2]=0;
+	}
+	continue;
+      }
+      if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);yval=NOVAL;continue;}
+      if(c==BRA){
+	yval=NOVAL;
+	if(t==exit_label&&localsize+argsize+rsavesize+rscnt==0)
+	  emit(f,ret);
+	else
+	  emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,t);
+	continue;
+      }
+      if(c>=BEQ&&c<BRA){
+	yval=NOVAL;
+	continue;
+      }
+
+      if(c==MOVETOREG){
+	p->code=c=ASSIGN;
+	p->typf=t=regtype[p->z.reg]->flags;
+	p->q2.val.vmax=sizetab[regtype[p->z.reg]->flags];
+      }
+      if(c==MOVEFROMREG){
+	p->code=c=ASSIGN;
+	p->typf=t=regtype[p->q1.reg]->flags;
+	p->q2.val.vmax=sizetab[regtype[p->q1.reg]->flags];
+      }
+      if(c==CONVERT&&ISCHAR(t)&&ISCHAR(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[CHAR];
+      }
+      if(c==CONVERT&&msizetab[t&NQ]==3&&msizetab[p->typf2&NQ]==3){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[SHORT];
+      }
+      if(c==CONVERT&&ISSHORT(t)&&ISSHORT(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[SHORT];
+      }
+      if(c==CONVERT&&ISLONG(t)&&ISLONG(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[LONG];
+      }
+      if(c==CONVERT&&ISLLONG(t)&&ISLLONG(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[LLONG];
+      }
+      if(c==CONVERT&&ISFLOAT(t)&&ISFLOAT(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[t&NQ];
+      }
+
+
+      /* switch commutative operands if suitable */
+      if(c==ADD||c==MULT||c==AND||c==XOR||c==OR||(c==ADDI2P&&ISSHORT(t)&&!ISFPOINTER(p->typf2))){
+	if((compare_objects(&p->q2,&p->z)&&!isacc(q1))||isacc(q2)){
+	  struct obj tmp;
+	  tmp=p->q1;
+	  p->q1=p->q2;
+	  p->q2=tmp;
+	}
+      }
+
+      if(c==COMPARE&&((p->q1.flags&(KONST|DREFOBJ))==KONST||ISRIDX(q2)||(isacc(q2)&&!ISRIDX(q1)))){
+	obj tmp;IC *b;
+	tmp=p->q1;
+	p->q1=p->q2;
+	p->q2=tmp;
+	for(b=p->next;b;b=b->next){
+	  int bc;
+	  if(!b||b->code==LABEL) ierror(0);
+	  bc=b->code;
+	  if(bc==BGT){b->code=BLT;break;}
+	  if(bc==BGE){b->code=BLE;break;}
+	  if(bc==BLT){b->code=BGT;break;}
+	  if(bc==BLE){b->code=BGE;break;}
+	  if(bc==BNE||bc==BEQ) break;
+	}
+      }
+
+      c=p->code;
+      if(c==SUBPFP) c=SUB;
+      /*if(c==ADDI2P) c=ADD;*/
+      /*if(c==SUBIFP) c=SUB;*/
+
+
+      if(c==MINUS){
+	if(isacc(q1)&&isacc(z)){
+	  emit(f,"\teor\t#255\n");
+	  if(c02&&ISCHAR(t)){
+	    emit(f,"\tina\n");
+	  }else{
+	    emit(f,"\tclc\n");
+	    emit(f,"\tadc\t#1\n");
+	  }
+	  if(!ISCHAR(t)){
+	    emit(f,"\tpha\n");
+	    emit(f,"\ttxa\n");
+	    emit(f,"\teor\t#255\n");
+	    emit(f,"\tadc\t#0\n");
+	    emit(f,"\ttax\n");
+	    emit(f,"\tpla\n");
+	  }
+	  continue;
+	}
+	p->code=c=SUB;
+	p->q2=p->q1;
+	p->q1.flags=KONST;
+	p->q1.am=0;
+	gval.vmax=Z0;
+	eval_const(&gval,MAXINT);
+	insert_const(&p->q1.val,t);
+      }
+
+      preload(f,p);
+
+      if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&compare_objects(&p->q1,&p->z)&&(!indirect(&p->q1)||(isreg(q1)&&ISIDX(p->q1.reg)))&&isconst(q2)&&!isacc(z)){
+	long l;
+	eval_const(&p->q2.val,q2typ(p));
+	l=zm2l(vmax);
+	if(c==ADDI2P/*&&(t2&NQ)==POINTER*/) {c=ADD;t=UNSIGNED|INT;}
+	if(c==SUBIFP/*&&(t2&NQ)==POINTER*/) {c=SUB;t=UNSIGNED|INT;}
+	if(c==SUB||c==SUBIFP) l=-l;
+	/*TODO: allow larger types */
+	if(l<3&&l>-3&&(t&NQ)<=INT){
+	  if(l<0){
+	    if(!c02||!isreg(q1)) get_acc(f,p,CHAR);
+	    incmem(f,&p->z,t,SUB,-l);
+	  }else
+	    incmem(f,&p->z,t,ADD,l);
+	  continue;
+	}
+	if(ISLONG(t)&&((m65&&labs(l)<3)||(optspeed&&l>0&&l<4)||(l>0&&l<2))){
+	  if(l<0){
+	    incmem(f,&p->z,t,SUB,-l);
+	  }else
+	    incmem(f,&p->z,t,ADD,l);
+	  continue;
+	}
+      }
+
+      if(m65&&handle_m65(f,p))
+	continue;
+
+      if(c==CONVERT){
+	int to=q1typ(p)&NU;
+	t&=NU;
+	if(ISCHAR(t)){
+	  if(!isacc(q1))
+	    get_acc(f,p,CHAR);
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  continue;
+	}
+	if(ISLONG(to)){
+	  if(!isacc(z))
+	    get_acc(f,p,CHAR);
+	  if(zm2l(sizetab[t&NQ])==3){
+	    do_byte3(f,"lda",&p->q1,to);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  if(zm2l(sizetab[t&NQ])>=2){
+	    if(isacc(z)&&!indirect(&p->q1)){
+	      do_hibyte(f,"ldx",&p->q1,to);
+	    }else{
+	      load_hibyte(f,&p->q1,to);
+	      store_hibyte(f,&p->z,t);
+	    }
+	  }
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  continue;
+	}
+	if(ISSHORT(to)){
+	  if((t&UNSIGNED)||ISFPOINTER(t))
+	    get_acc(f,p,CHAR);
+	  else
+	    get_acc(f,p,SHORT);
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  load_hibyte(f,&p->q1,to);
+	  store_hibyte(f,&p->z,t);
+	  if(ISFPOINTER(t)){
+	    int b=-1;
+	    if((p->q1.flags&(VARADR|DREFOBJ))==VARADR) b=bank(p->q1.v);
+	    emit(f,"\tlda\t#%d\n",b>=0?b:bankcnum);
+	    do_byte3(f,"sta",&p->z,t);
+	    continue;
+	  }
+	  if(to&UNSIGNED){
+	    if(zzero&&!indirect(&p->z)){
+	      do_byte3(f,"stz",&p->z,t);
+	      do_byte4(f,"stz",&p->z,t);
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      do_byte3(f,"sta",&p->z,t);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	  }else{
+	    emit(f,"\tldx\t#0\n");
+	    emit(f,"\tcmp\t#0\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(indirect(&p->z)){
+	      emit(f,"\ttxa\n");
+	      do_byte3(f,"sta",&p->z,t);
+	      do_byte4(f,"sta",&p->z,t);
+	    }else{
+	      do_byte3(f,"stx",&p->z,t);
+	      do_byte4(f,"stx",&p->z,t);
+	    }
+	  }
+	  continue;
+	}
+	if(ISCHAR(to)){
+	  if(to&UNSIGNED){
+	    char *s;
+	    get_acc(f,p,CHAR);
+	    if(isreg(q1)&&p->q1.reg==rx&&!indirect(&p->z)){
+	      do_lobyte(f,"stx",&p->z,CHAR);
+	    }else{
+	      load_lobyte(f,&p->q1,to);
+	      store_lobyte(f,&p->z,t);
+	    }
+	    if(isacc(z)){
+	      emit(f,"\tldx\t#0\n");
+	      continue;
+	    }
+	    if(zzero&&!indirect(&p->z))
+	      s="stz";
+	    else{
+	      emit(f,"\tlda\t#0\n");
+	      s="sta";
+	    }
+	    do_hibyte(f,s,&p->z,t);
+	    if(ISLONG(t)){
+	      do_byte3(f,s,&p->z,t);
+	      do_byte4(f,s,&p->z,t);
+	    }
+	  }else{
+	    int l=++label;
+	    get_acc(f,p,SHORT);
+	    emit(f,"\tldx\t#0\n");
+	    if(isreg(q1)&&p->q1.reg==ra)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      load_lobyte(f,&p->q1,to);
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    store_lobyte(f,&p->z,t);
+	    if(indirect(&p->z)&&(!isreg(z)||p->z.reg!=rax)){
+	      emit(f,"\ttxa\n");
+	      store_hibyte(f,&p->z,t);
+	      if(ISLONG(t)){
+		do_byte3(f,"sta",&p->z,t);
+		do_byte4(f,"sta",&p->z,t);
+	      }
+	    }else{
+	      if(!isreg(z)||p->z.reg!=rax){
+		emit(f,"\tstx\t");
+		emit_hibyte(f,&p->z,t);
+		emit(f,"\n");
+	      }
+	      if(ISLONG(t)){
+		do_byte3(f,"stx",&p->z,t);
+		do_byte4(f,"stx",&p->z,t);
+	      }
+	    }
+	  }
+	  if(ISFPOINTER(t)){
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  continue;
+	}
+	if(ISFPOINTER(to)){
+	  get_acc(f,p,CHAR);
+	  if(zm2l(sizetab[t&NQ])>=3){
+	    do_byte3(f,"lda",&p->q1,to);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  if(zm2l(sizetab[t&NQ])>=2){
+	    load_hibyte(f,&p->q1,to);
+	    store_hibyte(f,&p->z,t);
+	  }
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+
+	  continue;
+	}
+	pric2(stdout,p);
+	ierror(0);
+      }
+
+      if(c==KOMPLEMENT){
+	get_acc(f,p,CHAR);
+	if(ISCHAR(t)){
+	  load_acc(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_acc(f,&p->z,t);
+	}else{
+	  if(isacc(q1))
+	    emit(f,"\tpha\n");
+	  if(ISLONG(t)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\teor\t#-1\n");
+	    do_byte4(f,"sta",&p->z,t);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\teor\t#-1\n");
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  load_hibyte(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_hibyte(f,&p->z,t);
+	  if(isacc(q1))
+	    emit(f,"\tpla\n");
+	  load_lobyte(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_lobyte(f,&p->z,t);
+	}
+	continue;
+      }
+      if(c==SETRETURN){
+	hasretval=1;
+	t&=NQ;
+	if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+	if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+	  long l=zm2l(p->q2.val.vmax);
+	  int zr=p->z.reg;
+	  //get_acc(f,p,t);
+	  if((optsize||l>4)&&!ISFPOINTER(t)){
+	    int ind=indirect(&p->q1);
+	    if(ind) load_address(f,LAST_PAIR,&p->q1,t);
+	    BSET(regused,t3);
+	    BSET(regused,t4);
+	    sety(f,l-1);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    if(ind)
+	      emit(f,"\tlda\t(%s),y\n",mregnames[LAST_PAIR]);
+	    else{
+	      emit(f,"\tlda\t");
+	      if(!ISFLOAT(t)&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+		emit(f,"%s%d",labprefix,addfpconst(&p->q1,t));
+	      }else
+		emit_obj(f,&p->q1,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tsta\t%s,y\n",mregnames[zr]);
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    yval=255;
+	  }else{
+	    if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	      if(p->q1.reg==zr){
+		int r=get_reg(f,p,POINTER);
+		if(r==FIRST_PAIR||r==FIRST_PAIR+1)
+		  ierror(0);
+		if(!reg_pair(r,&rp2)) ierror(0);
+		emit(f,"\tlda\t%s\n",mregnames[zr]);
+		emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+		emit(f,"\tlda\t%s+1\n",mregnames[zr]);
+		emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+		p->q1.reg=r;
+	      }
+	    }
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[zr]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s+1\n",mregnames[zr]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s+2\n",mregnames[zr]);
+	    if(!ISFPOINTER(t)){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s+3\n",mregnames[zr]);
+	    }
+	    /*TODO:regused OLDFP */
+	    regused[zr]=1;
+	  }
+	  continue;
+	}
+	//get_acc(f,p,t);
+	load_acc(f,&p->q1,t);
+	regused[ra]=1;
+	regused[rx]=1;
+	continue;
+      }
+      if(c==GETRETURN){
+	t&=NQ;
+	if(isreg(z)&&p->q1.reg==p->z.reg) continue;
+	if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+	  long l=zm2l(p->q2.val.vmax);
+	  int qr=p->q1.reg;
+	  if((optsize||l>4)&&!ISFPOINTER(t)){
+	    int ind=indirect(&p->z);
+	    if(ind) load_address(f,LAST_PAIR,&p->z,t);
+	    BSET(regused,t3);
+	    BSET(regused,t4);
+	    sety(f,l-1);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    emit(f,"\tlda\t%s,y\n",mregnames[qr]);
+	    if(ind)
+	      emit(f,"\tsta\t(%s),y\n",mregnames[LAST_PAIR]);
+	    else{
+	      emit(f,"\tsta\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    yval=255;
+	  }else{
+	    if((p->z.reg&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	      if(p->z.reg==qr) ierror(0);
+	    }
+	    emit(f,"\tlda\t%s\n",mregnames[qr]);
+	    store_lobyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s+1\n",mregnames[qr]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s+2\n",mregnames[qr]);
+	    do_byte3(f,"sta",&p->z,t);
+	    if(!ISFPOINTER(t)){
+	      emit(f,"\tlda\t%s+3\n",mregnames[qr]);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	  }
+	  continue;
+	}
+	if(p->q1.reg)
+	  store_acc(f,&p->z,t);
+	continue;
+      }
+      if(c==CALL){
+	int reg;
+
+	if(argsize<zm2l(p->q2.val.vmax)) argsize=zm2l(p->q2.val.vmax);
+
+	/*FIXME*/
+#if 0      
+	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	  if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	    stack=framesize+zum2ul(p->q1.v->fi->stack1);
+	}else
+	  stack_valid=0;
+#endif
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	  long of=va_offset(v)+localsize+rsavesize+argsize;
+	  emit(f,"\tlda\t%s\n",mregnames[fp]);
+	  if(of){
+	    emit(f,"\tclc\n");
+	    if(of&255)
+	      emit(f,"\tadc\t#%d\n",(of&255));
+	  }
+	  emit(f,"\tldx\t%s+1\n",mregnames[fp]);
+	  if(of&0xff00){
+	    emit(f,"\tpha\n");
+	    emit(f,"\ttxa\n");
+	    emit(f,"\tadc\t#%d\n",(of>>8)&255);
+	    emit(f,"\ttax\n");
+	    emit(f,"\tpla\n");
+	  }else if(of){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	    emit(f,"\tinx\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }
+	  continue;
+	}
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	  emit(f,";startinline\n");
+	  emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	  emit(f,";endinline\n");
+	}else if(p->q1.flags&DREFOBJ){
+	  if(ISFPOINTER(p->q1.dtyp)){
+	    p->q1.flags&=~DREFOBJ;
+	    load_reg(f,LAST_PAIR,&p->q1,POINTER);
+	    if(indirect(&p->q1)){
+	      do_byte3(f,"lda",&p->q1,FPOINTER);
+	      emit(f,"\ttay\n");
+	    }else
+	      do_byte3(f,"ldy",&p->q1,FPOINTER);
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	    emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+	    yval=NOVAL;
+	  }else{
+	    if(!(p->q1.flags&REG)) ierror(0);
+	    emit(f,"\tjsr\t%s%d\n",labprefix,++label);
+	    yval=NOVAL;
+	    add_cmplist(label,p->q1.reg,JMPIND);
+	  }
+	}else{
+	  int tbank=-1;
+	  if(p->q1.flags&VAR) tbank=bank(p->q1.v);
+	  if(tbank!=cbank&&tbank>=0){
+	    if(cbank>=0){
+	      load_address(f,LAST_PAIR,&p->q1,t);
+	      sety(f,tbank);
+	      emit(f,"\tlda\t#%d\n",cbank);
+	      emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+	      yval=NOVAL;
+	      continue;
+	    }
+	    sety(f,tbank);
+	    emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+	    yval=NOVAL;
+	  }
+	  if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"_fmemcpy"))
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	  emit(f,"\tjsr\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+	pushed-=zm2l(p->q2.val.vmax);
+	if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+	yval=NOVAL;
+	continue;
+      }
+      if(c==ASSIGN||c==PUSH){
+	if(t==0) ierror(0);
+	if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)==LLONG){
+	  int i;
+	  eval_const(&p->q1.val,t);
+	  for(i=0;i<8;i++){
+	    emit(f,"\tlda\t#%d\n",zm2l(vmax)&255);
+	    vmax=zmrshift(vmax,l2zm(8L));
+	    if(c==PUSH||(p->z.flags&DREFOBJ)){
+	      sety(f,i+((c==PUSH)?pushed:0));
+	      emit(f,"\tsta\t(%s),y\n",(c==PUSH)?mregnames[sp]:mregnames[p->z.reg]);
+	    }else{
+	      p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((long)i));
+	      emit(f,"\tsta\t");
+	      emit_lobyte(f,&p->z,t);
+	      emit(f,"\n");
+	      p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)i));
+	    }
+	  }
+	  if(c==PUSH) pushed+=8;
+	  continue;
+	}  
+
+	if(!zmleq(p->q2.val.vmax,l2zm(4L))){
+	  long len=zm2l(p->q2.val.vmax);
+	  int r1,r2,loops,looplab;
+	  if(len>32767) ierror(0);
+	  if(!NOBANKVARS){
+	    int bq=-1,bz=-1,s=-1;
+	    if((p->q1.flags&(VAR|DREFOBJ))==VAR) bq=bank(p->q1.v);
+	    if((p->z.flags&(VAR|DREFOBJ))==VAR) bz=bank(p->z.v);
+	    if(((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp))||
+	       ((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp))){
+	      far_copy(f,p);
+	      continue;
+	    }
+	    if(cbank<0){
+	      if(bq>=0&&bz>=0){
+		if(bq!=bz){
+		  far_copy(f,p);
+		  continue;
+		}
+		s=bq;
+	      }else{
+		if(bq>=0) s=bq;
+		if(bz>=0) s=bz;
+	      }
+	      if(s>=0){
+		sety(f,s);
+		emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+		yval=NOVAL;
+	      }
+	    }else{
+	      if((bq>=0&&bq!=cbank)||(bz>=0&&bz!=cbank)){
+		far_copy(f,p);
+		continue;
+	      }
+	    }
+	  }
+	  get_acc(f,p,CHAR);
+	  if((p->q1.flags&(DREFOBJ|KONST))==DREFOBJ){
+	    if(p->q1.flags&REG){
+	      r1=p->q1.reg;
+	      if(!reg_pair(r1,&rp)) ierror(0);
+	      if(len>128){
+		emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+		emit(f,"\tclc\n");
+		if(len&128)
+		  emit(f,"\tadc\t#128\n");
+		emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+		if(len>255){
+		  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+		  emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+		  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);	
+		}else{
+		  emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+		  emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+		  emit(f,"%s%d:\n",labprefix,label);
+		}
+	      }
+	    }else
+	      ierror(0);
+	  }else if(!indirect(&p->q1)&&len<=128&&(p->q1.flags&(DREFOBJ|KONST))!=KONST){
+	    r1=0;
+	  }else{
+	    Var *v=p->q1.v;
+	    /*if((p->q1.flags&(VARADR|VAR))!=VAR) ierror(0);*/
+	    /*printf("len=%ld %ld\n",len,len&0xff80);*/
+	    r1=get_reg(f,p,POINTER);
+	    if(len>128) p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm((len-1)&0xff80));
+	    load_address(f,r1,&p->q1,t);
+	    if(len>128) p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm((len-1)&0xff80));
+	  }
+	  if((p->z.flags&(DREFOBJ|KONST))==DREFOBJ){
+	    if(p->z.flags&REG){
+	      r2=p->z.reg;
+	      if(!reg_pair(r2,&rp)) ierror(0);
+	      if(len>128){
+		emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+		emit(f,"\tclc\n");
+		if(len&128)
+		  emit(f,"\tadc\t#128\n");
+		emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+		if(len>255){
+		  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+		  emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+		  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);	
+		}else{
+		  emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+		  emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+		  emit(f,"%s%d:\n",labprefix,label);
+		}
+	      }
+	    }else
+	      ierror(0);
+	  }else if(c==PUSH){
+	    if(len<=128&&pushed==0){
+	      r2=sp;
+	    }else{
+	      r2=get_reg(f,p,POINTER);
+	      if(!reg_pair(r2,&rp)) ierror(0);
+	      emit(f,"\tlda\t%s\n",mregnames[sp]);
+	      emit(f,"\tclc\n");
+	      if(((pushed+(len&128))&255)!=0)
+		emit(f,"\tadc\t#%ld\n",(pushed+(len&128))&255);
+	      emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	      emit(f,"\tlda\t%s\n",mregnames[sp2]);
+	      emit(f,"\tadc\t#%ld\n",((pushed+len)>>8)&255);
+	      emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+	    }
+	  }else if(!indirect(&p->z)&&len<=128){
+	    r2=0;
+	  }else{
+	    Var *v=p->z.v;
+	    r2=get_reg(f,p,POINTER);
+	    if(len>128) p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((len-1)&0xff80));
+	    load_address(f,r2,&p->z,t);
+	    if(len>128) p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((len-1)&0xff80));
+	  }
+	  if(len>128){
+	    get_acc(f,p,POINTER); /* get x */
+	    emit(f,"\tldx\t#%ld\n",(((len-128)>>7)+1)&255);
+	  }
+	  sety(f,(len-1)&127);
+	  if((optsize&&len>4)||len>8){
+	    emit(f,"%s%d:\n",labprefix,looplab=++label);
+	    if(optsize)
+	      loops=1;
+	    else{
+	      if((len&3)==0)
+		loops=4;
+	      else if((len&1)==0)
+		loops=2;
+	      else
+		loops=1;
+	    }
+	  }else
+	    loops=len;
+	  if(r1&&!reg_pair(r1,&rp)) ierror(0);
+	  if(r2&&!reg_pair(r2,&rp2)) ierror(0);
+	  for(i=0;i<loops;i++){
+	    if(r1)
+	      emit(f,"\tlda\t(%s),y\n",mregnames[rp.r1]);
+	    else{
+	      emit(f,"\tlda\t");
+	      emit_obj(f,&p->q1,t);
+	      emit(f,",y\n");
+	    }
+	    if(r2)
+	      emit(f,"\tsta\t(%s),y\n",mregnames[rp2.r1]);
+	    else{
+	      emit(f,"\tsta\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tdey\n");
+	  }
+	  if(loops!=len){
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	  }	  
+	  if(len>128){
+	    emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	    emit(f,"\tsec\n");
+	    emit(f,"\tsbc\t#128\n");
+	    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	    emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	    emit(f,"\tlda\t%s\n",mregnames[rp2.r1]);
+	    emit(f,"\tsec\n");
+	    emit(f,"\tsbc\t#128\n");
+	    emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	    emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdec\t%s\n",mregnames[rp2.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	    emit(f,"\tldy\t#127\n");
+	    emit(f,"\tdex\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,looplab);
+	  }
+	  yval=NOVAL;
+	  if(c==PUSH)
+	    pushed+=zm2l(p->q2.val.vmax);
+	  continue;
+	}
+	if(c==PUSH){
+	  if(!scratch(p->next,ra,1))
+	    get_acc(f,p,CHAR);
+	  load_lobyte(f,&p->q1,t);
+	  if(zzero&&pushed==0){
+	    emit(f,"\tsta\t(%s)\n",mregnames[sp]);
+	  }else{
+	    sety(f,pushed);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,Z1)){
+	    load_hibyte(f,&p->q1,t);
+	    sety(f,pushed+1);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	    do_byte3(f,"lda",&p->q1,t);
+	    sety(f,pushed+2);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+	    do_byte4(f,"lda",&p->q1,t);
+	    sety(f,pushed+3);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+
+	  pushed+=zm2l(p->q2.val.vmax);
+	  continue;
+	}
+	if(c==ASSIGN){
+	  int c2m;unsigned long v;
+	  if(isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) continue;
+	  if(isacc(q1)){
+	    if(p->q1.reg==rax&&indirect(&p->z)) get_acc(f,p,CHAR);
+	    store_acc(f,&p->z,t);
+	    continue;
+	  }
+	  if(zzero&&!indirect(&p->z)&&(p->q1.flags&(DREFOBJ|KONST))==KONST){
+	    eval_const(&p->q1.val,t);
+	    if(ISFLOAT(t)){
+	      cnv_fp();
+	      v=zum2ul(zm2zum(vmax));
+	    }else
+	      v=zum2ul(vumax);
+	    c2m=1;
+	  }else
+	    c2m=0;
+	  if(!c2m||v!=0)
+	    get_acc(f,p,CHAR);
+	  if(0/*ISCHAR(t)*/){
+	    load_acc(f,&p->q1,t);
+	    store_acc(f,&p->z,t);
+	  }else{
+	    if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+	      if(c2m&&(v&0xFF000000)==0){
+		do_byte4(f,"stz",&p->z,t);
+	      }else{
+		do_byte4(f,"lda",&p->q1,t);
+		do_byte4(f,"sta",&p->z,t);
+	      }
+	    }
+	    if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	      if(c2m&&(v&0xFF0000)==0){
+		do_byte3(f,"stz",&p->z,t);
+	      }else{
+		do_byte3(f,"lda",&p->q1,t);
+		do_byte3(f,"sta",&p->z,t);
+	      }
+	    }
+	    if(!zmleq(p->q2.val.vmax,l2zm(1L))){
+	      if(isreg(z)&&p->z.reg==rax&&!indirect(&p->q1)){
+		do_hibyte(f,"ldx",&p->q1,t);
+	      }else if(c2m&&(v&0xFF00)==0){
+		do_hibyte(f,"stz",&p->z,t);
+	      }else{
+		load_hibyte(f,&p->q1,t);
+		store_hibyte(f,&p->z,t);
+	      }
+	    }
+	    if(c2m&&(v&0xFF)==0){
+	      do_lobyte(f,"stz",&p->z,t);
+	    }else{
+	      if(isreg(q1)&&ISIDX(p->q1.reg)){
+		store_reg(f,p->q1.reg,&p->z,CHAR);
+	      }else if(isreg(z)&&ISIDX(p->z.reg)){
+		load_reg(f,p->z.reg,&p->q1,t);
+	      }else{
+		load_lobyte(f,&p->q1,t);
+		store_lobyte(f,&p->z,t);
+	      }
+	    }
+	  }
+	}
+	continue;
+      }
+      if(c==ADDRESS){
+	long o=real_offset(&p->q1);
+	get_acc(f,p,CHAR);
+	emit(f,"\tlda\t%s\n",mregnames[fp1]);
+	if(o){
+	  emit(f,"\tclc\n");
+	  if((o&255)!=0)
+	    emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)&255);
+	}
+	if(isacc(z)){
+	  if(o==0) {emit(f,"\tldx\t%s\n",mregnames[fp2]);continue;}
+	  if(o==256){emit(f,"\tldx\t%s\n\tinx\n",mregnames[fp2]);continue;}
+	  if(o==512){emit(f,"\tldx\t%s\n\tinx\n\tinx\n",mregnames[fp2]);continue;}
+	  if(o<256){++label;emit(f,"\tldx\t%s\n\tbcc\t%s%d\n\tinx\n%s%d:\n",mregnames[fp2],labprefix,label,labprefix,label);continue;}
+	  if(o<512){++label;emit(f,"\tldx\t%s\n\tinx\n\tbcc\t%s%d\n\tinx\n%s%d:\n",mregnames[fp2],labprefix,label,labprefix,label);continue;}
+	}
+	store_lobyte(f,&p->z,t);
+	if(isacc(z)) emit(f,"\tpha\n");
+	emit(f,"\tlda\t%s\n",mregnames[fp2]);
+	if(o!=0)
+	  emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)>>8&255);
+	store_hibyte(f,&p->z,t);
+	if(isacc(z)) emit(f,"\tpla\n");
+	continue;
+      }
+
+      if(c==COMPARE||c==TEST){
+	IC *branch=p->next;
+	int pacc=0,bc,bout;
+	if(ISPOINTER(t)) t|=UNSIGNED;
+	while(branch){
+	  if(branch->code>=BEQ&&branch->code<BRA)
+	    break;
+	  if(branch->code!=FREEREG&&branch->code!=ALLOCREG&&branch->code!=NOP)
+	    ierror(0);
+	  branch=branch->next;
+	}
+	bc=branch->code;
+	bout=branch->typf;
+	if(c==TEST){
+	  p->q2.flags=KONST;
+	  gval.vmax=Z0;
+	  eval_const(&gval,MAXINT);
+	  insert_const(&p->q2.val,t);
+	}
+	if((t&NU)==(UNSIGNED|CHAR)&&(bc==BLE||bc==BGT)&&(p->q2.flags&(DREFOBJ|KONST))==KONST){
+	  eval_const(&p->q2.val,t);
+	  if(!zmeqto(vmax,l2zm(255L))){
+	    vmax=zmadd(vmax,Z1);
+	    gval.vmax=vmax;
+	    eval_const(&gval,t);
+	    insert_const(&p->q2.val,t);
+	    if(bc==BLE) bc=BLT; else bc=BGE;
+	    branch->code=bc;
+	  }
+	}
+	if(((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==LONG)&&(bc==BNE||bc==BEQ)&&isconst(q2)&&!isacc(q1)){
+	  eval_const(&p->q2.val,t);
+	  if(zmeqto(vmax,Z0)&&zumeqto(vumax,ZU0)){
+	    if(pacc=cmp_get_acc(f,p,branch))
+	      bout=++label;
+	    load_lobyte(f,&p->q1,t);
+	    do_hibyte(f,"ora",&p->q1,t);
+	    if((t&NQ)==LONG){
+	      do_byte3(f,"ora",&p->q1,t);
+	      do_byte4(f,"ora",&p->q1,t);
+	    }
+	    emit(f,"\t%s\t%s%d\n",(bc==BNE)?"bne":"beq",labprefix,bout);
+	    if(pacc){
+	      reload_acc(f);
+	      add_cmplist(bout,branch->typf,pacc);
+	    }
+	    continue;
+	  }
+	}
+	if(ieee&&ISFLOAT(t)){
+	  if(!ieee) ierror(0);
+	  t&=NQ;
+	  if(regs[LAST_PAIR]) ierror(0);
+	  regs[LAST_PAIR]=1;
+	  if(regs[ra]||regs[rax])
+	    ierror(0);
+	  load_address(f,LAST_PAIR,&p->q2,t);
+	  BSET(regused,t3);
+	  BSET(regused,t4);
+	  emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->q1,t);
+	  emit(f,"\tjsr\t%s__fcmp%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  regs[LAST_PAIR]=0;
+	  if(bc==BLT||bc==BLE)
+	    emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	  else if(bc==BGT|bc==BGE)
+	    emit(f,"\tbvs\t%s%d\n",labprefix,bout);
+	  if(bc==BEQ||bc==BLE||bc==BGE)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  continue;
+	}
+	if(ISCHAR(t)){
+	  char *s=0;
+	  if(isreg(q1)&&ISIDX(p->q1.reg)&&!indirect(&p->q2)&&(bc==BEQ||bc==BNE||(t&UNSIGNED))){
+	    static char buf[4]="cpr";
+	    s=buf;s[2]=mregnames[p->q1.reg][0];
+	  }else{
+	    if(pacc=cmp_get_acc(f,p,branch))
+	      bout=++label;
+	    load_acc(f,&p->q1,t);
+	    if(bc==BEQ||bc==BNE||(t&UNSIGNED)){
+	      s="cmp";
+	    }else{
+	      if(bc==BLT||bc==BGE)
+		emit(f,"\tsec\n");
+	      else
+		emit(f,"\tclc\n");
+	      s="sbc";
+	    }
+	  }
+	  if(c==TEST)
+	    emit(f,"\t%s\t#0\n",s);
+	  else
+	    do_lobyte(f,s,&p->q2,t);
+	  if(bc==BEQ)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(t&UNSIGNED){
+	    if(bc==BLT)
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    else if(bc==BGE)
+	      emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+	    else if(bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	    }else if(bc==BGT){
+	      emit(f,";\n\tbeq\t%s%d\n",labprefix,++label);
+	      emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+	      emit(f,"%s%d:\n",labprefix,label);
+	    }else
+	      ierror(0);
+	  }else{
+	    emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	    emit(f,"\teor\t#128\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(bc==BLT||bc==BLE)
+	      emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	    else
+	      emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	  }
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue;
+	}else if(bc==BEQ||bc==BNE||(t&UNSIGNED)||ISFPOINTER(t)){
+	  int in=0;
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+	  if(ISLONG(t)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_byte4(f,"cmp",&p->q2,t);
+	    if(bc==BEQ)
+	      emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+	    else if(bc==BNE)
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    else if(bc==BLT||bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+	    }else if(bc==BGE||bc==BGT){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,in=++label);	
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    }else
+	      ierror(0);
+	  }
+	  if(ISLONG(t)||ISFPOINTER(t)){
+	    do_byte3(f,"lda",&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_byte3(f,"cmp",&p->q2,t);
+	    if(bc==BEQ)
+	      emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	    else if(bc==BNE)
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    else if(bc==BLT||bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	    }else if(bc==BGE||bc==BGT){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));	
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    }else
+	      ierror(0);	  
+	  }
+	  if(isacc(q1)){
+	    if(!indirect(&p->q2)){
+	      do_hibyte(f,"cpx",&p->q2,t);
+	    }else{
+	      int r=get_reg(f,p,CHAR);
+	      emit(f,"\tpha\n");
+	      load_hibyte(f,&p->q2,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tpla\n");
+	      emit(f,"\tcpx\t%s\n",mregnames[r]);
+	    }
+	  }else{
+	    load_hibyte(f,&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_hibyte(f,"cmp",&p->q2,t);
+	  }
+	  if(bc==BEQ)
+	    emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(bc==BLT||bc==BLE){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	  }else if(bc==BGE||bc==BGT){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  }else
+	    ierror(0);
+	  load_lobyte(f,&p->q1,t);
+	  if(c==TEST)
+	    emit(f,"\tcmp\t#0\n");
+	  else
+	    do_lobyte(f,"cmp",&p->q2,t);
+	  if(bc==BEQ)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(bc==BLT)
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	  else if(bc==BGE)
+	    emit(f,"\tbcs\t%s%d\n",labprefix,bout);	
+	  else if(bc==BLE){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  }else if(bc==BGT){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,in);
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  }else
+	    ierror(0);
+	  if(in)
+	    emit(f,"%s%d:\n",labprefix,in);
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue;
+	}else{
+	  if(bc==BGT||bc==BLE){
+	    obj o;
+	    if(isacc(q1)){
+	      int r;
+	      if(pacc=cmp_get_acc(f,p,branch))
+		bout=++label;
+	      r=get_reg(f,p,CHAR);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_lobyte(f,&p->q2,t);
+	      emit(f,"\tcmp\t%s\n",mregnames[r]);
+	      emit(f,"\tstx\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q2,t);
+	      emit(f,"\tsbc\t%s\n",mregnames[r]);
+	      emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	      emit(f,"\teor\t#128\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      if(bc==BGT)
+		emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	      else
+		emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	      if(pacc){
+		reload_acc(f);
+		add_cmplist(bout,branch->typf,pacc);
+	      }
+	      continue;
+	    }else{
+	      o=p->q1;p->q1=p->q2;p->q2=o;
+	      if(bc==BGT) bc=BLT; else bc=BGE;
+	    }
+	  }
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+	  if(ISLONG(t)){
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,"cmp",&p->q2,t);
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,"sbc",&p->q2,t);
+	    do_byte3(f,"lda",&p->q1,t);
+	    do_byte3(f,"sbc",&p->q2,t);
+	    do_byte4(f,"lda",&p->q1,t);
+	    do_byte4(f,"sbc",&p->q2,t);
+	  }else{
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,"cmp",&p->q2,t);
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,"sbc",&p->q2,t);
+	  }
+	  emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	  emit(f,"\teor\t#128\n");
+	  emit(f,"%s%d:\n",labprefix,label);
+	  if(bc==BLT)
+	    emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	  else if(bc==BGE)
+	    emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	  else
+	    ierror(0);
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue; 
+	}
+	ierror(0);
+      }
+
+
+      if((c==ADD||c==SUB)&&ISRIDX(z)&&isconst(q2)){
+	eval_const(&p->q2.val,t);
+	if(zmeqto(vmax,l2zm(-1L))){ 
+	  vmax=Z1; vumax=ZU1; 
+	  if(c==ADD) c=SUB; else c=ADD;
+	}
+	if(zmeqto(vmax,Z1)&&zumeqto(vumax,ZU1)){
+	  if(indirect(&p->q1)){
+	    get_acc(f,p,CHAR);
+	    load_reg(f,p->z.reg,&p->q1,t);
+	  }else
+	    do_lobyte(f,"ldx",&p->q1,t);
+	  emit(f,"\t%s%s\n",(c==ADD)?"in":"de",mregnames[p->z.reg]);
+	  continue;
+	}
+      }
+
+      if((c==LSHIFT||c==RSHIFT)&&isconst(q2)&&
+	 (
+	 (isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->z.reg!=ra&&p->z.reg!=rax)||
+	 (!indirect(&p->q1)&&compare_objects(&p->q1,&p->z))
+	 )
+	 ){
+	long l;
+	eval_const(&p->q2.val,q2typ(p));
+	l=zm2l(vmax);
+	/*TODO: allow larger types */
+	if((l<3||(iszpage(&p->z)&&l<5))&&(t&NQ)<=LONG){
+	  if(c==RSHIFT&&(!c02&&!(t&UNSIGNED)))
+	    get_acc(f,p,CHAR);
+	  incmem(f,&p->z,t,c,l);
+	  continue;
+	}
+      }
+
+      if(c==LSHIFT||c==RSHIFT){
+	long l=-1,m;int loop=0,r=0,r2=0,r3=0,outl=0,same=0;
+	if(isconst(q2)){
+	  eval_const(&p->q2.val,q2typ(p));
+	  l=zm2l(vmax);
+	  loop=0;
+	}else
+	  loop=1;
+	if(l>=0&&optsize){
+	  if(c==LSHIFT&&(l&7)>6) 
+	    loop=1;
+	  else if(c==RSHIFT&&(t&UNSIGNED)&&(l&7)>3)
+	    loop=1;
+	  else if(c==RSHIFT&&!(t&UNSIGNED)&&(l&7)>2)
+	    loop=1;
+	}
+
+	if(ISLONG(t)){
+	  if(!indirect(&p->z)&&
+	     (isreg(z)||(p->z.flags&(VAR|DREFOBJ))==VAR)&&
+	     (iszpage(&p->z)||(l&7)<=2)&&
+	     (!(p->q2.flags&REG)||!(p->z.flags&REG)||p->q2.reg!=p->z.reg)&&
+	     (!(p->q2.flags&VAR)||!(p->z.flags&VAR)||p->q2.v!=p->z.v)
+	     ){
+	    if(isreg(z))
+	      strcpy(mregnames[REGDUMMY1],mregnames[p->z.reg]);
+	    else if(p->z.v->storage_class==STATIC)
+	      sprintf(mregnames[REGDUMMY1],"%s%ld",labprefix,zm2l(p->z.v->offset));
+	    else
+	      sprintf(mregnames[REGDUMMY1],"%s%s",idprefix,p->z.v->identifier);
+	    strcpy(mregnames[REGDUMMY2],mregnames[REGDUMMY1]);
+	    strcpy(mregnames[REGDUMMY3],mregnames[REGDUMMY1]);
+	    strcat(mregnames[REGDUMMY1],"+1");
+	    strcat(mregnames[REGDUMMY2],"+2");
+	    if(c!=RSHIFT||(t&UNSIGNED))
+	      strcat(mregnames[REGDUMMY3],"+3");
+	    if(c==RSHIFT&&!(t&UNSIGNED)){
+	      r=REGDUMMY2;r2=REGDUMMY1;r3=REGDUMMY3;
+	    }else{
+	      r=REGDUMMY1;r2=REGDUMMY2;r3=REGDUMMY3;
+	    }
+	    if(compare_objects(&p->q1,&p->z)) same=1;
+	  }else{
+	    r2=get_reg(f,p,CHAR);
+	    r3=get_reg(f,p,CHAR);
+	  }
+	}
+	if(!ISCHAR(t)&&r2!=REGDUMMY1&&r2!=REGDUMMY2)
+	  r=get_reg(f,p,CHAR);
+	if(ISLONG(t)){
+	  get_acc(f,p,CHAR);
+	  if(l>=24){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	      emit(f,"\tsty\t%s\n",mregnames[r2]);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      do_byte4(f,"lda",&p->q1,t);
+	      sety(f,0);
+	      emit(f,"\tsty\t%s\n",mregnames[r3]);
+	      emit(f,"\tsty\t%s\n",mregnames[r2]);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	    }
+	  }else if(l>=16){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      sety(f,0);
+	      emit(f,"\tsty\t%s\n",mregnames[r2]);
+	      emit(f,"\tsty\t%s\n",mregnames[r3]);
+	    }
+	  }else if(l>=8){
+	    if(c==LSHIFT){
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tlda\t#0\n");
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      if(same){
+		load_hibyte(f,&p->q1,t);
+		do_byte3(f,"ldy",&p->q1,t);
+		yval=NOVAL;
+		emit(f,"\tsty\t%s\n",mregnames[r]);
+		do_byte4(f,"ldy",&p->q1,t);
+		emit(f,"\tsty\t%s\n",mregnames[r2]);
+		sety(f,0);
+		emit(f,"\tsty\t%s\n",mregnames[r3]);
+	      }else{
+		emit(f,"\tlda\t#0\n");
+		emit(f,"\tsta\t%s\n",mregnames[r3]);
+		do_byte4(f,"lda",&p->q1,t);
+		emit(f,"\tsta\t%s\n",mregnames[r2]);
+		do_byte3(f,"lda",&p->q1,t);
+		emit(f,"\tsta\t%s\n",mregnames[r]);
+		load_hibyte(f,&p->q1,t);
+	      }
+	    }
+	  }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	    if(!same){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	    }
+	    do_byte4(f,"lda",&p->q1,t);
+	  }else{
+	    if(!same){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	    }
+	    load_lobyte(f,&p->q1,t);
+	  }
+	}else
+	  get_acc(f,p,t);
+	if(!ISLONG(t)){
+	  if(l>=8){
+	    if(!ISSHORT(t)) ierror(0);
+	    if(c==LSHIFT){
+	      if(indirect(&p->q1)){
+		load_lobyte(f,&p->q1,t);
+		emit(f,"\ttax\n");
+		emit(f,"\tlda\t#0\n");
+	      }else{
+		if(isacc(q1))
+		  emit(f,"\ttax\n");
+		else
+		  do_lobyte(f,"ldx",&p->q1,t);
+		emit(f,"\tlda\t#0\n");
+	      }
+	    }else{
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tldx\t#0\n");
+	      if(!(t&UNSIGNED)){
+		emit(f,"\tcmp\t#0\n");
+		emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+		emit(f,"\tdex\n");
+		emit(f,"%s%d:\n",labprefix,label);
+	      }
+	    }
+	  }else
+	    load_acc(f,&p->q1,t);
+	}
+	if(l>=0) l&=7;
+	m=l;
+	if(ISSHORT(t)&&(l>0||loop))
+	  emit(f,"\tstx\t%s\n",mregnames[r]);
+	if(loop){
+	  if(l>=0)
+	    sety(f,l);
+	  else{
+	    if(indirect(&p->q2)){
+	      emit(f,"\tpha\n");
+	      load_lobyte(f,&p->q2,q2typ(p));
+	      emit(f,"\ttay\n");
+	      emit(f,"\tpla\n");
+	      emit(f,"\tcpy\t#0\n");
+	    }else{
+	      emit(f,"\tldy\t");
+	      emit_lobyte(f,&p->q2,q2typ(p));
+	      emit(f,"\n");
+	    }
+	    outl=++label;
+	    emit(f,"\tbeq\t%s%d\n",labprefix,outl);
+	  }
+	  emit(f,"%s%d:\n",labprefix,++label);
+	}else{
+	  if(ISCHAR(t))
+	    l&=7;
+	  else if(ISSHORT(t))
+	    l&=15;
+	  else
+	    l&=31;
+	}
+	while(l>0||loop){
+	  if(c==LSHIFT){
+	    emit(f,"\tasl\n");
+	    if(!ISCHAR(t))
+	      emit(f,"\trol\t%s\n",mregnames[r]);
+	    if(ISLONG(t)){
+	      emit(f,"\trol\t%s\n",mregnames[r2]);
+	      emit(f,"\trol\t%s\n",mregnames[r3]);
+	    }
+	  }else if(t&UNSIGNED){
+	    emit(f,"\tlsr");
+	    if(ISLONG(t)){
+	      emit(f,"\t%s\n",mregnames[r3]);
+	      emit(f,"\tror\t%s\n",mregnames[r2]);
+	      emit(f,"\tror");
+	    }
+	    if(!ISCHAR(t)){
+	      emit(f,"\t%s\n",mregnames[r]);
+	      emit(f,"\tror");
+	    }
+	    emit(f,"\n");
+	  }else{
+	    if(ISLONG(t)){
+	      if(ce02)
+		emit(f,"\tasr\n");
+	      else{
+		emit(f,"\tcmp\t#128\n");
+		emit(f,"\tror\n");
+	      }
+	      emit(f,"\tror\t%s\n",mregnames[r]);
+	      emit(f,"\tror\t%s\n",mregnames[r2]);
+	      emit(f,"\tror\t%s\n",mregnames[r3]);
+	    }else{
+	      if(!ISCHAR(t)){
+		emit(f,"\tcpx\t#128\n");
+		emit(f,"\tror\t%s\n",mregnames[r]);
+	      }else
+		emit(f,"\tcmp\t#128\n");
+	      emit(f,"\tror\n");
+	    }
+	  }
+	  if(loop){
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,label);
+	    if(outl) emit(f,"%s%d:\n",labprefix,outl);
+	    yval=0;
+	    break;
+	  }
+	  l--;
+	}
+	if(ISLONG(t)){
+	  if(c==RSHIFT&&!(t&UNSIGNED)){
+	    do_byte4(f,"sta",&p->z,t);
+	    if(r!=REGDUMMY2){
+	      emit(f,"\tlda\t%s\n",mregnames[r]);
+	      do_byte3(f,"sta",&p->z,t);
+	      emit(f,"\tlda\t%s\n",mregnames[r2]);
+	      store_hibyte(f,&p->z,t);
+	      emit(f,"\tlda\t%s\n",mregnames[r3]);
+	      store_lobyte(f,&p->z,t);
+	    }
+	  }else{
+	    store_lobyte(f,&p->z,t);
+	    if(r!=REGDUMMY1){
+	      emit(f,"\tlda\t%s\n",mregnames[r]);
+	      store_hibyte(f,&p->z,t);
+	      emit(f,"\tlda\t%s\n",mregnames[r2]);
+	      do_byte3(f,"sta",&p->z,t);
+	      emit(f,"\tlda\t%s\n",mregnames[r3]);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	  }
+	}else{
+	  if(!ISCHAR(t)&&(m>0||loop))
+	    emit(f,"\tldx\t%s\n",mregnames[r]);
+	  if(ISCHAR(t)||indirect(&p->z))
+	    store_acc(f,&p->z,t);
+	  else{
+	    store_lobyte(f,&p->z,t);
+	    if(!isreg(z)||p->z.reg!=rax){
+	      emit(f,"\tstx\t");
+	      emit_hibyte(f,&p->z,t);
+	      emit(f,"\n");
+	    }
+	  }
+	}
+	continue;
+      }
+
+      if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP){
+	char *s;int t2=t,pt=p->typf2;
+	if(!isacc(z)){
+	  /* TODO: check other operations */
+	  if((c==ADD||c==SUB||c==AND||c==XOR||c==OR||c==ADDI2P||c==SUBIFP)&&isacc(q1)&&scratch(p->next,ra,1))
+	    ;
+	  else{
+	    if((c==ADDI2P||c==SUBIFP)&&(p->typf2&NU)==CHAR)
+	      get_acc(f,p,INT);
+	    else
+	      get_acc(f,p,CHAR);
+	  }
+	}
+	if(c==ADDI2P||c==SUBIFP){
+	  if(c==ADDI2P) c=ADD; else c=SUB;
+	  t=UNSIGNED|INT;
+	  if((pt&NQ)==POINTER&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q1.val,POINTER);
+	    insert_const(&p->q1.val,UNSIGNED|INT);
+	  }
+	}
+	if(c>=OR&&c<=AND)
+	  s=logicals[c-OR];
+	else
+	  s=arithmetics[c-LSHIFT];
+      
+	if(ISFLOAT(t)){
+	  if(!ieee) ierror(0);
+	  t&=NQ;
+	  if(regs[LAST_PAIR]) ierror(0);
+	  get_acc(f,p,INT);
+	  regs[LAST_PAIR]=1;
+	  load_address(f,LAST_PAIR,&p->q1,t);
+	  BSET(regused,t3);
+	  BSET(regused,t4);
+	  emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->q2,t);
+	  emit(f,"\tjsr\t%s__f%s%c\n",idprefix,ename[c],(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->z,t);
+	  emit(f,"\tjsr\t%s__fstore%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  regs[LAST_PAIR]=0;
+	  continue;
+	}else if(ISLONG(t)){
+	  long l;int cnst=0;
+	  if(c==ADD) emit(f,"\tclc\n");
+	  if(c==SUB) emit(f,"\tsec\n");
+	  if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q2.val,t);
+	    l=zm2l(vmax);
+	    cnst=1;
+	  }
+	  if(cnst&&c==AND&&(l&0xff)==0) emit(f,"\tlda\t#0\n");
+	  else if(cnst&&c==OR&&(l&0xff)==0xff) emit(f,"\tlda\t#255\n");
+	  else{
+	    load_lobyte(f,&p->q1,t);
+	    if(!(cnst&&((c==AND&&(l&0xff)==0xff)||(c==OR&&(l&0xff)==0)||(c==XOR&&(l&0xff)==0)))) do_lobyte(f,s,&p->q2,t);
+	  }
+	  store_lobyte(f,&p->z,t);
+	  if(cnst&&c==AND&&(l&0xff00)==0) emit(f,"\tlda\t#0\n");
+	  else if(cnst&&c==OR&&(l&0xff00)==0xff00) emit(f,"\tlda\t#255\n");
+	  else{
+	    load_hibyte(f,&p->q1,t);
+	    if(!(cnst&&((c==AND&&(l&0xff00)==0xff00)||(c==OR&&(l&0xff00)==0)||(c==XOR&&(l&0xff00)==0)))) do_hibyte(f,s,&p->q2,t);
+	  }
+	  store_hibyte(f,&p->z,t);
+	  if(cnst&&c==AND&&(l&0xff0000)==0) emit(f,"\tlda\t#0\n");
+	  else if(cnst&&c==OR&&(l&0xff0000)==0xff0000) emit(f,"\tlda\t#255\n");
+	  else{
+	    do_byte3(f,"lda",&p->q1,t);
+	    if(!(cnst&&((c==AND&&(l&0xff0000)==0xff0000)||(c==OR&&(l&0xff0000)==0)||(c==XOR&&(l&0xff0000)==0)))) do_byte3(f,s,&p->q2,t);
+	  }
+	  do_byte3(f,"sta",&p->z,t);
+	  if(cnst&&c==AND&&(l&0xff000000)==0) emit(f,"\tlda\t#0\n");
+	  else if(cnst&&c==OR&&(l&0xff000000)==0xff000000) emit(f,"\tlda\t#255\n");
+	  else{
+	    do_byte4(f,"lda",&p->q1,t);
+	    if(!(cnst&&((c==AND&&(l&0xff000000)==0xff000000)||(c==OR&&(l&0xff000000)==0)||(c==XOR&&(l&0xff000000)==0)))) do_byte4(f,s,&p->q2,t);
+	  }
+	  do_byte4(f,"sta",&p->z,t);
+	  continue;
+	}else if(ISCHAR(t)){
+	  load_acc(f,&p->q1,t);
+	  if(c02&&(c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q2.val,t);
+	    if(zmeqto(vmax,Z1)||zmeqto(vmax,l2zm(2L))){
+	      if(zmeqto(vmax,l2zm(2L)))
+		emit(f,"\t%s\n",c==ADD?"ina":"dea");
+	      emit(f,"\t%s\n",c==ADD?"ina":"dea");
+	      store_acc(f,&p->z,t);
+	      continue;
+	    }
+	  }
+	  if(c==ADD) emit(f,"\tclc\n");
+	  if(c==SUB) emit(f,"\tsec\n");
+	  if(isreg(q2)&&ISIDX(p->q2.reg)){
+	    int r=get_reg(f,p,CHAR);
+	    emit(f,"\tst%s\t%s\n",mregnames[p->q2.reg],mregnames[r]);
+	    p->q2.flags=REG;
+	    p->q2.reg=r;
+	  }
+	  do_lobyte(f,s,&p->q2,t);
+	  store_acc(f,&p->z,t);
+	}else if(c==ADD||c==SUB){
+	  int a,r;long l=1;
+	  if(isconst(q2)){
+	    eval_const(&p->q2.val,t2);
+	    l=zm2l(vmax);
+	    if(isacc(z)&&(l&0xffff)<=768){
+	      load_acc(f,&p->q1,t);
+	      if(c==ADD){
+		if(l&0xff)
+		  emit(f,"\tclc\n\tadc\t#%d\n",(int)(l&255));
+		l&=0xffff;
+		if(l==256){emit(f,"\tinx\n");continue;}
+		if(l==512){emit(f,"\tinx\n\tinx\n");continue;}
+		if(l==768){emit(f,"\tinx\n\tinx\n\tinx\n");continue;}
+		if(l<256){++label;emit(f,"\tbcc\t%s%d\n\tinx\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+		if(l<512){++label;emit(f,"\tinx\n\tbcc\t%s%d\n\tinx\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+		if(l<768){++label;emit(f,"\tinx\n\tinx\n\tbcc\t%s%d\n\tinx\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+	      }else{
+		if(l&0xff)
+		  emit(f,"\tsec\n\tsbc\t#%d\n",(int)(l&255));
+		l&=0xffff;
+		if(l==256){emit(f,"\tdex\n");continue;}
+		if(l==512){emit(f,"\tdex\n\tdex\n");continue;}
+		if(l==768){emit(f,"\tdex\n\tdex\n\tdex\n");continue;}
+		if(l<256){++label;emit(f,"\tbcs\t%s%d\n\tdex\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+		if(l<512){++label;emit(f,"\tdex\n\tbcs\t%s%d\n\tdex\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+		if(l<768){++label;emit(f,"\tdex\n\tdex\n\tbcs\t%s%d\n\tdex\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+	      }
+	    }
+	    l&=0xff00;
+	  }
+	  if(isreg(z)&&p->z.reg==rax) a=1; else a=0;
+	  if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+	    get_acc(f,p,INT);
+	    emit(f,"\tldx\t#0\n");
+	    load_lobyte(f,&p->q2,t);
+	    emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(c==ADD){
+	      if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+	      do_lobyte(f,s,&p->q1,t);
+	      if(isacc(z))
+		emit(f,"\tpha\n");
+	      else
+		store_lobyte(f,&p->z,t);
+	      emit(f,"\ttxa\n");
+	      do_hibyte(f,s,&p->q1,t);
+	      store_hibyte(f,&p->z,t);
+	      if(ISFPOINTER(pt)&&!compare_objects(&p->q1,&p->z)){
+		do_byte3(f,"lda",&p->q1,pt);
+		do_byte3(f,"sta",&p->z,pt);
+	      }
+	      if(isacc(z))
+		emit(f,"\tpla\n");
+	      continue;
+	    }
+	    r=get_reg(f,p,CHAR);
+	    emit(f,"\tstx\t%s\n",mregnames[r]);
+	  }
+	  load_lobyte(f,&p->q1,t);
+	  if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+	  do_lobyte(f,s,&p->q2,t2);
+	  store_lobyte(f,&p->z,t);
+	  if(l==0&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+	    if(c==ADD){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	      if(a)
+		emit(f,"\tinx\n");
+	      else{
+		/*if(!reg_pair(p->z.reg,&rp)) ierror(0);*/
+		emit(f,"\tinc\t%s+1\n",mregnames[p->z.reg]);
+	      }
+	    }else{
+	      emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	      if(a)
+		emit(f,"\tdex\n");
+	      else{
+		if(!reg_pair(p->z.reg,&rp)) ierror(0);
+		emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+	      }
+	    }
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }else{
+	    if(a==1) emit(f,"\tpha\n");
+	    if((t2&NQ)==CHAR){
+	      if(t2&UNSIGNED){
+		load_hibyte(f,&p->q1,t);
+		emit(f,"\t%s\t#0\n",s);
+	      }else{
+		load_hibyte(f,&p->q1,t);
+		if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+		  eval_const(&p->q2.val,t2);
+		  if(zmleq(Z0,vmax))
+		    emit(f,"\t%s\t#0\n",s);
+		  else
+		    emit(f,"\t%s\t#255\n",s);
+		}else{
+		  emit(f,"\t%s\t%s\n",s,mregnames[r]);
+		}
+	      }
+	    }else{
+	      load_hibyte(f,&p->q1,t);
+	      do_hibyte(f,s,&p->q2,t2);
+	    }
+	    store_hibyte(f,&p->z,t);
+	    if(a==1) emit(f,"\tpla\n");
+	    if(ISFPOINTER(pt)&&p->code!=SUBPFP){
+	      if(!compare_objects(&p->q1,&p->z)){
+		do_byte3(f,"lda",&p->q1,FPOINTER);
+		do_byte3(f,"sta",&p->z,FPOINTER);
+	      }
+	    }
+	  }
+	}else{
+	  long l=-1;int dello=0;
+	  if(c!=AND&&c!=OR&&c!=XOR) ierror(0);
+	  if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q2.val,t);
+	    l=zm2l(vmax)&0xffff;
+	  }
+	  if(l>0&&((c==AND&&(l&0xFF)==0)||(c==OR&&(l&0xFF)==0xFF))){
+	    dello=1;
+	  }else if(l>0&&((c==AND&&(l&0xFF)==0xFF)||((c==OR||c==XOR)&&(l&0xFF)==0))){
+	    if(!compare_objects(&p->q1,&p->z)){
+	      load_lobyte(f,&p->q1,t);
+	      store_lobyte(f,&p->z,t);
+	    }
+	  }else{
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,s,&p->q2,t);
+	    store_lobyte(f,&p->z,t);
+	  }
+	  if(l>0&&((c==AND&&(l&0xFF00)==0)||(c==OR&&(l&0xFF00)==0xFF00))){
+	    int val=(c==AND)?0:255;
+	    if(isacc(z)){
+	      emit(f,"\tldx\t#%d\n",val);
+	    }else{
+	      emit(f,"\tlda\t#%d\n",val);
+	      store_hibyte(f,&p->z,t);
+	    }
+	  }else if(l>0&&((c==AND&&(l&0xFF00)==0xFF00)||((c==OR||c==XOR)&&(l&0xFF00)==0))){
+	    if(isacc(z)&&!indirect(&p->q1)){
+	      do_hibyte(f,"ldx",&p->q1,t);
+	    }else{
+	      if(!compare_objects(&p->q1,&p->z)){
+		if(!dello&&isacc(z))
+		  emit(f,"\tpha\n");
+		load_hibyte(f,&p->q1,t);
+		store_hibyte(f,&p->z,t);
+		if(!dello&&isacc(z))
+		  emit(f,"\tpla\n");
+	      }
+	    }
+	  }else{
+	    if(!dello&&isacc(z))
+	      emit(f,"\tpha\n");
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,s,&p->q2,t);
+	    store_hibyte(f,&p->z,t);
+	    if(!dello&&isacc(z))
+	      emit(f,"\tpla\n");
+	  }
+	  if(dello){
+	    emit(f,"\tlda\t#%d\n",(c==AND)?0:255);
+	    store_lobyte(f,&p->z,t);
+	  }
+	}
+	continue;
+      }
+      pric2(stdout,p);
+      ierror(0);
+    }
+
+    function_bottom(f,v,localsize);
+    
+    for(c=1;c<=MAXR;c++){
+      if(regsa[c]||regused[c]){
+	BSET(regs_modified,c);
+      }
+    }
+
+    if(stack_valid){
+      if(!v->fi) v->fi=new_fi();
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=stack;
+    }
+  }
+
+  free_IC(mi);
+
+  emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  if(code==COMPARE||code==MULT||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT||code==MINUS||code==KOMPLEMENT||code==NEGATION)
+    return 1;
+
+  return 0;
+}
+
+static int fattr(type *p,char *s)
+{
+  if(p->attr&&strstr(p->attr,s))
+    return 1;
+  if(p->next)
+    return fattr(p->next,s);
+  else
+    return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+
+  if(vararg)
+    return 0;
+  f=t->flags&NQ;
+  if(OLDFP&&ISFLOAT(f)) return 0;
+  if(d&&fattr(d,"__stackparms__"))
+    return 0;
+  if(d&&fattr(d,"__cc65__")){
+    m->regs++;
+    printf("arg=%d cnt=%d\n",m->regs,d->exact->count);
+    if(m->regs==d->exact->count-1){
+      if(ISCHAR(t->flags))
+	return ra;
+      if(ISSHORT(t->flags))
+	return rax;
+    }
+    return 0;
+  }
+  if(ISCHAR(f)){
+    if(!t->exact){
+      if(m->regs>=GPR_ARGS-1)
+	return 0;
+      f=FIRST_GPR+m->regs;
+      m->regs+=2;
+      return f;
+    }else{
+      if(m->regs>=GPR_ARGS)
+	return 0;
+      else
+	return FIRST_GPR+m->regs++;
+    }
+  }
+  if(ISSHORT(f)||f==POINTER){
+    if(m->regs>=GPR_ARGS-1)
+      return 0;
+    else{
+      if(m->regs&1) m->regs+=1;
+      m->regs+=2;
+      return FIRST_PAIR+m->regs/2-1;
+    }
+  }
+  if(f==FPOINTER||f==LONG||f==FLOAT||(!ieee&&(f==DOUBLE||f==LDOUBLE))){
+    if(m->bregs>=4)
+      return 0;
+    else
+      return FIRST_BIG+m->bregs++;
+  }
+  if(f==LLONG||(ieee&&(f==DOUBLE||f==LDOUBLE))){
+    if(m->bregs>=3)
+      return 0;
+    else{
+      if(m->bregs&1)  m->bregs++;
+      m->bregs+=2;
+      return FIRST_BIGP+m->bregs/2-1;
+    }
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+  static char sec[SECLEN];
+  int i;
+  if(sscanf(s,"section %127s",sec)==1){
+    if(!strcmp(sec,"default"))
+      use_sec=0;
+    else
+      use_sec=sec;
+    return 1;
+  }
+  if(sscanf(s,"bank %d",&i)==1){
+    use_bank=i;
+    return 1;
+  }
+}
+void cleanup_cg(FILE *f)
+{
+  int i;
+  struct fpconstlist *p=firstfpc;
+
+  if(f&&p){
+    emit(f,rodataname);emit(f,"\n");
+    section=RODATA;
+  }
+  while(p=firstfpc){
+    emit(f,"%s%d:\n\tword\t",labprefix,p->label);
+    if(ieee)
+      emit_ieee(f,&p->val,p->t);
+    else{
+      int words=zm2l(sizetab[p->t&NQ])/2;
+      eval_const(&p->val,p->t);
+      if(ISFLOAT(p->t)) cnv_fp();
+      for(i=0;i<words;i++){
+	emit(f,"%ld",zm2l(vmax)&0xffff);
+	if(i<words-1){emit(f,",");vmax=zmrshift(vmax,l2zm(16L));}
+      }
+      emit(f,"\n");
+      /*emit(f,"%ld,%ld\n",zm2l(vmax)&0xffff,zm2l(zmrshift(vmax,l2zm(16L)))&0xffff);*/
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+
+  emit(f,"\tzpage\t%s\n",mregnames[sp]);
+  for(i=FIRST_GPR;i<=LAST_GPR;i++)
+    emit(f,"\tzpage\t%s\n",mregnames[i]);
+  for(i=FIRST_BIG;i<=LAST_BIG;i++)
+    emit(f,"\tzpage\t%s\n",mregnames[i]);
+
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
+static char *zops[]={
+  "adc","and","asl","bit","eor","lda","ora",
+  "tax","txa","tay","tya","sbc"};
+
+static int setszflag(char *op)
+{
+  int i;
+  for(i=0;i<sizeof(zops)/sizeof(zops[0]);i++)
+    if(!strcmp(op,zops[i]))
+      return 1;
+  return 0;
+}
+
+static char *zxops[]={
+  "tax","txa","ldx","inx","dex"};
+
+static int setszxflag(char *op)
+{
+  int i;
+  for(i=0;i<sizeof(zxops)/sizeof(zxops[0]);i++)
+    if(!strcmp(op,zxops[i]))
+      return 1;
+  return 0;
+}
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+
+
+int emit_peephole(void)
+{
+  int entries,i,j;
+  char *asmline[EMIT_BUF_DEPTH];
+  char buf1[1024],buf2[1024];
+  char op1[8],op2[8];
+  static char ca[1024],cx[1024],cy[1024],cz[1024];
+  static int rm,disabled;
+
+  static struct peeps elim[]={
+    "lda","sta",0,NEEDSAME,
+    "ldx","stx",0,NEEDSAME,
+    "ldy","sty",0,NEEDSAME,
+    "ldz","stz",0,NEEDSAME,
+    "ldq","stq",0,NEEDSAME,
+    "sta","sta",0,NEEDSAME,
+    "stx","stx",0,NEEDSAME,
+    "sty","sty",0,NEEDSAME,
+    "stz","stz",0,NEEDSAME,
+    "stq","stq",0,NEEDSAME,
+    "sta","lda",0,NEEDSAME,
+    "stx","ldx",0,NEEDSAME,
+    "sty","ldy",0,NEEDSAME,
+    "stz","ldz",0,NEEDSAME,
+    "stq","ldq",0,NEEDSAME,
+    "txa","tax",0,0,
+    "tax","txa",0,0,
+    "tay","tya",0,0,
+    "tya","tay",0,0,
+    "tza","taz",0,0,
+    "taz","tza",0,0,
+    "lda","lda",0,REMOVE1ST,
+    "ldx","ldx",0,REMOVE1ST,
+    "ldy","ldy",0,REMOVE1ST,
+    "ldz","ldz",0,REMOVE1ST,
+    "ldq","ldq",0,REMOVE1ST,
+    "lda","ldq",0,REMOVE1ST,
+    "ldx","ldq",0,REMOVE1ST,
+    "ldy","ldq",0,REMOVE1ST,
+    "lda","pla",0,REMOVE1ST,
+    "ldx","plx",0,REMOVE1ST,
+    "ldy","ply",0,REMOVE1ST,
+    "ldz","plz",0,REMOVE1ST,
+    "lda","txa",0,REMOVE1ST,
+    "lda","tya",0,REMOVE1ST,
+    "lda","tza",0,REMOVE1ST,
+    "ldx","tax",0,REMOVE1ST,
+    "ldy","tay",0,REMOVE1ST,
+    "ldz","taz",0,REMOVE1ST,
+    "tay","ldy",0,REMOVE1ST,
+    "tax","ldx",0,REMOVE1ST,
+    "taz","ldz",0,REMOVE1ST,
+    "txa","lda",0,REMOVE1ST,
+    "tya","lda",0,REMOVE1ST,
+    "tza","lda",0,REMOVE1ST,
+    "lda","ldx","\ttax\n",NEEDSAME,
+    "lda","ldy","\ttay\n",NEEDSAME,
+    "lda","ldz","\ttaz\n",NEEDSAME,
+    "ldx","lda","\ttxa\n",NEEDSAME,
+    "ldy","lda","\ttya\n",NEEDSAME,
+    "ldz","lda","\ttza\n",NEEDSAME,
+    "sta","ldx","\ttax\n",NEEDSAME,
+    "sta","ldy","\ttay\n",NEEDSAME,
+    "sta","ldz","\ttaz\n",NEEDSAME,
+    "stx","lda","\ttxa\n",NEEDSAME,
+    "sty","lda","\ttya\n",NEEDSAME,
+    "stz","lda","\ttza\n",NEEDSAME, /* must be last */
+  };
+
+  if(nopeep) return 0;
+
+  /* activate optimization that is not valid for c02 */
+  if(!ce02) elim[sizeof(elim)/sizeof(elim[0])-1].r="\tlda\t#0\n";
+
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+
+  if(!strcmp(asmline[0],";startinline\n")) disabled=1;
+  if(!strcmp(asmline[0],";endinline\n")) disabled=0;
+  if(disabled) return 0;
+
+  buf1[0]=0;op1[0]=0;
+  if((j=sscanf(asmline[0]," %6s %999s",op1,buf1))>=1){
+    /*printf("a=%s x=%s y=%s z=%s\n",ca,cx,cy,cz);
+      printf("\t\t%s %s\n",op1,buf1);*/
+    if(!strcmp(op1,"lda")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,ca)){remove_asm();return rm=1;}
+	if(!rm&&!strcmp(buf1,cx)){strcpy(asmline[0],"\ttxa\n");return rm=1;}
+	if(!rm&&!strcmp(buf1,cy)){strcpy(asmline[0],"\ttya\n");return rm=1;}
+	if(!rm&&!strcmp(buf1,cz)){strcpy(asmline[0],"\ttza\n");return rm=1;}
+	strcpy(ca,buf1);
+      }else ca[0]=0;
+    }else if(!strcmp(op1,"ldx")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cx)){remove_asm();return rm=1;}
+	if(!rm&&!strcmp(buf1,ca)){strcpy(asmline[0],"\ttax\n");return rm=1;}
+	strcpy(cx,buf1);
+      }else cx[0]=0;
+    }else if(!strcmp(op1,"ldy")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cy)){remove_asm();return rm=1;}
+	if(!rm&&!strcmp(buf1,ca)){strcpy(asmline[0],"\ttay\n");return rm=1;}
+	strcpy(cy,buf1);
+      }else cy[0]=0;
+    }else if(!strcmp(op1,"ldz")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cz)){remove_asm();return rm=1;}
+	if(!rm&&!strcmp(buf1,ca)){strcpy(asmline[0],"\ttaz\n");return rm=1;}
+	strcpy(cz,buf1);
+      }else cz[0]=0;
+    }else{
+      static char clobbernone[]="asw bit clc cld cli clv cmp cpx cpy dec deq dew inc inq inw nop pha php phw phz plp sec sed sei sta stq stx sty";
+      static char clobbera[]="adc and asl asr eor lsr ora pla rol ror sbc txa tya tza";
+      static char clobberx[]="dex inx tax tsx";
+      static char clobbery[]="dey iny tay";
+      static char clobberz[]="dez inz taz";
+      if(strstr(clobbernone,op1)){
+      }else if(strstr(clobbera,op1))
+	ca[0]=0;
+      else if(strstr(clobberx,op1))
+	cx[0]=0;
+      else if(strstr(clobbery,op1))
+	cy[0]=0;
+      else if(strstr(clobberz,op1))
+	cz[0]=0;
+      else
+	ca[0]=cx[0]=cy[0]=cz[0]=0;
+    }
+  }else{
+    ca[0]=cx[0]=cy[0]=cz[0]=0;
+  }
+
+  rm=0;
+
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"and")&&!strcmp(buf1,"#0")){
+    strcpy(asmline[0],"\tlda\t#0\n");
+    return rm=1;
+  }
+
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+
+
+    if(!strcmp(asmline[0],"; volatile barrier\n")&&!strcmp(asmline[0],asmline[1])){
+      remove_asm();
+      return rm=1;
+    }
+
+    if(sscanf(asmline[0]," %6s",op1)==1&&!strcmp(op1,"rts")&&
+       sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&!strcmp(op2,"jsr")){
+      sprintf(asmline[1],"\tjmp\t%s\n",buf2);
+      remove_asm();
+      return rm=1;
+    }
+
+    for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+      if(elim[j].flags&NEEDSAME){
+	if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+	   sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+	   !strcmp(buf1,buf2)){
+	  if(elim[j].r){
+	    strcpy(asmline[0],elim[j].r);
+	  }else{
+	    if(elim[j].flags&REMOVE1ST)
+	      strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	  }
+	  return rm=1;
+	}
+      }else{
+	if(sscanf(asmline[1]," %6s",op1)==1&&
+	   sscanf(asmline[0]," %6s",op2)==1&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+	  if(elim[j].flags&REMOVE1ST)
+	    strcpy(asmline[1],asmline[0]);
+	  remove_asm();
+	  return rm=1;
+	}
+      }
+    }
+
+
+  }
+
+  if(entries>=3){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[2]=emit_buffer[i];
+    if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+#if 0
+      if(!strcmp(op1,"lda")&&buf1[0]=='#'){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"sta")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)==2&&
+	     !strcmp(op2,"lda")&&!strcmp(buf1,buf2)){
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+#endif
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"cmp")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s",op2)==1&&
+	     setszflag(op2)){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"cpx")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s",op2)==1&&
+	     setszxflag(op2)){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+    }
+  }
+  if(entries>=4){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[3]=emit_buffer[i];
+  }
+  if(entries>=5){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[4]=emit_buffer[i];
+    if(sscanf(asmline[0]," %s %s",op1,buf1)>=1){
+      if(!strcmp(op1,"lda")||!strcmp(op1,"pla")||!strcmp(op1,"txa")||!strcmp(op1,"tya")){
+	if(sscanf(asmline[1]," %s %s",op1,buf1)>=1&&!strcmp(op1,"pla")&&
+	   sscanf(asmline[2]," %s %s",op1,buf1)>=1&&!strcmp(op1,"tay")&&
+	   sscanf(asmline[3]," %s %s",op1,buf1)>=1&&!strcmp(op1,"txa")&&
+	   sscanf(asmline[4]," %s %s",op1,buf1)>=1&&!strcmp(op1,"pha")){
+	  strcpy(asmline[4],asmline[3]);
+	  strcpy(asmline[3],asmline[2]);
+	  strcpy(asmline[2],asmline[0]);
+	  remove_asm();
+	  remove_asm();
+	  return rm=1;
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||(ISFLOAT(t)&&!ieee)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(ISSHORT(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+      return 0;
+    if(ISLONG(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+      return 0;
+
+    if(!ieee&&ISFLOAT(t)) t=FLOAT;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(!ieee&&ISFLOAT(t2)) t2=FLOAT;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if(c==MULT&&(t&NQ)==CHAR&&!m65) return "__mulint8";
+    if((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==LONG||(t&NQ)==LLONG||(!ieee&&ISFLOAT(t))){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+	if(m65&&ISLONG(t)&&(c==MULT||(c==DIV&&!divbug&&(t&UNSIGNED)))) return 0;
+	if(m65&&c==MULT&&ISSHORT(t)) return 0;
+        if(t==(UNSIGNED|LLONG)&&(c==MULT||c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint64",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+        }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint32",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LONG){
+          sprintf(fname,"__%sint32",ename[c]);
+          ret=fname;
+        }else if(t==(UNSIGNED|INT)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint16",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==INT){
+          sprintf(fname,"__%sint16",ename[c]);
+          ret=fname;
+        }else{
+          sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+        }
+      }
+    }
+  }
+
+  if(ret&&divbug&&(c==DIV||c==MOD)&&!ISFLOAT(t)) strcat(ret,"wo");
+
+  return ret;
+}
+
+
+int pointer_varadr(Var *v)
+{
+  int b=bank(v);
+  if(b>=0&&b!=bankcnum&&!NOBANKVARS){
+    if(cur_funcv&&bank(cur_funcv)!=b)
+      return FPOINTER;
+  }
+  return pointer_type(v->vtyp);
+}
+
+int pointer_type(struct Typ *p)
+{
+  struct Typ *merk=p;
+  if(!p) ierror(0);
+  if(LARGE) return FPOINTER;
+  while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+  if(p->attr){
+    char *s;
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return POINTER;
+  }
+  return POINTER;
+}
+
+unsigned char cbmconv(unsigned char x)
+{
+  static unsigned char ctab[256]={
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+    0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0xBF,0x5D,0x5E,0xA4,
+    0xAD,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB3,0xDD,0xAB,0xB1,0xDF,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0x5F,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0x7D,0xAC,0x60,0xAE,0xAF,
+    0xB0,0x7E,0xB2,0x7B,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0x5C,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0xDC,0x7C,0xDE,0x7F,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+  };
+
+  static unsigned char atab[]={0xfd,8,0x7f,0x9b,11,0x7d};
+
+  if(cbmascii)
+    return ctab[x&255];
+  else if(atascii&&x>=7&&x<=12)
+    return atab[x-7];
+  else
+    return x;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+/*  *p = (union atyps) 0 ; /* rfi: clear unused bits */
+  t&=NU;
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==POINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==POINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==POINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==POINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+        if(strstr(attr,STR_NEAR))
+          p->flags=((p->flags&~NU)|POINTER);
+        if(strstr(attr,STR_FAR))
+          p->flags=((p->flags&~NU)|FPOINTER);
+        if(strstr(attr,STR_HUGE))
+          p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    p=p->next;
+  }
+}
+
+void add_var_hook_post(Var *v)
+{
+  if(use_sec&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+    char buf[SECLEN+32];
+    sprintf(buf,"section(\"%s\");",use_sec);
+    add_attr(&v->vattr,buf);
+  }
+  if(use_bank>=0&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+    char buf[64];
+    /*sprintf(buf,"section(\"bank%d\");bank(%d)",use_bank,use_bank);*/
+    sprintf(buf,"bank(%d)",use_bank);
+    add_attr(&v->vattr,buf);
+  }
+}
+
+int decide_reverse(zmax v)
+{
+  if(zmeqto(v,Z1)||zmeqto(v,l2zm(2L)))
+    return 1;
+  if(optspeed)
+    if(zmeqto(v,l2zm(4L))||zmeqto(v,l2zm(8L))||zmeqto(v,l2zm(256L))||zmeqto(v,l2zm(512L)))
+      return 1;
+  
+  return 0;
+}
+
+static int is_single_eff_ic(struct IC *p)
+{
+  struct Var *v,*idx;
+  if(p->code!=ADDI2P||(p->typf2&NQ)!=POINTER)
+    return 0;
+  if(!(p->q2.flags&KONST)){
+    if((p->typf&NU)!=(UNSIGNED|CHAR))
+      return 0;
+    if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+      return 0;
+    if(p->q2.v->storage_class!=AUTO&&p->q2.v->storage_class!=REGISTER)
+      return 0;
+    idx=p->q2.v;
+  }else{
+    idx=0;
+    eval_const(&p->q2.val,p->typf);
+    /* TODO: more precise check considering data type useful? */
+    if(!zmleq(vumax,l2zm(255L)))
+      return 0;
+    return 1;
+  }
+  if(p->q1.flags&DREFOBJ)
+    return 0;
+  if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+    return 0;
+  v=p->z.v;
+  for(p=p->next;p;p=p->next){
+    int c=p->code;
+    if(c==LABEL||(c>=BEQ&&c<=BRA))
+      return 1; /* TODO: how elaborate should we test? */
+    if((p->q1.flags&VAR)&&p->q1.v==v){
+      if(p->q1.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==v){
+      if(p->q2.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->z.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==idx)
+      return 0;
+  }
+  return 0;
+}
+
+void mark_eff_ics(void)
+{
+  struct IC *p;
+  for(p=first_ic;p;p=p->next){
+    if(is_single_eff_ic(p))
+      p->flags|=EFF_IC;
+    else
+      p->flags&=~EFF_IC;
+  }
+}
diff --git a/machines/6502/machine.dt b/machines/6502/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/6502/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/6502/machine.h b/machines/6502/machine.h
new file mode 100755
index 0000000..b2c5e45
--- /dev/null
+++ b/machines/6502/machine.h
@@ -0,0 +1,267 @@
+/*  6502 backend for vbcc
+    (c) Volker Barthelmann 2020
+
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 32
+#define NUM_PAIRS (NUM_GPRS/2)
+#define NUM_BIG 4
+#define NUM_BIGP (NUM_BIG/2)
+#define FIXED_SP 1
+
+#include "dt.h"
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define FPOINTER 11
+#define HPOINTER 12
+#define ARRAY 13
+#define STRUCT 14
+#define UNION 15
+#define ENUM 16
+#define FUNKT 17
+#define BOOL 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+
+#define POINTER_TYPE(x) pointer_type(x)
+#define POINTER_VARADR(x) pointer_varadr(x)
+extern int pointer_type();
+extern int pointer_varadr();
+#define ISPOINTER(x) ((x&NQ)>=POINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+
+/* internally used by the backend */
+#define FIRST_GPR 8
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_PAIR (LAST_GPR+1)
+#define LAST_PAIR (FIRST_PAIR+NUM_PAIRS-1)
+#define FIRST_BIG (LAST_PAIR+1)
+#define LAST_BIG (FIRST_BIG+NUM_BIG-1)
+#define FIRST_BIGP (LAST_BIG+1)
+#define LAST_BIGP (FIRST_BIGP+NUM_BIGP-1)
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+  int flags;
+  int base;
+  int idx;
+  long offset;
+  void *v;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR LAST_BIGP
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 30
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P CHAR
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 128
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+  int regs;
+  int bregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 6 //6
+#define cost_load_reg(x,y) 10 //10
+#define cost_save_reg(x,y) 10 //10
+#define cost_pushpop_reg(x) 2 //12
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 8
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we have additional types */
+#define HAVE_EXT_TYPES
+#define HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#define HAVE_REGPAIRS 1
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 0
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 0
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* Use char for return of comparison libcalls */
+#define LIBCALL_CMPTYPE CHAR
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define BESTCOPYT CHAR
+
+#define HAVE_AOS4 1
+
+#define CHARCONV(x) cbmconv(x)
+unsigned char cbmconv(unsigned char);
+
+#define ALLOCVLA_REG FIRST_PAIR
+#define ALLOCVLA_INLINEASM "\tlda\tsp\n"\
+                           "\tsec\n"\
+                           "\tsbc\tr0\n"\
+                           "\tsta\tsp\n"\
+                           "\tlda\tsp+1\n"\
+                           "\tsbc\tr1\n"\
+                           "\tsta\tsp+1\n"\
+                           "\tlda\tsp\n"\
+                           "\tclc\n"\
+                           "\tldx\tsp+1\n"\
+                           "\tadc\t#___fo\n"\
+                           "\tbcc\t*+3\n"\
+                           "\tinx\n"
+
+#define FREEVLA_REG FIRST_PAIR
+#define FREEVLA_INLINEASM "\tlda\tr0\n"\
+                          "\tsta\tsp\n"\
+                          "\tlda\tr1\n"\
+                          "\tsta\tsp+1\n"
+
+#define OLDSPVLA_INLINEASM "\tlda\tsp+1\n"\
+                           "\ttax\n"\
+                           "\tlda\tsp"
+
+#define FPVLA_REG (LAST_PAIR-2)
+
+#define HAVE_TARGET_VARHOOK_POST 1
+
+#define HAVE_DECIDE_REVERSE 1
+
+#define HAVE_TARGET_EFF_IC 1
diff --git a/machines/832/addressingmodes.c b/machines/832/addressingmodes.c
new file mode 100644
index 0000000..6defe37
--- /dev/null
+++ b/machines/832/addressingmodes.c
@@ -0,0 +1,740 @@
+/* search for possible addressing-modes */
+
+/* DONE: Determine whether a given ob is disposable. */
+
+/* ToDo: Look for pairs of ICs with Z set to register,
+   followed by disposable q1 on the same register ->
+   use tmp for that register.  (Provided second IC won't trash tmp)
+   Can we avoid the passing register being allocated? */
+
+/* Look for ways to use ldidx when an IC adds to a pointer and the next one dereferences it */
+
+
+#define DEFERREDPOP_FLOWCONTROL 0
+#define DEFERREDPOP_NESTEDCALLS 1
+#define DEFERREDPOP_OK 2
+
+
+#define AM_DEBUG 0
+
+// If the obj doesn't already have an addressing mode, create one and zero it out.
+static void am_alloc(struct obj *o)
+{
+	if (!o->am) {
+		o->am = mymalloc(sizeof(struct AddressingMode));
+		memset(o->am, 0, sizeof(struct AddressingMode));
+	}
+}
+
+
+void am_deferredpop(struct IC *p)
+{
+	struct IC *p2;
+	int pushed=0;
+	int deferredpop=0;
+	int candefer=0;
+	for(;p;p=p->next)
+	{
+		switch(p->code)
+		{
+			case PUSH:
+				pushed+=pushsize(p);
+//				printf("Pushing %d bytes, %d so far\n",pushsize(p),pushed);
+				break;
+			case CALL:
+//				printf("CALL IC with pushedsize %d\n",pushedargsize(p));
+
+				am_alloc(&p->z);
+
+				/* We detected nested function calls by comparing the amount of data pushed to the 
+				   stack with this call's pushedargsize().  If they don't match we're dealing with
+                   nested calls.  If they do match, we might be able to defer stack popping. */
+				if(pushed==pushedargsize(p))
+				{
+//					printf("Checking for flow change\n");
+					p2=p->next;
+					candefer=1;
+					while(p2)
+					{
+						switch(p2->code)
+						{
+							/* If we encounter LABEL, COMPARE, TEST or a branch operation then program flow changes
+							   before the next PUSH, and we can't defer the stack pop. */
+							case LABEL:
+							case COMPARE:
+							case TEST:
+							case BLT:
+							case BGT:
+							case BLE:
+							case BGE:
+							case BEQ:
+							case BNE:
+							case BRA:
+//								printf("Flow control changed - can't defer\n");
+								p->z.am->deferredpop=DEFERREDPOP_FLOWCONTROL;
+								candefer=0;
+								p2=0;
+								break;
+							/* If we encounter another PUSH operation without a flow control change we can defer */
+							case PUSH:
+//								printf("Can defer stack popping\n");
+								p2=0;
+								break;
+							default:
+								p2=p2->next;
+								break;
+						}
+					}
+				}
+				else /* pushedargsize() and the contents of the stack differed in size - nested calls. */
+				{
+					p->z.am->deferredpop=DEFERREDPOP_NESTEDCALLS;
+//					printf("Nested call - can't defer stack popping\n");
+					candefer=0;
+				}
+
+				if(candefer)
+				{
+					p->z.am->deferredpop=DEFERREDPOP_OK;
+					deferredpop=pushedargsize(p);
+				}
+
+				pushed-=pushedargsize(p);
+				break;
+			default:
+				break;
+		}
+	}
+}
+
+
+static int is_arithmetic_bitwise(int code)
+{
+	switch(code)
+	{
+		case ADD:
+		case ADDI2P:
+		case SUB:
+		case SUBIFP:
+		case MULT:
+		case OR:
+		case XOR:
+		case AND:
+		case LSHIFT:
+		case RSHIFT:
+			return(1);
+			break;
+	}
+	return(0);
+}
+
+
+void am_conversions(struct IC *p)
+{
+	int c;
+	struct IC *p2;
+	struct IC *p3;
+	for (; p; p = p->next) {
+		c = p->code;
+		switch(c)
+		{
+			case BEQ:
+			case BNE:
+			case BLT:
+			case BLE:
+			case BGT:
+			case BGE:
+			case ALLOCREG:
+			case FREEREG:
+			case NOP:
+				break;
+			case CONVERT:
+				printf("(conversion)\n");
+				break;
+
+			default:
+				switch(q1typ(p)&NQ)
+				{
+					case CHAR:
+					case SHORT:
+						printf("IC %d, non-int operation %x, %x\n",c,q1typ(p),ztyp(p));
+					default:
+						break;
+				}
+				break;
+		}
+	}
+}
+
+// Look for 832-specific optimizations
+
+extern zmax sizetab[MAX_TYPE + 1];
+
+void am_simplify(struct IC *p)
+{
+	int c;
+	struct IC *p2;
+	struct IC *p3;
+	struct IC *prev;
+	for (; p; p = p->next) {
+		c = p->code;
+
+		p2=p->next;
+		if(!p2)
+			break;
+		p3=p2->next;
+		if(!p3)
+			break;
+
+		switch(c)
+		{
+			// Check for ADDRESS followed by push - can we merge?
+			case ADDRESS:
+				if((p->z.flags&(REG|DREFOBJ|SCRATCH))!=(REG|SCRATCH))
+					break;
+
+//				printf("Address IC candidate: zreg: %d, z flags %x\n",p->z.reg,p->z.flags);
+
+				while(p3)
+				{
+//					printf(" next op: %x, q1reg: %d, q1flags: %x, q2reg: %d, q2flags: %x\n",
+//						p2->code,p2->q1.reg,p2->q1.flags,p2->q2.reg,p2->q2.flags);
+					switch(p2->code)
+					{
+						case PUSH:
+							if((p2->q1.flags&(REG|DREFOBJ|VARADR))==REG && p2->q1.reg==p->z.reg)
+							{
+//								printf("p3 code: %x, reg: %d\n",p3->code,p3->q1.reg);
+								if(p3->code!=FREEREG || p3->q1.reg!=p->z.reg)
+									break;
+//								printf("Push: merging\n");
+								p->code=NOP;	// Don't prepare the address to a register...
+								p2->q1=p->q1;	// Push it directly.
+								p2->q1.flags|=VARADR;
+								p3=0;
+							}
+							break;
+						case FREEREG:
+							if(p2->q1.reg==p->z.reg)
+							{
+//								printf("Freereg: bailing out\n");
+								p3=0;
+							}
+							break;
+						default:
+							break;
+					}
+					// Does the IC reference the register?
+					if((p2->q1.flags&REG) && p2->q1.reg==p->z.reg)
+						p3=0;
+					else if((p2->q2.flags&REG) && p2->q2.reg==p->z.reg)
+						p3=0;
+					p2=p3;
+					if(p3)
+						p3=p3->next;
+				}
+				break;
+
+			// Check for GETRETURN followed by TEST/COMPARE of call result which is then discarded...
+			case GETRETURN:
+				if((p->z.flags&(REG|DREFOBJ|SCRATCH))!=(REG|SCRATCH))
+					break;
+
+				// FIXME - can do the same for other instructions, provided we don't need to use r0 to derive the second op.
+
+				if(p3->code!=FREEREG || p3->q1.reg!=p->z.reg)
+					break;
+
+				switch(p2->code)
+				{
+					case TEST:
+						if(p2->q1.flags&(REG|DREFOBJ)!=REG || p2->q1.reg!=p->z.reg)
+							break;
+						p->code=NOP;	// Don't bother retrieving the return value...
+						p2->q1.reg=p->q1.reg;	// Test it directly from return register.
+						break;
+					case SETRETURN:
+						if(p2->q1.flags&(REG|DREFOBJ)!=REG || p2->q1.reg!=p->z.reg)
+							break;
+						p->code=NOP;	// Don't bother retrieving the return value...
+						p2->q1.reg=p->q1.reg;
+						break;
+					case COMPARE:
+						if((p2->q1.flags&(REG|DREFOBJ))==REG && p2->q1.reg==p->z.reg)
+						{
+							// Make sure the other op is simple enough not to need r0: FIXME - can we improve this?
+//							if((p2->q2.flags&(REG|DREFOBJ))==REG || p2->q2.flags&KONST)
+//							{
+								// COMPARE is guaranteed not to touch t1 (r0).
+								p->code=NOP;	// Don't bother retrieving the return value...
+								p2->q1.reg=p->q1.reg;	// Test it directly from return register.
+//							}
+						}
+						else if((p2->q2.flags&(REG|DREFOBJ))==REG && p2->q2.reg==p->z.reg)
+						{
+//							if((p2->q1.flags&(REG|DREFOBJ))==REG || p2->q1.flags&KONST)
+//							{
+								// COMPARE is guaranteed not to touch t1 (r0).
+								p->code=NOP;	// Don't bother retrieving the return value...
+								p2->q2.reg=p->q1.reg;	// Test it directly from return register.
+//							}
+						}
+						break;
+				}
+				break;
+
+			// Loads cause automatic zero-extension so can avoid conversion
+			// in that case.  Arithmetic functions may require conversion - with the exception of AND and (unsigned) SHR,
+			// since neither can result in extra set bits in the MSBs.
+			case CONVERT:
+				if(p2->code==CONVERT)
+				{
+//					printf("Found successive Convert ICs\n");
+//					printf("p1: %x, %d, %x -> %x, p2: %x, %d, %x -> %x\n",p->z.flags,p->z.reg,q1typ(p),ztyp(p),
+//						p2->q1.flags,p2->q1.reg,q1typ(p2),ztyp(p2));
+					if((p->z.flags&(REG|DREFOBJ))==REG && ((p2->q1.flags&(REG|DREFOBJ))==REG) && p->z.reg==p2->q1.reg)
+					{
+//						printf("Register match\n");
+						if(((q1typ(p)&NQ)<(ztyp(p)&NQ)) && (q1typ(p)==ztyp(p2)))
+						{
+//							printf("Sizes match - nullifying conversion to wider type.\n");
+							p->code=NOP;
+							p2->q1=p->q1;
+						}
+					}
+				} else {
+					if (AM_DEBUG)
+						printf("Checking conversion from %d to %d, %d to %d\n",q1typ(p),ztyp(p),p->q1.reg,p->z.reg);
+					/* Eliminate conversions to wider types within a single register if the value is unsigned */
+					if((p->z.flags&(REG|DREFOBJ))==REG && ((p->q1.flags&(REG|DREFOBJ))==REG) && p->z.reg==p->q1.reg) {
+						if((q1typ(p)&UNSIGNED) && (sizetab[q1typ(p) & NQ] < sizetab[ztyp(p) & NQ])) {
+							if (AM_DEBUG)
+								printf("Eliminating unnecessary conversion\n");
+							p->code=NOP;
+						}
+					}
+				}
+//				printic(stdout,p);
+				break;
+
+			// Look for situations where an arithmetic operation will have set flags,
+			// rendering an explicit TEST unnecessary.
+			case TEST:
+				prev=p->prev;
+				if(prev)
+				{
+//					printf("TEST found, evaluating previous IC\n");
+					if(is_arithmetic_bitwise(prev->code))
+					{
+//							printf("Arithmetic / bitwise IC found\n");
+//							printf("%x, %d, %x, %d\n",prev->z.flags,prev->z.reg,p->q1.flags,p->q1.reg);
+						if((prev->z.flags&(REG|DREFOBJ))==REG && ((p->q1.flags&(REG|DREFOBJ))==REG) && prev->z.reg==p->q1.reg)
+						{
+//								printf("Register match\n");
+							p->code=NOP;
+						}
+					}
+				}
+				break;
+
+			default:
+				// Look for cases where multiple arithmetic / bitwise instructions are chained and could
+				// avoid writing to an intermediate register...
+				if(is_arithmetic_bitwise(c) && is_arithmetic_bitwise(p2->code) && p3->code==FREEREG)
+				{
+					if (AM_DEBUG)
+						printf("Evaluating pair of arithmetic ops followed by freereg...\n");
+					if(((p->z.flags&(REG|DREFOBJ))==REG) && ((p2->q1.flags&(REG|DREFOBJ))==REG) && ((p2->z.flags&(REG|DREFOBJ))==REG))
+					{
+						if (AM_DEBUG)
+							printf("Ops are all register based...\n");
+						if (AM_DEBUG)
+							printf("p1.q1: %s, p1.q2: %s, p1.z: %s  -  p2.q1: %s, p2.q2: %s, p2.z: %s\n",
+								regnames[p->q1.reg],regnames[p->q2.reg],regnames[p->z.reg],
+								regnames[p2->q1.reg],regnames[p2->q2.reg],regnames[p2->z.reg]);
+						if(p2->q1.reg==p3->q1.reg && p->z.reg==p2->q1.reg && p2->q1.reg!=p2->z.reg && p2->q2.reg!=p2->z.reg)
+						{
+							if (AM_DEBUG)
+								printf("Freereg matches - adjusting\n");
+							p->z.reg=p2->z.reg;
+							p2->q1.reg=p2->z.reg;
+						}
+					}
+					// FIXME - explore the lifetime of the register we've just avoided; can we
+					// avoid allocating / freeing it?  Won't help the code-generator but might be
+					// able to avoid saving / restoring it in the function head / tail.
+				}
+				else
+				{
+					// Look specificially for addt candidates...
+					if(c==ADD || c==ADDI2P)
+					{
+						int zr=(p->z.flags&(REG|DREFOBJ))==REG ? 1 : 0;
+
+//						printf("add %x, %x, %x, %s, %s, %s\n",p->q1.flags,p->q2.flags,p->z.flags,
+//								regnames[p->q1.reg],regnames[p->q2.reg],regnames[p->z.reg]);
+						if((p->q1.flags&(REG|DREFOBJ))==REG)
+						{
+							if(!zr || p->z.reg!=p->q1.reg)
+							{
+								if((p->q2.flags&(REG|DREFOBJ))==REG)  // reg + reg => reg
+								{
+									// All three operands are registers - are they all different?
+									if((zr || p->z.reg!=p->q2.reg) && p->q1.reg!=p->q2.reg)
+									{
+										am_alloc(&p->q1);
+										p->q1.am->type=AM_ADDT;
+										if (AM_DEBUG)
+											printf("Marked addt candidate\n");
+									}
+								}
+								if((p->q2.flags&(KONST|DREFOBJ))==KONST) // reg + const => reg
+								{
+									am_alloc(&p->q1);
+									p->q1.am->type=AM_ADDT;
+									if (AM_DEBUG)
+									{
+										printf("Marked addt candidate\n");
+										printf("Reg + Konst => Reg\n");
+									}
+								}
+							}
+						}
+					}
+				}
+				break;
+		}
+	}
+}
+
+void am_disposable(struct IC *p, struct obj *o)
+{
+	struct IC *p2;
+	int disposable = 0;
+	if (o->flags & REG) {
+		// Cover the case where q1 or q2 are the same register as z.
+		if(o!=&p->z)
+		{
+			// We're writing to the same register as we're reading from - not disposable!
+			if((p->z.flags&REG) && p->z.reg==o->reg)
+				return;
+		}
+		p2 = p->next;
+		while (p2) {
+			if (p2->code == FREEREG && p2->q1.reg == o->reg) {
+				if (AM_DEBUG)
+					printf("\t(%s disposable.)\n", regnames[o->reg]);
+				am_alloc(o);
+				o->am->disposable = 1;
+				return;
+			}
+			if (((p2->q1.flags & REG)
+			     && p2->q1.reg == o->reg)
+			    || ((p2->q2.flags & REG)
+				&& p2->q2.reg == o->reg)
+			    || ((p2->z.flags & REG)
+				&& p2->z.reg == o->reg)) {
+				//Found another instruction referencing reg - not disposable.
+				return;
+			}
+			switch (p2->code) {
+			case CALL:
+			case BEQ:
+			case BNE:
+			case BLT:
+			case BGE:
+			case BLE:
+			case BGT:
+			case BRA:
+				// Control flow changed, erring on the side of safety - not disposable.
+				return;
+				break;
+			default:
+				break;
+			}
+			p2 = p2->next;
+		}
+	}
+}
+
+struct obj *throwaway_reg(struct IC *p,int reg)
+{
+	struct obj *result=0;
+	if (AM_DEBUG)
+		printf("\tChecking IC for reg %s\n", regnames[reg]);
+	if(p) {
+		if((p->q1.flags&REG) && p->q1.reg==reg) {
+			am_disposable(p,&p->q1);
+			if(p->q1.am && p->q1.am->disposable)
+				result=&p->q1;
+		} else if((p->z.flags&REG) && p->z.reg==reg) {
+			am_disposable(p,&p->z);
+			if(p->z.am && p->z.am->disposable)
+				result=&p->z;
+		}
+	}
+	if (AM_DEBUG)
+		printf("\tReturning %x\n", result);
+	return(result);
+}
+
+
+struct IC *am_find_adjustment(struct IC *p, int reg)
+{
+	struct IC *p2 = p->next;
+	// FIXME - limit how many steps we check...
+	/* Look for a post-increment */
+	while (p2) {
+//		printf("\t\tChecking code %d\n",p2->code);
+		if (p2->code == ADDI2P) {
+//			if (AM_DEBUG)
+//				printf("\tFound Addi2p to register %s \n", regnames[p2->z.reg]);
+			if ((p2->q2.flags & KONST) && (p2->z.flags & REG)) {
+				if (p2->z.reg == reg) {
+					if (AM_DEBUG)
+						printf("\t\tAdjusting the correct register - match found\n");
+					break;
+				} else {
+					if(p2 && p2->q1.reg == reg) {	
+						if (AM_DEBUG)
+							printf("\t\tWriting to different reg - is source reg disposable?  ");
+						am_disposable(p2, &p2->q1);
+						if(p2->q1.am && p2->q1.am->disposable){
+							if (AM_DEBUG)
+								printf("yes\n");
+							break;
+						} else {
+							if (AM_DEBUG)
+								printf("no - bailing out\n");
+							p2=0;
+						}
+					} else {
+						if (AM_DEBUG)
+							printf("\t\tWrong register - keep looking\n");
+					}
+				}
+			} else {
+				if (AM_DEBUG)
+					printf("\t\tnot a constant, however - bailing out.\n");
+				p2 = 0;
+			}
+		} else if (((p2->q1.flags & (REG | DREFOBJ)) && p2->q1.reg == reg)
+			   || ((p2->q2.flags & (REG | DREFOBJ))
+			       && p2->q2.reg == reg)
+			   || ((p2->z.flags & (REG | DREFOBJ))
+			       && p2->z.reg == reg)) {
+			if (AM_DEBUG)
+				printf("\t\tFound another instruction referencing reg - bailing out\n");
+			p2 = 0;
+		} else if (p2->code>=BEQ && p2->code<=BRA) {
+			if (AM_DEBUG)
+				printf("\t\tFound a branch instruction - bailing out\n");
+			p2 = 0;
+		} else if (p2->code>=LABEL) {
+			if (AM_DEBUG)
+				printf("\t\tFound a label - bailing out\n");
+			p2 = 0;
+		}
+		if (p2)
+			p2 = p2->next;
+	}
+	if (p2)
+		return (p2);
+	if (AM_DEBUG)
+		printf("\tNo postincrements found - checking for predecrements\n");
+	/* Search for a predecrement */
+	p2 = p->prev;
+	while (p2) {
+		if (p2->code == SUBIFP) {
+			if (AM_DEBUG)
+				printf("\t\tFound subifp to register %s \n", regnames[p2->z.reg]);
+			if ((p2->q2.flags & KONST) && (p2->z.flags & REG)) {
+				if (p2 && p2->z.reg == reg) {
+					if (AM_DEBUG)
+						printf("\t\tAdjusting the correct register - match found\n");
+					break;
+				} else {
+					if(p2 && p2->q1.reg == reg) {	
+						if (AM_DEBUG)
+							printf("\t\tWriting to different reg - is source reg disposable?  ");
+						am_disposable(p2, &p2->q1);
+						if(p2->q1.am && p2->q1.am->disposable){
+							if (AM_DEBUG)
+								printf("yes\n");
+							break;
+						} else {
+							if (AM_DEBUG)
+								printf("no - bailing out\n");
+						}
+					}
+				}
+			} else {
+				if (AM_DEBUG)
+					printf("\t\tnot a constant, however - bailing out.\n");
+				p2 = 0;
+			}
+		} else if (((p2->q1.flags & (REG | DREFOBJ)) && p2->q1.reg == reg)
+			   || ((p2->q2.flags & (REG | DREFOBJ))
+			       && p2->q2.reg == reg)
+			   || ((p2->z.flags & (REG | DREFOBJ))
+			       && p2->z.reg == reg)) {
+			if (AM_DEBUG)
+				printf("\t\tFound another instruction referencing reg - bailing out\n");
+			p2 = 0;
+		}
+		// FIXME - check for control flow changes
+		if (p2)
+			p2 = p2->prev;
+	}
+	return (p2);
+}
+
+// If we have a candidate for pre/post increment/decrement, validate that we can use it,
+// and return the offset.  Zero if we can't use it.
+int am_get_adjvalue(struct IC *p, int type, int target)
+{
+	int offset = p->q2.val.vmax;
+	if (p->code == SUBIFP)
+		offset = -offset;
+	if (AM_DEBUG)
+		printf("Offset is %d, type is %d, writing to target? %s\n", offset, type & NQ, target ? "yes" : "no");
+	// Validate offset against type and CPU's capabilities.
+	switch (type & NQ) {
+	case CHAR:		// We only support postincrement for CHARs
+		if (offset != 1)
+			offset = 0;
+		if (p->code == SUBIFP)
+			offset = 0;
+		break;
+	case INT:
+	case LONG:
+	case POINTER:		// We support post-increment and predecrement for INTs/LONGs/PTRs
+//                      if(target && offset!=-4)        // We only support predec for writing.
+		if (target && ((offset != -4) && (offset != 4)))	// We now support predec and postinc for writing.
+			offset = 0;
+		if (!target && offset != 4)	// We only support postinc for reading
+			offset = 0;
+		if (p->code == ADDI2P && offset != 4)
+			offset = 0;
+		if (p->code == SUBIFP && offset != -4)
+			offset = 0;
+		break;
+	case SHORT:		// We don't support either mode for shorts or anything else.
+	default:
+		offset = 0;
+	}
+	if (AM_DEBUG)
+		printf("Validated offset is %d\n", offset);
+	return (offset);
+}
+
+void am_prepost_incdec(struct IC *p, struct obj *o)
+{
+	struct IC *p2 = 0;
+	int type;
+
+	if (o->flags & (REG) && (o->flags & DREFOBJ)) {
+		if (AM_DEBUG)
+			printf("Dereferencing register %s - searching for adjustments\n", regnames[o->reg]);
+		p2 = am_find_adjustment(p, o->reg);
+
+		if (p2)		// Did we find a candidate for postinc / predec?
+		{
+			int adj;
+			switch (p->code) {
+			case CONVERT:
+				// Are we considering q1 or z?
+				if(o==&p->z)
+					type = p->typf;
+				else
+					type = p->typf2;
+				if (AM_DEBUG)
+					printf("\tConvert operation - type is %d\n", type);
+				break;
+			default:
+				if (AM_DEBUG)
+					printf("\tRegular operation - type is %d\n", p->typf);
+				type = p->typf;
+				break;
+			}
+			adj = am_get_adjvalue(p2, type, o == &p->z);	// Validate the adjustment
+			if (adj) {
+				obj *tempob;
+				switch(p2->code)
+				{
+					case ADDI2P:
+					case SUBIFP:
+						// Are the source and destination regs the same?
+						if(p2->q1.reg==p2->z.reg) {
+							p2->code=NOP; // Nullify the manual adjustment if we can do it as an opcode side-effect
+							break;
+						}
+
+						// Check next IC to see if it's disposable, and referencing the same register:
+						if(tempob=throwaway_reg(p2->next,p2->z.reg)) {
+							if (AM_DEBUG)
+								printf("\tChangingnext IC from reg %s to reg %s\n", regnames[tempob->reg], regnames[p2->q1.reg]);
+							tempob->reg=p2->q1.reg; // Adjust the register referenced in the next IC.
+							p2->code=NOP; // Nullify the adjustment since we've aliased the register
+						}
+						else
+							p2->code=ASSIGN; // Otherwise replace it with an assign if the registers aren't equal.
+						break;
+					default:
+						p2->code = NOP;	// Nullify the manual adjustment if we can do it as an opcode side-effect
+						break;
+				}
+				am_alloc(o);
+				o->am->type = (adj > 0) ? AM_POSTINC : AM_PREDEC;
+			}
+		}
+	}
+}
+
+#define getreg(x) (x.flags&REG ? x.reg : 0)
+
+static void find_addressingmodes(struct IC *p)
+{
+	int c;
+	struct obj *o;
+	struct AddressingMode *am;
+
+	am_deferredpop(p);
+	am_simplify(p);
+//	am_conversions(p);
+
+	for (; p; p = p->next) {
+		c = p->code;
+
+		// Have to make sure that operands are different registers!
+		if ((getreg(p->q1) == getreg(p->q2))
+		    || (getreg(p->q1) == getreg(p->z))) {
+			if (getreg(p->q1))
+				if (AM_DEBUG)
+					printf("Collision between q1 and q2 or z - ignoring\n");
+		} else
+			am_prepost_incdec(p, &p->q1);
+
+		if ((getreg(p->q1) == getreg(p->q2))
+		    || (getreg(p->q2) == getreg(p->z))) {
+			if (getreg(p->q1))
+				if (AM_DEBUG)
+					printf("Collision between q2 and q1 or z - ignoring\n");
+		} else
+			am_prepost_incdec(p, &p->q2);
+
+		if ((getreg(p->q1) == getreg(p->z))
+		    || (getreg(p->q2) == getreg(p->z))) {
+			if (getreg(p->z))
+				if (AM_DEBUG)
+					printf("Collision between z and q1 or q2 - ignoring\n");
+		} else
+			am_prepost_incdec(p, &p->z);
+//		printic(stdout,p);
+
+		am_disposable(p, &p->q1);
+		am_disposable(p, &p->q2);
+		am_disposable(p, &p->z);
+	}
+}
+
diff --git a/machines/832/inlinememcpy.c b/machines/832/inlinememcpy.c
new file mode 100644
index 0000000..aa146f5
--- /dev/null
+++ b/machines/832/inlinememcpy.c
@@ -0,0 +1,262 @@
+/* FIXME - emit a memcpy function with weak linkage if -size is specified */
+
+void emit_inlinememcpy(FILE *f,struct IC *p, int t)
+{
+	int srctype=t;
+	int srcr = t1;
+	int dstr=0;
+	int cntr=0;
+	int savec=1;
+	int saved=0;
+	int wordcopy;
+	int bytecopy;
+	zmax copysize = opsize(p);
+	int unrollwords=0;
+	int unrollbytes=0;
+
+	// Can we create larger code in the interests of speed?  If so, partially unroll the copy.
+	wordcopy = copysize & ~3;
+	bytecopy = copysize - wordcopy;
+
+	if (wordcopy < 32 && !optsize)
+		unrollwords=1;
+	if (bytecopy < 5)
+		unrollbytes=1;
+
+	cleartempobj(f,t1);
+	cleartempobj(f,tmp);
+
+	// Even if a register is available we still have to save it because the current function wouldn't
+	// but the parent function may be using it.  Therefore we might as well use a hardcoded register.
+	dstr=t1+1;
+	if(p->z.flags&(REG|DREFOBJ)==REG)
+		dstr=p->z.reg;
+	// FIXME - check this logic.  If the target is a register, it may not be a scratch register.
+	if(regs[dstr]) // Scratch register - only need to save if it's in use?
+	{
+		saved=1;
+		emit(f,"\tmt\t%s\n",regnames[dstr]);
+		emit(f,"\tstdec\t%s\n",regnames[sp]);
+		pushed+=4;
+	}
+
+	cntr=t1+2;
+	if(cntr==dstr)	/* Use r1 instead of r2 if the dest pointer is in r2 already. */
+		cntr=t1+1;
+	if(cntr==srcr)  /* If cntr && srcr now clash, use r3 instead */
+		cntr=t1+3;
+
+	if((unrollwords && unrollbytes) || regs[cntr]==0)
+		savec=0;
+	else {
+		emit(f,"\tmt\t%s\n",regnames[cntr]);
+		emit(f,"\tstdec\t%s\n",regnames[sp]);
+		pushed+=4;
+	}
+
+	/* Prepare source register */
+	if ((t & NQ) == CHAR && (opsize(p) != 1)) {
+		emit(f, "\t\t\t\t\t// (char with size!=1 -> array of unknown type)\n");
+		srctype = ARRAY;	// FIXME - ugly hack
+	}
+	emit_objtoreg(f, &p->q1, srctype,srcr);
+
+	/* Prepare destination register */
+
+	emit_prepobj(f, &p->z, t, dstr, 0);
+
+	if (p->z.flags & REG) {
+		if(p->z.reg!=dstr) {// Move target register to dstr
+			emit(f, "\tmt\t%s\n", regnames[p->z.reg]);
+			emit(f, "\tmr\t%s\n", regnames[dstr]);
+		}
+	}
+
+	emit(f, "\t\t\t\t\t// Copying %d words and %d bytes to %s\n", wordcopy / 4, bytecopy,
+	     p->z.v ? p->z.v->identifier : "(null)");
+//	printf("memcpy: Copying %d words and %d bytes to %s\n", wordcopy / 4, bytecopy,
+//	     p->z.v ? p->z.v->identifier : "(null)");
+
+//	if(!p->z.v)
+//		printf("No z->v: z flags: %x\n",p->z.flags);
+
+	// Prepare the copy
+	// FIXME - we don't necessarily have a valid z->v!  If not, where does the target come from?
+	// Stack based variable?
+
+	if (unrollwords) {
+		wordcopy >>= 2;
+		if (wordcopy) {
+			emit(f, "\t\t\t\t\t// Copying %d words to %s\n", wordcopy, p->z.v ? p->z.v->identifier : "(null)");
+		}
+		while (wordcopy--) {
+			emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+		}
+	} else if(wordcopy) {
+		emit(f, "\t\t\t\t\t// Copying %d words to %s\n", wordcopy / 4, p->z.v ? p->z.v->identifier : "(null)");
+		// Copy bytes...
+		emit_constanttotemp(f, wordcopy);
+		emit(f, "\taddt\t%s\n", regnames[dstr]);
+		emit(f, "\tmr\t%s\n", regnames[cntr]);
+		emit(f, ".cpy%swordloop%d:\n", p->z.v ? p->z.v->identifier : "null", loopid);
+		emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+		emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+		emit(f, "\tcond\tNEQ\n");
+		emit(f, "\t\t.lipcrel\t.cpy%swordloop%d\n", p->z.v ? p->z.v->identifier : "null", loopid);
+		emit(f, "\t\tadd\t%s\n", regnames[pc]);
+	}
+
+	if (unrollbytes) {
+		if (bytecopy)
+			emit(f, "\t\t\t\t\t// Copying %d byte tail to %s\n", bytecopy,p->z.v ? p->z.v->identifier : "null");
+		while (bytecopy--)
+			emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+	} else if (bytecopy) {
+		emit(f, "\t\t\t\t\t// Copying %d bytes to %s\n", bytecopy, p->z.v ? p->z.v->identifier : "null");
+		// Copy bytes...
+		emit_constanttotemp(f, bytecopy);
+		emit(f, "\taddt\t%s\n", regnames[dstr]);
+		emit(f, "\tmr\t%s\n", regnames[cntr]);
+		emit(f, ".cpy%sloop%d:\n", p->z.v ? p->z.v->identifier : "null", loopid);
+		emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+		emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+		emit(f, "\tcond\tNEQ\n");
+		emit(f, "\t\t.lipcrel\t.cpy%sloop%d\n", p->z.v ? p->z.v->identifier : "null", loopid);
+		emit(f, "\t\tadd\t%s\n", regnames[pc]);
+
+	}
+	// cleanup
+	if(savec) {
+		emit(f,"\tldinc\t%s\n",regnames[sp]);
+		emit(f,"\tmr\t%s\n",regnames[cntr]);
+		pushed-=4;
+	}
+	if(saved) {
+		emit(f,"\tldinc\t%s\n",regnames[sp]);
+		emit(f,"\tmr\t%s\n",regnames[dstr]);
+		pushed-=4;
+	}
+	cleartempobj(f,t1);
+	cleartempobj(f,tmp);
+	loopid++;
+}
+
+
+/* Similar to inlinememcpy, but copies an array or struct to the stack */
+
+void emit_inlinepush(FILE *f,struct IC *p, int t)
+{
+	int srcr = t1;
+	int dstr=0;
+	int cntr=0;
+	int savec=1;
+	int saved=0;
+	int wordcopy;
+	int bytecopy;
+	zmax copysize = opsize(p);
+	int unrollwords=0;
+	int unrollbytes=0;
+
+	// Can we create larger code in the interests of speed?  If so, partially unroll the copy.
+	wordcopy = copysize & ~3;
+	bytecopy = copysize - wordcopy;
+
+	if ((wordcopy < 32 && !optsize) || (wordcopy<16))
+		unrollwords=1;
+	if (bytecopy < 5)
+		unrollbytes=1;
+
+	cleartempobj(f,t1);
+	cleartempobj(f,tmp);
+
+	// Even if a register is available we still have to save it because the current function wouldn't
+	// but the parent function may be using it.  Therefore we might as well use a hardcoded register.
+	dstr=sp;
+
+	// FIXME - don't necessarily need the counter register if the copy is small...
+
+	/* Is our source a register?  If so, set srcr accordingly */
+	if (p->q1.flags & REG) {
+		srcr=p->q1.reg;
+		cntr=t1;
+	} else
+		cntr=t1+2;
+
+	if((unrollwords && unrollbytes) || regs[cntr]==0)
+		savec=0;
+	else {
+		emit(f,"\tmt\t%s\n",regnames[cntr]);
+		emit(f,"\tstdec\t%s\n",regnames[sp]);
+		pushed+=4;
+	}
+
+	emit(f, "\t\t\t\t\t// Copying %d words and %d bytes to stack\n", wordcopy / 4, bytecopy);
+
+//	if(!p->z.v)
+//		printf("No z->v: z flags: %x\n",p->z.flags);
+
+	// Prepare the copy
+	emit_prepobj(f, &p->q1, t,srcr,0);
+
+	// Make room on the stack for the copied object
+
+	emit(f,"\t.liconst\t%d\n",pushsize(p));
+	emit(f,"\tsub\t%s\n",regnames[sp]);
+
+	if (unrollwords) {
+		wordcopy >>= 2;
+		if (wordcopy) {
+			emit(f, "\t\t\t\t\t// Copying %d words to stack\n", wordcopy);
+		}
+		while (wordcopy--) {
+			emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+		}
+	} else {
+		emit(f, "\t\t\t\t\t// Copying %d words to stack\n", wordcopy / 4);
+		// Copy bytes...
+		emit_constanttotemp(f, wordcopy);
+		emit(f, "\taddt\t%s\n", regnames[dstr]);
+		emit(f, "\tmr\t%s\n", regnames[cntr]);
+		emit(f, ".cpystackwordloop%d:\n", loopid);
+		emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+		emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+		emit(f, "\tcond\tNEQ\n");
+		emit(f, "\t\t.lipcrel\t.cpystackwordloop%d\n", loopid);
+		emit(f, "\t\tadd\t%s\n", regnames[pc]);
+	}
+
+	if (unrollbytes) {
+		if (bytecopy)
+			emit(f, "\t\t\t\t\t// Copying %d byte tail to stack\n", bytecopy);
+		while (bytecopy--)
+			emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+	} else {
+		emit(f, "\t\t\t\t\t// Copying %d bytes to stack\n", bytecopy);
+		// Copy bytes...
+		emit_constanttotemp(f, bytecopy);
+		emit(f, "\taddt\t%s\n", regnames[dstr]);
+		emit(f, "\tmr\t%s\n", regnames[cntr]);
+		emit(f, ".cpystackloop%d:\n", loopid);
+		emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+		emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+		emit(f, "\tcond\tNEQ\n");
+		emit(f, "\t\t.lipcrel\t.cpystackloop%d\n", loopid);
+		emit(f, "\t\tadd\t%s\n", regnames[pc]);
+
+	}
+	// cleanup
+
+	// Reset the stack pointer since we've been blithely post-incrementing it.
+	emit(f,"\t.liconst\t%d\n",opsize(p));
+	emit(f,"\tsub\t%s\n",regnames[sp]);
+
+	if(savec) {
+		emit(f,"\tldinc\t%s\n",regnames[sp]);
+		emit(f,"\tmr\t%s\n",regnames[cntr]);
+		pushed-=4;
+	}
+	cleartempobj(f,t1);
+	cleartempobj(f,tmp);
+	loopid++;
+}
+
diff --git a/machines/832/libcalls.c b/machines/832/libcalls.c
new file mode 100644
index 0000000..291f062
--- /dev/null
+++ b/machines/832/libcalls.c
@@ -0,0 +1,50 @@
+/* First steps towards LONG LONG and FLOAT support.
+   832 is not well suited to handling these types. */
+
+char *use_libcall(int code,int typf1, int typf2)
+{
+	char *result=0;
+//	printf("Querying libcall for %d, %d, %d\n",code,typf1,typf2);
+	switch(code)
+	{
+		case CONVERT:
+			if((typf1&NU)==LLONG && (typf2&NU)==INT)
+				return("__conv_ll_int\n");
+			if((typf1&NU)==(UNSIGNED|LLONG) && (typf2&NU)==(UNSIGNED|INT))
+				return("__conv_ull_uint\n");
+			if((typf1&NU)==INT && (typf2&NU)==LLONG)
+				return("__conv_int_ll\n");
+			if((typf1&NU)==(UNSIGNED|INT) && (typf2&NU)==(UNSIGNED|LLONG))
+				return("__conv_uint_ull\n");
+		case ADD:
+			if((typf1&NU)==LLONG)
+				return("__add_ll_ll\n");
+			if((typf1&NU)==(UNSIGNED|LLONG))
+				return("__add_ull_ull\n");
+		case MULT:
+			if((typf1&NU)==LLONG && (typf2&NU)==INT)
+				return("__mul_ll_int\n");
+			if((typf1&NU)==(UNSIGNED|LLONG) && (typf2&NU)==(UNSIGNED|INT))
+				return("__mul_ull_uint\n");
+			if((typf1&NU)==LLONG && (typf2&NU)==LLONG)
+				return("__mul_ll_ll\n");
+			if((typf1&NU)==(UNSIGNED|LLONG) && (typf2&NU)==(UNSIGNED|LLONG))
+				return("__mul_ull_ull\n");
+		default:
+			break;	
+	}
+	return(result);
+}
+
+void declare_builtins()
+{
+	declare_builtin("__conv_int_ll",INT,LLONG,0,LLONG,0,1,0);
+	declare_builtin("__conv_ull_ull",UNSIGNED|INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+	declare_builtin("__add_ll_ll",LLONG,LLONG,0,LLONG,0,1,0);
+	declare_builtin("__add_ull_ull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+	declare_builtin("__mul_ll_ll",LLONG,LLONG,0,LLONG,0,1,0);
+	declare_builtin("__mul_ull_ull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+	declare_builtin("__mul_ll_int",LLONG,LLONG,0,INT,0,1,0);
+	declare_builtin("__mul_ull_uint",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|INT,0,1,0);
+}
+
diff --git a/machines/832/machine.c b/machines/832/machine.c
new file mode 100644
index 0000000..03899e3
--- /dev/null
+++ b/machines/832/machine.c
@@ -0,0 +1,2420 @@
+/*  EightThirtyTwo backend for vbcc,
+	based on the generic RISC backend
+
+	The CPU targeted by this backend, and the latest version, can be found at
+    https://github.com/robinsonb5/EightThirtyTwo
+
+*/
+
+// DONE - T2 no longer used at all - frees up a register for the main code generator
+
+// DONE Update the memcpy code to save/allocate registers if needed.
+// DONE Update the div code likewise.
+
+// Complete the work on object tracking.  In particular take care of tracking an object vs
+// its address.
+// Also track via addressing-mode analysis whether or not it's valuable to save a value;
+// Values can also be saved to otherwise unused registers.  (The compiler is almost certainly
+// already smart enough to make use of unused registers for this, however!)
+
+// DONE: eliminate unnecessary register shuffling for compare.
+
+// DONE: Implement block copying
+
+// DONE: Implement division / modulo using library code.
+// DONE: Mark registers as disposable if their contents are never used beyond the current op.
+
+// Look at ways of improving code efficiency.  Look for situations where the output of one IC
+// becomes the input of another?  Would make a big difference when registers are all in use.
+
+// Minus could be optimised for the in-register case.
+
+// DONE: Do we need to reserve two temp registers?  Turns out one was sufficient, and giving
+// the code generator an extra one to play with helped a great deal.
+
+// Restrict byte and halfword storage to static and extern types, not stack-based variables.
+// (Having learned more, bytes and halfwords on the stack are fine, the complication is with
+// function parameters, which are promoted to int - thus the size modifier will be different
+// for parameters and local variables even though both live on the stack.)
+
+// DONE - Avoid moving registers for cmp and test when possible.
+
+// Condition code for test may well be already set by previous load.
+// Done for TEST, do the same for comparisons?
+
+// Deal with dereferencing in temp caching - can we avoid repeated setups in tmp, maybe using r0?
+
+
+#include "supp.h"
+
+#define DBGMSG 1
+
+static char FILE_[] = __FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[] =
+    "vbcc EightThirtyTwo code-generator, (c) 2019/2020 by Alastair M. Robinson\nBased on the generic RISC example backend (c) 2001 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF] = { 0 };
+
+#define FLAG_PIC 0
+#define FLAG_LE 1
+#define FLAG_BE 2
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+/* 832-specific flags, "fpic" enables position independent code - name chosen to match gcc */
+char *g_flags_name[MAXGF] = { "fpic","el","eb" };
+
+char flag_832_bigendian;
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF] = { 0,0,0 };
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE + 1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE + 1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE + 1];
+zumax t_max[MAX_TYPE + 1];
+zumax tu_max[MAX_TYPE + 1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR + 1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR + 1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR + 1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR + 1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR + 1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR + 1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle = { 0, 0 };
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[] = { "__interrupt", "__ctor", "__dtor", "__weak", 0 };
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define USE_COMMONS 0
+
+/* alignment of basic data-types, used to initialize align[] */
+/* In actual fact 832 has full load/store alignment so this is negotiable based on -speed / -size flags. */
+static long malign[MAX_TYPE + 1] = { 1, 1, 2, 4, 4, 4, 4, 8, 8, 1, 4, 1, 1, 1, 4, 1 };
+
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE + 1] = { 1, 1, 2, 4, 4, 8, 4, 8, 8, 0, 4, 0, 0, 0, 4, 0 };
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp = { LONG }, ldbl = {
+DOUBLE}, lchar = {
+CHAR};
+
+/* macros defined by the backend */
+static char *marray[] = { "__section(x)=__vattr(\"section(\"#x\")\")",
+	"__EIGHTTHIRTYTWO__",
+	"__constructor(pri)=__vattr(\"ctor(\"#pri\")\")",
+	"__destructor(pri)=__vattr(\"dtor(\"#pri\")\")",
+	"__weak=__vattr(\"weak\")",
+	0
+};
+
+/* special registers */
+static int pc;			/*  Program counter                     */
+static int sp;			/*  Stackpointer                        */
+static int tmp;
+static int t1, t2;		/*  temporary gprs */
+static int f1, f2, f3;		/*  temporary fprs */
+static int loopid = 0;	/* must be unique for every function in a compilation unit */
+
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+//static long stack;
+static int section = -1, newobj;
+static char *codename = "\t.section\t.text";
+static char *dataname = "\t.section\t.data";
+static char *bssname = "\t.section\t.bss";
+static char *rodataname = "\t.section\t.rodata";
+static int sectionid=0;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix = "l", *idprefix = "_";
+
+/* variables to keep track of the current stack-offset in the case of
+   a moving stack-pointer */
+static long pushed;
+static long notyetpopped;
+
+static long localsize, rsavesize, argsize;
+
+static int count_constantchunks(zmax v);
+static void emit_constanttotemp(FILE * f, zmax v);
+static void emit_statictotemp(FILE * f, char *lab, int suffix, int offset);
+static void emit_externtotemp(FILE * f, char *lab, int offset);
+static void emit_pcreltotemp2(FILE *f,struct obj *p);
+
+static void emit_prepobj(FILE * f, struct obj *p, int t, int reg, int offset);
+static int emit_objtoreg(FILE * f, struct obj *p, int t,int reg);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | return-address [size=4]                      |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+	long off = 0;
+	if((o->flags&VAR) && isauto(o->v->storage_class))
+		off=zm2l(o->v->offset);
+//      printf("Parameter offset: %d, localsize: %d, rsavesize: %d\n",off,localsize,rsavesize);
+	if (off < 0) {
+		/* function parameter */
+		off = localsize + rsavesize + 4 - off - zm2l(maxalign);
+	}
+	off += pushed;
+	off += notyetpopped;
+	off += zm2l(o->val.vmax);
+	return off;
+}
+
+
+static int isstackparam(struct obj *o)
+{
+	int result=0;
+//	if(o->flags&VAR && o->flags&REG && o->reg==sp)
+//	if(o->flags&(VAR|DREFOBJ)==VAR)
+	if((o->flags&VAR) && !(o->flags&REG))
+	{
+		if(isauto(o->v->storage_class))
+		{
+			long off = zm2l(o->v->offset);
+			if (off < 0)
+				result=1;
+		}
+	}
+	return(result);
+}
+
+/* Convenience function to determine whether we're assigning to 0(r6)
+   and can thus use a more efficient writing sequence. */
+
+int istopstackslot(struct obj *o)
+{
+	if(!o)
+		return(0);
+	if((o->flags&(VAR|REG|DREFOBJ))==VAR && o->v)
+	{
+		if(isauto(o->v->storage_class)
+				&& real_offset(o)==0)
+			return(1);
+	}
+	return(0);
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE * f, struct Var *v)
+{
+	char *sec;
+	if (!v->vattr)
+		return 0;
+	sec = strstr(v->vattr, "section(");
+	if (!sec)
+		return 0;
+	sec += strlen("section(");
+	emit(f, "\t.section\t");
+	while (*sec && *sec != ')')
+		emit_char(f, *sec++);
+	emit(f, "\n");
+	if (f)
+		section = SPECIAL;
+	return 1;
+}
+
+/* Returns 1 if the symbol has weak linkage */
+static int isweak(struct Var *v)
+{
+	if (!v->vattr)
+		return 0;
+	if (strstr(v->vattr, "weak"))
+		return (1);
+	return 0;
+}
+
+/* Emits a pointer to a function in a .ctor or .dtor section for automatic setup/cleanup */
+static int ctor_dtor(FILE * f, struct Var *v)
+{
+	int dtor = 0;
+	char *sec;
+	if (!v->vattr)
+		return 0;
+	sec = strstr(v->vattr, "ctor(");
+	if (!sec) {
+		dtor = 1;
+		sec = strstr(v->vattr, "dtor(");
+	}
+	if (!sec)
+		return 0;
+	sec += strlen("ctor(");
+	emit(f, "\t%s.", dtor ? ".dtor .dtor" : ".ctor .ctor");
+	while (*sec && *sec != ')')
+		emit_char(f, *sec++);
+	emit(f, "\n\t.ref\t%s%s\n", idprefix, v->identifier);
+
+	return 1;
+}
+
+
+#define TEMP_TMP 0
+#define TEMP_T1 1
+struct tempobj
+{
+	struct obj o;
+	int reg;
+};
+struct tempobj tempobjs[2];
+
+void cleartempobj(FILE *f, int reg)
+{
+	int i;
+	if(reg==tmp) i=TEMP_TMP;
+	else if(reg==t1) i=TEMP_T1;
+	else return;
+//	emit(f,"// clearing %s\n",regnames[reg]);
+
+	tempobjs[i].reg=0;
+}
+
+void settempkonst(FILE *f,int reg,int v)
+{
+	int i;
+	if(reg==tmp) i=TEMP_TMP;
+	else if(reg==t1) i=TEMP_T1;
+	else return;
+	tempobjs[i].reg=reg;
+	tempobjs[i].o.flags=KONST;
+	tempobjs[i].o.val.vlong=v;
+//	emit(f,"// set %s to konst %d\n",regnames[reg],v);
+}
+
+
+// Add an adjustment due to postinc / predec to a cached object
+void adjtempobj(FILE *f,int reg,int offset)
+{
+	if(reg<=1)
+		tempobjs[reg].o.val.vlong+=offset;
+}
+
+
+// Store any passing value in tempobj records for optimisation.
+// FIXME - need to figure out VARADR semantics for stored objects.
+void settempobj(FILE *f,int reg,struct obj *o,int offset,int varadr)
+{
+	int i;
+	if(reg==tmp) i=TEMP_TMP;
+	else if(reg==t1) i=TEMP_T1;
+	else return;
+//	if(reg==t1)
+//		emit(f,"// Setting %s to %x (%x)\n",regnames[reg],o,o->v);
+	tempobjs[i].reg=reg;
+	tempobjs[i].o=*o;
+	tempobjs[i].o.val.vlong+=offset;	// Account for any postinc / predec
+	if(varadr)
+		tempobjs[i].o.flags|=VARADR;
+}
+
+
+// Compare a pair of struct obj* for equivalence.
+// The first object should be the "live" object, the second one the cached object."
+int matchobj(FILE *f,struct obj *o1,struct obj *o2,int varadr)
+{
+	int result=1;
+	int flg=o1->flags;
+	if(varadr)
+		flg|=VARADR;
+//	emit(f,"// comparing flags %x with %x\n",o1->flags, o2->flags);
+//	if((o1->flags&~VARADR)!=(o2->flags&~VARADR))
+	// FIXME - need to figure out VARADR semantics for stored objects.
+	emit(f,"\t\t\t\t\t\t// matchobj comparing flags %d with %d\n",flg,o2->flags);
+	if(flg!=(o2->flags))
+		return(0);
+
+//	emit(f,"// comparing regs %d with %d\n",o1->reg, o2->reg);
+	// If the register-based value is being dereferenced we would have to track
+	// the register itself being updated.  Unless the value's in tmp using a cached
+	// version isn't a win anyway.
+	if((o1->flags&(REG|DREFOBJ)==REG) && (o1->reg==o2->reg))
+		return(1);
+
+	if(o1->flags&KONST)
+	{
+//		emit(f,"\t\t\t\t\t\t// Comparing constants %x with %x\n",o1->val.vlong,o2->val.vlong);
+		if(o1->val.vlong == o2->val.vlong)
+			return(1);
+		else
+		{			// Attempt fuzzy matching...
+			int d=o1->val.vlong-o2->val.vlong;
+			// Don't bother if we need fewer than four LIs to represent the value, or if we'd need more than 1 LI for the offset.
+			if(count_constantchunks(o1->val.vlong)<4 || count_constantchunks(d)>1)
+			{
+//				emit(f,"\t\t\t\t\t\t// Gains from fuzzy matching too small, ignoring.\n");
+				return(0);
+			}
+			else
+				return(2);
+		}
+	}
+
+	if(!(o1->flags&VAR))
+		return(0); // Not a var?  Can't do any more.
+
+	if(o1->v==0 || o2->v==0)
+		return(0);
+
+	if(o1->v == o2->v && o1->val.vlong == o2->val.vlong)
+		return(1);
+
+	if(!(flg&VARADR))
+		return(0); // Can only attempt fuzzy matching if this is a varadr
+
+	if(isauto(o1->v->storage_class) && isauto(o2->v->storage_class))
+	{
+		if(DBGMSG)
+			emit(f,"\t\t\t\t\t\t//auto: flags: %x, comparing %d, %d with %d, %d\n",
+				flg,o1->v->offset,o1->val.vlong, o2->v->offset,o2->val.vlong);
+		// Can't fuzzy match between parameters and vars on stack
+		if((o1->v->offset<0 && o2->v->offset>=0) || (o1->v->offset>=0 && o2->v->offset<0))
+			return(0);
+		if(o1->v->offset==o2->v->offset && o1->val.vlong==o2->val.vlong)
+			return(1);
+		if((o1->flags&DREFOBJ) || (o2->flags&DREFOBJ))	// Can't fuzzy match if we're dereferencing.
+			return(0);
+		return(2);
+	}
+
+	if(isextern(o1->v->storage_class) && isextern(o2->v->storage_class))
+	{
+		if(DBGMSG)
+			emit(f,"\t\t\t\t\t\t//extern: comparing %d with %d\n",o1->val.vlong, o2->val.vlong);
+		if(strcmp(o1->v->identifier,o2->v->identifier))
+			return(0);
+		if(o1->val.vlong==o2->val.vlong)
+			return(1);
+		if((o1->flags&DREFOBJ) || (o2->flags&DREFOBJ))	// Can't fuzzy match if we're dereferencing.
+			return(0);
+		return(2);
+	}
+
+	return(0);
+}
+
+
+int matchoffset(struct obj *o,struct obj *o2)
+{
+	if(o->flags&KONST)
+		return(o->val.vlong-o2->val.vlong);
+	if(isextern(o->v->storage_class))
+		return(o->val.vlong-o2->val.vlong);
+	if(isauto(o->v->storage_class))
+//		return((o->val.vlong+real_offset(o))-(o2->val.vlong+real_offset(o2)));
+		return((o->val.vlong+o->v->offset)-(o2->val.vlong+o2->v->offset));
+	return(0);
+}
+
+
+void obsoletetempobj(FILE *f,int reg,struct obj *o,int varadr)
+{
+//	emit(f,"\t\t\t\t\t// Attempting to obsolete obj\n");
+	if(tempobjs[0].reg==reg && matchobj(f,o,&tempobjs[0].o,varadr))
+	{
+		emit(f,"\t\t\t\t\t\t// Obsoleting tmp\n");
+		cleartempobj(f,tmp);
+	}
+	if(tempobjs[1].reg==reg && matchobj(f,o,&tempobjs[0].o,varadr))
+	{
+		emit(f,"\t\t\t\t\t\t// Obsoleting t1\n");
+		cleartempobj(f,t1);
+	}
+}
+
+
+// Check the tempobj records to see if the value we're interested in can be found in either.
+int matchtempobj(FILE *f,struct obj *o,int varadr,int preferredreg)
+{
+	int hit=0;	// Hit will be 1 for an exact match, 2 for a near miss.
+//	return(0); // Temporarily disable matching
+	if(tempobjs[0].reg && (hit=matchobj(f,o,&tempobjs[0].o,varadr)))
+	{
+//		emit(f,"//match found - tmp\n");
+//		printf("//match found - tmp\n");
+		if(hit==1)
+			return(tempobjs[0].reg);
+		else if(hit==2)
+		{
+			int offset=matchoffset(o,&tempobjs[0].o);
+			emit(f,"\t\t\t\t\t\t// Fuzzy match found against tmp.\n");
+			if(preferredreg==tmp)
+			{
+				emit(f,"\tmr\t%s\n",regnames[t1]);
+				emit(f,"\t.liconst\t%d\n",offset);
+				emit(f,"\taddt\t%s\n",regnames[t1]);
+				settempobj(f,t1,&tempobjs[0].o,0,0);
+				settempobj(f,tmp,o,0,varadr);
+			}
+			else
+			{
+				emit(f,"\tmr\t%s\n",regnames[preferredreg]);
+				emit(f,"\t.liconst\t%d\n",offset);
+				settempkonst(f,tmp,offset);
+				emit(f,"\tadd\t%s\n",regnames[preferredreg]);
+				settempobj(f,preferredreg,o,0,varadr);
+			}
+			return(preferredreg);
+//			return(tempobjs[0].reg);
+		}
+		else
+			return(0);
+	}
+	else if(tempobjs[1].reg && (hit=matchobj(f,o,&tempobjs[1].o,varadr)))
+	{
+		// Temporarily disable t1 matching.  FIXME - keep t1 records more up-to-date.
+//		return(0);
+//		emit(f,"//match found - t1\n");
+//		printf("//match found - t1\n");
+		if(hit==1)
+			return(tempobjs[1].reg);
+		else if(hit==2)
+		{
+			int offset=matchoffset(o,&tempobjs[1].o);
+			if(DBGMSG)
+				emit(f,"\t\t\t\t\t\t//Fuzzy match found, offset: %d (varadr: %d)\n",offset,varadr);
+			// Fuzzy match against t1 - if target is t1 use add, otherwise use addt.
+			emit(f,"\t.liconst\t%d\n",offset);
+			if(preferredreg!=tempobjs[1].reg)
+			{
+				emit(f,"\taddt\t%s\n",regnames[tempobjs[1].reg]);
+				if(preferredreg!=tmp)
+					emit(f,"\tmr\t%s\n",regnames[preferredreg]);
+				settempobj(f,tmp,o,0,0);
+				settempobj(f,preferredreg,o,0,varadr);
+			}
+			else
+			{
+				emit(f,"\tadd\t%s\n",regnames[tempobjs[1].reg]);
+				settempkonst(f,tmp,offset);
+				settempobj(f,tempobjs[1].reg,o,0,varadr);
+			}
+			return(preferredreg);
+		}
+		return(0);
+	}
+	else
+		return(0);
+}
+
+
+int matchtempkonst(FILE *f,int k,int preferredreg)
+{
+//	return(0); // Temporarily disable matching
+	struct obj o;
+	o.flags=KONST;
+	o.val.vlong=k;
+	return(matchtempobj(f,&o,0,preferredreg));
+}
+
+
+/*  Generates code to store register r into memory object o. */
+
+static void store_reg(FILE * f, int r, struct obj *o, int type)
+{
+	// Need to take different types into account here.
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t// Store_reg to type 0x%x, flags 0x%x\n", type,o->flags);
+
+	type &= NQ;		// Filter out unsigned, etc.
+	if((type==CHAR || type==SHORT) && isstackparam(o))
+	{
+		emit(f, "\t\t\t\t\t\t// Promoting storage size of stack parameter to int\n");
+		type=INT;
+	}
+
+	switch (type) {
+	case CHAR:
+		emit_prepobj(f, o, type & NQ, tmp, 0);
+		emit(f, "\texg\t%s\n", regnames[r]);
+		emit(f, "\tstbinc\t%s\t//WARNING - pointer / reg not restored, might cause trouble!\n", regnames[r]);
+		cleartempobj(f,tmp);
+		cleartempobj(f,r);
+		break;
+	case SHORT:
+		emit_prepobj(f, o, type & NQ, tmp, 0);
+		emit(f, "\texg\t%s\n", regnames[r]);
+		emit(f, "\thlf\n\tst\t%s\n", regnames[r]);
+		cleartempobj(f,tmp);
+		cleartempobj(f,r);
+		break;
+	case INT:
+	case LONG:
+	case POINTER:
+		// if o is a reg, can store directly.
+		if ((o->flags & (REG | DREFOBJ)) == (REG | DREFOBJ)) {
+			emit(f, "\tmt\t%s\n", regnames[r]);
+			emit(f, "\tst\t%s\n", regnames[o->reg]);
+//			settempobj(f,r,o,0,0);
+			if((type&NQ)!=INT || (type & VOLATILE) || (type & PVOLATILE))
+			{
+				emit(f,"\t// Volatile, or not int - not caching\n");
+				cleartempobj(f,r);
+			}
+			else
+				settempobj(f,r,o,0,0); // FIXME - is this correct?
+			settempobj(f,tmp,o,0,0); // FIXME - is this correct?
+		} else {
+			if(o->flags & DREFOBJ) {  // Can't use the offset / stmpdec trick for dereferenced objects.
+				// FIXME, not strictly true - could use it for dereferenced constants
+				emit_prepobj(f, o, type & NQ, tmp, 0);
+				emit(f, "\texg\t%s\n", regnames[r]);
+				emit(f, "\tst\t%s\n", regnames[r]);
+				if(r==t1 || (o->am && o->am->disposable))
+					emit(f, "\t\t\t\t\t\t// WARNING - Object is disposable, not bothering to undo exg - check correctness\n");
+				else
+					emit(f, "\texg\t%s\n", regnames[r]);
+				cleartempobj(f,tmp);
+				cleartempobj(f,r);
+			}
+			else {
+				emit_prepobj(f, o, type & NQ, tmp, 4);	// stmpdec predecrements, so need to add 4!
+				emit(f, "\tstmpdec\t%s\n \t\t\t\t\t\t// WARNING - check that 4 has been added.\n", regnames[r]);
+				adjtempobj(f,tmp,-4);
+//				cleartempobj(f,tmp);
+				if((type&NQ)!=INT || (type & VOLATILE) || (type & PVOLATILE))
+				{
+					emit(f,"\t// Volatile, or not int - not caching\n");
+					cleartempobj(f,r);
+				}
+				else
+					settempobj(f,r,o,0,0); // FIXME - is this correct?
+			}
+		}
+		break;
+	case LLONG:
+		if ((o->flags & (REG | DREFOBJ)) == (REG | DREFOBJ)) {
+			emit_prepobj(f, o, type & NQ, tmp, 0);
+			printf("store_reg: storing long long to dereferenced register\n");
+			emit(f,"//FIXME - need to store 64-bits\n");
+			ierror(0);
+		}
+		else {
+			// 
+			printf("store_reg: storing long long in %s to reg\n",regnames[r]);
+			ierror(0);
+		}
+		break;		
+	default:
+		printf("store_reg: unhandled type 0x%x\n", type);
+		ierror(0);
+		break;
+	}
+}
+
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+	zumax p;
+	int ln = 1;
+	p = ul2zum(1L);
+	while (ln <= 32 && zumleq(p, x)) {
+		if (zumeqto(x, p))
+			return ln;
+		ln++;
+		p = zumadd(p, p);
+	}
+	return 0;
+}
+
+
+static int availreg()
+{
+	int i;
+	for(i=FIRST_GPR+RESERVED_GPRS;i<(LAST_GPR-1);++i)
+		if(regs[i]==0)
+			return(i);
+	return(0);
+}
+
+
+static struct IC *preload(FILE *, struct IC *,int stacksubst);
+
+static void function_top(FILE *, struct Var *, long);
+static int function_bottom(FILE * f, struct Var *, long,int);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define involvesreg(x) ((p->x.flags&(REG))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg, q2reg, zreg;
+
+static char *ccs[] = { "EQ", "NEQ", "SLT", "GE", "LE", "SGT", "EX", "" };
+static char *logicals[] = { "or", "xor", "and" };
+
+static char *arithmetics[] = { "shl", "shr", "add", "sub", "mul", "(div)", "(mod)" };
+
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+static struct IC *preload(FILE * f, struct IC *p,int stacksubst)
+{
+	int r;
+
+	if(stacksubst)
+	{
+		if(istopstackslot(&p->q1))
+		{
+			p->q1.reg=sp;
+			p->q1.flags|=REG|DREFOBJ;
+		}
+
+		if(istopstackslot(&p->q2))
+		{
+			p->q2.reg=sp;
+			p->q2.flags|=REG|DREFOBJ;
+		}
+
+		if(istopstackslot(&p->z))
+		{
+			p->z.reg=sp;
+			p->z.flags|=REG|DREFOBJ;
+		}
+	}
+
+	if (involvesreg(q1))
+		q1reg = p->q1.reg;
+	else
+		q1reg = 0;
+
+	if (involvesreg(q2))
+		q2reg = p->q2.reg;
+	else
+		q2reg = 0;
+
+	if (isreg(z)) {
+		zreg = p->z.reg;
+	} else {
+		if (ISFLOAT(ztyp(p)))
+			zreg = f1;
+		else
+			zreg = t1;
+	}
+
+	return p;
+}
+
+/* Determine whether the register we're about to write to will merely be passed to SetReturn.
+   If so, return 1, and convert the SetReturn IC to NOP */
+int next_setreturn(struct IC *p,int reg)
+{
+	int result=0;
+	struct IC *p2=p->next;
+	while(p2 && p2->code==FREEREG)
+		p2=p2->next;
+	if(p2 && p2->code==SETRETURN && (p2->q1.flags&(REG|DREFOBJ))==REG && p2->q1.reg==reg)
+	{
+		p2->code=NOP;
+		result=1;
+	}
+	return(result);
+}
+
+
+int consecutiveaccess(struct IC *p,struct IC *p2)
+{
+	if(!p || !p2)
+		return(0);
+//	printf("Flags %x, %x\n",p->z.flags,p2->z.flags);
+	if(((p->z.flags&(VAR|DREFOBJ))==VAR) && ((p2->z.flags&(VAR|DREFOBJ))==VAR))
+	{
+		int result=real_offset(&p2->z)-real_offset(&p->z);
+//		printf("Got two vars\n");
+		if(strcmp(p->z.v->identifier,p2->z.v->identifier))
+			return(0);
+		if(isstatic(p->z.v->storage_class) && isstatic(p->z.v->storage_class))
+		{
+//			printf("Both static - dif %d\n",result);
+			return(result);
+		}
+		if(isextern(p->z.v->storage_class) && isextern(p->z.v->storage_class))
+		{
+//			printf("Both extern - dif %d\n",result);
+			return(result);
+		}
+	}
+	return(0);
+}
+
+/* save the result (in temp) into p->z */
+/* Guaranteed not to touch t1/t2 unless nominated */
+/* or followed by a SetReturn IC. */
+void save_temp(FILE * f, struct IC *p, int treg)
+{
+	int type = ztyp(p) & NQ;
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t// (save temp)");
+
+	if (isreg(z)) {
+		int target=p->z.reg;
+		if(DBGMSG)
+			emit(f, "isreg\n");
+		if(next_setreturn(p,target))
+			target=t1;
+		emit(f, "\tmr\t%s\n", regnames[target]);
+	} else {
+		if ((p->z.flags & DREFOBJ) && (p->z.flags & REG))
+			treg = p->z.reg;
+		else if(isstackparam(&p->z) && !(p->z.flags & DREFOBJ))
+			type=INT;
+
+		if(DBGMSG)
+			emit(f, "store type %x\n",type);
+
+		switch (type) {
+		case CHAR:
+			if (p->z.am && p->z.am->type == AM_POSTINC)
+			{
+				emit(f, "\tstbinc\t%s\n", regnames[treg]);
+				adjtempobj(f,treg,1);
+			}
+			else if ((p->z.am && p->z.am->disposable)
+				 || (treg == t1))
+			{
+				emit(f, "\tstbinc\t%s\n\t\t\t\t\t\t//Disposable, postinc doesn't matter.\n", regnames[treg]);
+				adjtempobj(f,treg,1);
+			}
+			else
+				emit(f, "\tbyt\n\tst\t%s\n", regnames[treg]);
+			break;
+		case SHORT:
+			emit(f, "\thlf\n\tst\t%s\n", regnames[treg]);
+			break;
+		case INT:
+		case LONG:
+		case POINTER:
+//			// Would need to adjust the pointer at the setup stage since we're predecrementing
+//			if (consecutiveaccess(p,p->next)==-4 || (p->z.am && p->z.am->type == AM_PREDEC))
+//			{
+//				emit(f, "\tstdec\t%s\n", regnames[treg]);
+//				adjtempobj(f,treg,-4);
+//			}
+			if (consecutiveaccess(p,p->next)==4 || (p->z.am && p->z.am->type == AM_POSTINC))
+			{
+				emit(f, "\tstinc\t%s\n", regnames[treg]);
+				adjtempobj(f,treg,4);
+			}
+			else
+				emit(f, "\tst\t%s\n", regnames[treg]);
+			break;
+		default:
+			printf("save_temp - type %d not yet handled\n", ztyp(p));
+			emit(f,"\t\t\t\t\t\t// FIXME - save_temp doesn't support size\n");
+			break;
+		}
+	}
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t//save_temp done\n");
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE * f, struct IC *p)
+{
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t// (save result) ");
+	if (isreg(z)) {
+		if(DBGMSG)
+			emit(f, "// isreg\n");
+		if (p->z.reg != zreg)
+		{
+			emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[zreg], regnames[p->z.reg]);
+			settempobj(f,tmp,&p->z,0,0);
+			settempobj(f,p->z.reg,&p->z,0,0);
+		}
+	}
+	else
+	{
+		emit(f, "// not reg\n");
+		store_reg(f,zreg,&p->z,ztyp(p));
+	}
+	return;
+}
+
+#include "addressingmodes.c"
+#include "tempregs.c"
+#include "inlinememcpy.c"
+#include "libcalls.c"
+
+/* generates the function entry code */
+static void function_top(FILE * f, struct Var *v, long offset)
+{
+	int i;
+	int regcount = 0;
+
+	cleartempobj(f,tmp);
+	cleartempobj(f,t1);
+
+	if(DBGMSG)
+	{
+		emit(f, "\t//registers used:\n");
+		for (i = FIRST_GPR+RESERVED_GPRS; i <= LAST_GPR; ++i) {
+			emit(f, "\t\t//%s: %s\n", regnames[i], regused[i] ? "yes" : "no");
+			if (regused[i] && (i >= (FIRST_GPR+SCRATCH_GPRS+RESERVED_GPRS)) && (i <= LAST_GPR - 2))
+				++regcount;
+		}
+	}
+
+// Emit ctor / dtor tables
+	ctor_dtor(f, v);
+
+	rsavesize = 0;
+	if (!special_section(f, v)) {
+		emit(f, "\t.section\t.text.%x\n", sectionid);
+		section=CODE;
+		++sectionid;
+	}
+	if (v->storage_class == EXTERN) {
+		if ((v->flags & (INLINEFUNC | INLINEEXT)) != INLINEFUNC) {
+			if (isweak(v))
+				emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
+			else
+				emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+		}
+		emit(f, "%s%s:\n", idprefix, v->identifier);
+	} else
+		emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
+
+	if (regcount < 3) {
+		emit(f, "\tstdec\t%s\n", regnames[sp]);
+		for (i = FIRST_GPR + SCRATCH_GPRS; i <= LAST_GPR - 3; ++i) {
+			if (regused[i] && !regscratch[i]) {
+				emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[i], regnames[sp]);
+				rsavesize += 4;
+			}
+		}
+	} else {
+		emit(f, "\texg\t%s\n\tstmpdec\t%s\n", regnames[sp], regnames[sp]);
+		for (i = FIRST_GPR + SCRATCH_GPRS; i <= LAST_GPR - 3; ++i) {
+			if (regused[i] && !regscratch[i]) {
+				emit(f, "\tstmpdec\t%s\n", regnames[i]);
+				rsavesize += 4;
+			}
+		}
+		emit(f, "\texg\t%s\n", regnames[sp]);
+	}
+
+	// FIXME - Allow the stack to float, in the hope that we can use stdec to adjust it.
+
+	if ((offset == 4) && optsize)
+		emit(f, "\tstdec\tr6\t// shortest way to decrement sp by 4\n");
+	else if (offset) {
+		emit_constanttotemp(f, -offset);
+		emit(f, "\tadd\t%s\n", regnames[sp]);
+	}
+}
+
+/* generates the function exit code */
+/* Returns 1 if tail code was generated. */
+static int function_bottom(FILE * f, struct Var *v, long offset,int firsttail)
+{
+	int i;
+	int tail=0;
+
+	int regcount = 0;
+	for (i = FIRST_GPR + SCRATCH_GPRS + RESERVED_GPRS; i <= LAST_GPR - 3; ++i) {
+		if (regused[i] && !regscratch[i])
+			++regcount;
+	}
+
+	if ((offset == 4) && optsize)
+		emit(f, "\tldinc\t%s\t// shortest way to add 4 to sp\n", regnames[sp]);
+	else if (offset) {
+		emit_constanttotemp(f, -offset);	// Negative range extends one integer further than positive range.
+		emit(f, "\tsub\t%s\n", regnames[sp]);
+	}
+
+	if(optsize) // If we're optimising for size we can potentially save some bytes in the function tails.
+	{
+		if(regcount)
+		{
+			/* We have to restore some registers.  Jump into the tail code at the appropriate place. */
+			if(regcount<(5-SCRATCH_GPRS) || !firsttail)
+			{
+				emit(f,"\t.lipcrel\t.functiontail, %d\n",((5-SCRATCH_GPRS)-regcount)*2);
+				emit(f,"\tadd\t%s\n\n",regnames[pc]);
+			}
+			if(firsttail)
+			{
+				/* This is the first time we've needed to restore registers - generate tail code */
+				emit(f,".functiontail:\n");
+				for (i = LAST_GPR - 3; i >= FIRST_GPR + SCRATCH_GPRS; --i) {
+					if (!regscratch[i])
+						emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[i]);
+				}
+				emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
+				if(f)
+					tail=1; /* Higher optimisation levels do a dummy run with null file */
+			}
+		}
+		else
+		{
+			/* Didn't need to preserve any registers, just restore PC */
+			emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
+		}
+	}
+	else
+	{
+		for (i = LAST_GPR - 3; i >= FIRST_GPR + SCRATCH_GPRS; --i) {
+			if (regused[i] && !regscratch[i])
+				emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[i]);
+		}
+		emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
+	}
+	return(tail);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+	int i;
+	/*  Initialize some values which cannot be statically initialized   */
+	/*  because they are stored in the target's arithmetic.             */
+	maxalign = l2zm(4L);
+	char_bit = l2zm(8L);
+	stackalign = l2zm(4);
+
+	flag_832_bigendian=0;
+	if(g_flags[FLAG_BE]&USEDFLAG)
+		flag_832_bigendian=1;
+	else if(!g_flags[FLAG_BE]&USEDFLAG)
+		printf("Neither -eb nor -el specified - defaulting to little-endian\n");
+
+#ifndef V09G
+	clist_copy_stack=0;
+	clist_copy_static=0;
+	clist_copy_pointer=0;
+#endif
+
+	// We have full load-store align, so in size mode we can pack data more tightly...
+
+	for (i = 0; i <= MAX_TYPE; i++) {
+		sizetab[i] = l2zm(msizetab[i]);
+		align[i] = optsize ? 1 : l2zm(malign[i]);
+
+// Can't align everything to 4 bytes for speed without messing up struct packing.  Is there a better way?
+//		align[i] = optspeed ? 4 : (optsize ? 1 : l2zm(malign[i]));
+//		align[i] = l2zm(malign[i]);
+	}
+
+	regnames[0] = "noreg";
+	for (i = FIRST_GPR; i <= LAST_GPR - 1; i++) {
+		regnames[i] = mymalloc(5);
+		sprintf(regnames[i], "r%d", i - FIRST_GPR);
+		regsize[i] = l2zm(4L);
+		regtype[i] = &ltyp;
+		regsa[i] = 0;
+	}
+	regnames[i] = mymalloc(5);
+	sprintf(regnames[i], "tmp");
+	regsize[i] = l2zm(4L);
+	regtype[i] = &ltyp;
+	regsa[i] = 1;
+	for (i = FIRST_FPR; i <= LAST_FPR; i++) {
+		regnames[i] = mymalloc(10);
+		sprintf(regnames[i], "fpr%d", i - FIRST_FPR);
+		regsize[i] = l2zm(8L);
+		regtype[i] = &ldbl;
+	}
+
+	/*  Use multiple ccs.   */
+	multiple_ccs = 0;
+
+	/*  Initialize the min/max-settings. Note that the types of the     */
+	/*  host system may be different from the target system and you may */
+	/*  only use the smallest maximum values ANSI guarantees if you     */
+	/*  want to be portable.                                            */
+	/*  That's the reason for the subtraction in t_min[INT]. Long could */
+	/*  be unable to represent -2147483648 on the host system.          */
+	t_min[CHAR] = l2zm(-128L);
+	t_min[SHORT] = l2zm(-32768L);
+	t_min[INT] = zmsub(l2zm(-2147483647L), l2zm(1L));
+	t_min[LONG] = t_min(INT);
+	t_min[LLONG] = zmlshift(l2zm(1L), l2zm(63L));
+	t_min[MAXINT] = t_min(LLONG);
+	t_max[CHAR] = ul2zum(127L);
+	t_max[SHORT] = ul2zum(32767UL);
+	t_max[INT] = ul2zum(2147483647UL);
+	t_max[LONG] = t_max(INT);
+	t_max[LLONG] = zumrshift(zumkompl(ul2zum(0UL)), ul2zum(1UL));
+	t_max[MAXINT] = t_max(LLONG);
+	tu_max[CHAR] = ul2zum(255UL);
+	tu_max[SHORT] = ul2zum(65535UL);
+	tu_max[INT] = ul2zum(4294967295UL);
+	tu_max[LONG] = t_max(UNSIGNED | INT);
+	tu_max[LLONG] = zumkompl(ul2zum(0UL));
+	tu_max[MAXINT] = t_max(UNSIGNED | LLONG);
+
+	/*  Reserve a few registers for use by the code-generator.      */
+	/*  This is not optimal but simple.                             */
+	tmp = FIRST_GPR + 8;
+	pc = FIRST_GPR + 7;
+	sp = FIRST_GPR + 6;
+	t1 = FIRST_GPR;		// r0, also return register.
+	t2 = FIRST_GPR + 1;
+//  f1=FIRST_FPR;
+//  f2=FIRST_FPR+1;
+
+	for (i = FIRST_GPR; i <= LAST_GPR; i++)
+		regscratch[i] = 0;
+	for (i = FIRST_FPR; i <= LAST_FPR; i++)
+		regscratch[i] = 0;
+
+	regsa[FIRST_GPR] = 1;	// Allocate the return register
+	regsa[t1] = 1;
+	regsa[t2] = 0;
+	regsa[sp] = 1;
+	regsa[pc] = 1;
+	regsa[tmp] = 1;
+	regscratch[FIRST_GPR] = 0;
+	for(i=FIRST_GPR+RESERVED_GPRS;i<(FIRST_GPR+RESERVED_GPRS+SCRATCH_GPRS);++i)
+		regscratch[i] = 1;
+	regscratch[sp] = 0;
+	regscratch[pc] = 0;
+
+	target_macros = marray;
+
+	return 1;
+}
+
+void init_db(FILE * f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+	if (ISFLOAT(t->flags))
+		return 0;
+	if (ISSTRUCT(t->flags) || ISUNION(t->flags))
+		return 0;
+	if (zmleq(szof(t), l2zm(4L)))
+		return FIRST_GPR;
+	else
+		return 0;
+}
+
+int reg_pair(int r, struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+	return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p, int r, struct obj *o)
+{
+	int c = p->code;
+	if(o->v && isextern(o->v->storage_class))  // Externs are particularly costly due to the ldinc r7 shuffle
+		return(o->flags & DREFOBJ ? 5 : 3);
+	if (o->flags & VKONST) {
+		if (isextern(o->flags) || isstatic(o->flags))
+			return 2;
+		else {
+			struct obj *o2 = &o->v->cobj;
+			int c = count_constantchunks(o2->val.vmax);
+			return c - 1;
+		}
+	}
+	if (o->flags & DREFOBJ)
+		return 2;
+	if (c == SETRETURN)// && r == p->z.reg && !(o->flags & DREFOBJ))
+		return 1;
+	if (c == GETRETURN)// && r == p->q1.reg && !(o->flags & DREFOBJ))
+		return 1;
+	return 1;
+}
+
+int regok(int r, int t, int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+	if (r == 0)
+		return 0;
+	t &= NQ;
+	if (ISFLOAT(t) && r >= FIRST_FPR && r <= LAST_FPR)
+		return 1;
+	if (t == POINTER && r >= FIRST_GPR && r <= LAST_GPR)
+		return 1;
+	if (t >= CHAR && t <= LONG && r >= FIRST_GPR && r <= LAST_GPR)
+		return 1;
+	return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+	int c = p->code;
+	if ((p->q1.flags & DREFOBJ) || (p->q2.flags & DREFOBJ)
+	    || (p->z.flags & DREFOBJ))
+		return 1;
+	if ((c == DIV || c == MOD) && !isconst(q2))
+		return 1;
+	return 0;
+}
+
+int must_convert(int o, int t, int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+	int op = o & NQ, tp = t & NQ;
+	if ((op == INT || op == LONG || op == POINTER)
+	    && (tp == INT || tp == LONG || tp == POINTER))
+		return 0;
+	if (op == DOUBLE && tp == LDOUBLE)
+		return 0;
+	if (op == LDOUBLE && tp == DOUBLE)
+		return 0;
+	return 1;
+}
+
+void gen_ds(FILE * f, zmax size, struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+	if (newobj && section != SPECIAL)
+		emit(f, "%ld\n", zm2l(size));
+	else
+		emit(f, "\t.space\t%ld\n", zm2l(size));
+	newobj = 0;
+}
+
+
+/*  This function has to make sure the next data is
+    aligned to multiples of <align> bytes.
+    If the speed optimisation flag is set, always align
+    to four bytes. */
+void gen_align(FILE * f, zmax align)
+{
+	if(optspeed)
+		emit(f,"\t.align\t4\n");
+	else if (zm2l(align) > 1)
+		emit(f, "\t.align\t%d\n", align);
+}
+
+void gen_var_head(FILE * f, struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+	int constflag;
+	char *sec;
+	if (v->clist)
+		constflag = is_const(v->vtyp);
+	if (v->storage_class == STATIC) {
+		if (ISFUNC(v->vtyp->flags))
+			return;
+		if (!special_section(f, v)) {
+			if (v->clist && (!constflag)) { // || (g_flags[2] & USEDFLAG))
+//			    && section != DATA) {
+				emit(f, "%s.%x\n",dataname,sectionid);
+				++sectionid;
+				if (f)
+					section = DATA;
+			}
+			if (v->clist && constflag) { // && !(g_flags[2] & USEDFLAG)
+//			    && section != RODATA) {
+				emit(f, "%s.%x\n",rodataname,sectionid);
+				++sectionid;
+				if (f)
+					section = RODATA;
+			}
+			if (!v->clist) { // && section != BSS) {
+				emit(f, "%s.%x\n",bssname,sectionid);
+				++sectionid;
+				if (f)
+					section = BSS;
+			}
+		}
+		if (v->clist || section == SPECIAL) {
+			gen_align(f, falign(v->vtyp));
+			emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
+		} else {
+			gen_align(f, falign(v->vtyp));
+			emit(f, "\t.lcomm\t%s%ld,", labprefix, zm2l(v->offset));
+		}
+		newobj = 1;
+	}
+	if (v->storage_class == EXTERN) {
+//		emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+		if (v->flags & (DEFINED | TENTATIVE)) {
+			if (!special_section(f, v)) {
+				if (v->clist && (!constflag)) { // || (g_flags[2] & USEDFLAG))
+//				    && section != DATA) {
+					emit(f, "%s.%x\n",dataname,sectionid);
+					++sectionid;
+					if (f)
+						section = DATA;
+				}
+				if (v->clist && constflag) { // && !(g_flags[2] & USEDFLAG)
+//				    && section != RODATA) {
+					emit(f, "%s.%x\n",rodataname,sectionid);
+					++sectionid;
+					if (f)
+						section = RODATA;
+				}
+				if (!v->clist) { // && section != BSS) {
+					emit(f, "%s.%x\n",bssname,sectionid);
+					++sectionid;
+					if (f)
+						section = BSS;
+				}
+			}
+			if (v->clist || section == SPECIAL) {
+				gen_align(f, falign(v->vtyp));
+				if (isweak(v))
+					emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
+				else
+					emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+				emit(f, "%s%s:\n", idprefix, v->identifier);
+			} else {
+				gen_align(f, falign(v->vtyp));
+				if (isweak(v))
+					emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
+				else {
+					emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+					emit(f, "\t.comm\t%s%s,", idprefix, v->identifier);
+				}
+			}
+			newobj = 1;
+		}
+	}
+}
+
+void gen_dc(FILE * f, int t, struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+	if (!p->tree) {
+		switch (t & NQ) {
+		case CHAR:
+			emit(f, "\t.byte\t");
+			break;
+		case SHORT:
+			emit(f, "\t.short\t");
+			break;
+		case LONG:
+		case INT:
+		case MAXINT:
+		case POINTER:
+			emit(f, "\t.int\t");
+			break;
+		case LLONG:
+			emit(f, "//FIXME - unsupported type\n");
+			emit(f, "\t.long\t");
+//			ierror(0);
+			break;
+		default:
+			printf("gen_dc: unsupported type 0x%x\n", t);
+			ierror(0);
+		}
+		emitval(f, &p->val, t & NU);
+		emit(f, "\n");
+
+#if 0
+		if (ISFLOAT(t)) {
+			/*  auch wieder nicht sehr schoen und IEEE noetig   */
+			unsigned char *ip;
+			ip = (unsigned char *)&p->val.vdouble;
+			emit(f, "0x%02x%02x%02x%02x", ip[0], ip[1], ip[2], ip[3]);
+			if ((t & NQ) != FLOAT) {
+				emit(f, ",0x%02x%02x%02x%02x", ip[4], ip[5], ip[6], ip[7]);
+			}
+		} else {
+			emitval(f, &p->val, t & NU);
+		}
+#endif
+	} else {
+		struct obj *o = &p->tree->o;
+		emit(f, "\t\t\t\t\t\t// Declaring from tree\n");
+		if (isextern(o->v->storage_class)) {
+			emit(f, "\t\t\t\t\t\t// extern (offset %d)\n", o->val.vmax);
+			if (o->val.vmax)
+				emit(f, "\t.ref\t_%s, %d\n", o->v->identifier, o->val.vmax);
+			else
+				emit(f, "\t.ref\t_%s\n", o->v->identifier);
+		} else if (isstatic(o->v->storage_class)) {
+			emit(f, "\t\t\t\t\t\t// static\n");
+			if(o->val.vlong)
+				emit(f, "\t.ref\t%s%d,%d\n", labprefix, zm2l(o->v->offset),o->val.vlong);
+			else
+				emit(f, "\t.ref\t%s%d\n", labprefix, zm2l(o->v->offset));
+		} else {
+			printf("error: GenDC (tree) - unknown storage class 0x%x!\n", o->v->storage_class);
+		}
+	}
+	newobj = 0;
+}
+
+
+/* Return 1 if any of p's operands uses predec or postinc addressing mode */
+int check_am(struct IC *p)
+{
+	if(p->q1.am && (p->q1.am->type==AM_POSTINC || p->q1.am->type==AM_PREDEC))
+		return(1);
+	if(p->q2.am && (p->q2.am->type==AM_POSTINC || p->q2.am->type==AM_PREDEC))
+		return(1);
+	if(p->z.am && (p->z.am->type==AM_POSTINC || p->z.am->type==AM_PREDEC))
+		return(1);
+	return(0);
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE * f, struct IC *p, struct Var *v, zmax offset)
+/*  The main code-generation.                                           */
+{
+	static int idemp = 0;
+	static int firsttail=1;
+	int reversecmp=0;
+	int c, t, i;
+	struct IC *m;
+	argsize = 0;
+	// if(DEBUG&1) 
+
+	if(!p)
+		printf("(gen_code called with null IC list?)\n");
+
+	for (c = 1; c <= MAXR; c++)
+		regs[c] = regsa[c];
+	pushed = 0;
+	notyetpopped = 0;
+
+#if 0
+	if (!idemp) {
+		sectionid = 0;
+		if (p && p->file) {
+			int v;
+			char *c = p->file;
+			idemp = 1;
+			while (v = *c++) {
+				sectionid <<= 3;
+				sectionid ^= v;
+			}
+			printf("Created section ID %x\n",sectionid);
+		}
+		else
+			printf("No sectionid created (%x, %x)\n",p,p ? p->file : 0);
+	}
+#endif
+
+	for (m = p; m; m = m->next) {
+		c = m->code;
+		t = m->typf & NU;
+		if (c == ALLOCREG) {
+			regs[m->q1.reg] = 1;
+			continue;
+		}
+		if (c == FREEREG) {
+			regs[m->q1.reg] = 0;
+			continue;
+		}
+
+		/* convert MULT/DIV/MOD with powers of two */
+		// Perversely, mul is faster than shifting on 832, so we only want to do this for div.
+		// FIXME - we can do this for signed values too.
+		if ((t & NQ) <= LONG && (m->q2.flags & (KONST | DREFOBJ)) == KONST && (t & NQ) <= LONG
+		    && (((c == DIV || c == MOD) && (t & UNSIGNED)))) {
+			eval_const(&m->q2.val, t);
+			i = pof2(vmax);
+			if (i) {
+				if (c == MOD) {
+					vmax = zmsub(vmax, l2zm(1L));
+					m->code = AND;
+				} else {
+					vmax = l2zm(i - 1);
+					if (c == DIV)
+						m->code = RSHIFT;
+					else
+						m->code = LSHIFT;
+				}
+				c = m->code;
+				gval.vmax = vmax;
+				eval_const(&gval, MAXINT);
+				if (c == AND) {	// FIXME - why?
+					insert_const(&m->q2.val, t);
+				} else {
+					insert_const(&m->q2.val, INT);
+					p->typf2 = INT;
+				}
+			}
+		}
+	}
+
+	for (c = 1; c <= MAXR; c++) {
+		if (regsa[c] || regused[c]) {
+			BSET(regs_modified, c);
+		}
+	}
+	localsize = (zm2l(offset) + 3) / 4 * 4;
+
+//    printf("\nSeeking addressing modes for function %s\n",v->identifier);
+	find_addressingmodes(p);
+
+	function_top(f, v, localsize);
+//    printf("%s:\n",v->identifier);
+
+	for (; p; p = p->next) {
+//		printic(stdout,p);
+		c = p->code;
+		t = q1typ(p);
+
+		if (c == NOP) {
+			p->z.flags = 0;
+			continue;
+		}
+		if (c == ALLOCREG) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// allocreg %s\n", regnames[p->q1.reg]);
+			regs[p->q1.reg] = 1;
+			continue;
+		}
+		if (c == FREEREG) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// freereg %s\n", regnames[p->q1.reg]);
+			regs[p->q1.reg] = 0;
+			continue;
+		}
+		if (c == LABEL) {
+			int i;
+			emit(f, "%s%d: # \n", labprefix, t);
+			cleartempobj(f,tmp);	// Can't carry temporary context past a label
+			cleartempobj(f,t1);
+			continue;
+		}
+
+		if (DBGMSG && p->file)
+			emit(f, "\n\t\t\t\t\t\t//%s, line %d\n", p->file, p->line);
+		if(p->q1.am && p->q1.am->disposable)
+			emit(f, "\t\t\t\t\t\t// Q1 disposable\n");
+		if(p->q2.am && p->q2.am->disposable)
+			emit(f, "\t\t\t\t\t\t// Q2 disposable\n");
+		if(p->z.am && p->z.am->disposable)
+			emit(f, "\t\t\t\t\t\t// Z disposable\n");
+
+		// OK
+		if (c == BRA) {
+			if(0) // FIXME - could duplicate function tail here.  Perhaps do it depending on number of saved registers?
+				function_bottom(f, v, localsize, 0);
+			else
+				emit_pcreltotemp(f, labprefix, t);
+			emit(f, "\tadd\t%s\n", regnames[pc]);
+			continue;
+		}
+		// OK
+		if (c >= BEQ && c < BRA) {
+			if(reversecmp)
+			{
+				switch(c)
+				{
+					case BLT:
+						c=BGT;
+						break;
+					case BLE:
+						c=BGE;
+						break;
+					case BGT:
+						c=BLT;
+						break;
+					case BGE:
+						c=BLE;
+						break;
+				}
+			}
+			emit(f, "\tcond\t%s\n",ccs[c - BEQ]);
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//conditional branch %s\n",reversecmp ? "reversed" : "regular");
+			reversecmp=0;
+			emit_pcreltotemp(f, labprefix, t);	// FIXME - double-check that we shouldn't include an offset here.
+			emit(f, "\t\tadd\tr7\n");
+			continue;
+		}
+		// Investigate - but not currently seeing it used.
+		if (c == MOVETOREG) {
+			emit(f, "\t\t\t\t\t\t//CHECKME movetoreg\n");
+			emit_objtoreg(f, &p->q1, ztyp(p),zreg);
+			continue;
+		}
+		// Investigate - but not currently seeing it used.
+		if (c == MOVEFROMREG) {
+			emit(f, "\t\t\t\t\t\t//CHECKME movefromreg\n");
+			store_reg(f, p->q1.reg, &p->z, regtype[p->q1.reg]->flags);
+			continue;
+		}
+		// Reject types we can't handle - anything beyond a pointer and chars with more than 1 byte.
+//		if ((c == PUSH)
+//		    && ((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1))) {
+//			printf("Pushing a type we don't yet handle: 0x%x\n", t);
+//			ierror(0);
+//		}
+
+		if ((c == ASSIGN) && ((t & NQ) > UNION)) {
+			printf("Assignment of a type we don't yet handle: 0x%x\n", t);
+			ierror(0);
+		}
+
+		// Avoid stack top slot trickery if the operation involves pushing operands to the stack
+	    if(c==DIV || c==MOD ||
+			((c==ASSIGN || c==PUSH) && ((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1))))
+			p = preload(f, p, 0);	// Setup zreg, etc.
+		else
+			p = preload(f, p, 1);	// Setup zreg, etc.
+
+		c = p->code;
+
+		if (c == SUBPFP)
+			c = SUB;
+		if (c == ADDI2P)
+			c = ADD;
+		if (c == SUBIFP)
+			c = SUB;
+
+//		emit(f, "// code 0x%x, q1->v: %x\n", c,&p->q1.v);
+//		if(p->prev && matchobj(f,&p->q1,&p->prev->q1))
+//			emit(f, "// Matching objs found\n", p->prev->code,&p->prev->q1.v);
+
+		if (c == CONVERT) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//FIXME convert\n");
+			if (ISFLOAT(q1typ(p)) || ISFLOAT(ztyp(p))) {
+				printf("Float not yet supported\n");
+				ierror(0);
+			}
+			if (sizetab[q1typ(p) & NQ] < sizetab[ztyp(p) & NQ]) {
+				int shamt = 0;
+				if(DBGMSG)
+					emit(f,"\t\t\t\t\t\t//Converting to wider type...\n");
+				switch (q1typ(p) & NU) {
+					case CHAR | UNSIGNED:
+					case SHORT | UNSIGNED:
+						if(DBGMSG)
+							emit(f,"\t\t\t\t\t\t//But unsigned, so no need to extend\n");
+
+						if(involvesreg(z)) {
+							emit_prepobj(f, &p->z, ztyp(p), zreg, 0);
+							emit_objtoreg(f, &p->q1, q1typ(p), tmp);
+							save_temp(f, p, zreg);
+							// WARNING - might need to invalidate temp objects here...
+						} else {
+							emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+							save_result(f, p);
+							// WARNING - might need to invalidate temp objects here...
+						}
+						break;
+					case CHAR:
+						emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+						emit_constanttotemp(f,0xffffff80);
+						emit(f,"\tadd\t%s\n",regnames[zreg]);
+						emit(f,"\txor\t%s\n",regnames[zreg]);
+						cleartempobj(f,zreg);
+						save_result(f, p);
+						break;
+					case SHORT:
+						emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+						emit_constanttotemp(f,0xffff8000);
+						emit(f,"\tadd\t%s\n",regnames[zreg]);
+						emit(f,"\txor\t%s\n",regnames[zreg]);
+						cleartempobj(f,zreg);
+						save_result(f, p);
+						break;
+				}
+//				settempobj(f,zreg,&p->z,0,0);
+			} else if(sizetab[q1typ(p) & NQ] >= sizetab[ztyp(p) & NQ]) {	// Reducing the size, must mask off excess bits...
+				if(DBGMSG)
+					emit(f,"\t\t\t\t\t\t// (convert - reducing type %x to %x\n",q1typ(p),ztyp(p));
+
+				// If Z is not a register then we're storing a halfword or byte, and thus don't need to mask...
+
+				if(((p->q1.flags&(REG|DREFOBJ))==REG) && (p->z.flags&(REG|DREFOBJ))!=REG) {
+					if(p->z.flags&DREFOBJ) {	// Can't use stmpdec for dereferenced objects
+						emit_prepobj(f, &p->z, t, zreg, 0); // Need an offset
+						emit_objtoreg(f, &p->q1, q1typ(p), tmp);
+						save_temp(f,p,zreg);
+#if 0
+						emit_prepobj(f, &p->z, t, tmp, 0); // Need an offset
+						emit(f, "\texg\t%s\n", regnames[q1reg]);
+//						if(!isstackparam(&p->z) || (p->z.flags&DREFOBJ))
+							emit_sizemod(f,ztyp(p));
+						emit(f, "\tst\t%s\n", regnames[q1reg]);
+						if(p->z.am && p->z.am->disposable && p->q1.am && p->q1.am->disposable)
+							emit(f, "\t\t\t\t\t\t// Both q1 and z are disposable, not bothering to undo exg\n");
+						else
+							emit(f, "\texg\t%s\n", regnames[q1reg]);
+#endif
+					}
+					else {
+						// Use stmpdec if q1 is already in a register...
+						emit_prepobj(f, &p->z, ztyp(p), tmp, 4); // Need an offset
+						if(!isstackparam(&p->z))
+							emit_sizemod(f,ztyp(p));
+						emit(f,"\tstmpdec\t%s\n",regnames[q1reg]);
+					}
+				}
+				else { // Destination is a register - we must mask...
+					// Potential optimisation here - track which ops could have caused a value to require truncation.
+					// Also figure out what's happening next to the value.  If it's only being added, anded, ored, xored
+					// and then truncated by a write to memory we don't need to worry.
+					if(!isreg(q1) || !isreg(z) || q1reg!=zreg) // Do we just need to mask in place, or move the value first?
+					{
+						if(!isreg(z))
+							zreg=t1;
+						emit_prepobj(f, &p->z, ztyp(p), t1, 0);
+
+						emit_objtoreg(f, &p->q1, t,tmp);
+						emit(f,"\t\t\t\t\t\t//Saving to reg %s\n",regnames[zreg]);
+						save_temp(f, p, zreg);
+					}
+//					else
+					if(zreg!=sp && (p->z.flags&(DREFOBJ|REG))==REG)
+					{
+						switch(ztyp(p)&NQ) {
+							case SHORT:
+								emit_constanttotemp(f, 0xffff);
+								emit(f, "\tand\t%s\n", regnames[zreg]);
+								break;
+							case CHAR:
+								emit_constanttotemp(f, 0xff);
+								emit(f, "\tand\t%s\n", regnames[zreg]);
+								break;
+							default:
+								emit(f,"\t\t\t\t\t\t//No need to mask - same size\n");
+								break;
+						}
+					}
+				}
+			}
+			continue;
+		}
+
+		if (c == KOMPLEMENT) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//comp\n");
+			emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+			emit_constanttotemp(f,-1);
+			emit(f, "\txor\t%s\n", regnames[zreg]);
+//			cleartempobj(f,zreg);
+			save_result(f, p);
+			continue;
+		}
+		// May not need to actually load the register here - certainly check before emitting code.
+		if (c == SETRETURN) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//setreturn\n");
+			emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+			BSET(regs_modified, p->z.reg);
+			continue;
+		}
+		// Investigate - May not be needed for register mode?
+		if (c == GETRETURN) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (getreturn)");
+			if (p->q1.reg) {
+				zreg = p->q1.reg;
+				save_result(f, p);
+			} else {
+				if(DBGMSG)
+					emit(f, " not reg\n");
+				p->z.flags = 0;
+			}
+			continue;
+		}
+		// OK - figure out what the bvunite stuff is all about.
+		if (c == CALL) {
+			int reg;
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//call\n");
+			if ((p->q1.flags & (VAR | DREFOBJ)) == VAR && p->q1.v->fi && p->q1.v->fi->inline_asm) {
+				emit_inline_asm(f, p->q1.v->fi->inline_asm);
+				cleartempobj(f,t1);
+				cleartempobj(f,tmp);
+				/* FIXME - restore stack from pushed arguments? */
+			} else {
+				/* FIXME - deal with different object types here */
+				if (p->q1.v->storage_class == STATIC) {
+					// FIXME - double-check that we shouldn't include an offset here.
+					emit_pcreltotemp2(f, &p->q1);
+					if (p->q1.flags & DREFOBJ) {
+						emit(f, "\taddt\t%s\t//Deref function pointer\n", regnames[pc]);
+						emit(f, "\tldt\n\texg\t%s\n", regnames[pc]);
+					} else
+						emit(f, "\tadd\t%s\n", regnames[pc]);
+				} else if (p->q1.v->storage_class == EXTERN) {
+					if (p->q1.flags & DREFOBJ) {	// Is this a function pointer?
+						emit_externtotemp(f, p->q1.v->identifier, p->q1.val.vmax);
+						emit(f, "\tldt\t// deref function ptr\n");
+						emit(f, "\texg\t%s\n", regnames[pc]);
+					}
+					else {
+						emit_pcreltotemp2(f, &p->q1);
+						emit(f, "\tadd\t%s\n", regnames[pc]);
+					}
+				} else {
+					emit_objtoreg(f, &p->q1, t, tmp);
+					emit(f, "\texg\t%s\n", regnames[pc]);
+				}
+
+				cleartempobj(f,tmp);
+
+				/* If we have an addressingmode, see if we're able to defer stack popping. */
+				if(p->z.am)
+				{
+					switch(p->z.am->deferredpop)
+					{
+						/* If we couldn't defer popping due to flow control changes, we need to pop any previously
+						   deferred stack entries at this point.*/
+						case DEFERREDPOP_FLOWCONTROL:
+							emit(f,"\t\t\t\t\t\t// Flow control - popping %d + %d bytes\n",pushedargsize(p),notyetpopped);
+							if(pushedargsize(p)+notyetpopped)
+							{
+								emit_constanttotemp(f, pushedargsize(p)+notyetpopped);				
+								emit(f, "\tadd\t%s\n", regnames[sp]);
+							}
+							pushed -= pushedargsize(p);
+							notyetpopped=0;
+							break;
+
+						/* If we couldn't defer popping due to nested calls then we only pop this function's stack entries. */
+						case DEFERREDPOP_NESTEDCALLS:
+							emit(f,"\t\t\t\t\t\t// Nested call - popping %d bytes\n",pushedargsize(p));
+							if(pushedargsize(p))
+							{
+								emit_constanttotemp(f, pushedargsize(p));
+								emit(f, "\tadd\t%s\n", regnames[sp]);
+							}
+							pushed -= pushedargsize(p);
+							break;
+
+						/*	Otherwise, we're OK to defer popping until later. */
+						case DEFERREDPOP_OK:
+							notyetpopped+=pushedargsize(p);
+							pushed -= pushedargsize(p);
+							emit(f,"\t\t\t\t\t\t// Deferred popping of %d bytes (%d in total)\n",pushedargsize(p),notyetpopped);
+							break;
+					}
+				}
+				else if(pushedargsize(p))
+				{
+					emit_constanttotemp(f, pushedargsize(p));
+					pushed -= pushedargsize(p);
+					emit(f, "\tadd\t%s\n", regnames[sp]);
+				}
+//				cleartempobj(f,tmp);
+				cleartempobj(f,t1);
+			}
+			 /*FIXME*/
+			if ((p->q1.flags & (VAR | DREFOBJ)) == VAR && p->q1.v->fi
+				       && (p->q1.v->fi->flags & ALL_REGS)) {
+				bvunite(regs_modified, p->q1.v->fi->regs_modified, RSIZE);
+			} else {
+				int i;
+				for (i = 1; i <= MAXR; i++) {
+					if (regscratch[i])
+						BSET(regs_modified, i);
+				}
+			}
+			continue;
+		}
+
+		if ((c == ASSIGN || c == PUSH) && t == 0) {
+			printf("Bad type for assign / push\n");
+			ierror(0);
+		}
+		// Basically OK.
+		if (c == PUSH) {
+			int matchreg;
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (a/p push)\n");
+
+			/* Handle composite types */
+		    if((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1)) {
+//				if(DBGMSG)
+					emit(f,"\t\t\t\t\t\t// Pushing composite type - size %d, pushed size %d\n",opsize(p),pushsize(p));
+				emit_inlinepush(f,p,t);
+				pushed += pushsize(p);
+			}
+			else
+			{
+				/* need to take dt into account */
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// a: pushed %ld, regnames[sp] %s\n", pushed, regnames[sp]);
+				switch(t&NQ)
+				{
+					case INT:
+					case LONG:
+					case POINTER:
+						emit_objtoreg(f, &p->q1, t, tmp);
+						emit(f, "\tstdec\t%s\n", regnames[sp]);
+						break;
+					default:
+						printf("Pushing unhandled type 0x%x to the stack\n",t);
+						ierror(0);
+						break;
+				}
+				pushed += pushsize(p);
+			}
+			continue;
+		}
+
+		if (c == ASSIGN) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (a/p assign)\n");
+			if (((t & NQ) == STRUCT) || ((t & NQ) == UNION) || ((t & NQ) == ARRAY)
+			    || ((t & NQ) == CHAR && opsize(p) != 1)) {
+				emit_inlinememcpy(f,p,t);
+			} else {
+				// Is the small speedup here worth the complexity?  (Yes, because it improves code density)
+				// Use stmpdec if q1 is already in a register and we're not using addressing modes...
+				if(!check_am(p) && ((p->q1.flags&(REG|DREFOBJ))==REG) && !(p->z.flags&REG))
+				{
+					if(p->z.flags&DREFOBJ)	// Can't use stmpdec for dereferenced objects
+					{
+						emit_prepobj(f, &p->z, t, tmp, 0);
+						emit(f, "\texg\t%s\n", regnames[q1reg]);
+						emit_sizemod(f,t);
+						emit(f, "\tst\t%s\n", regnames[q1reg]);
+						if(p->z.am && p->z.am->disposable)
+						{
+							cleartempobj(f,tmp);
+							emit(f, "\t\t\t\t\t\t// Object is disposable, not bothering to undo exg\n");
+						}
+						else
+							emit(f, "\texg\t%s\n", regnames[q1reg]);
+					}
+					else
+					{
+						emit_prepobj(f, &p->z, t, tmp, 4); // Need an offset
+						if(!isstackparam(&p->z))
+							emit_sizemod(f,t);
+						emit(f,"\tstmpdec\t%s\n",regnames[q1reg]);
+						cleartempobj(f,tmp);
+					}
+				}
+				else
+				{
+					emit_prepobj(f, &p->z, t, t1, 0);
+					emit_objtoreg(f, &p->q1, t, tmp);
+					save_temp(f, p, t1);
+				}
+			}
+			continue;
+		}
+		// Seems to work.
+		if (c == ADDRESS) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (address)\n");
+			if(involvesreg(z))
+			{
+				emit_prepobj(f, &p->q1, POINTER, tmp, 0);
+				save_temp(f,p,zreg);
+			}
+			else
+			{
+				emit_prepobj(f, &p->q1, POINTER, zreg, 0);
+				save_result(f, p);
+			}
+			continue;
+		}
+		// OK
+		if (c == MINUS) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (minus)\n");
+			emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+			emit_constanttotemp(f,0);
+			emit(f, "\texg %s\n\tsub %s\n", regnames[zreg], regnames[zreg]);
+			settempobj(f,tmp,&p->q1,0,0); // Temp contains un-negated value
+			// cleartempobj(f,tmp);
+			save_result(f, p);
+			continue;
+		}
+		// Compare - #
+		// Revisit
+		if (c == TEST) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (test)\n");
+			if(!emit_objtoreg(f, &p->q1, t, tmp)) /* emit_objtoreg might already have set the Z flag */
+			{
+				emit(f,"\t\t\t\t// flags %x\n",p->q1.flags);
+				if ((p->q1.flags & (REG|DREFOBJ)) == REG)	// Can avoid mr if the value came from a register
+						emit(f, "\tand\t%s\n", regnames[p->q1.reg]);
+				else
+				{
+						emit(f, "\tmr\t%s\n\tand\t%s\n", regnames[t1], regnames[t1]);
+						settempobj(f,t1,&p->q1,0,0);
+				}
+//				cleartempobj(f,tmp);
+//				cleartempobj(f,t1);
+			}
+			continue;
+		}
+		// Compare
+		// Revisit
+		if (c == COMPARE) {
+			if(DBGMSG)
+			{
+					emit(f, "\t\t\t\t\t\t// (compare)");
+				if (q1typ(p) & UNSIGNED)
+					emit(f, " (q1 unsigned)");
+				else
+					emit(f, " (q1 signed)");
+				if (q2typ(p) & UNSIGNED)
+					emit(f, " (q2 unsigned)");
+				else
+					emit(f, " (q2 signed)");
+				emit(f,"\n");
+			}
+
+			// If q2 is a register but q1 isn't we could reverse the comparison, but would then have to reverse
+			// the subsequent conditional branch.
+			// FIXME - can also reverse if one value is cached
+
+			if (!isreg(q1)) {
+				if(isreg(q2)) {	// Reverse the test.
+					emit_objtoreg(f, &p->q1, t,tmp);
+					q1reg=q2reg;
+					reversecmp=1;
+				} else { // Neither object is in a register, so load q1 into t1 and q2 into tmp.
+					emit_objtoreg(f, &p->q1, t,t1);
+					cleartempobj(f,t1);
+					q1reg = t1;
+					emit_objtoreg(f, &p->q2, t,tmp);
+				}
+			}
+			else
+				emit_objtoreg(f, &p->q2, t,tmp);
+			if ((!(q1typ(p) & UNSIGNED)) && (!(q2typ(p) & UNSIGNED))) {	// If we have a mismatch of signedness we treat as unsigned.
+				int nextop=p->next->code;	// Does the sign matter for the branch being done?
+				if(nextop==FREEREG)
+					nextop=p->next->next->code;
+				if((nextop!=BEQ) && (nextop!=BNE))
+					emit(f, "\tsgn\n");	// Signed comparison
+			}
+			emit(f, "\tcmp\t%s\n", regnames[q1reg]);
+			continue;
+		}
+
+		// Division and modulo
+		if ((c == MOD) || (c == DIV)) {
+			int targetreg=zreg;
+			int doneq2=0;
+			// FIXME - do we need to use switch_IC here?
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//Call division routine\n");
+
+			// determine here whether R1 and R2 really need saving - may not be in use, or may be the target register.
+			if(regs[t2] && zreg!=t2)
+			{
+				emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[t2], regnames[sp]);
+				cleartempobj(f,tmp);
+				pushed+=4;
+			}
+			if(regs[t2+1] && zreg!=(t2+1))
+			{
+				emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[t2 + 1], regnames[sp]);
+				cleartempobj(f,tmp);
+				pushed += 4;
+			}
+			// q1 must be written to t2, q2 must be written to t2+2
+			// if q2 starts in t2 we have to avoid overwriting it.
+
+			// If q1 is already in t2, q2 can't be, so we don't need to worry about swapping
+			if(!isreg(q1) || q1reg!=t2)
+			{
+				emit_objtoreg(f, &p->q1, t,tmp);
+
+				// Need to make sure we're not about to overwrite the other operand!
+				if(isreg(q2) && q2reg==t2)
+				{
+					emit(f,"\texg\t%s\n",regnames[t2]);
+					emit(f,"\tmr\t%s\n",regnames[t2+1]);
+					doneq2=1;
+				}
+				else
+					emit(f, "\tmr\t%s\n", regnames[t2]);
+			}
+			if(!doneq2 && (!isreg(q2) || q2reg!=t2+1))
+			{
+				emit_objtoreg(f, &p->q2, t,tmp);
+				emit(f, "\tmr\t%s\n", regnames[t2 + 1]);
+			}
+			cleartempobj(f,t1);
+			cleartempobj(f,t2);
+
+			if ((!(q1typ(p) & UNSIGNED)) && (!(q2typ(p) & UNSIGNED)))	// If we have a mismatch of signedness we treat as unsigned.
+				emit(f, "\t.lipcrel\t_div_s32bys32\n");
+			else
+				emit(f, "\t.lipcrel\t_div_u32byu32\n");
+			emit(f, "\tadd\t%s\n", regnames[pc]);
+
+			// If the next IC is SetReturn from the same register we can skip saving the result.
+			if(next_setreturn(p,zreg))
+			{
+				emit(f,"\t\t\t\t\t\t// Skipping save_result...\n");
+				targetreg=t1;
+			}
+
+			if (c == MOD)
+			{
+				if(targetreg!=t2)
+					emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[t2], regnames[zreg]);
+			}
+			else
+			{
+				if(targetreg!=t1)
+					emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[t1], regnames[zreg]);
+			}
+
+			if(regs[t2+1] && zreg!=(t2+1))
+			{
+				emit(f, "\tldinc\t%s\n\tmr\t%s\n", regnames[sp], regnames[t2+1]);
+				pushed -= 4;
+			}
+			if(regs[t2] && zreg!=t2)
+			{
+				emit(f, "\tldinc\t%s\n\tmr\t%s\n", regnames[sp], regnames[t2]);
+				pushed -= 4;
+			}
+
+			cleartempobj(f,tmp);
+			cleartempobj(f,t1);
+
+			// Target not guaranteed to be a register.
+			save_result(f, p);
+
+			continue;
+		}
+
+		// Remaining arithmetic and bitwise operations
+
+		if ((c >= OR && c <= AND) || (c >= LSHIFT && c <= MULT)) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// (bitwise/arithmetic) ");
+			if(DBGMSG)
+				emit(f, "\t//ops: %d, %d, %d\n", q1reg, q2reg, zreg);
+			if(p->q1.am && p->q1.am->type==AM_ADDT)
+			{
+				if(DBGMSG)
+					emit(f,"\t\t\t\t\t\t//Special case - addt\n");
+				// FIXME - if q2 is already in tmp could reverse this
+				if(p->q2.flags&KONST)
+				{
+					zreg=t1;
+					emit_prepobj(f, &p->z, t, t1, 0);
+
+					emit_objtoreg(f, &p->q2, t,tmp);
+					emit(f,"\taddt\t%s\n",regnames[p->q1.reg]);
+					settempobj(f,tmp,&p->z,0,0);
+					save_temp(f, p, zreg);
+					obsoletetempobj(f,t1,&p->z,0);
+//					emit(f,"\tmr\t%s\n",regnames[p->z.reg]);
+				}
+				else
+				{
+					zreg=t1;
+					emit_prepobj(f, &p->z, t, t1, 0);
+
+					emit_objtoreg(f, &p->q1, t,tmp);
+					emit(f,"\taddt\t%s\n",regnames[p->q2.reg]);
+					settempobj(f,tmp,&p->z,0,0);
+					save_temp(f, p, zreg);
+					obsoletetempobj(f,t1,&p->z,0);
+//					emit(f,"\tmr\t%s\n",regnames[p->z.reg]);
+				}
+				continue;
+			}
+
+			if (involvesreg(q2) && q2reg == zreg) {
+//                      printf("Target register and q2 are the same!  Attempting a switch...\n");
+				if (switch_IC(p)) {
+					preload(f,p,1);	// refresh q1reg, etc after switching the IC
+				} else {
+					emit(f,
+					     "\t\t\t\t\t\t// WARNING - evading q2 and target collision - check code for correctness.\n");
+					zreg = t1;
+				}
+			}
+			if (involvesreg(q1) && q1reg == zreg)
+				emit(f,"\t\t\t\t\t\t// WARNING - q1 and target collision - check code for correctness.\n");
+
+			if (!isreg(q1) || q1reg != zreg) {
+				emit_objtoreg(f, &p->q1, t,zreg);
+//				emit(f, "\tmr\t%s\n", regnames[zreg]);	// FIXME - what happens if zreg and q1/2 are the same?
+			}
+			emit_objtoreg(f, &p->q2, t,tmp);
+			if (c >= OR && c <= AND)
+				emit(f, "\t%s\t%s\n", logicals[c - OR], regnames[zreg]);
+			else {
+				if (c == RSHIFT || c==MULT)	// Modify right shift operations with appropriate signedness...
+				{
+//					printf("q1typ: %x, q2typ: %x, ztyp: %x\n",q1typ(p),q2typ(p),ztyp(p));
+					if (!(t & UNSIGNED))
+					{
+						// Evaluate q1 - if we're dealing with a constant that doesn't have bit 31 set we don't need sgn...
+						if((!(p->typf2 & UNSIGNED) && c==RSHIFT) 
+									|| (p->q1.flags&(KONST|DREFOBJ)!=KONST)
+											|| (val2zmax(&p->q1,p->typf)&0x80000000))
+							emit(f, "\tsgn\n");
+					}
+				}
+				emit(f, "\t%s\t%s\n", arithmetics[c - LSHIFT], regnames[zreg]);
+				if(c==MULT)
+					cleartempobj(f,tmp);
+			}
+			settempobj(f,zreg,&p->z,0,0);
+			cleartempobj(f,zreg);
+			save_result(f, p);
+			continue;
+		}
+		printf("Unhandled IC\n");
+		pric2(stdout, p);
+		ierror(0);
+	}
+	if(function_bottom(f, v, localsize+notyetpopped,firsttail))
+		firsttail=0;
+}
+
+int shortcut(int code, int typ)
+{
+	// Only RSHIFT and AND are safe on 832.
+	// So far have seen shortcut requests for
+	// DIV
+	// ADD
+	// RSHIFT
+	// COMPARE
+	// SUB
+	// LSHIFT
+	// AND
+	// MULT
+	// OR
+
+//	printf("Evaluating shortcut for code %d, type %x\n",code,typ);
+	if(code==RSHIFT)
+		return(1);
+	if(code==AND)
+		return(1);
+
+	return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t, int vararg, struct Typ *d)
+{
+	int f;
+	f = t->flags & NQ;
+	if(is_varargs(d))	/* Disallow register parameters for varargs functions */
+		return(0);
+
+	if (f <= LONG || f == POINTER) {
+		if (m->gregs >= REGPARM_COUNT)
+			return 0;
+		else
+			return FIRST_GPR + 1 + m->gregs++;
+	}
+	if (ISFLOAT(f)) {
+		return(0);
+/*		if (m->fregs >= 0)
+			return 0;
+		else
+			return FIRST_FPR + 2 + m->fregs++;
+*/
+	}
+	return 0;
+}
+
+int iscomment(char *str)
+{
+	char c;
+	while(c=*str++)
+	{
+		if(!c || c=='\n' || c=='/')
+			return(1);
+		if(c!=' '&&c!='\t')
+			return(0);
+	}
+	return(1);
+}
+
+
+int emit_peephole(void)
+{
+	int i;
+	int havemr=0;
+	int havemt=0;
+	int havestore=0;
+	int haveload=0;
+	int loadidx=0;
+	i=emit_f;
+
+	while(i!=emit_l)
+	{
+		int reg,reg2;
+	    if(sscanf(emit_buffer[i],"\tmr\tr%d",&reg)==1)
+		{
+			if(havemt && reg==reg2)
+			{
+				strcpy(emit_buffer[i],"\t//mr\n");
+				return(1);
+			}
+			reg2=reg;
+			havemr=1;
+			havemt=0;
+		}
+	    else if(sscanf(emit_buffer[i],"\tmt\tr%d",&reg)==1)
+		{
+			if(havemr && reg==reg2)
+			{
+				strcpy(emit_buffer[i],"\t//mt\n");
+				return(1);
+			}
+			reg2=reg;
+			havemr=0;
+			havemt=1;
+		}
+		else if(sscanf(emit_buffer[i],"\tst\tr%d",&reg)==1)
+		{
+			havemr=havemt=0;
+			havestore=1;
+		}
+		else if(sscanf(emit_buffer[i],"\tld\tr%d",&reg2)==1 && havestore)
+		{
+			havemr=havemt=0;
+			if(reg==reg2 && reg==6) /* Only stack ops - others would be risky due to potential hardware registers. */
+			{
+				loadidx=i;
+				haveload=1;
+//				printf("Found matching load directive, r%d\n",reg);
+//				strcpy(emit_buffer[i],"\t//nop\n");
+//				return(1);
+			}
+		}
+		else if(!iscomment(emit_buffer[i])) /* Check that the next instruction isn't "cond" */
+		{
+			havemr=havemt=0;
+			if(haveload && strncmp(emit_buffer[i],"\tcond",5)) /* If not, we're OK to zero out the load */
+			{
+				strcpy(emit_buffer[loadidx],"\t//nop\n");
+				return(1);
+			}
+			else
+			{
+				havestore=haveload=0;
+			}
+		}
+		i=(i+1)%EMIT_BUF_DEPTH;
+	}
+	return 0;                                                                    
+}
+
+
+int handle_pragma(const char *s)
+{
+	return(0);
+}
+
+void cleanup_cg(FILE * f)
+{
+}
+
+void cleanup_db(FILE * f)
+{
+	if (f)
+		section = -1;
+}
diff --git a/machines/832/machine.dt b/machines/832/machine.dt
new file mode 100644
index 0000000..526c8d4
--- /dev/null
+++ b/machines/832/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/832/machine.h b/machines/832/machine.h
new file mode 100644
index 0000000..43aba53
--- /dev/null
+++ b/machines/832/machine.h
@@ -0,0 +1,148 @@
+/*  EightThirtyTwo backend for vbcc.
+    Based on the "generic" backend.
+*/
+
+/* build-time configurable options: */
+#define NUM_GPRS 9
+#define SCRATCH_GPRS 2
+#define NUM_FPRS 0
+#define NUM_CCRS 0
+#define FIXED_SP 0
+
+#include "dt.h"
+
+/* Define this if you need to build with 0.9g */
+/* #define V09G */
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define RESERVED_GPRS 1
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+/*  FIXME - we can make use of ldidx here */
+enum AddressingMode_Type { AM_POSTINC=1, AM_PREDEC, AM_ADDT };
+struct AddressingMode{
+    enum AddressingMode_Type type;
+	int disposable;
+	int deferredpop;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 3
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+
+extern char flag_832_bigendian;
+#define BIGENDIAN (flag_832_bigendian)
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN (!flag_832_bigendian)
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 1
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+#define REGPARM_COUNT 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+// #define ORDERED_PUSH 1
+// FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have implemented our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 5
+#define cost_save_reg(x,y) 5
+#define cost_pushpop_reg(x) 1
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 16
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+/* We (will eventually) use libcalls for 64-bit and float support */
+/* Enabling this completely changes code generation - investigate. */
+#define HAVE_LIBCALLS 0
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
diff --git a/machines/832/tempregs.c b/machines/832/tempregs.c
new file mode 100644
index 0000000..c4b177f
--- /dev/null
+++ b/machines/832/tempregs.c
@@ -0,0 +1,624 @@
+/*
+To do: 
+	Peephole optimise away such constructs as mr r0, mt r0
+	| Optimise addresses of stack variables - lea's can mostly be replaced with simple adds.
+	Detect absolute moves to reg, prune any that aren't needed.
+
+	tempreg logic should be correct - now it's up to machine.c to make good use of it.
+*/
+
+zmax val2zmax(struct obj *o, int t)
+{
+	union atyps *p = &o->val;
+	t &= NU;
+	if (t == CHAR)
+		return (zc2zm(p->vchar));
+	if (t == (UNSIGNED | CHAR))
+		return (zuc2zum(p->vuchar));
+	if (t == SHORT)
+		return (zs2zm(p->vshort));
+	if (t == (UNSIGNED | SHORT))
+		return (zus2zum(p->vushort));
+
+	/*
+	   if(t==FLOAT) return(zf2zld(p->vfloat);emitzld(f,vldouble);}
+	   if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+	   if(t==LDOUBLE){emitzld(f,p->vldouble);}
+	 */
+
+	if (t == INT)
+		return (zi2zm(p->vint));
+	if (t == (UNSIGNED | INT))
+		return (zui2zum(p->vuint));
+	if (t == LONG)
+		return (zl2zm(p->vlong));
+	if (t == (UNSIGNED | LONG))
+		return (zul2zum(p->vulong));
+	if (t == LLONG)
+		return (zll2zm(p->vllong));
+	if (t == (UNSIGNED | LLONG))
+		return (zull2zum(p->vullong));
+	if (t == MAXINT)
+		return (p->vmax);
+	if (t == (UNSIGNED | MAXINT))
+		return (p->vumax);
+	if (t == POINTER)
+		return (zul2zum(p->vulong));
+	printf("#FIXME - no float support yet\n");
+	ierror(0);
+}
+
+static void emit_sizemod(FILE * f, int type)
+{
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t//sizemod based on type 0x%x\n", type);
+	switch (type & NQ) {
+	case 0:
+		if(DBGMSG)
+			emit(f, "\t\t\t\t\t\t//sizemod type is zero (movefromreg?)");
+		break;
+	case CHAR:
+		emit(f, "\tbyt\n");
+		break;
+	case SHORT:
+		emit(f, "\thlf\n");
+		break;
+	case INT:
+	case LONG:
+	case LLONG:
+	case POINTER:
+	case FUNKT:		// Function pointers are dereferenced by calling them.
+	case STRUCT:
+	case UNION:
+	case ARRAY:
+		break;		// Structs and unions have to remain as pointers
+	default:
+		printf("emit_sizemod - type %d not handled\n", type);
+		ierror(0);
+		break;
+	}
+}
+
+
+// WARNING: Must invalidate tmp if control flow doesn't change immediately after this instruction.
+
+static void emit_pcreltotemp(FILE * f, char *lab, int suffix)
+{
+	int i;
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t//pcreltotemp\n");
+	emit(f, "\t.lipcrel\t%s%d\n", lab, suffix);
+//	cleartempobj(f,tmp);
+}
+
+static void emit_pcreltotemp2(FILE *f,struct obj *p)
+{
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t//pcreltotemp\n");
+	if (p->v->storage_class == STATIC)
+		emit(f,"\t.lipcrel\t%s%d\n",labprefix, zm2l(p->v->offset));
+	else if(p->v->storage_class == EXTERN)
+	{
+		if(p->val.vmax)
+			emit(f,"\t.lipcrel\t_%s%d\n",p->v->identifier, p->val.vmax);
+		else
+			emit(f,"\t.lipcrel\t_%s\n",p->v->identifier);
+	}
+//	cleartempobj(f,tmp);
+}
+
+// tempobj logic should be correct.
+
+static void emit_externtotemp(FILE * f, char *lab, int offset)	// FIXME - need to find a way to do this PC-relative.
+{
+#if 0
+	emit(f, "\tldinc\t%s\n", regnames[pc]);
+	if (offset)
+		emit(f, "\t.ref\t_%s, %d\n",lab, offset);
+	else
+		emit(f, "\t.ref\t_%s\n",lab);
+#else
+	if(g_flags[FLAG_PIC]&USEDFLAG)
+	{
+		if (offset)
+			emit(f, "\t.lipcrel\t_%s, %d\n",lab, offset);
+		else
+			emit(f, "\t.lipcrel\t_%s\n",lab);
+		emit(f, "\taddt\t%s\n",regnames[pc]);
+	}
+	else
+	{
+		if (offset)
+			emit(f, "\t.liabs\t_%s, %d\n",lab, offset);
+		else
+			emit(f, "\t.liabs\t_%s\n",lab);
+	}
+#endif
+	cleartempobj(f,tmp);
+}
+
+
+// tempobj logic should be correct.
+
+static void emit_statictotemp(FILE * f, char *lab, int suffix, int offset)	// FIXME - need to find a way to do this PC relative
+{
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t//statictotemp (FIXME - make PC-relative?)\n");
+	if(g_flags[FLAG_PIC]&USEDFLAG)
+	{
+		emit(f, "\t.lipcrel\t%s%d,%d\n", lab, suffix, offset);
+		emit(f, "\taddt\t%s\n",regnames[pc]);
+	}
+	else
+	{
+		emit(f, "\t.liabs\t%s%d,%d\n", lab, suffix, offset);
+	}
+	cleartempobj(f,tmp);
+}
+
+static int count_constantchunks(zmax v)
+{
+	int chunk = 1;
+	int v2 = (int)v;
+	while (((v2 & 0xffffffe0) != 0) && ((v2 & 0xffffffe0) != 0xffffffe0))	// Are we looking at a sign-extended 6-bit value yet?
+	{
+//               printf("%08x\n",v2);
+		v2 >>= 6;
+		++chunk;
+	}
+	return (chunk);
+}
+
+
+// tempobj logic should be correct.
+
+static void emit_constanttoreg(FILE * f, zmax v,int reg)
+{
+	int matchreg=matchtempkonst(f,v,reg);
+//	emit(f,"// matchreg %s\n",regnames[matchreg]);
+
+//	if(matchreg==tmp)
+//		return;
+//	else if(matchreg)
+//		emit(f,"\tmt\t%s\n",regnames[matchreg]);
+	if(matchreg) {
+		// Need to deal with the case where a constant is in r0 but required in tmp or vice versa.
+		if(matchreg!=reg) {
+			if(reg==tmp)
+				emit(f,"\tmt\t%s\n",regnames[matchreg]);
+			else
+				emit(f,"\tmr\t%s\n",regnames[reg]);
+			settempkonst(f,reg,v);
+		}
+	} else {
+		emit(f, "\t.liconst\t%d\n", v);
+		settempkonst(f,tmp,v);
+		if(reg!=tmp)
+		{
+			emit(f,"\tmr\t%s\n",regnames[reg]);
+			settempkonst(f,reg,v);
+		}
+	}
+}
+
+static void emit_constanttotemp(FILE * f, zmax v)
+{
+	emit_constanttoreg(f,v,tmp);
+}
+
+
+// tempobj logic should be correct.
+
+static void emit_stackvartotemp(FILE * f, zmax offset, int deref)
+{
+	if (deref) {
+		if (offset) {
+			emit_constanttotemp(f, offset);
+			emit(f, "\tldidx\t%s\n", regnames[sp]);
+		} else
+			emit(f, "\tld\t%s\n", regnames[sp]);
+	} else {
+		if (offset) {
+			emit_constanttotemp(f, offset);
+			emit(f, "\taddt\t%s\n", regnames[sp]);
+		} else
+			emit(f, "\tmt\t%s\n", regnames[sp]);
+	}
+	cleartempobj(f,tmp);
+}
+
+
+// Load the address of a target obj into reg in preparation for a store.
+// If the target is simply a register then does nothing.
+// The nominated register can be tmp or any gpr.
+// Guaranteed not to modify t1 or t2 except when nominated.
+// tempobj logic should be correct.
+
+static void emit_prepobj(FILE * f, struct obj *p, int t, int reg, int offset)
+{
+	int matchreg=0;
+
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t// (prepobj %s)\n ", regnames[reg]);
+
+	if (p->flags & REG) {
+		if(DBGMSG)
+			emit(f, "\t\t\t\t\t\t// reg %s - no need to prep\n", regnames[p->reg]);
+		if(p->flags & DREFOBJ)
+		{
+			if (reg == tmp)
+			{
+				emit(f, "\tmt\t%s\n", regnames[p->reg]);
+				cleartempobj(f,tmp);
+			}
+		}
+		return;
+	}
+
+	if(!offset)
+		matchreg=matchtempobj(f,p,1,t1);  // FIXME - we're hunting for varadr here.
+
+	if(matchreg)
+	{
+		if(DBGMSG)
+			emit(f,"\n\t\t\t\t\t\t// required value found in %s\n",regnames[matchreg]);
+		if(matchreg==reg)
+			return;
+		else if(matchreg==tmp) {
+			emit(f,"\tmr\t%s\n",regnames[reg]);
+			settempobj(f,reg,p,0,0);
+			return;
+		} else {
+			emit(f,"\tmt\t%s\n",regnames[matchreg]);
+			settempobj(f,tmp,p,0,0);
+			if(reg!=tmp)
+			{
+				emit(f,"\tmr\t%s\n",regnames[reg]);
+				settempobj(f,reg,p,0,0);
+			}
+			return;
+		}
+	}
+
+	if (p->flags & DREFOBJ) {
+		if (p->flags & VARADR)
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t//varadr AND ");
+		if(DBGMSG)
+			emit(f, "\t\t\t\t\t\t// deref\n");
+		/* Dereferencing a pointer */
+		if (p->flags & KONST) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// const to %s\n",regnames[reg]);
+			emit_constanttoreg(f, val2zmax(p, p->dtyp) + offset,reg);
+//			if (reg != tmp)
+//				emit(f, "\tmr\t%s\n", regnames[reg]);
+			settempkonst(f,reg,val2zmax(p, p->dtyp) + offset);
+		} else if (p->flags & REG) {
+			if (reg == tmp)
+			{
+				emit(f, "\tmt\t%s\n", regnames[p->reg]);
+				cleartempobj(f,tmp);
+			}
+			else if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// reg %s - no need to prep\n", regnames[p->reg]);
+		} else if (p->flags & VAR) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// var FIXME - deref?\n");
+			if(offset)
+			{
+				printf("emit_prepobj: Offset supplied but object is being dereferenced!\n");
+				ierror(0);
+			}
+			if (isauto(p->v->storage_class)) {
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// reg - auto\n");
+				emit_stackvartotemp(f, real_offset(p) + offset, 1);
+				if (reg != tmp)
+				{
+					emit(f, "\tmr\t%s\n", regnames[reg]);
+					cleartempobj(f,reg);
+				}
+			} else if (isstatic(p->v->storage_class)) {
+				cleartempobj(f,tmp);
+				cleartempobj(f,reg);
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// static\n");
+				emit(f, "\tldinc\tr7\n\t.ref\t%s%d,%d\n",
+				     labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+				emit(f, "\tldt\n");
+				if (reg != tmp)
+					emit(f, "\tmr\t%s\n", regnames[reg]);
+			} else if (isextern(p->v->storage_class)) {
+				emit(f, "\t\t\t\t\t\t//Extern\n");
+				emit_externtotemp(f, p->v->identifier, p->val.vmax);
+				emit(f, "\tldt\n");
+				if (reg != tmp)
+					emit(f, "\tmr\t%s\n", regnames[reg]);
+			} else {
+				if(DBGMSG)
+					printf("// emit_prepobj (deref): - unknown storage class!\n");
+				ierror(0);
+			}
+//                              if(!zmeqto(l2zm(0L),p->val.vmax)){
+//                                      emit(f," offset ");
+//                                      emit(f," FIXME - deref?\n");
+//                                      emit_constanttotemp(f,val2zmax(f,p,LONG));
+//                                      emit(f,"\tmr\t%s\n",regnames[reg]);
+//                                      emit_pcreltotemp(f,labprefix,zm2l(p->v->offset));
+//                                      emit(f,"\tadd\t%s\n",regnames[reg]);
+//                              }
+		}
+	} else {
+		if (p->flags & REG) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// reg %s - no need to prep\n", regnames[p->reg]);
+		} else if (p->flags & VAR) {
+			if (isauto(p->v->storage_class)) {
+				/* Set a register to point to a stack-base variable. */
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// var, auto|reg\n");
+				if (p->v->storage_class == REGISTER)
+					if(DBGMSG)
+						emit(f, "\t\t\t\t\t\t// (is actually REGISTER)\n");
+				emit_stackvartotemp(f, real_offset(p) + offset, 0);
+				if (reg != tmp)
+					emit(f, "\tmr\t%s\n\n", regnames[reg]);
+			} else if (isextern(p->v->storage_class)) {
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// extern (offset %d)\n", p->val.vmax);
+				emit_externtotemp(f, p->v->identifier, p->val.vmax + offset);
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// extern pe %s varadr\n", p->flags & VARADR ? "is" : "not");
+				if (reg != tmp)
+					emit(f, "\tmr\t%s\n", regnames[reg]);
+			} else if (isstatic(p->v->storage_class)) {
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// static\n");
+//				emit(f, "\tldinc\tr7\n\t.ref\t%s%d,%d\n",
+//				     labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+				if(g_flags[FLAG_PIC]&USEDFLAG)
+				{
+					emit(f, "\t.lipcrel\t%s%d,%d\n",
+						 labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+					emit(f, "\taddt\t%s\n",regnames[pc]);
+				}
+				else
+					emit(f, "\t.liabs\t%s%d,%d\n",
+						 labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// static pe %s varadr\n", p->flags & VARADR ? "is" : "not");
+				if (reg != tmp)
+					emit(f, "\tmr\t%s\n", regnames[reg]);
+			} else {
+				if(DBGMSG)
+					printf("emit_prepobj: - unknown storage class!\n");
+				ierror(0);
+			}
+			settempobj(f,tmp,p,0,1);
+			settempobj(f,reg,p,0,1);
+		}
+	}
+}
+
+
+// Returns 1 if the Z flag has been set (i.e. a load has occurred)
+// Guaranteed not to modify t1 or t2.
+
+static int emit_objtoreg(FILE * f, struct obj *p, int t,int reg)
+{
+	int result=0;
+	int matchreg;
+	int elementary;
+	int postinc=0;
+	if(DBGMSG)
+		emit(f, "\t\t\t\t\t\t// (obj to %s) flags %x type %x\n",regnames[reg],p->flags,t);
+
+	/* If we're dealing with an elementary type on the stack we'll copy the actual object into
+	   a register.  If we're dealing with a composite type, or taking the address of an elementary
+	   type then instead we'll take its address into the register.  There's a subtlety to take care
+	   of with ASSIGN ICs and inline memcpy/strcpy where they type can be CHAR with a size!=1.
+	   I hack around this by overriding type in the parent fucction. */
+	if ((!(p->flags & VARADR)) && ((t & NQ) != STRUCT) && ((t & NQ) != UNION) && ((t & NQ) != ARRAY))
+		elementary=1;
+	else
+		elementary=0;
+
+	matchreg=matchtempobj(f,p,0,reg);
+
+	if ((p->flags & (REG|DREFOBJ)) == REG) {
+		settempobj(f,reg,p,0,0);
+		if(DBGMSG)
+			emit(f, "\t\t\t\t\t\t// reg %s - only match against tmp\n", regnames[p->reg]);
+		if (reg == p->reg)
+			return(0);
+		if(matchreg!=tmp)
+		{
+			emit(f,"\tmt\t%s\n",regnames[p->reg]);
+			settempobj(f,tmp,p,0,0);
+		}
+		if(reg!=tmp)
+		{
+			emit(f, "\tmr\t%s\n", regnames[reg]);
+			settempobj(f,reg,p,0,0);
+		}
+		return(0);
+	}
+
+	if(matchreg)
+	{
+		if(DBGMSG)
+			emit(f,"\n\t\t\t// required value found in %s\n",regnames[matchreg]);
+		if(matchreg==reg)
+			return(0);
+		if(matchreg!=tmp)
+		{
+			emit(f,"\tmt\t%s\n",regnames[matchreg]);
+			settempobj(f,tmp,p,0,0);
+		}
+		if(reg!=tmp)
+		{
+			emit(f,"\tmr\t%s\n",regnames[reg]);
+			settempobj(f,reg,p,0,0);
+		}
+		emit(f,"\t\t\t\t//return 0\n");
+		return(0);
+	}
+
+	// FIXME - does this have implications for structs, unions, fptrs, etc?
+	if(p->flags&VARADR)
+	{
+		emit_prepobj(f,p,t,reg,0);
+		return(0);
+	}
+	if ((p->flags & (KONST | DREFOBJ)) == (KONST | DREFOBJ)) {
+		if(DBGMSG)
+			emit(f, "\t\t\t\t\t\t// const/deref\n");
+		matchreg=matchtempkonst(f, val2zmax(p, p->dtyp),tmp);
+		if(matchreg && matchreg!=tmp) {
+			emit_sizemod(f, t);
+			emit(f,"\tld\t%s\n",regnames[matchreg]);
+		} else {
+			emit_prepobj(f, p, t, tmp, 0);
+			emit_sizemod(f, t);
+			emit(f, "\tldt\n");
+		}
+		settempobj(f,tmp,p,0,0);
+		settempobj(f,reg,p,0,0);
+		if(reg!=tmp)
+			emit(f,"\tmr\t%s\n",regnames[reg]);
+		return(1);
+	}
+
+//	printf("p->flags %x, type %d\n",p->flags,t);
+
+	if (p->flags & DREFOBJ) {
+		if(DBGMSG)
+			emit(f, "\t\t\t\t\t\t// deref \n");
+		/* Dereferencing a pointer */
+		if (p->flags & REG) {
+			switch (t & NQ) {
+			case CHAR:
+				if (p->am && p->am->type == AM_POSTINC)
+				{
+					emit(f, "\tldbinc\t%s\n", regnames[p->reg]);
+					postinc=1;
+				}
+				else if (p->am && p->am->disposable)
+					emit(f,
+					     "\tldbinc\t%s\n//Disposable, postinc doesn't matter.\n", regnames[p->reg]);
+				else
+					emit(f, "\tbyt\n\tld\t%s\n", regnames[p->reg]);
+				break;
+			case SHORT:
+				emit(f, "\thlf\n");
+				emit(f, "\tld\t%s\n", regnames[p->reg]);
+				break;
+			case INT:
+			case LONG:
+			case POINTER:
+				if (p->am && p->am->type == AM_POSTINC)
+				{
+					emit(f, "\tldinc\t%s\n", regnames[p->reg]);
+					postinc=4;
+				}
+				else
+					emit(f, "\tld\t%s\n", regnames[p->reg]);
+				break;
+			case STRUCT:
+			case UNION:
+			case ARRAY:
+			case FUNKT:	// Function pointers are dereferenced by calling them.
+				emit(f, "\tmt\t%s\n", regnames[p->reg]);
+				break;
+			default:
+				fprintf(stderr,"Objtoreg - unhandled type %d\n",t);
+				ierror(0);
+				break;
+			}
+			result=1;
+		} else {
+			emit_prepobj(f, p, t, tmp, 0);
+			// Exclusions for fptrs, structs and unions to avoid double-dereference.
+			// Included array type in these exclusions.  FIXME - is this sufficient?
+			if ((t & NQ) != FUNKT && (t & NQ) != STRUCT && (t & NQ) != UNION && (t & NQ) != ARRAY)
+			{
+				emit_sizemod(f, t);
+				emit(f, "\tldt\n");
+				result=1;
+			}
+		}
+	} else {
+		if (p->flags & REG) {
+			// Already handled in the preamble.
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// reg %s\n", regnames[p->reg]);
+			emit(f, "\tmt\t%s\n", regnames[p->reg]);
+		} else if (p->flags & VAR) {
+			if (isauto(p->v->storage_class)) {
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// var, auto|reg\n");
+				/* Do we need to deference? */
+				if (elementary) {
+					if (real_offset(p)) {
+						emit_constanttotemp(f, real_offset(p));
+						if(!isstackparam(p))
+							emit_sizemod(f, t);
+						emit(f, "\tldidx\t%s\n", regnames[sp]);
+					} else {
+						emit_sizemod(f, t);
+						emit(f, "\tld\t%s\n", regnames[sp]);
+					}
+					result=1;
+				} else {
+					if (real_offset(p)) {
+						emit_constanttotemp(f, real_offset(p));
+						emit(f, "\taddt\t%s\n", regnames[sp]);
+					} else {
+						emit(f, "\tmt\t%s\n", regnames[sp]);
+					}
+				}
+			} else if (isextern(p->v->storage_class)) {
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t// extern\n");
+				emit_externtotemp(f, p->v->identifier, p->val.vmax);
+				// Structs, unions and arrays have to remain as pointers
+				if (elementary) {
+					if(DBGMSG)
+						emit(f, "\t\t\t\t\t\t//extern deref\n");
+					emit_sizemod(f, t);
+					emit(f, "\tldt\n");
+					result=1;
+				}
+			} else if (isstatic(p->v->storage_class)) {
+				if(DBGMSG)
+					emit(f, "\t\t\t\t\t\t//static %s\n", p->flags & VARADR ? "varadr" : "not varadr");
+				emit_statictotemp(f, labprefix, zm2l(p->v->offset), p->val.vmax);
+				// Structs, unions and arrays have to remain as pointers
+				if (elementary) {
+					if(DBGMSG)
+						emit(f, "\t\t\t\t\t\t//static deref\n");
+					emit_sizemod(f, t);
+					emit(f, "\tldt\n");
+					result=1;
+				}
+			} else {
+				printf("Objtotemp: Unhandled storage class: %d\n", p->v->storage_class);
+				ierror(0);
+			}
+		} else if (p->flags & KONST) {
+			if(DBGMSG)
+				emit(f, "\t\t\t\t\t\t// const\n");
+			emit_constanttotemp(f, val2zmax(p, t));
+		} else {
+			printf("Objtotemp: unknown flags %d\n", p->flags);
+			ierror(0);
+		}
+	}
+	if(reg!=tmp)
+		emit(f,"\tmr\t%s\n",regnames[reg]);
+	settempobj(f,reg,p,-postinc,0);
+	settempobj(f,tmp,p,-postinc,0);
+	return(result);
+}
+
diff --git a/machines/alpha/machine.c b/machines/alpha/machine.c
new file mode 100755
index 0000000..c5038c0
--- /dev/null
+++ b/machines/alpha/machine.c
@@ -0,0 +1,1707 @@
+/*  Code generator for a DEC Alpha 64bit RISC cpu with 32       */
+/*  general purpose and 32 floating point registers.            */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for DEC Alpha V0.3c (c) in 1997-2000 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","const-in-data","sd","merge-constants","stabs","no-builtins"};
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  Tabelle fuer die Groesse der einzelnen Typen                */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[MAXR+1]={"noreg",
+                        "$0","$1","$2","$3","$4","$5","$6","$7",
+                        "$8","$9","$10","$11","$12","$13","$14","$15",
+                        "$16","$17","$18","$19","$20","$21","$22","$23",
+                        "$24","$25","$26","$27","$28","$29","$30","$31",
+                        "$f0","$f1","$f2","$f3","$f4","$f5","$f6","$f7",
+                        "$f8","$f9","$f10","$f11","$f12","$f13","$f14","$f15",
+                        "$f16","$f17","$f18","$f19","$f20","$f21","$f22","$f23",
+                        "$f24","$f25","$f26","$f27","$f28","$f29","$f30","$f31"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  A type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+                          1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,
+                          1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
+                          1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+
+struct reg_handle empty_reg_handle={0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+static long malign[MAX_TYPE+1]=  {1,1,2,4,8,8,4,8,8,1,8,1,1,1,4,1};
+static long msizetab[MAX_TYPE+1]={1,1,2,4,8,8,4,8,8,0,8,0,0,0,4,0};
+
+static struct Typ ltyp={LONG};
+
+static char x_t[MAX_TYPE+1]={'?','b','w','l','q','q','s','t','t','?','q'};
+
+static int sp=31;                  /*  Stackpointer                        */
+static int gp=30;                  /*  Global pointer                      */
+static int lr=27;                  /*  Link Register                       */
+static int vp=28;                  /*  Virtual frame pointer               */
+static int r31=32;                 /*  Read as zero                        */
+static int f31=64;                 /*  Read as zero                        */
+static int sd=14;                  /*  SmallDataPointer                    */
+static int t1=2,t2=3,t3=4;         /*  Temporaries used by code generator  */
+static int t4=5,t5=6;
+static int f1=34,f2=35,f3=36;      /*  Temporaries used by code generator  */
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+
+static char *marray[]={"__ALPHA__",0};
+
+static int section=-1,newobj,crsave,helpl,helps,stabs;
+static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="";
+static int balign(struct obj *);
+static char *labprefix="$C",*idprefix="";
+static long framesize,frameoffset;
+static void probj2(FILE *f,struct obj *p,int t);
+
+#define ESGN 1
+#define EUNS 2
+static int st[MAXR+1];
+
+static struct fpconstlist {
+  struct fpconstlist *next;
+  int label,typ;
+  union atyps val;
+} *firstfpc;
+
+static void move_reg(FILE *f,int s,int t)
+{
+  if(t==r31||t==f31) ierror(0);
+  if(s<=32&&t>32) ierror(0);
+  if(t<=32&&s>32) ierror(0);
+  if(s==t) return;
+  if(s<=32){
+    emit(f,"\tbis\t%s,%s,%s\n",regnames[r31],regnames[s],regnames[t]);
+  }else{
+    emit(f,"\tcpys\t%s,%s,%s\n",regnames[s],regnames[s],regnames[t]);
+  }
+  st[t]=st[s];
+}
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+        eval_const(&p->val,t);
+        if(t==INT&&zmeqto(vmax,zi2zm(o->val.vint))) return p->label;
+        if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+        if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+        if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+        if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+        if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+#define REG_IND 1
+#define IMM_IND 2
+
+static struct obj *cam(int flags,int base,int align,long offset)
+/*  Initializes an addressing-mode structure and returns a pointer to   */
+/*  that object. Will not survive a second call!                        */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  am.align=align;
+  return &obj;
+}
+
+void title(FILE *f)
+{
+  static int done;
+  extern char *inname; /*grmpf*/
+  if(!done&&f){
+    done=1;
+    emit(f,"\t.file\t\"%s\"\n",inname);
+  }
+} 
+
+static char *dct[]={"??","byte","short","long","quad","long","long","quad","??","??","??","??"};
+
+static void load_address(FILE *f,int r,struct obj *o,int typ)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if((o->flags&VAR)&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    long of=zm2l(o->v->offset);
+    if(of>=0)
+      of+=frameoffset+zm2l(o->val.vlong);
+    else
+      of=-of-zm2l(maxalign)+framesize+zm2l(o->val.vmax);
+    if(of>32767) ierror(0);
+    emit(f,"\tlda\t%s,%ld(%s)\n",regnames[r],of,regnames[sp]);
+  }else{
+    emit(f,"\tlda\t%s,",regnames[r]);
+    probj2(f,o,typ);emit(f,"\n");
+  }
+  st[r]=ESGN;
+}
+static void load_obj(FILE *f,int r,struct obj *o,int typ,int tmp)
+{
+  int adr,shift,al;
+  switch(typ&NQ){
+  case POINTER:
+  case LDOUBLE:
+  case DOUBLE:
+  case FLOAT:
+  case LLONG:
+  case LONG:
+  case INT:
+    emit(f,"\tld%c\t%s,",x_t[typ&NQ],regnames[r]);
+    probj2(f,o,typ);emit(f,"\n");
+    st[r]=ESGN;return;
+  case SHORT:
+    al=balign(o);
+    if(al>=0){
+      emit(f,"\tldq_u\t%s,",regnames[r]);
+      probj2(f,o,typ);emit(f,"\n");
+      shift=64-16-al*8;
+      if(shift) emit(f,"\tsll\t%s,%d,%s\n",regnames[r],shift,regnames[r]);
+      if(typ&UNSIGNED){
+        emit(f,"\tsrl\t%s,%d,%s\n",regnames[r],64-16,regnames[r]);
+        st[r]=EUNS;
+      }else{
+        emit(f,"\tsra\t%s,%d,%s\n",regnames[r],64-16,regnames[r]);
+        st[r]=ESGN;
+      }
+      return;
+    }
+    adr=0;
+    if(o->am&&o->am->offset==0)
+      adr=o->am->base;
+    else if(zmeqto(o->val.vmax,l2zm(0L)))
+      adr=o->reg;
+    if(!adr){
+      adr=tmp;load_address(f,adr,o,POINTER);
+    }
+
+    if(typ&UNSIGNED){
+      emit(f,"\tbic\t%s,6,%s\n",regnames[adr],regnames[t4]); /* ldq_u ? */
+      emit(f,"\tldq\t%s,0(%s)\n",regnames[t5],regnames[t4]);
+      emit(f,"\tbic\t%s,1,%s\n",regnames[adr],regnames[t4]);
+      emit(f,"\textwl\t%s,%s,%s\n",regnames[t5],regnames[t4],regnames[r]);
+      /*
+      emit(f,"\tbic\t%s,2,%s\n",regnames[adr],regnames[t4]);
+      emit(f,"\tand\t%s,2,%s\n",regnames[adr],regnames[t5]);
+      emit(f,"\tldq\t%s,0(%s)\n",regnames[r],regnames[t4]);
+      emit(f,"\textwh\t%s,%s,%s\n",regnames[r],regnames[t5],regnames[r]);
+      */
+      st[r]=EUNS;return;
+    }else{
+      emit(f,"\tbic\t%s,6,%s\n",regnames[adr],regnames[t4]);
+      emit(f,"\tand\t%s,6,%s\n",regnames[adr],regnames[t5]);
+      emit(f,"\tldq\t%s,0(%s)\n",regnames[r],regnames[t4]);
+      emit(f,"\tlda\t%s,2(%s)\n",regnames[t5],regnames[t5]);
+      emit(f,"\textqh\t%s,%s,%s\n",regnames[r],regnames[t5],regnames[r]);
+      emit(f,"\tsra\t%s,48,%s\n",regnames[r],regnames[r]);
+      st[r]=ESGN;return;
+    }
+  case CHAR:
+    al=balign(o);
+    if(al>=0){
+      emit(f,"\tldq_u\t%s,",regnames[r]);
+      probj2(f,o,typ);emit(f,"\n");
+      shift=64-8-al*8;
+      if(shift&&al) emit(f,"\tsll\t%s,%d,%s\n",regnames[r],shift,regnames[r]);
+      if(typ&UNSIGNED){
+        if(al==0)
+          emit(f,"\tand\t%s,255,%s\n",regnames[r],regnames[r]);
+        else
+          emit(f,"\tsrl\t%s,%d,%s\n",regnames[r],64-8,regnames[r]);
+        st[r]=EUNS;
+      }else{
+        if(al==0)
+          emit(f,"\tsextb\t%s,%s\n",regnames[r],regnames[r]);
+        else
+          emit(f,"\tsra\t%s,%d,%s\n",regnames[r],64-8,regnames[r]);
+        st[r]=ESGN;
+      }
+      return;
+    }
+    if(typ&UNSIGNED){
+      adr=0;
+      if(o->am&&o->am->offset==0)
+        adr=o->am->base;
+      else if(zmeqto(o->val.vmax,l2zm(0L)))
+        adr=o->reg;
+      if(!adr){
+        adr=tmp; load_address(f,adr,o,POINTER);
+      }
+      emit(f,"\tldq_u\t%s,0(%s)\n",regnames[r],regnames[adr]);
+      emit(f,"\textbl\t%s,%s,%s\n",regnames[r],regnames[adr],regnames[r]);
+      st[r]=EUNS;return;
+    }else{
+      emit(f,"\tldq_u\t%s,",regnames[t5]);
+      probj2(f,o,typ);emit(f,"\n\tlda\t%s,",regnames[t4]);
+      if(o->am) o->am->offset++; else o->val.vmax=zmadd(o->val.vmax,l2zm(1L));
+      probj2(f,o,typ);
+      if(o->am) o->am->offset--; else o->val.vmax=zmsub(o->val.vmax,l2zm(1L));
+      emit(f,"\n\textqh\t%s,%s,%s\n",regnames[t5],regnames[t4],regnames[t5]);
+      emit(f,"\tsra\t%s,56,%s\n",regnames[t5],regnames[r]);
+      st[r]=ESGN;return;
+    }
+  }
+  ierror(0);
+}
+static void load_reg(FILE *f,int r,struct obj *o,int typ,int tmp)
+/*  Generates code to load a memory object into register r. tmp is a    */
+/*  general purpose register which may be used. tmp can be r.           */
+{
+  typ&=NU;
+  if(o->am){
+    load_obj(f,r,o,typ,tmp);
+    return;
+  }
+  if(o->flags&KONST){
+    long l;int lab;
+    eval_const(&o->val,typ);
+    if(ISFLOAT(typ)){
+      lab=addfpconst(o,typ);
+      emit(f,"\tlda\t%s,%s%d\n",regnames[tmp],labprefix,lab);
+      emit(f,"\tld%c\t%s,0(%s)\n",x_t[typ&NQ],regnames[r],regnames[tmp]);
+      st[r]=ESGN;
+      return;
+    }
+    if(zmleq(vmax,l2zm(32767))&&zmleq(l2zm(-32768),vmax)){
+      emit(f,"\tlda\t%s,%ld(%s)\n",regnames[r],zm2l(vmax),regnames[r31]);
+    }else{
+/*       if((typ&NQ)<INT) ierror(0); */
+      lab=addfpconst(o,typ);
+      emit(f,"\tlda\t%s,%s%d\n",regnames[tmp],labprefix,lab);
+      emit(f,"\tldq\t%s,0(%s)\n",regnames[r],regnames[tmp]);
+    }
+    st[r]=ESGN;
+    return;
+  }
+  if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+    if(!(o->flags&VARADR)){
+      load_address(f,tmp,o,POINTER);
+      load_obj(f,r,cam(IMM_IND,tmp,balign(o),0L),typ,tmp);
+    }else{
+      load_address(f,r,o,POINTER);
+    }
+  }else{
+    if(o->am||(o->flags&(DREFOBJ|REG))==REG){
+      if(r!=o->reg)
+        move_reg(f,o->reg,r);
+    }else{
+      if(o->flags&DREFOBJ) ierror(0);
+      load_obj(f,r,o,typ,tmp);
+    }
+  }
+}
+
+
+static void store_reg(FILE *f,int r,struct obj *o,int typ)
+/*  Generates code to store register r into memory object o.            */
+{
+  int adr,t6,t7;
+  if((o->flags&(REG|DREFOBJ))==REG) ierror(0);
+  if(r==t1){ t6=t2;t7=t3;}
+  else if(r==t2) {t6=t1;t7=t3;}
+  else {t6=t1;t7=t2;}
+  if((typ&NQ)>SHORT){
+    if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+      load_address(f,t6,o,POINTER);
+      emit(f,"\tst%c\t%s,0(%s)\n",x_t[typ&NQ],regnames[r],regnames[t6]);
+      return;
+    }
+    emit(f,"\tst%c\t%s,",x_t[typ&NQ],regnames[r]);
+    probj2(f,o,typ);emit(f,"\n");
+    return;
+  }else{
+    adr=0;
+    if(o->am&&o->am->offset==0){
+      adr=o->am->base;
+      if(adr<1||adr>32) ierror(0);
+    }else if((o->flags&REG)&&zmeqto(o->val.vmax,l2zm(0L))){
+      adr=o->reg;
+      if(adr<1||adr>32) ierror(0);
+    }
+    if(!adr){
+      adr=t7; load_address(f,adr,o,POINTER);
+    }
+    if(adr<1||adr>32) ierror(0);
+    if((typ&NQ)==SHORT){
+      emit(f,"\tbic\t%s,2,%s\n",regnames[adr],regnames[t4]);
+      emit(f,"\tldl\t%s,0(%s)\n",regnames[t6],regnames[t4]);
+      emit(f,"\tand\t%s,2,%s\n",regnames[adr],regnames[t5]);
+      emit(f,"\tmskwl\t%s,%s,%s\n",regnames[t6],regnames[t5],regnames[t6]);
+      emit(f,"\tinswl\t%s,%s,%s\n",regnames[r],regnames[t5],regnames[t7]);
+      emit(f,"\tbis\t%s,%s,%s\n",regnames[t6],regnames[t7],regnames[t6]);
+      emit(f,"\tstl\t%s,0(%s)\n",regnames[t6],regnames[t4]);
+      return;
+    }else{
+      emit(f,"\tldq_u\t%s,0(%s)\n",regnames[t4],regnames[adr]);
+      emit(f,"\tmskbl\t%s,%s,%s\n",regnames[t4],regnames[adr],regnames[t4]);
+      emit(f,"\tinsbl\t%s,%s,%s\n",regnames[r],regnames[adr],regnames[t5]);
+      emit(f,"\tbis\t%s,%s,%s\n",regnames[t4],regnames[t5],regnames[t4]);
+      emit(f,"\tstq_u\t%s,0(%s)\n",regnames[t4],regnames[adr]);
+      return;
+    }
+  }
+}
+
+static void extend(FILE *f,int r)
+{
+  if(!r) return;
+  if(st[r]==ESGN) return;
+  emit(f,"\taddl\t%s,%s,%s\n",regnames[r],regnames[r31],regnames[r]);
+  st[r]=ESGN;
+}
+static void uextend(FILE *f,int r)
+{
+  if(!r) return;
+  if(st[r]==EUNS) return;
+  emit(f,"\tzapnot\t%s,15,%s\n",regnames[r],regnames[r]);
+  st[r]=EUNS;
+}
+
+static struct IC *do_refs(FILE *,struct IC *);
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long,long);
+static void function_bottom(FILE *f,struct Var *,long,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"bis","xor","and"};
+static char *arithmetics[]={"sll","srl","add","sub","mul","div","rem"};
+
+static struct IC *do_refs(FILE *f,struct IC *p)
+/*  Does some pre-processing like fetching operands from memory to      */
+/*  registers etc.                                                      */
+{
+  int typ=p->typf,typ1,reg,c=p->code;
+
+  typ=q1typ(p);
+  if(ISPOINTER(typ)) typ=(UNSIGNED|LONG);
+
+  q1reg=q2reg=zreg=0;
+  if(p->q1.flags&REG) q1reg=p->q1.reg;
+  if(p->q2.flags&REG) q2reg=p->q2.reg;
+  if((p->z.flags&(REG|DREFOBJ))==REG) zreg=p->z.reg;
+
+
+  if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->q1.val,typ);
+    if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+      if(ISFLOAT(typ)) q1reg=f31; else q1reg=r31;
+    }else{
+      if(ISFLOAT(typ)) reg=f1; else reg=t1;
+      if(c==ASSIGN&&zreg) reg=zreg;
+      if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+      if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[25]) reg=25; /* Linux-div */
+      if(ISFLOAT(typ)||c==DIV||c==SUB||c==ASSIGN||c==PUSH||c==SETRETURN||c==LSHIFT||c==RSHIFT||c==COMPARE){
+        load_reg(f,reg,&p->q1,typ,t1);
+        q1reg=reg;
+      }else{
+        if(ISINT(typ)){
+          if(!zumleq(vumax,ul2zum(255UL))||!zmleq(vmax,l2zm(255L))||zmleq(vmax,l2zm(-1L))){
+            load_reg(f,reg,&p->q2,typ,t1);
+            q1reg=reg;
+          }
+        }
+      }
+    }
+  }else if(c!=ADDRESS){
+    if(p->q1.flags&&!q1reg){
+      if(ISFLOAT(typ)) reg=f1; else reg=t1;
+      if((c==ASSIGN||c==CONVERT)&&zreg&&(reg-r31)*(zreg-r31)>0) reg=zreg;
+      if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+      if((p->q1.flags&DREFOBJ)||c==ADDI2P||c==SUBIFP) {typ1=POINTER;reg=t1;} else typ1=typ;
+      if(c==CALL) reg=vp;
+      if((c==MOD||c==DIV)&&ISINT(typ1)&&!regs[25]) reg=25; /* Linux-div */
+      if(ISSCALAR(typ1)){
+        int m=p->q1.flags;
+        p->q1.flags&=~DREFOBJ;
+        load_reg(f,reg,&p->q1,typ1,t1);
+        p->q1.flags=m;
+        q1reg=reg;
+      }
+    }
+    if((p->q1.flags&DREFOBJ)&&ISSCALAR(typ)){
+      if(ISFLOAT(typ)) reg=f1; else reg=t1;
+      if((c==ASSIGN||c==CONVERT)&&zreg&&regok(zreg,typ,0)) reg=zreg;
+      if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+      if((c==MOD||c==DIV)&&(typ&NQ)<=LONG&&!regs[25]) reg=25; /* Linux-div */
+      if(c==ADDI2P||c==SUBIFP)
+        load_reg(f,reg,cam(IMM_IND,q1reg,-1,0),POINTER,t1);
+      else
+        load_reg(f,reg,cam(IMM_IND,q1reg,-1,0),typ,t1);
+      q1reg=reg;
+    }
+  }
+  typ=q2typ(p);
+  if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->q2.val,typ);
+    if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+      if(ISFLOAT(typ)) q2reg=f31; else q2reg=r31;
+    }else{
+      if(ISFLOAT(typ)) reg=f2; else reg=t2;
+      if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[26]) reg=26; /* Linux-div */
+      if(ISFLOAT(typ)){
+        load_reg(f,reg,&p->q2,typ,t2);
+        q2reg=reg;
+      }else{
+        if(ISINT(typ)){
+          if(!zumleq(vumax,ul2zum(255UL))||!zmleq(vmax,l2zm(255L))||zmleq(vmax,l2zm(-1L))){
+            load_reg(f,reg,&p->q2,typ,t2);
+            q2reg=reg;
+          }
+        }
+      }
+    }
+  }else{
+    if(p->q2.flags&&!q2reg){
+      if(p->q2.flags&DREFOBJ) typ1=POINTER; else typ1=typ;
+      if(ISFLOAT(typ1)) reg=f2; else reg=t2;
+      if((c==MOD||c==DIV)&&ISINT(typ1)&&!regs[26]) reg=26; /* Linux-div */
+      if(ISSCALAR(typ1)){
+        int m=p->q2.flags;
+        p->q2.flags&=~DREFOBJ;
+        load_reg(f,reg,&p->q2,typ1,t2);
+        p->q2.flags=m;
+        q2reg=reg;
+      }
+    }
+    if((p->q2.flags&DREFOBJ)&&ISSCALAR(typ)){
+      if(ISFLOAT(typ)) reg=f2; else reg=t2;
+      if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[26]) reg=26; /* Linux-div */
+      load_reg(f,reg,cam(IMM_IND,q2reg,-1,0),typ,t2);
+      q2reg=reg;
+    }
+  }
+  if(p->z.flags&&!isreg(z)){
+    typ=ztyp(p);
+    if(ISFLOAT(typ)) zreg=f3; else zreg=t3;
+    if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[28]) zreg=28; /* Linux-div */
+  }
+  if(q1reg){ p->q1.flags=REG; p->q1.reg=q1reg;}
+  if(q2reg){ p->q2.flags=REG; p->q2.reg=q2reg;}
+  return p;
+}
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+    zumax p;int ln=1;
+    p=ul2zum(1L);
+    while(ln<=64&&zumleq(p,x)){
+        if(zumeqto(x,p)) return ln;
+        ln++;p=zumadd(p,p);
+    }
+    return 0;
+}
+static void pr(FILE *f,struct IC *p)
+/*  Writes the destination register to the real destination if necessary.   */
+{
+  int typ=p->typf;
+  if(p->z.flags){
+    if(p->code==ADDRESS||p->code==ADDI2P||p->code==SUBIFP) typ=POINTER;
+    if(!isreg(z)){
+      if(p->z.flags&DREFOBJ){
+        if(p->z.flags&REG){
+          store_reg(f,zreg,cam(IMM_IND,p->z.reg,-1,0),typ);
+        }else{
+          int r,m;
+          if(t1==zreg) r=t2; else r=t1;
+          m=p->z.flags;
+          p->z.flags&=~DREFOBJ;
+          load_reg(f,r,&p->z,POINTER,r);
+          p->z.flags=m;
+          store_reg(f,zreg,cam(IMM_IND,r,balign(&p->z),0),typ);
+        }
+      }else{
+        store_reg(f,zreg,&p->z,typ);
+      }
+    }else{
+      if(p->z.reg!=zreg)
+        move_reg(f,zreg,p->z.reg);
+    }
+  }
+}
+
+static void probj2(FILE *f,struct obj *p,int t)
+/*  Prints an object.                               */
+{
+  if(p->am){
+    if(p->am->flags==REG_IND) ierror(0);
+    if(p->am->flags==IMM_IND) emit(f,"%ld(%s)",p->am->offset,regnames[p->am->base]);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      if(p->flags&REG){
+        emit(f,"%s",regnames[p->reg]);
+      }else{
+        long of=zm2l(p->v->offset);
+        if(of>=0)
+          of+=frameoffset+zm2l(p->val.vmax);
+        else
+          of=-of-zm2l(maxalign)+framesize+zm2l(p->val.vmax);
+        if(of>32767) ierror(0);
+        emit(f,"%ld(%s)",of,regnames[sp]);
+      }
+    }else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if((p->flags&REG)&&!(p->flags&VAR)) emit(f,"%s",regnames[p->reg]);
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+  struct obj o;
+  o.flags=REG;
+  /*FIXME: need correct register translation */
+  o.reg=sp;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+  /*FIXME: needs correct translation */
+  return r-1;
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+  long of;
+  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+  of=zm2l(v->offset);
+  if(of>=0)
+    of+=frameoffset;
+  else
+    of=-of-zm2l(maxalign)+framesize;
+  if(of>32767) ierror(0);
+  return l2zm(of);
+}
+static void function_top(FILE *f,struct Var *v,long offset,long maxpushed)
+/*  Generates function top.                             */
+{
+  int i;
+   emit(f,"\t.set\tnoat\n");
+  if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+  emit(f,"\t.align\t3\n");
+  if(v->storage_class==EXTERN)
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+  emit(f,"\t.ent\t%s%s\n",idprefix,v->identifier);
+  if(v->storage_class==STATIC)
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  else
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  if(function_calls) emit(f,"\tldgp\t%s,0(%s)\n",regnames[gp],regnames[vp]);
+  if(v->storage_class==STATIC)
+    emit(f,"%s%ld..ng:\n",labprefix,zm2l(v->offset));
+  else  
+    emit(f,"%s%s..ng:\n",idprefix,v->identifier);
+  framesize=offset+maxpushed;
+  if(function_calls) framesize+=8; /* lr */
+  for(i=1;i<=MAXR;i++)
+    if(regused[i]&&!regscratch[i]&&!regsa[i])
+      framesize+=8;
+  framesize=((framesize+16-1)/16)*16;
+  if(framesize>32767) ierror(0);
+  if(framesize) emit(f,"\tlda\t%s,%ld(%s)\n",regnames[sp],-framesize,regnames[sp]);
+  emit(f,"\t.frame\t%s,%ld,%s,0\n",regnames[sp],framesize,regnames[lr]);
+  frameoffset=maxpushed;
+  if(function_calls){
+    emit(f,"\tstq\t%s,%ld(%s)\n",regnames[lr],frameoffset,regnames[sp]);
+    frameoffset+=8;
+  }
+  for(i=1;i<=MAXR;i++){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      if(i<=32){
+        emit(f,"\tstq\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+      }else{
+        emit(f,"\tstt\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+      }
+      frameoffset+=8;
+    }
+  }
+  emit(f,"\t.mask\t0x4000000,%ld\n",-framesize);
+  emit(f,"\t.prologue\t%c\n",function_calls?'1':'0');
+}
+static void function_bottom(FILE *f,struct Var *v,long offset,long maxpushed)
+/*  Generates function bottom.                          */
+{
+  int i;
+  frameoffset=maxpushed;
+  if(function_calls){
+    emit(f,"\tldq\t%s,%ld(%s)\n",regnames[lr],frameoffset,regnames[sp]);
+    frameoffset+=8;
+  }
+  for(i=1;i<=MAXR;i++){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      if(i<=32){
+        emit(f,"\tldq\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+      }else{
+        emit(f,"\tldt\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+
+      }
+      frameoffset+=8;
+    }
+  }
+  if(framesize) emit(f,"\tlda\t%s,%ld(%s)\n",regnames[sp],framesize,regnames[sp]);
+  emit(f,"\tret\t%s,(%s),1\n",regnames[r31],regnames[lr]);
+  emit(f,"\t.end\t%s%s\n",idprefix,v->identifier);
+  emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+  emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+}
+static int balign(struct obj *o)
+/*  Liefert die unteren 3 Bits des Objekts. -1 wenn unklar. */
+{
+  int sc;
+  if(o->flags&DREFOBJ) return -1;
+  if(o->am) return o->am->align;
+  if(!(o->flags&VAR)) ierror(0);
+  sc=o->v->storage_class;
+  if(sc==EXTERN||sc==STATIC){
+    /* Alle statischen Daten werden vom cg auf 64bit alignt. */
+    return zm2l(zmand(o->val.vmax,l2zm(7L)));
+  }
+  if(sc==AUTO||sc==REGISTER){
+    zmax of=o->v->offset;
+    if(!zmleq(l2zm(0L),of))
+      of=zmsub(l2zm(0L),zmadd(of,maxalign));
+    return zm2l(zmand(zmadd(of,o->val.vmax),l2zm(7L)));
+  }
+  ierror(0);
+}
+
+/* Routinen fuer Debug-Informationen mit stabs. */
+
+static int debug_blabel,debug_elabel;
+static int debug_type(FILE *,struct Typ *);
+static void debug_init(FILE *,struct Var *);
+static void debug_exit(FILE *,struct Var *);
+static void debug_var(FILE *,struct obj *);
+static void debug_IC(FILE *,struct IC *);
+static void debug_cleanup(FILE *);
+
+static int debug_type(FILE *f,struct Typ *t)
+     /* Liefert Typindex.  */
+{
+  return t->flags&NU;
+}
+static void debug_init(FILE *f,struct Var *v)
+     /* Debug-Infos. Wird am Anfang von gen_code aufgerufen. */
+{
+  static int did_header;
+  if(!did_header){
+    emit(f,"\t.stabs \"\",100,0,0,%stext0\n",labprefix);
+    emit(f,"\t.stabs \"%s\",100,0,0,%stext0\n",filename,labprefix);
+    emit(f,"\t.text\n%stext0:\n",labprefix);if(f) section=CODE;
+    emit(f,"\t.stabs\t\"char:t%d=r1;-128;127;\",128,0,0,0\n",CHAR);
+    emit(f,"\t.stabs\t\"short:t%d=r1;-32768;32767;\",128,0,0,0\n",SHORT);
+    emit(f,"\t.stabs\t\"int:t%d=r1;-2147483648;2147483647;\",128,0,0,0\n",INT);
+    emit(f,"\t.stabs\t\"long:t%d=r1;001000000000000000000000;000777777777777777777777;\",128,0,0,0\n",LONG);
+    emit(f,"\t.stabs\t\"unsigned char:t%d=r1;0;255;\",128,0,0,0\n",UNSIGNED|CHAR);
+    emit(f,"\t.stabs\t\"unsigned short:t%d=r1;0;65535;\",128,0,0,0\n",UNSIGNED|SHORT);
+    emit(f,"\t.stabs\t\"unsigned int:t%d=r1;0;-1;\",128,0,0,0\n",UNSIGNED|INT);
+    emit(f,"\t.stabs\t\"unsigned long:t%d=r1;0;-1;\",128,0,0,0\n",UNSIGNED|LONG);
+    emit(f,"\t.stabs\t\"float:t%d=r1;4;0;\",128,0,0,0\n",FLOAT);
+    emit(f,"\t.stabs\t\"double:t%d=r1;8;0;\",128,0,0,0\n",DOUBLE);
+    emit(f,"\t.stabs\t\"void:t%d=%d;8;0;\",128,0,0,0\n",VOID,VOID);
+    did_header=1;
+  }
+  emit(f,"\t.stabs\t\"%s:F%d\",36,0,0,%s%s\n",v->identifier,debug_type(f,v->vtyp->next),idprefix,v->identifier);
+  debug_blabel=++label;debug_elabel=++label;
+}
+static void debug_exit(FILE *f,struct Var *v)
+     /* Debug-Infos. Wird am Ende von gen_code aufgerufen. */
+{
+  struct IC *p;
+  ierror(0);
+  emit(f,"\t.stabn\t192,0,0,%s%d\n",labprefix,debug_blabel);
+  emit(f,"\t.stabn\t224,0,0,%s%d\n",labprefix,debug_elabel);
+  for(p=first_ic;p;p=p->next){
+    if(p->q1.flags&VAR) debug_var(f,&p->q1);
+    if(p->q2.flags&VAR) debug_var(f,&p->q2);
+    if(p->z.flags&VAR) debug_var(f,&p->z);
+  }
+}
+static void debug_var(FILE *f,struct obj *o)
+     /* Debug-Infos fuer eine Variable ausgeben. */
+{
+  struct Var *v=o->v; int td;
+  if(!*v->identifier) return;
+  td=debug_type(f,v->vtyp);
+  if(ISFUNC(td)) return;
+  if(o->flags&REG){
+    emit(f,"\t.stabs\t\"%s:r%d\",0x40,0,0,%d\n",v->identifier,td,o->reg-1);
+    return;
+  }
+  if(v->storage_class==AUTO||v->storage_class==REGISTER){
+    long of=zm2l(v->offset);
+    if(!zmleq(l2zm(0L),v->offset)){
+      of=-of-zm2l(maxalign)+framesize;
+      emit(f,"#\toffset %ld:\n",of);
+      emit(f,"\t.stabs\t\"%s:p%d\",0x80,0,0,%ld\n",v->identifier,td,of-framesize);
+    }else{
+      of+=frameoffset;
+      emit(f,"#\toffset %ld:\n",of);
+      emit(f,"\t.stabs\t\"%s:%d\",0x80,0,0,%ld\n",v->identifier,td,of-framesize);
+    }
+    return;
+  }
+  ierror(td);
+}
+static void debug_IC(FILE *f,struct IC *p)
+     /* Debug-Infos. Wird fuer jedes IC aufgerufen. */
+{
+  static int lastline;int lab;
+  printf("%d",p->line);pric2(stdout,p);
+  if(!p->prev)
+    emit(f,"%s%d:\n",labprefix,debug_blabel);
+/*   if(p->q1.flags&VAR) debug_var(f,&p->q1); */
+/*   if(p->q2.flags&VAR) debug_var(f,&p->q2); */
+/*   if(p->z.flags&VAR) debug_var(f,&p->z); */
+  if(p->line&&p->line!=lastline){
+    lab=++label;lastline=p->line;
+    emit(f,"%s%d:\n",labprefix,lab);
+    emit(f,"\t.stabn\t68,0,%d,%s%d\n",lastline,labprefix,lab);
+  }
+  if(!p->next) emit(f,"%s%d:\n",labprefix,debug_elabel);
+}
+static void debug_cleanup(FILE *f)
+     /* Debug-Infos. Wird in cleanup_cg aufgerufen. */
+{
+}
+
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  char_bit=l2zm(8L);
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i= 1;i<=32;i++) {regsize[i]=l2zm(8L);regtype[i]=&ltyp;}
+  for(i=33;i<=64;i++) {regsize[i]=l2zm(8L);regtype[i]=&ltyp;}
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0; /* not yet */
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[LONG]=t_min[LLONG];
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[LONG]=t_max[LLONG];
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[LONG]=tu_max[LLONG];
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=regsa[t5]=1;
+  regsa[f1]=regsa[f2]=regsa[f3]=1;
+  regsa[sp]=regsa[gp]=regsa[sd]=1;
+  regsa[lr]=regsa[r31]=regsa[f31]=1;
+  regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=regscratch[t5]=0;
+  regscratch[f1]=regscratch[f2]=regscratch[f3]=0;
+  regscratch[sp]=regscratch[gp]=regscratch[sd]=0;
+  regscratch[lr]=regscratch[r31]=regscratch[f31]=0;
+  /* reserve at - noch aendern */
+  /* regsa[29]=1;regscratch[29]=0; */
+  /* Debug stabs? */
+  stabs=(g_flags[5]&USEDFLAG);
+  target_macros=marray;
+  return 1;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) return 33;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) return 0;
+  if(zmleq(szof(t),l2zm(8L)))
+    return 1; 
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}     
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0) return 0;
+  if(t==0) return 0;
+  if(ISFLOAT(t)){
+    if(r>=33&&r<=64)
+      return 1;
+    else
+      return 0;
+  }
+  if(ISSCALAR(t)&&r>=1&&r<=32) return 1;
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if((op==LONG||op==LLONG||op==POINTER)&&(tp==LONG||tp==LLONG||tp==POINTER)) return 0;
+  if((op==DOUBLE||op==LDOUBLE)&&(tp==DOUBLE||tp==LDOUBLE)) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  title(f);
+  if(newobj){
+    size=zmmult(zmdiv(zmadd(size,l2zm(7L)),l2zm(8L)),l2zm(8L));
+    emitzm(f,size);
+  }else{
+    emit(f,"\t.zero\t");
+    emitzm(f,size);
+  }
+  emit(f,"\n");
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  title(f);
+  if(zm2l(align)>1)
+    emit(f,"\t.align\t3\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  title(f);
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+    if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+    if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+    if(section!=BSS)
+      emit(f,"\t.align\t3\n%s%ld:\n",labprefix,zm2l(v->offset));
+    else{
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+      newobj=1;
+    }
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+      if(section!=BSS)
+	emit(f,"\t.align\t3\n%s%s:\n",idprefix,v->identifier);
+      else{
+	emit(f,"\t.comm\t%s%s,",idprefix,v->identifier);
+	newobj=1;
+      }
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  title(f);
+  if(ISPOINTER(t)) t=UNSIGNED|LONG;
+  emit(f,"\t.%s\t",dct[t&NQ]);
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+      if((t&NQ)!=FLOAT){
+        emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+      }
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    if(p->tree->o.am) ierror(9);
+    probj2(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int addbuf,c,t,cmpreg,cmpflag,wasnoreg,i,varargs=0,fixargs;struct IC *m;
+  long pushed,maxpushed;
+  if(DEBUG&1) printf("gen_code()\n");
+  if(stabs) debug_init(f,v);
+  for(c=1;c<=MAXR;c++){regs[c]=regsa[c];st[c]=ESGN;}
+  /* We do a pass over the code to retrieve some info and prepare certain optimizations */
+  addbuf=0;maxpushed=0;
+  title(f);
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+    if(c==COMPARE&&(m->q2.flags&KONST)){
+      eval_const(&m->q2.val,t);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+        m->q2.flags=0;m->code=c=TEST;
+      }
+    }
+    if(ISINT(t)&&(m->q2.flags&KONST)&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vumax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t&NU);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  p->typf2=INT;
+	}
+      }
+    }
+    /* Need one stack slot for transfrring between integer and floating-point registers. */
+    t&=NQ;
+    if(c==CONVERT&&addbuf<8&&((ISFLOAT(t)&&!ISFLOAT(m->typf2))||(!ISFLOAT(t)&&ISFLOAT(p->typf2)))) addbuf=8;
+    /* May need one stack slot for inline memcpy. */
+/*     if((c==ASSIGN||c==PUSH)&&t>=POINTER&&addbuf<8) addbuf=8; */
+    /* Need additional stack slots for passing function arguments. */
+    if(c==CALL&&maxpushed<zm2l(m->q2.val.vmax)) maxpushed=zm2l(m->q2.val.vmax);
+    if(c==CALL&&(m->q1.flags&VAR)&&!strcmp(m->q1.v->identifier,"__va_start")) varargs=1;
+    /* Need up to 4 stack slots for calling div/mod-functions. */
+    if((c==DIV||c==MOD)&&ISINT(t)&&addbuf<32){
+      if(regs[25]||regs[26]||regs[28]||regs[29]) addbuf=32;
+    }
+  }
+  /* Noch nicht ok. */
+  if(varargs){
+    fixargs=0;
+    for(i=0;i<v->vtyp->exact->count;i++){
+      c=(*v->vtyp->exact->sl)[i].styp->flags;
+      if(ISPOINTER(c)) fixargs++;
+    }
+    if(fixargs<6) addbuf+=(6-fixargs)*16;
+  }
+  function_top(f,v,zm2l(offset+addbuf),maxpushed);
+  if(varargs){
+    for(i=fixargs+1;i<=6;i++){
+      emit(f,"\tstq\t%s,%ld(%s)\n",regnames[16+i],framesize-(7-i)*16,regnames[sp]);
+      emit(f,"\tstt\t%s,%ld(%s)\n",regnames[48+i],framesize-(7-i)*16+8,regnames[sp]);
+    }
+  }
+  pushed=0;
+  for(;p;pr(f,p),p=p->next){
+    if(DEBUG) pric2(stdout,p);
+    if(debug_info){
+      if(stabs) 
+	debug_IC(f,p);
+      else
+	dwarf2_line_info(f,p);
+    }
+    c=p->code;t=p->typf;
+    if(c==NOP) continue;
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+    if(c==LABEL||(c>=BEQ&&c<=BRA)){
+      int i;
+      for(i=1;i<=32;i++)
+        if(regs[i]&&!regsa[i]) extend(f,i);
+    }
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA) {emit(f,"\tbr\t%s%d\n",labprefix,t);continue;}
+    if(c>=BEQ&&c<BRA){
+      if(cmpflag){
+        emit(f,"\t%sb%s\t%s,%s%d\n",cmpreg<=32?"":"f",cmpflag<0?"eq":"ne",regnames[cmpreg],labprefix,t);
+      }else{
+        emit(f,"\t%sb%s\t%s,%s%d\n",cmpreg<=32?"":"f",ccs[c-BEQ],regnames[cmpreg],labprefix,t);
+      }
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,p->z.reg<=32?LONG:DOUBLE,0);
+      p->z.flags=0;
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->q1.reg,&p->z,p->q1.reg<=32?LONG:DOUBLE);
+      p->z.flags=0;
+      continue;
+    }
+    if(ISPOINTER(t)) t=((t&~NU)|UNSIGNED|LONG);
+    if((c==ASSIGN||c==PUSH)&&(!ISSCALAR(t)||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      zmax size; struct obj loops;
+      int salign,dalign,cl,a1,a2,mr,ms;
+      size=p->q2.val.vmax;
+      salign=balign(&p->q1);
+      if(c==PUSH) dalign=0; else dalign=balign(&p->z);
+      if(salign>=0&&dalign>=0&&(salign&3)==(dalign&3)){
+        a1=t1; a2=t2;
+      }else{
+        if(!helpl) helpl=++label;
+        cl=0;mr=0;ms=0;
+        for(i=1;i<=32;i++){
+          if(i!=17&&i!=18&&i!=19&&regused[i]&&!regscratch[i]&&!regs[i]) mr=i;
+          if(regs[i]&&regscratch[i]) ms=1;
+        }
+        if(mr==0) mr=t3;
+        if(regs[17]||regs[18]||regs[19]||function_calls==0) ms=1;
+        if(ms) emit(f,"\tlda\t%s,%s%d\n",regnames[mr],labprefix,helpl);
+        if(regs[17]) emit(f,"\tstq\t%s,%d(%s)\n",regnames[17],8*cl++,regnames[mr]);
+        if(regs[18]) emit(f,"\tstq\t%s,%d(%s)\n",regnames[18],8*cl++,regnames[mr]);
+        if(regs[19]) emit(f,"\tstq\t%s,%d(%s)\n",regnames[19],8*cl++,regnames[mr]);
+        a1=18;a2=17;
+        if(p->z.am&&p->z.am->base==18) ierror(0);
+        if(!p->z.am&&(p->z.flags&REG)&&p->z.reg==18) ierror(0);
+      }
+      if(p->q1.flags&DREFOBJ){
+        p->q1.flags&=~DREFOBJ;
+        load_reg(f,a1,&p->q1,POINTER,a1);
+        p->q1.flags|=DREFOBJ;
+      }else{
+        load_address(f,a1,&p->q1,POINTER);
+      }
+      if(p->z.flags&DREFOBJ){
+        p->z.flags&=~DREFOBJ;
+        load_reg(f,a2,&p->z,POINTER,a2);
+        p->z.flags|=DREFOBJ;
+      }else{
+        if(c==PUSH){
+          emit(f,"\tlda\t%s,%ld(%s)\n",regnames[a2],pushed,regnames[sp]);
+          pushed+=zm2l(p->q2.val.vmax);
+        }else{
+          load_address(f,a2,&p->z,POINTER);
+        }
+      }
+      if(salign>=0&&dalign>=0&&(salign&3)==(dalign&3)){
+        int do64,m,s;
+        if((salign&7)==(dalign&7))
+          {do64=1;m=8;s='q';}
+        else
+          {do64=0;m=4;s='l';salign&=3;}
+        if(salign&7){
+          emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t3],-salign,regnames[t1]);
+          emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],-salign,regnames[t2]);
+          cl=(1<<salign)-1;
+          if(!zmleq(l2zm(m-salign),size)) cl+=((1<<(m-salign-zm2l(size)))-1)<<(salign+zm2l(size));
+          emit(f,"\tzap\t%s,%d,%s\n",regnames[t3],cl,regnames[t3]);
+          emit(f,"\tzapnot\t%s,%d,%s\n",regnames[t4],cl,regnames[t4]);
+          emit(f,"\tbis\t%s,%s,%s\n",regnames[t3],regnames[t4],regnames[t3]);
+          emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t3],-salign,regnames[t2]);
+          size=zmsub(size,zm2l(m-salign));
+          salign=m-salign;
+        }else
+          salign=0;
+        loops.val.vmax=zmdiv(size,l2zm(8*m));
+        if(zmleq(l2zm(2L),loops.val.vmax)){
+          loops.flags=KONST;
+          loops.am=0;
+          load_reg(f,t3,&loops,LONG,t3);
+          cl=++label;
+          emit(f,"\t.align\t4\n%s%d:\n",labprefix,cl);
+        }
+        if(!zmeqto(loops.val.vmax,l2zm(0))){
+          for(i=0;i<8;i+=2){
+            emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+            emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t1]);
+            emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+            emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t2]);
+          }
+        }
+        if(zmleq(l2zm(2L),loops.val.vmax)){
+          emit(f,"\taddq\t%s,%d,%s\n",regnames[t1],8*m,regnames[t1]);
+          emit(f,"\taddq\t%s,%d,%s\n",regnames[t2],8*m,regnames[t2]);
+          emit(f,"\tsubq\t%s,1,%s\n",regnames[t3],regnames[t3]);
+          emit(f,"\tbne\t%s,%s%d\n",regnames[t3],labprefix,cl);
+        }else{
+          if(!zmeqto(loops.val.vmax,l2zm(0L)))
+            salign+=8*m;
+        }
+        size=zmand(size,l2zm(8*m-1));
+        for(i=0;i<(zm2l(size)/m/2)*2;i+=2){
+          emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+          emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t1]);
+          emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+          emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t2]);
+        }
+        size=zmand(size,l2zm(2*m-1));
+        if(zm2l(size)>=m){
+          emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+          emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+          size=zmsub(size,l2zm(m));i++;
+        }
+        if(zm2l(size)>0){
+          if(zm2l(size)==4){
+            emit(f,"\tldl\t%s,%d(%s)\n",regnames[t4],salign+i*m,regnames[t1]);
+            emit(f,"\tstl\t%s,%d(%s)\n",regnames[t4],salign+i*m,regnames[t2]);
+          }else{
+            emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+            emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m,regnames[t2]);
+            cl=(1<<zm2l(size))-1;
+            emit(f,"\tzapnot\t%s,%d,%s\n",regnames[t4],cl,regnames[t4]);
+            emit(f,"\tzap\t%s,%d,%s\n",regnames[t5],cl,regnames[t5]);
+            emit(f,"\tbis\t%s,%s,%s\n",regnames[t4],regnames[t5],regnames[t4]);
+            emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+          }
+        }
+        p->z.flags=0; /* to prevent pr() from... */
+        continue;
+      }
+      for(i=1;i<=32;i++){
+        if(i!=17&&i!=18&&i!=19&&regs[i]&&regscratch[i])
+          emit(f,"\tstq\t%s,%d(%s)\n",regnames[i],8*cl++,regnames[mr]);
+      }
+      if(function_calls==0) emit(f,"\tstq\t%s,%d(%s)\n",regnames[lr],8*cl++,regnames[mr]);
+      if(cl>helps) helps=cl;
+      loops.val.vmax=size;
+      loops.flags=KONST;
+      loops.am=0;
+      load_reg(f,19,&loops,LONG,19);
+      emit(f,"\t.global\t%smemcpy\n",idprefix);
+      emit(f,"\tjsr\t%s,%smemcpy\n",regnames[lr],idprefix);
+      emit(f,"\tldgp\t%s,0(%s)\n",regnames[gp],regnames[lr]);
+      cl=0;
+      if(ms&&mr==t3) emit(f,"\tlda\t%s,%s%d\n",regnames[mr],labprefix,helpl);
+      if(regs[17]) emit(f,"\tldq\t%s,%d(%s)\n",regnames[17],8*cl++,regnames[mr]);
+      if(regs[18]) emit(f,"\tldq\t%s,%d(%s)\n",regnames[18],8*cl++,regnames[mr]);
+      if(regs[19]) emit(f,"\tldq\t%s,%d(%s)\n",regnames[19],8*cl++,regnames[mr]);
+      for(i=1;i<=32;i++){
+        if(i!=17&&i!=18&&i!=19&&regs[i]&&regscratch[i])
+          emit(f,"\tldq\t%s,%d(%s)\n",regnames[i],8*cl++,regnames[mr]);
+      }
+      if(function_calls==0) emit(f,"\tldq\t%s,%d(%s)\n",regnames[lr],8*cl++,regnames[mr]);
+      p->z.flags=0;
+      continue;
+    }
+    if(isreg(q1)) wasnoreg=1; else wasnoreg=0;
+    p=do_refs(f,p);
+    c=p->code;
+    if(c==CONVERT){
+      int to;
+      to=p->typf2&NU;
+      if(ISPOINTER(to)) to=(UNSIGNED|LONG);
+      if(ISINT(to)&&ISINT(t)){
+        if((to&NQ)>=(t&NQ)){
+          if((t&NQ)<INT){
+            if(t&UNSIGNED){
+              emit(f,"\tzapnot\t%s,%d,%s\n",regnames[q1reg],(t&NQ)==CHAR?1:3,regnames[zreg]);
+              st[zreg]=EUNS;continue;
+            }else{
+              emit(f,"\tsext%c\t%s,%s\n",(t&NQ)==CHAR?'b':'w',regnames[q1reg],regnames[zreg]);
+              st[zreg]=ESGN;continue;
+            }
+          }
+          zreg=q1reg;
+        }else if((t&NQ)==LONG||(t&NQ)==LLONG){
+          if(to&UNSIGNED)
+            uextend(f,q1reg);
+          else
+            extend(f,q1reg);
+          st[q1reg]=ESGN;
+          zreg=q1reg;
+        }else{
+          if((to&UNSIGNED)==(t&UNSIGNED)){
+            zreg=q1reg;
+          }else{
+            if(to&UNSIGNED){
+              emit(f,"\tzapnot\t%s,%d,%s\n",regnames[q1reg],(t&NQ)==CHAR?1:3,regnames[zreg]);
+              st[zreg]=EUNS;continue;
+            }else{
+              emit(f,"\tsext%c\t%s,%s\n",(t&NQ)==CHAR?'b':'w',regnames[q1reg],regnames[zreg]);
+              st[zreg]=ESGN;continue;
+            }
+          }
+        }
+        continue;
+      }
+      if(ISFLOAT(to)){
+        st[zreg]=ESGN;
+        if(ISFLOAT(t)){
+          emit(f,"\tcvt%c%c\t%s,%s\n",x_t[to&NQ],x_t[t&NQ],regnames[q1reg],regnames[zreg]);
+          continue;
+        }
+/*      if(t&UNSIGNED) ierror(0); */
+        emit(f,"\tcvttqc\t%s,%s\n",regnames[q1reg],regnames[f3]);
+/*      emit(f,"\tftoit\t%s,%s\n",regnames[q1reg],regnames[zreg]);  */
+/*      emit(f,"\t.long\t%ld\n",(0x1cl<<26)+(0x70l<<5)+(31l<<16)+((long)(q1reg-33)<<21)+zreg-1); */
+        emit(f,"\tstt\t%s,%ld(%s)\n",regnames[f3],framesize-addbuf,regnames[sp]);
+        emit(f,"\tldq\t%s,%ld(%s)\n",regnames[zreg],framesize-addbuf,regnames[sp]);
+        st[zreg]=ESGN;
+        continue;
+      }
+      if(ISFLOAT(t)){
+/*      if(to&UNSIGNED) ierror(0); */
+/*      emit(f,"\titoft\t%s,%s\n",regnames[q1reg],regnames[zreg]);  */
+        emit(f,"\tstq\t%s,%ld(%s)\n",regnames[q1reg],framesize-addbuf,regnames[sp]);
+        emit(f,"\tldt\t%s,%ld(%s)\n",regnames[zreg],framesize-addbuf,regnames[sp]);
+        emit(f,"\tcvtq%c\t%s,%s\n",x_t[t&15],regnames[zreg],regnames[zreg]);
+
+        continue;
+      }
+    }
+    if(c==KOMPLEMENT){
+      emit(f,"\tornot\t%s,%s,%s\n",regnames[r31],regnames[q1reg],regnames[zreg]);
+      if((t&NQ)==INT) st[zreg]=0; else st[zreg]=ESGN;
+      continue;
+    }
+    if(c==SETRETURN){
+      if(p->z.reg){
+        if(zreg==0) load_reg(f,p->z.reg,&p->q1,t,t3);
+        extend(f,p->z.reg);
+      }else
+        ierror(0);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+        st[zreg]=ESGN;
+      }else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      int reg;
+      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+        pushed-=zm2l(p->q2.val.vmax);
+        continue;
+      }
+      if((p->q1.flags&VAR)&&p->q1.v->storage_class==EXTERN&&!(g_flags[6]&USEDFLAG)){
+        char *s=p->q1.v->identifier;
+        if(!strcmp("abs",s)||!strcmp("labs",s)){
+          emit(f,"\tsubq\t%s,%s,%s\n",regnames[r31],regnames[17],regnames[1]);
+          emit(f,"\tcmovge\t%s,%s,%s\n",regnames[17],regnames[17],regnames[1]);
+          continue;
+        }
+        if(!strcmp("fabs",s)){
+          emit(f,"\tfabs\t%s,%s\n",regnames[17],regnames[1]);
+          continue;
+        }
+        if(!strcmp("__va_fixargs",s)){
+          emit(f,"\tlda\t%s,%d(%s)\n",regnames[1],fixargs,regnames[r31]);
+          continue;
+        }
+        if(!strcmp("__va_start",s)){
+          emit(f,"\tlda\t%s,%ld(%s)\n",regnames[1],framesize-(6-fixargs)*16,regnames[sp]);
+          continue;
+        }
+      }
+      for(reg=17;reg<=22;reg++)
+        extend(f,reg);
+      if(q1reg){
+        if(q1reg!=vp) move_reg(f,q1reg,vp);
+        emit(f,"\tjsr\t%s,(%s),0\n",regnames[lr],regnames[vp]);
+      }else{
+        emit(f,"\tjsr\t%s,",regnames[lr]);
+        probj2(f,&p->q1,t);emit(f,"\n");
+      }
+      emit(f,"\tldgp\t%s,0(%s)\n",regnames[gp],regnames[lr]);
+      pushed-=zm2l(p->q2.val.vmax);
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(q1reg){
+        if(c==PUSH){
+          extend(f,q1reg);
+          if((t&NQ)==FLOAT){
+            emit(f,"\tcvtst\t%s,%s\n",regnames[q1reg],regnames[f1]);
+            q1reg=f1;
+	    emit(f,"\tsts\t%s,%ld(%s)\n",regnames[q1reg],pushed,regnames[sp]);
+          }else{
+	    emit(f,"\tst%c\t%s,%ld(%s)\n",q1reg<=32?'q':'t',regnames[q1reg],pushed,regnames[sp]);
+	  }
+          pushed+=8;
+          continue;
+        }
+        if(c==ASSIGN) zreg=q1reg;
+        continue;
+      }else ierror(0);
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      continue;
+    }
+    if(c==MINUS){
+      if(ISINT(t))
+        emit(f,"\tsub%c\t%s,%s,%s\n",x_t[t&NQ],regnames[r31],regnames[q1reg],regnames[zreg]);
+      else
+        emit(f,"\tsub%c\t%s,%s,%s\n",x_t[t&NQ],regnames[f31],regnames[q1reg],regnames[zreg]);
+      st[zreg]=ESGN;
+      continue;
+    }
+    if(c==TEST){
+      if(st[q1reg]==0) extend(f,q1reg);
+      cmpreg=q1reg;
+      cmpflag=0;
+      continue;
+    }
+    if(c==COMPARE){
+      struct IC *br=p->next;
+      while(1){
+        if(br->code>=BEQ&&br->code<BRA) break;
+        if(br->code!=FREEREG) ierror(0);
+        br=br->next;
+      }
+      if(ISFLOAT(t)) cmpreg=f3; else cmpreg=t3;
+      if(br->code==BEQ||br->code==BNE){
+        if((t&NU)==(UNSIGNED|INT)){
+          if(st[q1reg]==ESGN) extend(f,q2reg);
+          else if(st[q2reg]==ESGN) extend(f,q1reg);
+          else if(st[q1reg]==EUNS) uextend(f,q2reg);
+          else if(st[q2reg]==EUNS) uextend(f,q1reg);
+          else {extend(f,q1reg);extend(f,q2reg);}
+        }
+        if((t&NU)==INT){extend(f,q1reg);extend(f,q2reg);}
+        if(ISFLOAT(t)) emit(f,"\tsub%c\t%s,",x_t[t&NQ],regnames[q1reg]);
+          else emit(f,"\tsub%c\t%s,",x_t[t&NQ],regnames[q1reg]);
+        probj2(f,&p->q2,t);emit(f,",%s\n",regnames[cmpreg]);
+        cmpflag=0;st[cmpreg]=ESGN;
+      }else{
+        char *s="";
+        if(t&UNSIGNED) s="u";
+        if((t&NU)==(UNSIGNED|INT)){uextend(f,q1reg);uextend(f,q2reg);}
+        if((t&NU)==INT){extend(f,q1reg);extend(f,q2reg);}
+        if(ISFLOAT(t)) s="t";
+        if(br->code==BLT||br->code==BGE){
+          emit(f,"\tcmp%slt\t%s,",s,regnames[q1reg]);
+          probj2(f,&p->q2,t);emit(f,",%s\n",regnames[cmpreg]);
+          if(br->code==BGE) cmpflag=-1; else cmpflag=1;
+        }else{
+          emit(f,"\tcmp%sle\t%s,",s,regnames[q1reg]);
+          probj2(f,&p->q2,t);emit(f,",%s\n",regnames[cmpreg]);
+          if(br->code==BGT) cmpflag=-1; else cmpflag=1;
+        }
+      }
+      continue;
+    }
+    if(c>=OR&&c<=AND){
+      emit(f,"\t%s\t%s,",logicals[c-OR],regnames[q1reg]);
+      probj2(f,&p->q2,t);emit(f,",%s\n",regnames[zreg]);
+      /* hier ist mehr moeglich */
+      if((t&NQ)==INT) st[zreg]=0; else st[zreg]=ESGN;
+      continue;
+    }
+    if(c>=LSHIFT&&c<=MOD){
+      int xt;
+      if(c==LSHIFT&&(p->q2.flags&KONST)){
+        eval_const(&p->q2.val,t);
+        if(zumeqto(vumax,ul2zum(1UL))){
+          emit(f,"\tadd%c\t%s,%s,%s\n",x_t[t&NQ],regnames[q1reg],regnames[q1reg],regnames[zreg]);
+          st[zreg]=ESGN;continue;
+        }
+        if(zumeqto(vumax,ul2zum(2UL))){
+          emit(f,"\ts4add%c\t%s,0,%s\n",x_t[t&NQ],regnames[q1reg],regnames[zreg]);
+          st[zreg]=ESGN;continue;
+        }
+        if(zumeqto(vumax,ul2zum(3UL))){
+          emit(f,"\ts8add%c\t%s,0,%s\n",x_t[t&NQ],regnames[q1reg],regnames[zreg]);
+          st[zreg]=ESGN;continue;
+        }
+      }
+      if(c==RSHIFT||c==LSHIFT){
+        if(c==RSHIFT){
+          if(t&UNSIGNED){
+            if((t&NQ)<LONG) uextend(f,q1reg);
+            emit(f,"\tsrl\t");
+          }else{
+            extend(f,q1reg);
+            emit(f,"\tsra\t");
+          }
+          st[zreg]=st[q1reg];
+        }else{
+          emit(f,"\tsll\t");
+          if((t&NQ)<=INT) st[zreg]=0; else st[zreg]=ESGN;
+        }
+        emit(f,"%s,",regnames[q1reg]);
+        probj2(f,&p->q2,t);emit(f,",%s\n",regnames[zreg]);
+        continue;
+      }
+      if((c==DIV||c==MOD)&&ISINT(t)){
+        /* Linux-Routinen aufrufen. q1=$24 q2=$25 z=$27 $28 scratch */
+        if(!q1reg) ierror(0);
+        if(q1reg!=25){
+          if(regs[25]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[25],framesize-addbuf,regnames[sp]);
+          move_reg(f,q1reg,25);
+        }
+        if(q2reg!=26&&regs[26]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[26],framesize-addbuf+8,regnames[sp]);
+        if(q2reg==25)
+          emit(f,"\tldq\t%s,%ld(%s)\n",regnames[26],framesize-addbuf,regnames[sp]);
+        else
+          load_reg(f,26,&p->q2,t,26);
+        if(zreg!=28&&regs[28]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[28],framesize-addbuf+16,regnames[sp]);
+        if(regs[29]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[29],framesize-addbuf+24,regnames[sp]);
+        emit(f,"\t%sq%s\t%s,%s,%s\n",arithmetics[c-LSHIFT],(t&UNSIGNED)?"u":"",regnames[25],regnames[26],regnames[28]);
+        if(zreg!=28) move_reg(f,28,zreg);
+        if(q1reg!=25&&regs[25]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[25],framesize-addbuf,regnames[sp]);
+        if(q2reg!=26&&regs[26]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[26],framesize-addbuf+8,regnames[sp]);
+        if(zreg!=28&&regs[28]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[28],framesize-addbuf+16,regnames[sp]);
+        if(regs[29]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[29],framesize-addbuf+24,regnames[sp]);
+        /* Was fuer st[zreg]? */
+        continue;
+      }
+      xt=x_t[t&NQ];
+      if((t&NQ)<INT) xt='l';
+      emit(f,"\t%s%c\t%s,",arithmetics[c-LSHIFT],xt,regnames[q1reg]);
+      probj2(f,&p->q2,t);emit(f,",%s\n",regnames[zreg]);
+      st[zreg]=ESGN;
+      continue;
+    }
+    if(c==SUBPFP){
+      emit(f,"\tsubq\t%s,%s,%s\n",regnames[q1reg],regnames[q2reg],regnames[zreg]);
+      st[zreg]=ESGN;continue;
+    }
+    if(c==ADDI2P||c==SUBIFP){
+      if(t&UNSIGNED){
+        if((t&NQ)<LONG) uextend(f,q2reg);
+      }else
+        extend(f,q2reg);
+      if(c==ADDI2P) emit(f,"\taddq\t%s,",regnames[q1reg]);
+      else emit(f,"\tsubq\t%s,",regnames[q1reg]);
+      probj2(f,&p->q2,t);
+      emit(f,",%s\n",regnames[zreg]);
+      st[zreg]=ESGN;continue;
+    }
+    ierror(0);
+  }
+  function_bottom(f,v,zm2l(offset+addbuf),maxpushed);
+  if(debug_info){
+    if(stabs){
+      debug_exit(f,v);
+    }else{
+      emit(f,"%s%d:\n",labprefix,++label);
+      dwarf2_function(f,v,label);
+      if(f) section=-1;    
+    }
+  }  
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *fkt)
+{
+  int f;
+  f=t->flags&NQ;
+  if(ISINT(f)||ISPOINTER(f)){
+    if(m->nextr>=6) return 0;
+    return 17+m->nextr++;
+  }
+  if(ISFLOAT(f)){
+    if(m->nextr>=6) return 0;
+    return 49+m->nextr++;
+  }
+  return 0;
+}
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+
+  title(f);
+  if(f&&stabs) debug_cleanup(f);
+  while(p=firstfpc){
+    if(f){
+      int t=p->typ&NQ;
+      if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+      emit(f,"\t.align\t3\n%s%d:\n\t",labprefix,p->label);
+      if(ISFLOAT(t)){
+        ip=(unsigned char *)&p->val.vdouble;
+        emit(f,"\t.long\t0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+        if((p->typ&NQ)!=FLOAT){
+          emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+        }
+      }else{
+        emit(f,"\t.quad\t");
+        emitval(f,&p->val,p->typ);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+  if(f&&helps) emit(f,"\t.lcomm\t%s%d,%d\n",labprefix,helpl,helps*8);
+}
+
+void init_db(FILE *f)
+{
+  if(!stabs){
+    dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".8byte",labprefix,idprefix,".section");
+    dwarf2_print_comp_unit_header(f);
+  }
+} 
+void cleanup_db(FILE *f)
+{
+  if(!stabs&&f)
+    dwarf2_cleanup(f);
+  if(f) section=-1;
+}
diff --git a/machines/alpha/machine.dt b/machines/alpha/machine.dt
new file mode 100755
index 0000000..60cf0b9
--- /dev/null
+++ b/machines/alpha/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S64BULE S64BUBE
+
+
diff --git a/machines/alpha/machine.h b/machines/alpha/machine.h
new file mode 100755
index 0000000..aa05ba8
--- /dev/null
+++ b/machines/alpha/machine.h
@@ -0,0 +1,70 @@
+/*  Example of a code-generator for a DEC Alpha                     */
+
+#include "dt.h"
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+  int flags;
+  int base;
+  int align;
+  long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 64
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 10
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P LONG
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 1
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH 1
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    int nextr;
+};
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
diff --git a/machines/alpha/schedule.c b/machines/alpha/schedule.c
new file mode 100755
index 0000000..e19e13b
--- /dev/null
+++ b/machines/alpha/schedule.c
@@ -0,0 +1,106 @@
+#include "vsc.h"
+
+char tg_copyright[]="Alpha scheduler V0.0 (c) in 1997 by Volker Barthelmann";
+
+int sched_init(void)
+{
+  return 1;
+}
+void sched_cleanup(void)
+{
+}
+int sched_info(struct sinfo *p)
+{
+  char buf[20];int q1,q2,z,i;
+  if(sscanf(p->txt,"$C%d:",&i)==1){
+    p->label=i;
+    p->flags=LABEL;
+    return 1;
+  }
+  /* lda $r1,imm($r2) */
+  if(sscanf(p->txt,"lda $%d,%d($%d)",&z,&i,&q1)==3){
+    p->latency=1;
+    BSET(p->pipes,0);
+    BSET(p->pipes,1);
+    BSET(p->uses,q1);
+    BSET(p->modifies,z);
+    return 1;
+  }
+  /* lda $r1,... */
+  if(sscanf(p->txt,"lda $%d,",&z)==1){
+    BSET(p->pipes,0);
+    BSET(p->pipes,1);
+    BSET(p->modifies,z);
+    return 1;
+  }
+  /* op $r1,$r2,$r3 */
+  if(sscanf(p->txt,"%19s $%d,$%d,$%d",buf,&q1,&q2,&z)==4){
+    p->latency=1;
+    BSET(p->pipes,0);
+    BSET(p->pipes,1);
+    BSET(p->uses,q1);
+    BSET(p->uses,q2);
+    BSET(p->modifies,z);
+    return 1;
+  }
+  /* op $r1,$r2 */
+  if(sscanf(p->txt,"%19s $%d,$%d",buf,&q1,&z)==3){
+    p->latency=1;
+    BSET(p->pipes,0);
+    BSET(p->pipes,1);
+    BSET(p->uses,q1);
+    BSET(p->modifies,z);
+    return 1;
+  }
+  /* op $r1,imm,$r2 */
+  if(sscanf(p->txt,"%19s $%d,%d,$%d",buf,&q1,&i,&z)==4){
+    p->latency=1;
+    BSET(p->pipes,0);
+    BSET(p->pipes,1);
+    BSET(p->uses,q1);
+    BSET(p->modifies,z);
+    return 1;
+  }
+  /* op $fr1,$fr2,$fr3 */
+  if(sscanf(p->txt,"%19s $f%d,$f%d,$f%d",buf,&q1,&q2,&z)==4){
+    p->latency=1;
+    BSET(p->pipes,2);
+    BSET(p->pipes,3);
+    BSET(p->uses,q1+32);
+    BSET(p->uses,q2+32);
+    BSET(p->modifies,z+32);
+    return 1;
+  }
+  /* load/store $r1,c($r2) */
+  if(sscanf(p->txt,"%19s $%d,%d($%d)",buf,&z,&i,&q1)==4){
+    p->latency=3;
+    BSET(p->pipes,0);
+    BSET(p->uses,q1);
+    if(*buf=='l'){
+      BSET(p->pipes,1);
+      BSET(p->modifies,z);
+      BSET(p->uses,MEM);
+    }else{
+      BSET(p->uses,z);
+      BSET(p->modifies,MEM);
+    }
+    return 1;
+  }
+  /* load/store $fr1,c($r2) */
+  if(sscanf(p->txt,"%19s $f%d,%d($%d)",buf,&z,&i,&q1)==4){
+    p->latency=3;
+    BSET(p->pipes,0);
+    BSET(p->uses,q1);
+    if(*buf=='l'){
+      BSET(p->pipes,1);
+      BSET(p->modifies,z+32);
+      BSET(p->uses,MEM);
+    }else{
+      BSET(p->uses,z+32);
+      BSET(p->modifies,MEM);
+    }
+    return 1;
+  }
+  p->flags=BARRIER;
+  return 1;
+}
diff --git a/machines/alpha/schedule.h b/machines/alpha/schedule.h
new file mode 100755
index 0000000..8603727
--- /dev/null
+++ b/machines/alpha/schedule.h
@@ -0,0 +1,4 @@
+
+#define PIPES 4
+#define REGS 64
+
diff --git a/machines/arm/machine.c b/machines/arm/machine.c
new file mode 100755
index 0000000..1462bef
--- /dev/null
+++ b/machines/arm/machine.c
@@ -0,0 +1,2460 @@
+/*
+ * ARM code generator
+ * A 32-bit RISC with 16 general purpose registers.
+ * Written by Frank Wille <frank@phoenix.owl.de>
+ */
+
+#include "supp.h"
+#include "vbc.h"
+
+static char FILE_[] = __FILE__;
+
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[] = "vbcc code-generator for ARM V0.0 (c) in 2006 by Frank Wille";
+
+/* Commandline-flags the code-generator accepts:
+   0: just a flag
+   VALFLAG: a value must be specified
+   STRINGFLAG: a string can be specified
+   FUNCFLAG: a function will be called
+   apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF] = {
+    STRINGFLAG,STRINGFLAG,0,0,0,0,
+    0,0,0,0
+};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF] = {
+    "cpu","fpu","little-endian","big-endian","arm","thumb",
+    "const-in-data","merge-constants","elf","use-commons"
+};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. */
+char *regnames[MAXR+1] = {
+    "noreg",
+    "r0","r1","r2","r3","r4","r5","r6","r7",
+    "r8","r9","r10","r11","r12","sp","lr","pc",
+    "s0","s1","s2","s3","s4","s5","s6","s7",
+    "s8","s9","s10","s11","s12","s13","s14","s15",
+    "cpsr",
+    "r0/r1","r2/r3","r4/r5","r6/r7","r10/r11",
+    "d0","d1","d2","d3","d4","d5","d6","d7"
+};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1] = {
+    0,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,  /* r0-r3,r12 */
+    1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,    /* vfp s0-s3 */
+    1,                                  /* cpsr */
+    1,1,0,0,0,                          /* r0/r1, r2/r3 */
+    1,1,0,0,0,0,0,0                     /* vfp d0-d1 */
+};
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1] = {
+    0,10,11,12,13,2,3,4,5,6,7,8,9,14,0,1,0,
+    1,2,3,4,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,
+    10,12,2,4,8,
+    1,2,0,0,0,0,0,0
+};
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle = {0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[] = {
+    "__arm","__thumb","__interrupt","__syscall",0
+};
+#define ARM 1
+#define THUMB 2
+#define INTERRUPT 4
+#define SYSCALL 8
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define LE_MODE (g_flags[2]&USEDFLAG)
+#define BE_MODE (g_flags[3]&USEDFLAG)
+#define ARM_DEFAULT (g_flags[4]&USEDFLAG)
+#define THUMB_DEFAULT (g_flags[5]&USEDFLAG)
+#define CONST_IN_DATA (g_flags[6]&USEDFLAG)
+#define ELF_LABELS (g_flags[8]&USEDFLAG)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+int arm_le_mode = 1;          /* defaults to little-endian */
+static int thumb_default = 0; /* we start in ARM mode */
+static int thumb = 0;         /* current mode */
+
+enum {
+  AAANY=0,AA2,AA3,AA3M,AA4,AA4T,AA5,AA5T,AA5TE
+};
+static int aa = AAANY;        /* ARM architecture version */
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1] = {
+    1,1,2,4,4,8,4,8,8,1,4,1,1,1,4,1
+};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1] = {
+    1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0
+};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp  = {LONG};
+static struct Typ lltyp = {LLONG};
+static struct Typ ftyp  = {FLOAT};
+static struct Typ dtyp  = {DOUBLE};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+                       "__ARM__",
+                       0};
+
+/* special registers */
+static int ip = FIRST_GPR+12;       /* inter-procedural scratch register */
+static int sp = FIRST_GPR+13;       /* stack pointer */
+static int lr = FIRST_GPR+14;       /* link register */
+static int pc = FIRST_GPR+15;       /* program counter */
+static int r0 = FIRST_GPR;
+static int r1 = FIRST_GPR+1;
+
+/* load/store instructions */
+static char *ldts[MAX_TYPE+1] = {
+    "ldr","ldrsb","ldrsh","ldr","ldr","ldr","ldr","ldr","ldr","??","ldr"};
+static char *ldtu[MAX_TYPE+1] = {
+    "ldr","ldrb","ldrh","ldr","ldr","ldr","??","??","??","??","??"};
+static char *sdts[MAX_TYPE+1] = {
+    "str","strb","strh","str","str","str","str","str","str","??","str"};
+static char *sdtu[MAX_TYPE+1] = {
+    "str","strb","strh","str","str","str","??","??","??","??","??"};
+#define ldt(t) ((t&UNSIGNED) ? ldtu[(t)&NQ] : ldts[(t)&NQ])
+#define sdt(t) ((t&UNSIGNED) ? sdtu[(t)&NQ] : sdts[(t)&NQ])
+
+static char *ldstprefix[] = {
+    "ld","st"
+};
+
+static char *dct[] = {
+    "","byte","short","word","word","word","word","word","word"
+};
+
+static char *ccs[] = {
+    "eq","ne","lt","ge","le","gt",""
+};
+
+static char *logicals[] = {
+    "orr","eor","and"
+};
+
+static char *shifts[2][2] = {
+    "lsl","asr","lsl","lsr"
+};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+#if 0
+static long stack;
+static int stack_valid;
+#endif
+static int newobj;
+static int section = -1;
+
+static char *codename = "\t.text\n";
+static char *dataname = "\t.data\n";
+static char *bssname = "";
+static char *rodataname = "\t.rodata\n";
+
+/* list of floating point constants to output at end of file */
+struct fpconstlist {
+  struct fpconstlist *next;
+  int label;
+  int typ;
+  union atyps val;
+};
+static struct fpconstlist *firstfpc = NULL;
+
+/* data reference pointers at the end of each function */
+struct DataRefPtrList {
+  struct DataRefPtrList *next;
+  int label;
+  struct Var *vptr;             /* valid, when label==0 */
+};
+static struct DataRefPtrList *dataptrs = NULL;
+static int drefptr_array_label; /* current array's label */
+
+#define isreg(x) (((x)&(REG|DREFOBJ))==REG)
+#define isconst(x) (((x)&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+static struct Var *current_function;
+static int icnt;                /* counts number of lines in cur. function */
+
+#define MAXCODELINES 500        /* emit data-ref. ptr array after that */
+#define MAXCOPYINSTS 4          /* max. nb. of load/store copy-instructions */
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l";
+static char *idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame */
+static long frameoffset,pushoffs,framesize;
+static int needframe;
+static long localsize,rsavesize,argsize,rsaveoffs,maxrsaveoffs;
+
+
+
+static long real_offset(struct obj *o)
+/* calculate the actual current offset of an object relative to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | stack-arguments to this function             |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   The stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+*/
+{
+  long off = zm2l(o->v->offset);
+
+  if (off < 0) {
+    /* function parameter */
+    off = localsize + rsavesize - off - zm2l(maxalign);
+  }
+  else {
+    /* local variable */
+    off += argsize;
+    off += zm2l(o->val.vmax);
+  }
+
+  return off;
+}
+
+
+static struct obj *cam(int flags,int base,long offset)
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+
+#if 0
+  obj.am = &am;
+  am.flags = flags;
+  am.base = base;
+  am.offset = offset;
+#endif
+  return &obj;
+}
+
+
+static int objalign(struct obj *o)
+/* yields the object's lower two bits, 1 when unknown */
+{
+  if (o->flags & DREFOBJ)
+    return 1;
+  if (o->am)
+    ierror(0);
+  if (!(o->flags & VAR))
+    ierror(0);
+
+  if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+    /* all static data should be 32-bits aligned */
+    return zm2l(zmand(o->val.vmax,l2zm(3L)));
+  }
+
+  if (isauto(o->v->storage_class)) {
+    zmax of = o->v->offset;
+
+    if (!zmleq(l2zm(0L),of))
+      of = zmsub(l2zm(0L),zmadd(of,maxalign));
+    return zm2l(zmand(zmadd(of,o->val.vmax),l2zm(3L)));
+  }
+
+  ierror(0);
+}
+
+
+static void title(FILE *f)
+/* set file symbol with input file name */
+{
+  extern char *inname;
+  static int done;
+
+  if (!done && f) {
+    done = 1;
+    emit(f,"\t.file\t\"%s\"\n",inname);
+  }
+}
+
+
+static void emitnl(FILE *f)
+/* emit a newline character */
+{
+  emit(f,"\n");
+}
+
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* prints an object */
+{
+  if (p->flags & VAR) {
+    if (isauto(p->v->storage_class)) {
+      emit(f,"[%s,#%ld]",regnames[sp],real_offset(p));
+    }
+    else {
+      if (!zmeqto(l2zm(0L),p->val.vmax)) {
+        emitval(f,&p->val,LONG);
+        emit(f,"+");
+      }
+      if (isstatic(p->v->storage_class))
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      else
+        emit(f,"%s%s",idprefix,p->v->identifier);
+    }
+  }
+
+  if (p->flags & REG) {
+    emit(f,"%s",regnames[p->reg]);
+  }
+
+  if (p->flags & KONST) {
+    emit(f,"#");
+    emitval(f,&p->val,t&NU);
+  }
+}
+
+
+static int special_section(FILE *f,struct Var *v)
+/* changes to a special section, used for __section() */
+{
+  char *sec;
+
+  if (v->vattr) {
+    if (sec = strstr(v->vattr,"section(")) {
+      sec += strlen("section(");
+      emit(f,"\t.section\t");
+      while (*sec && *sec!=')')
+        emit_char(f,*sec++);
+      emitnl(f);
+      if (f)
+        section = SPECIAL;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+static int addfpconst(struct obj *o,int t)
+/* return label for a float-constant, create if it didn't exist */
+{
+  struct fpconstlist *p=firstfpc;
+
+  t &= NQ;
+  if (t == LDOUBLE)
+    t = DOUBLE;
+
+  for (p=firstfpc; p; p=p->next) {
+    if (t == p->typ) {
+      eval_const(&p->val,t);
+      if (t==FLOAT && zldeqto(vldouble,zf2zld(o->val.vfloat)))
+        return p->label;
+      if (t==DOUBLE && zldeqto(vldouble,zd2zld(o->val.vdouble)))
+        return p->label;
+    }
+  }
+
+  p = mymalloc(sizeof(struct fpconstlist));
+  p->next = firstfpc;
+  p->label = ++label;
+  p->typ = t;
+  p->val = o->val;
+  firstfpc = p;
+
+  return p->label;
+}
+
+
+static void emit_dataptr_array(FILE *f)
+/* emit all data-reference pointers which were collected until now,
+   then reset the array */
+{
+  struct DataRefPtrList *drp,*next;
+
+  if (next = dataptrs) {
+    emit(f,"\t.align\t2\n");
+    emit(f,"%s%d:\n",labprefix,drefptr_array_label);
+
+    while (drp = next) {
+      next = drp->next;
+      emit(f,"\t.%s\t",dct[LONG]);
+      if (drp->label) {
+        emit(f,"%s%d\n",labprefix,drp->label);
+      }
+      else {
+        if (isstatic(drp->vptr->storage_class))
+          emit(f,"%s%ld\n",labprefix,zm2l(drp->vptr->offset));
+        else
+          emit(f,"%s%s\n",idprefix,drp->vptr->identifier);
+      }
+      free(drp);
+    }
+    dataptrs = NULL;
+  }
+  drefptr_array_label = 0;
+}
+
+
+static int cg_getreg(FILE *f,struct IC *ic)
+/* allocate a code generator internal general purpose register */
+{
+  /* alloc_code: 1:compiler, 2:backend, >=4:backend rsave-area offset - 4 */
+  int alloc_code = 2;
+  int i,p,r;
+
+  /* try to get a free scratch-register or a non-volatile
+     register which has to be saved anyway,
+     r12 (ip) is reserved to the backend and will be used as well,
+     r14 (lr) is available when the function builds a stack frame */
+  for (i=FIRST_GPR,p=0,r=0; i<FIRST_GPR+13; i++) {
+    if (((i==ip && regs[i]==1) ||
+         (i==lr && regs[i]==1 && needframe) ||
+         (regs[i]==0 && (regscratch[i] || regused[i]))) &&
+        reg_prio[i]+(regused[i]<<8) > p) {
+      p = reg_prio[i] + (regused[i] << 8);
+      r = i;
+    }
+  }
+  if (!r) {
+    /* seems we have to save a new non-volatile register */
+    for (i=FIRST_GPR,p=0; i<FIRST_GPR+13; i++) {
+      if (regs[i]==0 && reg_prio[i]>p) {
+        p = reg_prio[i];
+        r = i;
+      }
+    }
+  }
+  if (!r) {
+    /* no register available - save one to the stack-frame, but
+       make sure it is not used in this IC */
+    for (i=FIRST_GPR,p=0; i<FIRST_GPR+13; i++) {
+      if (regs[i]<2 && reg_prio[i]>p) {
+        if ((!isreg(ic->q1.flags) || ic->q1.reg!=i) &&
+            (!isreg(ic->q2.flags) || ic->q2.reg!=i) &&
+            (!isreg(ic->z.flags) || ic->z.reg!=i)) {
+          p = reg_prio[i];
+          r = i;
+        }
+      }
+    }
+    if (r) {
+      if (f)
+        emit(f,"\tstr\t%s,[%s,#%ld]\n",
+             regnames[r],regnames[sp],argsize+localsize+rsaveoffs);
+      rsaveoffs += 4;
+      if (rsaveoffs > maxrsaveoffs)
+        maxrsaveoffs = rsaveoffs;
+      alloc_code = rsaveoffs;
+    }
+    else
+      ierror(0);
+  }
+
+  regs[r] = alloc_code;
+  regused[r] = 1;
+  return r;
+}
+
+
+static int cg_getdpreg(FILE *f,struct IC *ic)
+/* allocate a code generator internal double precision FP register */
+{
+  int i,p,r;
+  struct rpair rp;
+
+  /* try to get a free scratch-register or a non-volatile
+     register which has to be saved anyway */
+  for (i=FIRST_DOUBLE,p=0,r=0; i<=LAST_PAIR; i++) {
+    if (regs[i]==0 && (regscratch[i] || regused[i]) &&
+        reg_prio[i]+(regused[i]<<8) > p && reg_pair(i,&rp)) {
+      if (regs[rp.r1]==0 && regs[rp.r2]==0) {
+        p = reg_prio[i] + (regused[i] << 8);
+        r = i;
+      }
+    }
+  }
+  if (!r) {
+    ierror(0); /* @@@ FIXME */
+  }
+
+  regs[r] = 2;
+  regused[r] = 1;
+  if (!reg_pair(i,&rp))
+    ierror(0);
+  regs[rp.r1] = regs[rp.r2] = 2;
+  regused[rp.r1] = regused[rp.r2] = 1;
+  return r;
+}
+
+
+static void cg_restorereg(FILE *f,int r)
+{
+  if (f) {
+    if (r <= LAST_GPR)
+      emit(f,"\tldr\t%s,[%s,#%ld]\n",
+           regnames[r],regnames[sp],argsize+localsize+regs[r]-4);
+    else
+      ierror(0);  /* @@@ FIXME */
+  }
+}
+
+
+static void cg_freereg(FILE *f,int r)
+/* free a code generator internal general purpose register */
+{
+  struct rpair rp;
+
+  if (regs[r] > 1) {
+    if (regs[r] > 2)
+      cg_restorereg(f,r);
+    regs[r] = (r==ip||r==lr) ? 1 : 0;  /* ip/lr need to stay reserved */
+  }
+  else
+    ierror(0);
+
+  if (reg_pair(r,&rp)) {
+    if (regs[rp.r1]>1 && regs[rp.r2]>1) {
+      if (regs[rp.r1] > 2)
+        cg_restorereg(f,rp.r1);
+      if (regs[rp.r2] > 2)
+        cg_restorereg(f,rp.r2);
+      regs[rp.r1] = regs[rp.r2] = 0;
+    }
+    else
+      ierror(0);
+  }
+}
+
+
+static void cg_freeall(FILE *f)
+/* reset internal register allocations */
+{
+  int i;
+
+  for (i=1; i<=MAXR; i++) {
+    if (regs[i] > 1) {
+      if (regs[i] > 2)
+        cg_restorereg(f,i);
+      regs[i] = (i==ip||i==lr) ? 1 : 0;  /* ip/lr need to stay reserved */
+    }
+  }
+  rsaveoffs = 0;
+}
+
+
+static long dataptr_offset(int label,struct obj *o)
+/* return offset into data-reference-pointer array for label l
+   or for object o (mutually exclusive) */
+{
+  long off = 0;
+  struct DataRefPtrList **olddrp = &dataptrs;
+  struct DataRefPtrList *drp = dataptrs;
+
+  if (!label) {
+    if (!(o->flags & VAR))
+      ierror(0);
+    if (!isstatic(o->v->storage_class) && !isextern(o->v->storage_class))
+      ierror(0);
+  }
+
+  /* check if a pointer to this object already exists */
+  while (drp) {
+    if (label) {
+      if (drp->label == label)
+        break;
+    }
+    else {
+      if (drp->vptr == o->v)
+        break;
+    }
+    olddrp = &drp->next;
+    drp = drp->next;
+    off += 4;
+  }
+
+  /* create a new entry if it doesn't exist */
+  if (drp == NULL) {
+    *olddrp = drp = mymalloc(sizeof(struct DataRefPtrList));
+
+    drp->next = NULL;
+    if (drp->label = label)
+      drp->vptr = NULL;
+    else
+      drp->vptr = o->v;
+  }
+
+  return off;
+}
+
+
+static void load_dataptr(FILE *f,int r,int l,struct obj *o)
+/* load data-reference-pointer array entry for label l or object o into r */
+{
+  BSET(regs_modified,r);
+
+  if (!drefptr_array_label)
+    drefptr_array_label = ++label;
+
+  emit(f,"\tldr\t%s,%s%d+%ld\n",
+       regnames[r],labprefix,drefptr_array_label,dataptr_offset(l,o));
+}
+
+
+static void ldst64(FILE *f,int store,struct rpair *rp,int base)
+/* generate a ldmia or stmia (store=1) instruction to transfer a 64-bit
+   value in register pair rp pointed to by base-register base */
+{
+  emit(f,"%smia\t%s,{%s-%s}\n",
+       ldstprefix[store],regnames[base],regnames[rp->r1],regnames[rp->r2]);
+}
+
+
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r. */
+{
+  BSET(regs_modified,r);
+
+  if (!(o->flags & VAR))
+    ierror(0);
+
+  if (isauto(o->v->storage_class))
+    emit(f,"\tadd\t%s,%s,#%ld\n",regnames[r],regnames[sp],real_offset(o));
+  else
+    load_dataptr(f,r,0,o);
+}
+
+
+static void load_regindir(FILE *f,struct IC *p,int type,
+                          int dst,int base,long off)
+/*  Load register dst of type type from [base,#off].
+    base and dst may be the same.
+    Perform size extensions as required by architecture. */
+{
+  BSET(regs_modified,dst);
+
+  if (aa >= AA4) {
+    emit(f,"\t%s\t%s,[%s,#%ld]\n",
+         ldt(type),regnames[dst],regnames[base],off);
+  }
+
+  else {
+    /* this requires more effort on older ARMs */
+    int tmp;
+
+    switch (sizetab[type&NQ]) {
+      case 1:
+        emit(f,"\tldrb\t%s,[%s,#%ld]\n",regnames[dst],regnames[base],off);
+        if (!(type & UNSIGNED)) {
+          emit(f,"\tmov\t%s,%s,lsl #24\n",regnames[dst],regnames[dst]);
+          emit(f,"\tmov\t%s,%s,asr #24\n",regnames[dst],regnames[dst]);
+        }
+        break;
+      case 2:
+        tmp = cg_getreg(f,p);
+        emit(f,"\tldrb\t%s,[%s,#%ld]\n",regnames[tmp],regnames[base],
+                                        off+1-arm_le_mode);
+        emit(f,"\tldrb\t%s,[%s,#%ld]\n",regnames[dst],regnames[base],
+                                        off+arm_le_mode);
+        if (!(type & UNSIGNED)) {
+          emit(f,"\tmov\t%s,%s,lsl #24\n",regnames[dst],regnames[dst]);
+          emit(f,"\torr\t%s,%s,%s asr #16\n",
+               regnames[dst],regnames[tmp],regnames[dst]);
+        }
+        else {
+          emit(f,"\torr\t%s,%s,%s lsl #8\n",
+               regnames[dst],regnames[tmp],regnames[dst]);
+        }
+        cg_freereg(f,tmp);
+        break;
+      case 4:
+        emit(f,"\tldr\t%s,[%s,#%ld]\n",regnames[dst],regnames[base],off);
+        break;
+      default:
+        ierror(0);
+    }
+  }
+}
+
+
+static void load_reg(FILE *f,struct IC *p,int r,struct obj *o,int type)
+/* Generates code to load a memory object into register r. */
+{
+  type &= NU;
+  BSET(regs_modified,r);
+
+  if (o->flags & KONST) {
+    /* evaluate and load a constant */
+
+    eval_const(&o->val,type);
+
+    if (ISFLOAT(type)) {
+      int lab = addfpconst(o,type);
+
+      load_dataptr(f,r,lab,NULL);
+      if (type == FLOAT)
+        load_regindir(f,p,type,r,r,0);
+      else
+        ierror(0);  /* double can only be in a register-pair */
+    }
+
+    else {
+      /* integer constant */
+      emit(f,"\tmov\t%s,",regnames[r]);
+      emit_obj(f,o,type);
+      emitnl(f);
+    }
+  }
+
+  else if (isreg(o->flags)) {
+    if (r != o->reg)
+      emit(f,"\tmov\t%s,%s\n",regnames[r],regnames[o->reg]);
+  }
+
+  else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+    load_regindir(f,p,type,r,o->reg,0);
+  }
+
+  else if (o->flags & VAR) {
+    if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+      /* load from a static variable */
+      if (o->flags & VARADR) {
+        load_address(f,r,o,POINTER);
+      }
+      else {
+        load_dataptr(f,r,0,o);
+        load_regindir(f,p,type,r,r,zm2l(o->val.vmax));
+      }
+    }
+    else {
+      /* dynamic variable on stack */
+      load_regindir(f,p,type,r,sp,real_offset(o));
+    }
+  }
+
+  else
+    ierror(0);
+}
+
+
+static void store_regindir(FILE *f,struct IC *p,int type,
+                           int src,int base,long off)
+/*  Store register src of type type to [base,#off]. */
+{
+  if (aa>=AA4 || sizetab[type&NQ]!=2) {
+    emit(f,"\t%s\t%s,[%s,#%ld]\n",
+         sdt(type),regnames[src],regnames[base],off);
+  }
+
+  else {
+    /* storing halfwords requires more effort on older ARMs */
+    int tmp = cg_getreg(f,p);
+
+    emit(f,"\tstrb\t%s,[%s,#%ld]\n",regnames[src],regnames[base],
+                                    off+1-arm_le_mode);
+    emit(f,"\tmov\t%s,%s,asr #8\n",regnames[tmp],regnames[src]);
+    emit(f,"\tstrb\t%s,[%s,#%ld]\n",regnames[src],regnames[base],
+                                    off+arm_le_mode);
+    cg_freereg(f,tmp);
+  }
+}
+
+
+static void store_reg(FILE *f,struct IC *p,int r,struct obj *o,int type)
+/* Generates code to store register r into memory object o. */
+{
+  if (isreg(o->flags)) {
+    if (r != o->reg)
+      emit(f,"\tmov\t%s,%s\n",regnames[o->reg],regnames[r]);
+  }
+
+  else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+    store_regindir(f,p,type,r,o->reg,0);
+  }
+
+  else if (o->flags & VAR) {
+    if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+      /* store to a static variable */
+      int tmp = cg_getreg(f,p);
+
+      load_dataptr(f,tmp,0,o);
+      store_regindir(f,p,type,r,tmp,zm2l(o->val.vmax));
+      cg_freereg(f,tmp);
+    }
+    else {
+      /* dynamic variable on stack */
+      store_regindir(f,p,type,r,sp,real_offset(o));
+    }
+  }
+
+  else
+    ierror(0);
+}
+
+
+static int load_objptr(FILE *f,struct IC *p,struct obj *o)
+/* Make sure object o can be dereferenced by a single load.
+   Return new base register, or 0 if object was not modified. */
+{
+  if ((o->flags & (REG|DREFOBJ)) == DREFOBJ) {
+    int r = cg_getreg(f,p);
+
+    load_reg(f,p,r,o,POINTER);
+    o->flags |= REG;
+    o->reg = r;
+    return r;
+  }
+
+  if ((o->flags & (VAR|REG)) == VAR) {
+    if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+      int r = cg_getreg(f,p);
+
+      load_dataptr(f,r,0,o);
+      o->reg = r;
+      o->flags = REG|DREFOBJ;
+      return r;
+    }
+  }
+
+  return 0;
+}
+
+
+static void load_regpair(FILE *f,struct IC *p,struct rpair *rp,
+                         struct obj *o,int type)
+/* Generates code to load a memory object into the register pair rp.
+   tmp is a general purpose register which may be used. */
+{
+  BSET(regs_modified,rp->r1);
+  BSET(regs_modified,rp->r2);
+
+  if (o->flags & KONST) {
+    /* evaluate and load a constant */
+    eval_const(&o->val,type);
+
+    if (ISFLOAT(type)) {
+      int lab = addfpconst(o,type);
+      int tmp = cg_getreg(f,p);
+
+      load_dataptr(f,tmp,lab,NULL);
+      if (type != FLOAT)
+        ldst64(f,0,rp,tmp);
+      else
+        ierror(0);  /* have to load float in a single register */
+      cg_freereg(f,tmp);
+    }
+    else {
+      struct obj cobj;
+
+      cobj.flags = KONST;
+      cobj.val.vulong = zum2zul(zumand(vumax,ul2zum(0xffffffff))); 
+      load_reg(f,p,arm_le_mode?rp->r1:rp->r2,&cobj,UNSIGNED|LONG);
+      cobj.val.vulong = zum2zul(zumand(zumrshift(vumax,ul2zum(32UL)),
+                                       ul2zum(0xffffffff)));
+      load_reg(f,p,arm_le_mode?rp->r2:rp->r1,&cobj,UNSIGNED|LONG);
+    }
+  }
+
+  else {
+    /* make sure that object can be addressed through a register */
+    load_objptr(f,p,o);
+
+    if (isreg(o->flags)) {
+      struct rpair qrp;
+
+      if (!reg_pair(o->reg,&qrp))
+        ierror(0);
+      if (qrp.r1 != rp->r1) {
+        emit(f,"\tmov\t%s,%s\n\tmov\t%s,%s\n",regnames[rp->r1],
+             regnames[qrp.r1],regnames[rp->r2],regnames[qrp.r2]);
+      }
+    }
+    else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+      ldst64(f,0,rp,o->reg);
+    }
+    else
+      ierror(0);
+  }
+}
+
+
+static void store_regpair(FILE *f,struct IC *p,struct rpair *rp,
+                          struct obj *o,int type)
+/* Generates code to store the register pair rp into memory object o.
+   tmp is a general purpose register which may be used. */
+{
+  /* make sure that object can be addressed through a register */
+  load_objptr(f,p,o);
+
+  if (isreg(o->flags)) {
+    struct rpair zrp;
+
+    if (!reg_pair(o->reg,&zrp))
+      ierror(0);
+    if (zrp.r1 != rp->r1) {
+      emit(f,"\tmov\t%s,%s\n\tmov\t%s,%s\n",regnames[zrp.r1],
+           regnames[rp->r1],regnames[zrp.r2],regnames[rp->r2]);
+    }
+  }
+  else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+    ldst64(f,1,rp,o->reg);
+  }
+  else
+    ierror(0);
+}
+
+
+static long pof2(zumax x)
+/* yields log2(x)+1 or 0 */
+{
+  zumax p;
+  int ln = 1;
+
+  p = ul2zum(1L);
+  while (ln<=32 && zumleq(p,x)) {
+    if (zumeqto(x,p))
+        return ln;
+    ln++;
+    p = zumadd(p,p);
+  }
+  return 0;
+}
+
+
+static struct IC *preload(FILE *f,struct IC *p)
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+/* @@@ FIXME - Is this function needed at all ??? */
+{
+#if 0
+  if (isreg(p->q1.flags))
+    q1reg = p->q1.reg;
+  else
+    q1reg = 0;
+
+  if (isreg(p->q2.flags))
+    q2reg = p->q2.reg;
+  else
+    q2reg = 0;
+#endif
+
+  if (isreg(p->z.flags)) {
+    zreg = p->z.reg;
+  }
+  else {
+    if (ISFLOAT(ztyp(p)))
+      zreg = FIRST_PAIR;  /* @@@ VFP? ->f1 */
+    else
+      zreg = cg_getreg(f,p);
+  }
+  
+#if 0  /* Better use load_objptr() when needed? */
+  if ((p->q1.flags & (REG|DREFOBJ)) == DREFOBJ) {
+    int tmp = cg_getreg(f,p);
+
+    p->q1.flags &= ~DREFOBJ;
+    load_reg(f,p,tmp,&p->q1,q1typ(p));
+    p->q1.reg = tmp;
+    p->q1.flags |= REG|DREFOBJ;
+  }
+
+  if ((p->q2.flags & (REG|DREFOBJ)) == DREFOBJ) {
+    int tmp = cg_getreg(f,p);
+
+    p->q2.flags &= ~DREFOBJ;
+    load_reg(f,p,tmp,&p->q2,q2typ(p));
+    p->q2.reg = tmp;
+    p->q2.flags |= REG|DREFOBJ;
+  }
+#endif
+
+  return p;
+}
+
+
+static void save_result(FILE *f,struct IC *p)
+/* save the result (in zreg) into p->z */
+{
+  if ((p->z.flags&(REG|DREFOBJ)) == DREFOBJ) {
+    int tmp = cg_getreg(f,p);
+
+    p->z.flags &= ~DREFOBJ;
+    load_reg(f,p,tmp,&p->z,POINTER);
+    p->z.reg = tmp;
+    p->z.flags |= REG|DREFOBJ;
+  }
+  if (isreg(p->z.flags)) {
+    if (p->z.reg != zreg)
+      emit(f,"\tmov\t%s,%s\n",regnames[p->z.reg],regnames[zreg]);
+  }
+  else {
+    store_reg(f,p,zreg,&p->z,ztyp(p));
+  }
+}
+
+
+static void registerize(FILE *f,struct IC *p,struct obj *o,int t)
+/* make sure object is loaded into a register */
+{
+  if (!(isreg(o->flags))) {
+    int r;
+
+    r = load_objptr(f,p,o);
+    if (!r)
+      r = cg_getreg(f,p);
+    if ((o->flags & (REG|DREFOBJ)) == DREFOBJ)
+      ierror(0);
+    load_reg(f,p,r,o,t);
+    o->reg = r;
+  }
+  o->flags = REG;
+}
+
+
+static void cg_memcopy(FILE *f,struct IC *p)
+/* generates code to copy an object of non-elementary type (ARRAY, STRUCT) */
+{
+  unsigned long size = opsize(p);
+  int a1 = objalign(&p->q1);
+  int a2 = (p->code==ASSIGN) ? objalign(&p->z) : 0;
+  int b = 1;
+  char *ld = ldt(CHAR);
+  char *st = sdt(CHAR);
+  unsigned long l;
+  int srcreg,dstreg,tmpreg,cntreg,ncp;
+
+  if (p->q1.flags & VAR) {
+    if (p->q1.flags & DREFOBJ) {
+      if (p->q1.v->vtyp->next &&
+          zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp->next)) && (a1&1)) {
+        a1 = zm2l(falign(p->q1.v->vtyp->next)) & 3;
+        a2 &= a1;
+      }
+    }
+    else {
+      if (zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp)) && (a1&1)) {
+        a1 = zm2l(falign(p->q1.v->vtyp)) & 3;
+        a2 &= a1;
+      }
+    }
+  }
+  if (p->z.flags & VAR) {
+    if (p->z.flags & DREFOBJ) {
+      if (p->z.v->vtyp->next &&
+          zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp->next)) && (a2&1)) {
+        a2 = zm2l(falign(p->z.v->vtyp->next)) & 3;
+        a1 &= a2;
+      }
+    }
+    else {
+      if (zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp)) && (a2&1)) {
+        a2 = zm2l(falign(p->z.v->vtyp)) & 3;
+        a1 &= a2;
+      }
+    }
+  } 
+
+  /* @@@ implement with ldmia/stmia */
+  if (a1>=0 && a2>=0) {
+    if (a1==0 && a2==0) {
+      /* 32-bit copy */
+      b = 4;
+      ld = ldt(LONG);
+      st = sdt(LONG);
+    }
+    else if ((a1&1)==0 && (a2&1)==0 && aa>=AA4) {
+      /* 16-bit copy for ARM-architecture 4 and better only */
+      b = 2;
+      ld = ldt(SHORT);
+      st = sdt(SHORT);
+    }
+  }
+
+  srcreg = cg_getreg(f,p);
+  BSET(regs_modified,srcreg);
+
+  if (p->q1.flags & DREFOBJ) {
+    p->q1.flags &= ~DREFOBJ;
+    if (isreg(p->q1.flags))
+      emit(f,"\tmov\t%s,%s\n",regnames[srcreg],regnames[p->q1.reg]);
+    else
+      load_reg(f,p,srcreg,&p->q1,POINTER);
+    p->q1.flags |= DREFOBJ;
+  }
+  else {
+    load_address(f,srcreg,&p->q1,POINTER);
+  }
+
+  dstreg = cg_getreg(f,p);
+  BSET(regs_modified,dstreg);
+
+  if (p->z.flags & DREFOBJ) {
+    p->z.flags &= ~DREFOBJ;
+    if (isreg(p->z.flags))
+      emit(f,"\tmov\t%s,%s\n",regnames[dstreg],regnames[p->z.reg]);
+    else
+      load_reg(f,p,dstreg,&p->z,POINTER);
+    p->z.flags |= DREFOBJ;
+  }
+  else {
+    if (p->code == PUSH) {
+      emit(f,"\tadd\t%s,%s,#%ld\n",regnames[dstreg],regnames[sp],pushoffs);
+      pushoffs += size;
+    }
+    else
+      load_address(f,dstreg,&p->z,POINTER);
+  }
+
+  tmpreg = cg_getreg(f,p);
+  BSET(regs_modified,tmpreg);
+  l = size/b;
+
+  if (l > MAXCOPYINSTS) { /* @@@ make MAXCOPYINSTS changeable by an option? */
+    cntreg = cg_getreg(f,p);
+    BSET(regs_modified,cntreg);
+    emit(f,"\tmov\t%s,#%lu\n",regnames[cntreg],l);
+    emit(f,"%s%d:\n",labprefix,++label);
+    ncp = 1;
+  }
+  else
+    ncp = l;
+  while (ncp--) {
+    emit(f,"\t%s\t%s,[%s],#%d\n",ld,regnames[tmpreg],regnames[srcreg],b);
+    emit(f,"\t%s\t%s,[%s],#%d\n",st,regnames[tmpreg],regnames[dstreg],b);
+  }
+  if (l > MAXCOPYINSTS) {
+    emit(f,"\tsubs\t%s,%s,#1\n",regnames[cntreg],regnames[cntreg]);
+    emit(f,"\tbne\t%s%d\n",labprefix,label);
+    cg_freereg(f,cntreg);
+  }
+
+  size = size % b;
+  ncp = 0;
+  if (size & 2) {
+    if (aa >= AA4) {
+      emit(f,"\t%s\t%s,[%s],#%d\n",ldt(SHORT),regnames[tmpreg],regnames[srcreg],b);
+      emit(f,"\t%s\t%s,[%s],#%d\n",sdt(SHORT),regnames[tmpreg],regnames[dstreg],b);
+    }
+    else
+      ncp = 2;
+  }
+  ncp += (size & 1);
+  while (ncp--) {
+    emit(f,"\t%s\t%s,[%s],#%d\n",ldt(CHAR),regnames[tmpreg],regnames[srcreg],b);
+    emit(f,"\t%s\t%s,[%s],#%d\n",sdt(CHAR),regnames[tmpreg],regnames[dstreg],b);
+  }
+}
+
+
+static int exists_freereg(struct IC *p,int reg)
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole(). */
+{
+  while (p && (p->code==FREEREG || p->code==ALLOCREG)) {
+    if (p->code==FREEREG && p->q1.reg==reg)
+      return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+
+#if 0
+static void peephole(struct IC *p)
+/* search for possible addressing-modes */
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(p->q1.flags)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(p->z.flags)&&isconst(p->q2.flags)){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+        r=p->z.reg;
+        if(isreg(p->q1.flags)) base=p->q1.reg; else base=r;
+        o=0;
+        for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+          if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+          if(c2!=FREEREG&&isreg(p2->q1.flags)&&p2->q1.reg==r) break;
+          if(c2!=FREEREG&&isreg(p2->q2.flags)&&p2->q2.reg==r) break;
+          if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+            if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+              if(o) break;
+              o=&p2->q1;
+            }
+            if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+              if(o) break;
+              o=&p2->q2;
+            }
+            if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+              if(o) break;
+              o=&p2->z;
+            }
+          }
+          if(c2==FREEREG||isreg(p2->z.flags)){
+            int m;
+            if(c2==FREEREG)
+              m=p2->q1.reg;
+            else
+              m=p2->z.reg;
+            if(m==r){
+              if(o){
+                o->am=am=mymalloc(sizeof(*am));
+                am->flags=IMM_IND;
+                am->base=base;
+                am->offset=zm2l(of);
+                if(isreg(p->q1.flags)){
+                  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+                }else{
+                  p->code=c=ASSIGN;p->q2.flags=0;
+                  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+                }
+              }
+              break;
+            }
+            if(c2!=FREEREG&&m==base) break;
+            continue;
+          }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(GPR_IND&&c==ADDI2P&&isreg(p->q2.flags)&&isreg(p->z.flags)&&(isreg(p->q1.flags)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(p->q1.flags)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&isreg(p2->q1.flags)&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&isreg(p2->q2.flags)&&p2->q2.reg==r) break;
+        if(isreg(p2->z.flags)&&p2->z.reg==idx&&idx!=r) break;
+        
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||isreg(p2->z.flags)){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=GPR_IND;
+              am->base=base;
+              am->offset=idx;
+              if(isreg(p->q1.flags)){
+                p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+              }else{
+                p->code=c=ASSIGN;p->q2.flags=0;
+                p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+              }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+#endif
+
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/* generates the function entry code */
+{
+  static char ret_instr[64];
+  char gprsave[32];
+  char *p;
+  int i;
+
+  title(f);
+
+  /* determine rsavesize and registers to save */
+  rsavesize = 0;
+  gprsave[0] = '\0';
+  for (i=FIRST_GPR,p=gprsave; i<=LAST_GPR; i++) {
+    if (!regsa[i] && !regscratch[i] && regused[i]) {
+      p += sprintf(p,"%s,",regnames[i]);
+      rsavesize += 4;
+    }
+  }
+
+  if (!special_section(f,v) && section!=CODE) {
+    emit(f,codename);
+    section = CODE;
+  } 
+
+  if (isextern(v->storage_class)) {
+    if ((v->flags & (INLINEFUNC|INLINEEXT)) != INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }
+  else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+  if (rsavesize==0 && !needframe) {
+    ret = "\tmov\tpc,lr\n";
+  }
+  else {
+    rsavesize += 3*4;  /* sp,lr,pc to be saved as well */
+    emit(f,"\tstmfd\t%s!,{%s%s,%s,%s}\n",
+         regnames[sp],gprsave,regnames[sp],regnames[lr],regnames[pc]);
+    sprintf(ret_instr,"\tldmfd\t%s,{%s%s,%s}\n",
+            regnames[sp],gprsave,regnames[sp],regnames[pc]);
+    ret = ret_instr;
+    if (localsize+argsize > 0) {
+      emit(f,"\tsub\t%s,%s,#%ld\n",
+           regnames[sp],regnames[sp],localsize+argsize);
+    }
+  }
+}
+
+
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* generates the function exit code */
+{
+  if (localsize+argsize > 0) {
+    emit(f,"\tadd\t%s,%s,#%ld\n",
+         regnames[sp],regnames[sp],localsize+argsize);
+  }
+  emit(f,ret);
+  emit_dataptr_array(f);
+
+  if (isextern(v->storage_class)) {
+    emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+    emit(f,"\t.size\t%s%s,.-%s%s\n\n",
+         idprefix,v->identifier,idprefix,v->identifier);
+  }
+  else {
+    emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,.-%s%ld\n\n",
+         labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+  }    
+
+  /*if(all_regs&&v->fi) v->fi->flags|=ALL_REGS;*/
+}
+
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign = l2zm(8L);
+  stackalign = l2zm(4L);
+  char_bit = l2zm(8L);
+
+  for (i=0; i<=MAX_TYPE; i++) {
+    sizetab[i] = l2zm(msizetab[i]);
+    align[i] = l2zm(malign[i]);
+  }
+
+  for (i=FIRST_GPR; i<=LAST_GPR; i++) {
+    regsize[i] = l2zm(4L);
+    regtype[i] = &ltyp;
+  }
+
+  for (i=FIRST_FPR; i<=LAST_FPR; i++) {
+    regsize[i] = l2zm(8L);
+    regtype[i] = &ftyp;
+  }
+
+  for (i=FIRST_CCR; i<=LAST_CCR; i++) {
+    regsize[i] = l2zm(4L);
+    regtype[i] = &ltyp;
+  }
+
+  for (i=FIRST_PAIR; i<FIRST_DOUBLE; i++) {
+    regsize[i] = l2zm(8L);
+    regtype[i] = &lltyp;
+  }
+
+  for (i=FIRST_DOUBLE; i<=LAST_PAIR; i++) {
+    regsize[i] = l2zm(8L);
+    regtype[i] = &dtyp;
+  }
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR] = l2zm(-128L);
+  t_min[SHORT] = l2zm(-32768L);
+  t_min[INT] = zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG] = t_min(INT);
+  t_min[LLONG] = zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT] = t_min(LLONG);
+  t_max[CHAR] = ul2zum(127L);
+  t_max[SHORT] = ul2zum(32767UL);
+  t_max[INT] = ul2zum(2147483647UL);
+  t_max[LONG] = t_max(INT);
+  t_max[LLONG] = zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT] = t_max(LLONG);
+  tu_max[CHAR] = ul2zum(255UL);
+  tu_max[SHORT] = ul2zum(65535UL);
+  tu_max[INT] = ul2zum(4294967295UL);
+  tu_max[LONG] = t_max(UNSIGNED|INT);
+  tu_max[LLONG] = zumkompl(ul2zum(0UL));
+  tu_max[MAXINT] = t_max(UNSIGNED|LLONG);
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  regsa[ip] = regsa[sp] = regsa[lr] = regsa[pc] = 1;
+  regscratch[ip] = regscratch[sp] = regscratch[lr] = regscratch[pc] = 0;
+
+  if (LE_MODE)
+    arm_le_mode = 1;
+  if (BE_MODE)
+    arm_le_mode = 0;
+  if (ARM_DEFAULT)
+    thumb_default = 0;
+  if (THUMB_DEFAULT)
+    thumb_default = 1;
+  if (ELF_LABELS) {
+    labprefix = ".l";
+    idprefix = "";
+  }
+
+  target_macros = marray;
+
+
+  /* TODO: set argument registers */
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);
+
+  declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+
+  return 1;
+}
+
+
+void init_db(FILE *f)
+{
+}
+
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  int tu = t->flags&NQ;
+
+  /* @@@ handle VFP */
+
+  if (tu==LLONG || tu==DOUBLE)
+    return FIRST_PAIR;
+
+  if (zmleq(szof(t),l2zm(4L)))
+    return FIRST_GPR;
+
+  return 0;
+}
+
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if (r<FIRST_PAIR || r>LAST_PAIR)
+    return 0;
+
+  switch (r) {
+    case FIRST_PAIR:
+      p->r1 = FIRST_GPR;
+      p->r2 = FIRST_GPR+1;
+      return 1;
+    case FIRST_PAIR+1:
+      p->r1 = FIRST_GPR+2;
+      p->r2 = FIRST_GPR+3;
+      return 1;
+    case FIRST_PAIR+2:
+      p->r1 = FIRST_GPR+4;
+      p->r2 = FIRST_GPR+5;
+      return 1;
+    case FIRST_PAIR+3:
+      p->r1 = FIRST_GPR+6;
+      p->r2 = FIRST_GPR+7;
+      return 1;
+    case FIRST_PAIR+4:
+      p->r1 = FIRST_GPR+10;
+      p->r2 = FIRST_GPR+11;
+      return 1;
+    case FIRST_DOUBLE:
+      p->r1 = FIRST_FPR;
+      p->r2 = FIRST_FPR+1;
+      return 1;
+    case FIRST_DOUBLE+1:
+      p->r1 = FIRST_FPR+2;
+      p->r2 = FIRST_FPR+3;
+      return 1;
+    case FIRST_DOUBLE+2:
+      p->r1 = FIRST_FPR+4;
+      p->r2 = FIRST_FPR+5;
+      return 1;
+    case FIRST_DOUBLE+3:
+      p->r1 = FIRST_FPR+6;
+      p->r2 = FIRST_FPR+7;
+      return 1;
+    case FIRST_DOUBLE+4:
+      p->r1 = FIRST_FPR+8;
+      p->r2 = FIRST_FPR+9;
+      return 1;
+    case FIRST_DOUBLE+5:
+      p->r1 = FIRST_FPR+10;
+      p->r2 = FIRST_FPR+11;
+      return 1;
+    case FIRST_DOUBLE+6:
+      p->r1 = FIRST_FPR+12;
+      p->r2 = FIRST_FPR+13;
+      return 1;
+    case FIRST_DOUBLE+7:
+      p->r1 = FIRST_FPR+14;
+      p->r2 = FIRST_FPR+15;
+      return 1;
+    default:
+      ierror(0);
+  }
+
+  return 0;
+}
+
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+/* estimate the cost-saving if object o from IC p is placed in */
+/* register r                                                  */
+{
+  int c = p->code;
+
+  /* @@@ FIXME */
+  if (o->flags & VKONST) {
+    if (o==&p->q1 && p->code==ASSIGN && (p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if (o->flags & DREFOBJ)
+    return 4;
+  if (c==SETRETURN && r==p->z.reg && !(o->flags&DREFOBJ))
+    return 3;
+  if (c==GETRETURN && r==p->q1.reg && !(o->flags&DREFOBJ))
+    return 3;
+  return 2;
+}
+
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if (r==0)
+    return 0;
+
+  if (t==0 && r>=FIRST_CCR && r<=LAST_CCR)
+    return 1;
+
+  t &= NQ;
+
+  if (ISFLOAT(t)) {
+    /* @@@ handle VFP */
+    if (t==FLOAT && r>=FIRST_GPR && r<=LAST_GPR)
+      return 1;
+    else if (r>=FIRST_PAIR && r<=LAST_PAIR)
+      return 1;
+  }
+  else if (t==POINTER && r>=FIRST_GPR && r<=LAST_GPR)
+    return 1;
+  else if (t>=CHAR && t<=LONG && r>=FIRST_GPR && r<=LAST_GPR)
+    return 1;
+  else if (t==LLONG && r>=FIRST_PAIR && r<=LAST_PAIR)
+    return 1;
+
+  return 0;
+}
+
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  if ((p->q1.flags&DREFOBJ) || (p->q2.flags&DREFOBJ) || (p->z.flags&DREFOBJ))
+    return 1;
+  /* ARM has no division/modulo instructions */
+  return 0;
+}
+
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op = o & NQ;
+  int tp = t & NQ;
+
+  if ((op==INT||op==LONG||op==POINTER) && (tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if (op==DOUBLE && tp==LDOUBLE)
+    return 0;
+  if (op==LDOUBLE && tp==DOUBLE)
+    return 0;
+  if(op==tp)
+    return 0;
+  return 1;
+}
+
+
+char *use_libcall(int c,int t,int t2)
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+{
+  static char fname[16];
+  char *ret = NULL;
+
+  if (((c==MULT && aa<AA2) ||
+       (c>MULT && c<=MOD)) && (t&NQ) <= LONG) {
+    if ((t&UNSIGNED) && (c==DIV || c==MOD))
+      sprintf(fname,"__%s",ename[c]);
+    else
+      sprintf(fname,"__%ss",ename[c]);
+    ret = fname;
+  }
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)&&(t&NU)==LLONG){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+	if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%suint64",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+        }else{
+	  sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+	}
+      }
+    }
+  }
+
+  return ret;
+}
+
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  title(f);
+
+  if (newobj && section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+
+  newobj = 0;
+}
+
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  title(f);
+
+  if (zm2l(align) > 1)
+    emit(f,"\t.align\t2\n");
+}
+
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  char *sec;
+
+  title(f);
+
+  if(v->clist)
+    constflag = is_const(v->vtyp);
+
+  if (isstatic(v->storage_class)) {
+    if (ISFUNC(v->vtyp->flags))
+      return;
+    if (!special_section(f,v)) {
+      if (v->clist && (!constflag || CONST_IN_DATA) && section!=DATA) {
+        emit(f,dataname);
+        if (f)
+          section = DATA;
+      }
+      if (v->clist && constflag && !CONST_IN_DATA && section!=RODATA) {
+        emit(f,rodataname);
+        if (f)
+          section = RODATA;
+      }
+      if (!v->clist && section!=BSS) {
+        emit(f,bssname);
+        if (f)
+          section = BSS;
+      }
+    }
+    if (v->clist || section==SPECIAL) {
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }
+    else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj = 1;
+  }
+
+  if (isextern(v->storage_class)) {
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if (v->flags & (DEFINED|TENTATIVE)) {
+      if (!special_section(f,v)) {
+        if (v->clist && (!constflag || CONST_IN_DATA) && section!=DATA) {
+          emit(f,dataname);
+          if(f)
+            section = DATA;
+        }
+        if (v->clist && constflag && !CONST_IN_DATA && section!=RODATA) {
+          emit(f,rodataname);
+          if (f)
+            section = RODATA;
+        }
+        if (!v->clist && section!=BSS) {
+          emit(f,bssname);
+          if (f)
+            section = BSS;
+        }
+      }
+      if (v->clist || section==SPECIAL) {
+        gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }
+      else {
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,
+             v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      }
+      newobj = 1;
+    }
+  }
+}
+
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  title(f);
+
+  if ((t&NQ) == POINTER)
+    t = UNSIGNED|LONG;
+  emit(f,"\t.%s\t",dct[t&NQ]);
+
+  if (!p->tree) {
+    if (ISFLOAT(t)) {
+      unsigned char *ip = (unsigned char *)&p->val.vdouble;
+
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if ((t&NQ) != FLOAT)
+        emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+    }
+    else {
+      emitval(f,&p->val,t&NU);
+    }
+  }
+  else {
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+
+  emitnl(f);
+  newobj = 0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation routine.                   */
+{
+  FILE *outfile = f;
+  struct IC *p_start = p;
+  int c,t,i,pass;
+  struct rpair rp;
+
+  if (DEBUG & 1)
+    printf("gen_code()\n");
+
+  current_function = v;
+  icnt = 0;
+  drefptr_array_label = 0;
+  argsize = 0;
+  rsavesize = 0;
+  maxrsaveoffs = 0;
+  needframe = 0;
+
+  for (c=1; c<=MAXR; c++)
+    regs[c] = regsa[c];
+
+  for (p=p_start; p; p=p->next) {
+    c = p->code;
+    t = p->typf & NU;
+
+    if (c == ALLOCREG) {
+      if (reg_pair(p->q1.reg,&rp)) {
+        regs[rp.r1] = 1;
+        regs[rp.r2] = 1;
+      }
+      regs[p->q1.reg] = 1;
+      continue;
+    }
+
+    if (c == FREEREG) {
+      if (reg_pair(p->q1.reg,&rp)) {
+        regs[rp.r1] = 0;
+        regs[rp.r2] = 0;
+      }
+      regs[p->q1.reg] = 0;
+      continue;
+    }
+
+    /* try MULT/DIV/MOD with powers of two */
+    if ((c==MULT || ((c==DIV || c==MOD) && (t&UNSIGNED))) &&
+        (t&NQ)<=LONG && isconst(p->q2.flags)) {
+      eval_const(&p->q2.val,t);
+      if (i = pof2(vmax)) {
+        if (c == MOD) {
+          vmax = zmsub(vmax,l2zm(1L));
+          p->code = AND;
+        }
+        else {
+          vmax = l2zm(i-1);
+          p->code = c==DIV ? RSHIFT : LSHIFT;
+        }
+        c = p->code;
+        gval.vmax = vmax;
+        eval_const(&gval,MAXINT);
+        if (c == AND) {
+          insert_const(&p->q2.val,t);
+        }
+        else {
+          insert_const(&p->q2.val,INT);
+          p->typf2 = INT;
+        }
+      }
+    }
+
+    if (c == CALL) {
+      needframe = 1;
+      if (argsize < zm2l(pushedargsize(p)))
+        argsize = zm2l(pushedargsize(p));  /* set max argsize */
+    }
+  }
+
+  /*peephole(p); @@@ FIXME */
+
+  for (c=i; i<=MAXR; i++) {
+    if (regsa[i] || regused[i])
+      BSET(regs_modified,i);
+    if (!regsa[i] && !regscratch[i] && regused[i])
+      needframe = 1;
+  }
+
+  /* determine word-aligned space for local variables */
+  localsize = ((zm2l(offset) + 3) / 4) * 4;
+  if (localsize > 0)
+    needframe = 1;
+
+  for (pass=0,f=NULL; pass<2; pass++,f=outfile) {
+    struct IC my_ic;
+    struct IC *p2;
+
+    if (pass) {
+      emit_dataptr_array(NULL);  /* reset ptr-array */
+      icnt = 0;
+      function_top(f,v,argsize+localsize);
+    }
+
+    pushoffs = 0;
+
+    for (p2=p_start; p2; p2=p2->next) {
+      if (pass) {
+        p = p2;
+      }
+      else {  /* work on a copy in first pass */
+        p = &my_ic;
+        *p = *p2;
+      }
+
+      c = p->code;
+      t = p->typf;
+
+      cg_freeall(f);  /* reset internal register allocations */
+
+      if (icnt > MAXCODELINES) {
+        /* function has grown too big, emit all data-reference pointers first */
+        emit(f,"\tb\t%s%d\n",labprefix,++label);
+        emit_dataptr_array(f);
+        emit(f,"%s%d:\n",labprefix,label);
+        icnt = 0;
+      }
+
+      if (c == NOP) {
+        p->z.flags = 0;
+        continue;
+      }
+
+      if (c == ALLOCREG) {
+        if (reg_pair(p->q1.reg,&rp)) {
+          regs[rp.r1] = 1;
+          regs[rp.r2] = 1;
+        }
+        regs[p->q1.reg] = 1;
+        continue;
+      }
+
+      if (c == FREEREG) {
+        if (reg_pair(p->q1.reg,&rp)) {
+          regs[rp.r1] = 0;
+          regs[rp.r2] = 0;
+        }
+        regs[p->q1.reg] = 0;
+        continue;
+      }
+
+      if (c == LABEL) {
+        emit(f,"%s%d:\n",labprefix,t);
+        continue;
+      }
+
+      if (c == BRA) {
+        if (t==exit_label && framesize==0)
+          emit(f,ret);
+        else
+          emit(f,"\tb\t%s%d\n",labprefix,t);
+        continue;
+      }
+
+      if (c>=BEQ && c<BRA) {
+        emit(f,"\tb%s\t",ccs[c-BEQ]);
+        if (isreg(p->q1.flags)) {
+          ierror(0);  /* @@@ was ist das? */
+          emit_obj(f,&p->q1,0);
+          emit(f,",");
+        }
+        emit(f,"%s%d\n",labprefix,t);
+        continue;
+      }
+
+      if (c == MOVETOREG) {
+        if (p->z.reg>=FIRST_GPR && p->z.reg<=LAST_GPR) {
+          load_reg(f,p,p->z.reg,&p->q1,t);
+        }
+        else if (reg_pair(p->z.reg,&rp)) {
+          BSET(regs_modified,p->z.reg);
+          load_regpair(f,p,&rp,&p->q1,t);
+        }
+        else
+          ierror(0);  /* @@@ VFP registers */
+        p->z.flags = 0;
+        continue;
+      }
+
+      if (c == MOVEFROMREG) {
+        if (p->q1.reg>=FIRST_GPR && p->q1.reg<=LAST_GPR) {
+          store_reg(f,p,p->q1.reg,&p->z,t);
+        }
+        else if (reg_pair(p->q1.reg,&rp)) {
+          store_regpair(f,p,&rp,&p->z,t);
+        }
+        else
+          ierror(0);  /* @@@ VFP registers */
+        p->z.flags = 0;
+        continue;
+      }
+
+      if ((c==ASSIGN || c==PUSH) &&
+          ((t&NQ)>POINTER || ((t&NQ)==CHAR && zm2l(opsize(p))!=1))) {
+        cg_memcopy(f,p);
+        p->z.flags = 0;
+        continue;
+      }
+
+      p = preload(f,p);
+      c = p->code;
+
+      if (c == SUBPFP)
+        c = SUB;
+      else if (c == ADDI2P)
+        c = ADD;
+      else if (c == SUBIFP)
+        c = SUB;
+
+      if (c == CONVERT) {
+        if (ISFLOAT(q1typ(p)) || ISFLOAT(ztyp(p)))   /* @@@ */
+          ierror(0);
+
+        if (sizetab[q1typ(p)&NQ] < sizetab[ztyp(p)&NQ]) {
+          int sh = 0;
+
+          if ((q1typ(p)&NQ) == CHAR)
+            sh = 24;
+          else if ((q1typ(p)&NQ) == SHORT)
+            sh = 16;
+          else if (sizetab[ztyp(p)&NQ] > 4)
+            ierror(0);  /* @@@ */
+
+          if (sh) {
+            registerize(f,p,&p->q1,q1typ(p));
+            emit(f,"\tmov\t%s,%s,lsl #%d\n",regnames[zreg],regnames[p->q1.reg],sh);
+            emit(f,"\tmov\t%s,%s,%csr #%d\n",regnames[zreg],regnames[zreg],
+                                             (q1typ(p)&UNSIGNED)?'l':'a',sh);
+          }
+        }
+        save_result(f,p);
+        continue;
+      }
+
+      if (c == KOMPLEMENT) {
+        registerize(f,p,&p->q1,t);
+        emit(f,"\tmvn\t%s,%s\n",regnames[zreg],regnames[p->q1.reg]);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c == SETRETURN) {
+        load_reg(f,p,p->z.reg,&p->q1,t);
+        BSET(regs_modified,p->z.reg);
+        continue;
+      }
+
+      if (c == GETRETURN) {
+        if (p->q1.reg) {  /* REG-flag is not set!? */
+          zreg = p->q1.reg;
+          save_result(f,p);
+        }
+        else
+          p->z.flags = 0;
+        continue;
+      }
+
+      if (c == CALL) {
+        if ((p->q1.flags & (VAR|DREFOBJ))==VAR &&
+            p->q1.v->fi && p->q1.v->fi->inline_asm) {
+          emit_inline_asm(f,p->q1.v->fi->inline_asm);
+        }
+        else if (p->q1.flags & DREFOBJ) {
+          int reg;
+
+          if (p->q1.flags & REG) {
+            reg = p->q1.reg;
+          }
+          else {
+            reg = cg_getreg(f,p);
+            load_reg(f,p,reg,&p->q1,POINTER);
+          }
+          emit(f,"\tmov\t%s,%s\n",regnames[lr],regnames[pc]);
+          if (aa < AA4T)
+            emit(f,"\tmov\t%s,%s\n",regnames[pc],regnames[reg]);
+          else
+            emit(f,"\tbx\t%s\n",regnames[reg]);
+        }
+        else {
+          emit(f,"\tbl\t");
+          emit_obj(f,&p->q1,t);
+          emitnl(f);
+        }
+
+        pushoffs -= zm2l(pushedargsize(p));
+
+        if ((p->q1.flags & (VAR|DREFOBJ))==VAR &&
+            p->q1.v->fi && (p->q1.v->fi->flags & ALL_REGS)) {
+          bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+        }
+        else{
+          int i;
+
+          for (i=1; i<=MAXR; i++) {
+            if (regscratch[i])
+              BSET(regs_modified,i);
+          }
+        }
+        continue;
+      }
+
+      if (c == PUSH) {
+        if (t == 0)
+          ierror(0);
+        registerize(f,p,&p->q1,t);
+        emit(f,"\tstr\t%s,[%s,#%ld]\n",
+             regnames[p->q1.reg],regnames[sp],pushoffs);
+        pushoffs += zm2l(opsize(p));
+        continue;
+      }
+
+      if (c == ASSIGN) {
+        if (t == 0)
+          ierror(0);
+        if (isreg(p->q1.flags))
+          zreg = p->q1.reg;
+        else
+          load_reg(f,p,zreg,&p->q1,t);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c == ADDRESS) {
+        load_address(f,zreg,&p->q1,POINTER);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c == MINUS) {
+        registerize(f,p,&p->q1,t);
+        emit(f,"\trsb\t%s,%s,#0\n",regnames[zreg],regnames[p->q1.reg]);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c == TEST) {
+        registerize(f,p,&p->q1,t);
+        emit(f,"\tteq\t%s,#0\n",regnames[p->q1.reg]);
+        continue;
+      }
+
+      if (c == COMPARE) {
+        if (!isconst(p->q1.flags))
+          registerize(f,p,&p->q1,t);
+        emit(f,"\tcmp\t%s,",regnames[p->q1.reg]);
+        emit_obj(f,&p->q2,t);
+        emitnl(f);
+        continue;
+      }
+
+      if ((c>=OR && c<=AND)) {
+        registerize(f,p,&p->q1,t);
+        if (!isconst(p->q2.flags))
+          registerize(f,p,&p->q2,t);
+        emit(f,"\t%s\t%s,%s,",logicals[c-OR],regnames[zreg],
+             regnames[p->q1.reg]);
+        emit_obj(f,&p->q2,t);
+        emitnl(f);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c>=LSHIFT && c<=RSHIFT) {
+        registerize(f,p,&p->q1,t);
+        if (!isconst(p->q2.flags))
+          registerize(f,p,&p->q2,t);
+        emit(f,"\tmov\t%s,%s,%s ",regnames[zreg],regnames[p->q1.reg],
+             shifts[(t&UNSIGNED)!=0][c-LSHIFT]);
+        emit_obj(f,&p->q2,t);
+        emitnl(f);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c>=ADD && c<=SUB) {
+        registerize(f,p,&p->q1,t);
+        if (!isconst(p->q2.flags))
+          registerize(f,p,&p->q2,t);
+        emit(f,"\t%s\t%s,%s,",c==ADD?"add":"sub",
+             regnames[zreg],regnames[p->q1.reg]);
+        emit_obj(f,&p->q2,t);
+        emitnl(f);
+        save_result(f,p);
+        continue;
+      }
+
+      if (c==MULT && aa>=AA2 && sizetab[t&NQ]<=4) {
+        registerize(f,p,&p->q1,t);
+        registerize(f,p,&p->q2,t);
+        emit(f,"\tmul\t%s,%s,%s\n",
+             regnames[zreg],regnames[p->q1.reg],regnames[p->q2.reg]);
+        save_result(f,p);
+        continue;
+      }
+
+      if (pass) {
+        pric2(stdout,p);
+        ierror(0);
+      }
+    }
+  }
+
+  cg_freeall(f);
+  function_bottom(f,v,argsize+localsize+rsavesize);
+
+#if 0  /* @@@ wozu? */
+  if (stack_valid) {
+    if (!v->fi)
+      v->fi = new_fi();
+    v->fi->flags |= ALL_STACK;
+    v->fi->stack1 = stack;
+  }
+  emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+#endif
+}
+
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+
+  if (!m || !t)
+    ierror(0);
+
+  f = t->flags & NQ;
+
+  if (f<=LONG || f==POINTER) {
+    if (m->gregs >= GPR_ARGS)
+      return 0;
+    else
+      return FIRST_GPR + m->gregs++;
+  }
+
+  if (f == LLONG) {
+    if (m->gregs >= GPR_ARGS-1)
+      return 0;
+    else
+      ierror(0);  /* @@@ check ABI if odd registers are skipped!? */
+  }
+
+  if (ISFLOAT(f)) {
+#if 0 /* @@@ VFP only! */
+    if (m->fregs >= FPR_ARGS)
+      return 0;
+    else
+      return FIRST_DOUBLE + m->fregs++;
+#endif
+  }
+
+  return 0;
+}
+
+
+int emit_peephole(void)
+/* This function will not optimize anything, but just update the
+   number of lines counter, icnt, for the current function.
+   It is required to estimate if a data-reference-pointer array
+   is still reachable with a 12-bit offset. */
+{
+  int entries;
+
+  entries = emit_f ? EMIT_BUF_DEPTH : emit_l - emit_f + 1;
+  icnt += entries;
+  return 0;
+}
+
+
+int handle_pragma(const char *s)
+{
+  return 0;
+}
+
+
+void cleanup_cg(FILE *f)
+{
+}
+
+
+void cleanup_db(FILE *f)
+{
+  if (f)
+    section = -1;
+}
diff --git a/machines/arm/machine.dt b/machines/arm/machine.dt
new file mode 100755
index 0000000..47b1bfa
--- /dev/null
+++ b/machines/arm/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S32BULE S32BUBE
+
+
diff --git a/machines/arm/machine.h b/machines/arm/machine.h
new file mode 100755
index 0000000..7730379
--- /dev/null
+++ b/machines/arm/machine.h
@@ -0,0 +1,141 @@
+/*
+ * ARM code generator
+ * Written by Frank Wille <frank@phoenix.owl.de>
+ */
+
+/* built-time configurable options: */
+#define NUM_GPRS 16
+#define NUM_FPRS 16
+#define NUM_CCRS 1
+#define NUM_PAIRS 13
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+#define FIRST_PAIR (LAST_CCR+1)
+#define FIRST_DOUBLE (FIRST_PAIR+5)
+#define LAST_PAIR (FIRST_PAIR+NUM_PAIRS-1)
+
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int never_used;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS+NUM_PAIRS
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 10
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  This specifies the largest integer type that can be added to a  */
+/*  pointer.                                                        */
+#define MAXADDI2P LONG
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN (!arm_le_mode)
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN (arm_le_mode)
+
+extern int arm_le_mode;
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH 1
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+/*  Number registers used for function arguments */
+#define GPR_ARGS 4
+#define FPR_ARGS 4
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have no target-specific pragmas */
+#undef HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have to implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we have register-pairs */
+#define HAVE_REGPAIRS 1
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 12
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
diff --git a/machines/bc16/machine.c b/machines/bc16/machine.c
new file mode 100755
index 0000000..82ab96f
--- /dev/null
+++ b/machines/bc16/machine.c
@@ -0,0 +1,1179 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+    CPU.
+ 
+    Configurable at build-time are:
+    - number of (32bit) general-purpose-registers
+    - number of (64bit) floating-point-registers
+    - number of (8bit) condition-code-registers
+    - mechanism for stack-arguments (moving ot fixed sp)
+ 
+    It allows to select as run-time-options:
+    - two- or three-address code
+    - memory operands or load-store-architecture
+    - number of register-arguments
+    - number of caller-save-registers
+*/                                                                             
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc bc16 code-generator V0.1 (c) in 2021 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+		    VALFLAG,VALFLAG,VALFLAG,
+		    0,0,
+		    VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+			   "volatile-gprs","volatile-fprs","volatile-ccrs",
+			   "imm-ind","gpr-ind",
+			   "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS   ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS   ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND    ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND    ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS   ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__GENERIC__",
+		       0};
+
+/* special registers */
+static int sp;                     /*  Stackpointer                        */
+static int t1,t2,t3;               /*  temporary gprs */
+static int f1,f2,f3;               /*  temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+  *dataname="\t.data\n",
+  *bssname="",
+  *rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+   a moving stack-pointer */
+static long notpopped,dontpop,pushed,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | return-address [size=4]                      |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static void push(int i)
+{
+  pushed-=i;
+  if(pushed<maxpushed)
+    maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+  pushed+=i;
+  if(pushed>0) ierror(0);
+}
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize+4-off-zm2l(maxalign);
+  }
+
+#if FIXED_SP
+  off+=argsize;
+#else
+  off+=stackoffset;
+#endif
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if(!(o->flags&VAR)) ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    if(THREE_ADDR){
+      emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+    }else{
+      emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+      if(off)
+	emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+    }
+  }else{
+    emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+   general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NU;
+  if(o->flags&VARADR){
+    load_address(f,r,o,POINTER);
+  }else{
+    if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+      return;
+    emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NQ;
+  emit(f,"\tmov.%s\t",dt(type));
+  emit_obj(f,o,type);
+  emit(f,",%s\n",regnames[r]);
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+
+  if(isreg(z)&&(THREE_ADDR||!compare_objects(&p->q2,&p->z))){
+    zreg=p->z.reg;
+  }else{
+    if(ISFLOAT(ztyp(p)))
+      zreg=f1;
+    else
+      zreg=t1;
+  }
+  
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q1,q1typ(p));
+    p->q1.reg=t1;
+    p->q1.flags|=(REG|DREFOBJ);
+  }
+  if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+    if(p->code==ASSIGN&&isreg(z))
+      q1reg=p->z.reg;
+    else if(ISFLOAT(q1typ(p)))
+      q1reg=f1;
+    else
+      q1reg=t1;
+    load_reg(f,q1reg,&p->q1,q1typ(p));
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q2,q2typ(p));
+    p->q2.reg=t1;
+    p->q2.flags|=(REG|DREFOBJ);
+  }
+  if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+    if(ISFLOAT(q2typ(p)))
+      q2reg=f2;
+    else
+      q2reg=t2;
+    load_reg(f,q2reg,&p->q2,q2typ(p));
+    p->q2.reg=q2reg;
+    p->q2.flags=REG;
+  }
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->z,POINTER);
+    p->z.reg=t2;
+    p->z.flags|=(REG|DREFOBJ);
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+    if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=zm2l(of);
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=GPR_IND;
+              am->base=base;
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  rsavesize=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  emit(f,ret);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(4);
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  regnames[0]="noreg";
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+    regsize[i]=l2zm(4L);
+    regtype[i]=&ltyp;
+  }
+  for(i=FIRST_FPR;i<=LAST_FPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+    regsize[i]=l2zm(8L);
+    regtype[i]=&ldbl;
+  }
+  for(i=FIRST_CCR;i<=LAST_CCR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+    regsize[i]=l2zm(1L);
+    regtype[i]=&lchar;
+  }
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  sp=FIRST_GPR;
+  t1=FIRST_GPR+1;
+  t2=FIRST_GPR+2;
+  f1=FIRST_FPR;
+  f2=FIRST_FPR+1;
+  regsa[t1]=regsa[t2]=1;
+  regsa[f1]=regsa[f2]=1;
+  regsa[sp]=1;
+  regscratch[t1]=regscratch[t2]=0;
+  regscratch[f1]=regscratch[f2]=0;
+  regscratch[sp]=0;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+    regscratch[i]=1;
+
+  target_macros=marray;
+
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) 
+    return FIRST_FPR+2;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 
+    return 0;
+  if(zmleq(szof(t),l2zm(4L))) 
+    return FIRST_GPR+3;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    if(!LOAD_STORE)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  t&=NQ;
+  if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+    return 1;
+  if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+    return 1;
+  if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(v->clist||section==SPECIAL){
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||section==SPECIAL){
+	gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\tdc.%s\t",dt(t&NQ));
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *m;
+  argsize=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  maxpushed=0;
+
+  /*FIXME*/
+  ret="\trts\n";
+
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+    /* convert MULT/DIV/MOD with powers of two */
+    if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  p->typf2=INT;
+	}
+      }
+    }
+#if FIXED_SP
+    if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+  }
+  peephole(p);
+
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+
+  localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+  /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+  function_top(f,v,localsize);
+
+#if FIXED_SP
+  pushed=0;
+#endif
+
+  for(;p;p=p->next){
+    c=p->code;t=p->typf;
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(0/*t==exit_label&&framesize==0*/)
+	emit(f,ret);
+      else
+	emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      emit(f,"\tb%s\t",ccs[c-BEQ]);
+      if(isreg(q1)){
+	emit_obj(f,&p->q1,0);
+	emit(f,",");
+      }
+      emit(f,"%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      ierror(0);
+    }
+    /* switch commutative operands if suitable */
+    if(c==ADD||c==MULT||c==AND||c==XOR||c==OR){
+      if(compare_objects(&p->q2,&p->z)){
+	struct obj tmp;
+	tmp=p->q1;
+	p->q1=p->q2;
+	p->q2=tmp;
+      }
+    }
+
+    p=preload(f,p);
+    c=p->code;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+      if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+	if(q1typ(p)&UNSIGNED)
+	  emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+	else
+	  emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+      }
+      save_result(f,p);
+      continue;
+    }
+    if(c==KOMPLEMENT){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==SETRETURN){
+      load_reg(f,p->z.reg,&p->q1,t);
+      BSET(regs_modified,p->z.reg);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+	save_result(f,p);
+      }else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      int reg;
+      /*FIXME*/
+#if 0      
+      if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	  stack=framesize+zum2ul(p->q1.v->fi->stack1);
+      }else
+	stack_valid=0;
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+	emit(f,"\tcall\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      /*FIXME*/
+#if FIXED_SP
+      pushed-=zm2l(p->q2.val.vmax);
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+	int i;
+	for(i=1;i<=MAXR;i++){
+	  if(regscratch[i]) BSET(regs_modified,i);
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(c==PUSH){
+#if FIXED_SP
+	emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	pushed+=zm2l(p->q2.val.vmax);
+#else
+	emit(f,"\tpush.%s\t",dt(t));
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	push(zm2l(p->q2.val.vmax));
+#endif
+	continue;
+      }
+      if(c==ASSIGN){
+	load_reg(f,zreg,&p->q1,t);
+	save_result(f,p);
+      }
+      continue;
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      save_result(f,p);
+      continue;
+    }
+    if(c==MINUS){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==TEST){
+      emit(f,"\ttst.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if(c==COMPARE){
+      emit(f,"\tcmp.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,",");
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+      if(!THREE_ADDR)
+	load_reg(f,zreg,&p->q1,t);
+      if(c>=OR&&c<=AND)
+	emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+      else
+	emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+      if(THREE_ADDR){
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+      }
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      save_result(f,p);
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  function_bottom(f,v,localsize);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=stack;
+  }
+  emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+  f=t->flags&NQ;
+  if(f<=LONG||f==POINTER){
+    if(m->gregs>=GPR_ARGS)
+      return 0;
+    else
+      return FIRST_GPR+3+m->gregs++;
+  }
+  if(ISFLOAT(f)){
+    if(m->fregs>=FPR_ARGS)
+      return 0;
+    else
+      return FIRST_FPR+2+m->fregs++;
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
diff --git a/machines/bc16/machine.dt b/machines/bc16/machine.dt
new file mode 100755
index 0000000..cd2cdef
--- /dev/null
+++ b/machines/bc16/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S16BUBE S16BULE
+
+
diff --git a/machines/bc16/machine.h b/machines/bc16/machine.h
new file mode 100755
index 0000000..83579be
--- /dev/null
+++ b/machines/bc16/machine.h
@@ -0,0 +1,153 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+    CPU.
+
+    Configurable at build-time are:
+    - number of (32bit) general-purpose-registers
+    - number of (64bit) floating-point-registers
+    - number of (8bit) condition-code-registers
+    - mechanism for stack-arguments (moving ot fixed sp)
+
+    It allows to select as run-time-options:
+    - two- or three-address code
+    - memory operands or load-store-architecture
+    - number of register-arguments
+    - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 8
+#define NUM_FPRS 0
+#define NUM_CCRS 1
+#define FIXED_SP 0
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
+
+#define HAVE_WANTBNE 1
diff --git a/machines/bi386/machine.c b/machines/bi386/machine.c
new file mode 100755
index 0000000..37fe7a1
--- /dev/null
+++ b/machines/bi386/machine.c
@@ -0,0 +1,1446 @@
+/*  Code generator for Intel 80386 or higher.			*/
+
+#include "supp.h"
+
+/* Was gehoert hier hin? */
+#define N_SO 128
+#define N_LSYM 128
+#define N_FUN 36
+#define N_PSYM 128
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.				*/
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for i386/BE V0.1 (c) in 1997 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts		*/
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+		    0,0,0,0,
+                    0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+			   "merge-constants","elf","longalign","use-framepointer",
+                           "g"};
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.		*/
+zlong align[16];
+
+/*  Alignment that is sufficient for every object.		*/
+zlong maxalign;
+
+/*  CHAR_BIT of the target machine.				*/
+zlong char_bit;
+
+/*  Sizes of all elementary types in bytes.			*/
+zlong sizetab[16];
+
+/*  Minimum and Maximum values each type can have.		*/
+/*  Must be initialized in init_cg().                           */
+zlong t_min[32];
+zulong t_max[32];
+
+/*  Names of all registers.					*/
+char *regnames[MAXR+1]={"noreg","%eax","%ecx","%edx","%ebx",
+				"%esi","%edi","%ebp","%esp",
+				"%st(0)","%st(1)","%st(2)","%st(3)",
+				"%st(4)","%st(5)","%st(6)","%st(7)"};
+
+/*  The Size of each register in bytes. 			*/
+zlong regsize[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.				*/
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.	*/
+int regscratch[MAXR+1]={0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1};
+
+
+/****************************************/
+/*  Some private data and functions.	*/
+/****************************************/
+
+static long malign[16]={1,1,2,2,2,2,2,2,2,2,2,2,2,2,2};
+static long msizetab[16]={0,1,2,4,4,4,8,0,4,0,0,0,4,0};
+
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+
+static int section=-1,newobj;
+static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="";
+static int is_const(struct Typ *);
+static const int ax=1,cx=2,dx=3,bx=4,si=5,di=6,bp=7,sp=8;
+static char x_t[]={'?','b','w','l','l','s','l','v','l','a','s','u','e','f','?','?'};
+static int is_const(struct Typ *);
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+
+static long loff,stackoffset,notpopped,dontpop;
+
+static char *ccs[]={"z","nz","l","ge","le","g","mp"};
+static char *ccu[]={"z","nz","b","ae","be","a","mp"};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"sal","sar","add","sub","imul","div","mod"};
+static char *farithmetics[]={"f?","f?","fadd","fsub","fmul","fdiv","fsubr","fdivr"};
+static char *dct[]={"","byte","short","long","long","long","long","long","long"};
+static pushedsize,pushorder=2;
+static int fst[8];
+static int cxl,dil,sil;
+static char *idprefix="_",*labprefix="l";
+
+static struct fpconstlist {
+    struct fpconstlist *next;
+    int label,typ;
+    union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+    struct fpconstlist *p=firstfpc;
+    t&=NQ;
+    if(g_flags[4]&USEDFLAG){
+	for(p=firstfpc;p;p=p->next){
+	    if(t==p->typ){
+		eval_const(&p->val,t);
+		if(t==FLOAT&&zdeqto(vdouble,zf2zd(o->val.vfloat))) return(p->label);
+		if(t==DOUBLE&&zdeqto(vdouble,o->val.vdouble)) return(p->label);
+	    }
+	}
+    }
+    p=mymalloc(sizeof(struct fpconstlist));
+    p->next=firstfpc;
+    p->label=++label;
+    p->typ=t;
+    p->val=o->val;
+    firstfpc=p;
+    return(p->label);
+}
+
+void title(FILE *f)
+{
+  static int done;
+  extern char *inname; /*grmpf*/
+  if(!done&&f){
+    done=1;
+    emit(f,"\t.file\t\"%s\"\n",inname);
+  }
+} 
+
+static void probj2(FILE *f,struct obj *p,int t)
+/*  Gibt Objekt auf Bildschirm aus			*/
+{
+    if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) fprintf(f,"(");
+    if(p->flags&VARADR) fprintf(f,"$");
+    if((p->flags&VAR)&&!(p->flags&REG)) {
+	if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+	    if(p->v->offset<0) fprintf(f,"%ld(%%esp)",(long)(loff-zl2l(p->v->offset)+zl2l(p->val.vlong))-stackoffset+pushedsize);
+		else	       fprintf(f,"%ld(%%esp)",(long)(zl2l(p->v->offset)+zl2l(p->val.vlong)-stackoffset));
+	}else{
+	    if(!zleqto(l2zl(0L),p->val.vlong)){printval(f,&p->val,LONG,0);fprintf(f,"+");}
+	    if(p->v->storage_class==STATIC&&(p->v->vtyp->flags&NQ)!=FUNKT){
+		fprintf(f,"%s%ld",labprefix,zl2l(p->v->offset));
+	    }else{
+		fprintf(f,"%s%s",idprefix,p->v->identifier);
+	    }
+	}
+    }
+    if(p->flags&REG){
+	if(p->reg>8){
+	    int i;
+	    for(i=0;i<8;i++){
+		if(fst[i]==p->reg)
+		    fprintf(f,"%s",regnames[i+9]);
+	    }
+	}else{
+	    fprintf(f,"%s",regnames[p->reg]);
+	}
+    }
+    if(p->flags&KONST){
+	if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+	    fprintf(f,"%s%d",labprefix,addfpconst(p,t));
+	}else{
+	    fprintf(f,"$");printval(f,&p->val,t&NU,0);
+	}
+    }
+    if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) fprintf(f,")");
+}
+static void fxch(FILE *f,int i)
+{
+    int m;
+    fprintf(f,"\tfxch\t%s\n",regnames[i+9]);
+    m=fst[0];fst[0]=fst[i];fst[i]=m;
+}
+static int freest(void)
+{
+    int i;
+    for(i=0;i<8;i++){
+	if(fst[i]<0) return(i);
+    }
+    for(i=0;i<8;i++){
+	if(fst[i]==0) return(i);
+    }
+    ierror(0);
+}
+static void fpush(FILE *f)
+{
+    int i;
+    if(fst[7]>0){
+	i=freest();
+	if(fst[i]==0) fprintf(f,"\tffree\t%s\n",regnames[i+9]);
+	fxch(f,i);fxch(f,7);
+    }
+    for(i=7;i>0;i--)
+	fst[i]=fst[i-1];
+    fst[0]=-1;
+}
+static void fpop(void)
+{
+    int i;
+/*    if(fst[0]>0&&regs[fst[0]]) ierror(0);*/
+    for(i=0;i<7;i++)
+	fst[i]=fst[i+1];
+    fst[7]=-1;
+}
+static void fload(FILE *f,struct obj *o,int t)
+{
+    fprintf(f,"\tfld");
+    if((o->flags&(REG|DREFOBJ))==REG) fprintf(f,"\t");
+	else fprintf(f,"%c\t",x_t[t&NQ]);
+    probj2(f,o,t);fprintf(f,"\n");
+    fpush(f);
+}
+static void fstore(FILE *f,struct obj *o,int t)
+{
+    int i;
+    if((o->flags&(REG|DREFOBJ))==REG){
+	for(i=0;i<8;i++)
+	    if(fst[i]==o->reg) fst[i]=-1;
+	fst[0]=o->reg;
+    }else{
+	fprintf(f,"\tfstp%c\t",x_t[t&NQ]);probj2(f,o,t);
+	fpop();fprintf(f,"\n");
+    }
+}
+static void prfst(FILE *f,char *s)
+{
+    int i;
+    if(DEBUG==0) return;
+    fprintf(f,"*\t%s\t",s);
+    for(i=0;i<8;i++){
+	if(fst[i]>=0){
+	    if(fst[i]==0) fprintf(f,"+++ ");
+	      else	  fprintf(f,"%s ",regnames[fst[i]]+3);
+	}else{
+	    fprintf(f,"--- ");
+	}
+    }
+    fprintf(f,"\n");
+}
+static void finit(void)
+{
+    int i;
+    for(i=0;i<8;i++){
+	if(regs[i+9])
+	    fst[i]=i+9;
+	else
+	    fst[i]=-1;
+    }
+}
+static void forder(FILE *f)
+{
+    int i,m,unordered;
+    prfst(f,"forder");
+    for(i=0;i<8;i++){
+	if(fst[i]==0){fprintf(f,"\tffree\t%s\n",regnames[i+9]);fst[i]=-1;}
+    }
+oloop:
+    unordered=0;
+    for(i=0;i<8;i++){
+	if(fst[i]>0&&fst[i]!=i+9&&regs[fst[i]]){unordered=1;break;}
+    }
+    if(!unordered) return;
+    if(fst[0]>=0&&regs[fst[0]]){
+	if(fst[0]!=9){
+	    fxch(f,fst[0]-9);
+	    goto oloop;
+	}else{
+	    fxch(f,freest());
+	}
+    }
+    for(i=1;i<8;i++){
+	if(fst[i]>=0&&fst[i]!=i+9&&regs[fst[i]]&&fst[i]!=9){
+	    fxch(f,i);
+	    goto oloop;
+	}
+    }
+    if(regs[9]){
+	for(i=1;i<8;i++){
+	    if(fst[i]==9){ fxch(f,i);return;}
+	}
+    }
+}
+static void pr(FILE *f,struct IC *p)
+{
+    int i;
+    for(;pushorder>2;pushorder>>=1){
+	for(i=1;i<=8;i++){
+	    if(regs[i]&pushorder){
+		fprintf(f,"\tpopl\t%s\n",regnames[i]);
+		stackoffset+=4;regs[i]&=~pushorder;
+	    }
+	}
+    }
+    for(i=1;i<=8;i++)
+	if(regs[i]&2) regs[i]&=~2;
+}
+
+/*ADA*/
+static int local_debug_line_count;
+static int local_debug_func_count;
+static char * debug_offset_func = NULL;
+
+static void emitdebugline (FILE *f, int line)
+{
+  if(g_flags[8]&USEDFLAG){
+    if (debug_offset_func && line)
+      {
+	/*
+	  Tell GDB that a new line starts here.
+	  
+	  Format: 68,0,<line>,<offset>
+	  
+	  <line> is the current line number
+	  <offset> is the offset to the current function.
+	  */
+	fprintf (f, ".stabn 68,0,%d,%sM%d-%s\n", line, labprefix, local_debug_line_count, debug_offset_func);
+	fprintf (f, "%sM%d:\n", labprefix, local_debug_line_count);
+	local_debug_line_count ++;
+    }
+  }
+}
+
+#ifndef PATH_MAX
+#   define PATH_MAX  1024
+#endif
+
+static int next_free_typeid = 32;
+
+static void begin_file (FILE *f, char *name)
+{
+    char * ptr;
+    char path[PATH_MAX];
+    int len1, len2, t;
+
+    ptr = strrchr (name, '/');
+    if (!ptr)
+	ptr = name-1;
+
+    /* Filename without path */
+    fprintf (f, "\t.file\t\"%s\"\n", ptr+1);
+    fprintf (f, "\t.version\t\"01.01\"\n");
+
+    getcwd (path, sizeof(path));
+    strcat (path, "/");
+    if (ptr != name-1)
+    {
+	len1 = strlen(path);
+	len2 = ptr-name;
+	strncpy (path+len1, name, len2);
+	path[len1+len2] = 0;
+	strcat (path, "/");
+    }
+
+    /* Emit absolute path to source file and the filename with any
+	path the user gave to the frontend */
+    fprintf (f, "\t.stabs \"%s\",%d,0,0,%stext0\n", path, N_SO, labprefix);
+    fprintf (f, "\t.stabs \"%s\",%d,0,0,%stext0\n", name, N_SO, labprefix);
+    fprintf (f, ".text\n%stext0:\n",labprefix);
+    fprintf (f, "\t.stabs  \"vbcc_compiled.\", 0x3c, 0, 0, 0\n");
+
+    /* Emit types. Format is:
+
+	"<name>:<t#1>=<r#2;min;max;>",128,0,0,0
+
+	128,0,0,0 tells GDB this is a type definition
+	<name> is the name of the symbol.
+	<t#1> is the name of the type and its number
+        <r#2;min;max;> is a range. The min and max values are in the format
+               of the type #2. min and max values for this type can be
+               omitted.
+        void is defined by <t#1=#1>.
+      */
+    for (t=CHAR; t<=LONG; t++)
+      {
+	fprintf (f, ".stabs \"%s:t%d=r%d;%ld;%ld;\",%d,0,0,0\n", typname[t],t,t==CHAR ? CHAR:INT,
+		 zl2l(t_min[t]),zl2l(t_max[t]),N_LSYM);
+	fprintf (f, ".stabs \"unsigned %s:t%d=r%d;%lu;%lu;\",%d,0,0,0\n", typname[t],
+		 t|UNSIGNED, INT,
+		 zul2ul(t_min[t|UNSIGNED]),zul2ul(t_max[t|UNSIGNED]), N_LSYM);
+      }
+ 
+    fprintf (f, ".stabs \"float:t%d=r%d;%ld;0;\",%d,0,0,0\n",
+	     FLOAT,INT,zl2l(sizetab[FLOAT]),N_LSYM);
+    fprintf (f, ".stabs \"double:t%d=r%d;%ld;0;\",%d,0,0,0\n",
+	     DOUBLE,INT,zl2l(sizetab[DOUBLE]),N_LSYM);
+    fprintf (f, ".stabs \"void:t%d=r%d\",%d,0,0,0\n",
+	     VOID,VOID,N_LSYM);
+	     
+ 
+    /*
+      fprintf (f, ".stabs \"char:t2=r2;0;127;\",128,0,0,0\n");
+      fprintf (f, ".stabs \"int:t1=r1;-2147483648;2147483647;\",128,0,0,0\n");
+      fprintf (f, ".stabs \"long int:t3=r1;-2147483648;2147483647;\",128,0,0,0\n");
+      fprintf (f, ".stabs \"unsigned int:t4=r1;0;-1;\",128,0,0,0\n");
+      fprintf (f, ".stabs \"long unsigned int:t5=r1;0;-1;\",128,0,0,0\n");
+      fprintf (f, ".stabs \"void:t19=19\",128,0,0,0\n");
+      */
+}
+
+static void debug_print_stab_type (FILE *f, struct Typ *typ)
+{
+  int t = typ->flags & NU;
+  
+  if (t <= VOID)
+    fprintf (f, "%d", t);
+  else if (t == ARRAY || t == POINTER)
+    {
+      fprintf (f, "%d=*", next_free_typeid++);
+      debug_print_stab_type (f, typ->next);
+    }
+  else
+    {
+      ierror(t);
+    }
+}
+
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionskopf			*/
+{
+    int i;
+    struct struct_declaration *p;
+
+    if(section!=CODE){fprintf(f,codename);section=CODE;}
+
+    /*ADA*/
+    if(g_flags[8]&USEDFLAG){ /*vb*/
+      fprintf (f, "\t.align\t16\n");
+      /* Tell GDB that a new function starts here.
+	 
+	 Format: "<name>:F<type>",36,0,<line>,<symname>
+	 
+	 <name> Is the name of the function
+	 <type> is the return type (only the number as defined above, ie.
+	        if int is t1, then this is 1).
+	 <line> The line in the source
+	 <symname> The name of the symbol as it appears in the object file.
+
+	 Right now, all functions return void.
+	 */
+
+      fprintf (f, ".stabs \"%s:F", v->identifier);
+      debug_print_stab_type (f, v->vtyp->next);
+      fprintf (f, "\",%d,0,%d,%s%s\n", N_FUN, fline, idprefix,v->identifier);
+  
+      p=v->vtyp->exact;
+      for (i=0; i<p->count; i++)
+	{
+	  if((*p->sl)[i].styp->flags==VOID) break;
+	  fprintf (f, ".stabs \"%s:p", (*p->sl)[i].identifier);
+	  debug_print_stab_type (f, (*p->sl)[i].styp);
+	  /* TODO i*4+4 is a crude method to find the offset of a parameter on
+	     the stack */
+	  fprintf (f, "\",%d,0,0,%d\n", N_PSYM, i*4+4);
+	}
+    }
+
+    if(v->storage_class==EXTERN) fprintf(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    fprintf(f,"%s%s:\n",idprefix,v->identifier);
+
+    /*ADA*/
+    debug_offset_func=v->identifier;
+
+    for(pushedsize=0,i=1;i<sp;i++){
+	if(regused[i]&&!regscratch[i]){
+	    fprintf(f,"\tpushl\t%s\n",regnames[i]);
+	    pushedsize+=4;
+	}
+    }
+
+    if(offset) fprintf(f,"\tsubl\t$%ld,%%esp\n",offset);
+    if(g_flags[7]&USEDFLAG) fprintf(f,"\tmovl\t%s,%s\n",regnames[sp],regnames[7]);
+    if(g_flags[8]&USEDFLAG){
+      /* Tell GDB that the code of the function starts here */
+      emitdebugline (f,fline);
+      local_debug_func_count ++;
+      fprintf (f, "%sBB%d:\n", labprefix, local_debug_func_count);
+    }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionsende			*/
+{
+    int i;
+    forder(f);
+
+    if(g_flags[8]&USEDFLAG){
+      emitdebugline (f,fline);
+      fprintf (f, "%sBE%d:\n", labprefix, local_debug_func_count);
+    }
+
+    if(offset) fprintf(f,"\taddl\t$%ld,%%esp\n",offset);
+    for(i=sp-1;i>0;i--){
+	if(regused[i]&&!regscratch[i]){
+	    fprintf(f,"\tpopl\t%s\n",regnames[i]);
+	}
+    }
+    fprintf(f,"\tret\n");
+    
+    if(g_flags[8]&USEDFLAG){
+      fprintf (f, "%sfe%d:\n\t.size\t%s,%sfe%d-%s%s\n", labprefix, local_debug_func_count, v->identifier, labprefix, local_debug_func_count, idprefix,v->identifier);
+      /* Tell GDB the real size of the function */
+      fprintf (f, ".stabn 192,0,0,%sBB%d-%s%s\n",labprefix,local_debug_func_count, idprefix,v->identifier);
+      fprintf (f, ".stabn 224,0,0,%sBE%d-%s%s\n", labprefix, local_debug_func_count, idprefix,v->identifier);
+    }
+}
+static int is_const(struct Typ *t)
+/*  Tests if a type can be placed in the code-section.	*/
+{
+    if(!(t->flags&(CONST|STRINGCONST))){
+	do{
+	    if(t->flags&(CONST|STRINGCONST)) return(1);
+	    if((t->flags&NQ)!=ARRAY) return(0);
+	    t=t->next;
+	}while(1);
+    }else return(1);
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+    if(o1->flags==o2->flags&&o1->am==o2->am){
+	if(!(o1->flags&VAR)||(o1->v==o2->v&&zleqto(o1->val.vlong,o2->val.vlong))){
+	    if(!(o1->flags&REG)||o1->reg==o2->reg){
+		return(1);
+	    }
+	}
+    }
+    return(0);
+}
+static int get_reg(FILE *f,struct IC *p)
+{
+    int i;
+    /*	If we can use a register which was already used by the compiler */
+    /*	or it is a sratch register then we can use it without problems. */
+    for(i=1;i<=8;i++){
+	if(!regs[i]&&(regused[i]||regscratch[i])){
+	    regs[i]=2;
+	    return(i);
+	}
+    }
+    /*	Otherwise we have to save this register.			*/
+    /*	We may not use a register which is used in this IC.		*/
+    for(i=1;i<=8;i++){
+	if(regs[i]<2
+	    &&(!(p->q1.flags&REG)||p->q1.reg!=i)
+	    &&(!(p->q2.flags&REG)||p->q2.reg!=i)
+	    &&(!(p->z.flags&REG)||p->z.reg!=i) ){
+
+	    fprintf(f,"\tpushl\t%s\n",regnames[i]);
+	    /*	Mark register as pushed (taking care of the order). */
+	    pushorder<<=1; regs[i]|=pushorder;
+	    stackoffset-=4;
+	    return(i);
+	}
+    }
+    ierror(0);
+}
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/*  Generates code to move object q (or register qr) into object z (or  */
+/*  register zr).							*/
+{
+    if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+    if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+    if(qr&&zr){
+	if(qr!=zr)
+	    fprintf(f,"\tmovl\t%s,%s\n",regnames[qr],regnames[zr]);
+	return;
+    }
+    if(zr&&(q->flags&KONST)){
+	eval_const(&q->val,t);
+	if(zleqto(vlong,l2zl(0L))&&zuleqto(vulong,ul2zul(0UL))&&zdeqto(vdouble,d2zd(0.0))){
+	    fprintf(f,"\txorl\t%s,%s\n",regnames[zr],regnames[zr]);
+	    return;
+	}
+    }
+    fprintf(f,"\tmov%c\t",x_t[t&NQ]);
+    if(qr) fprintf(f,"%s",regnames[qr]); else probj2(f,q,t);
+    fprintf(f,",");
+    if(zr) fprintf(f,"%s",regnames[zr]); else probj2(f,z,t);
+    fprintf(f,"\n");
+}
+static long pof2(zulong x)
+/*  Yields log2(x)+1 oder 0. */
+{
+    zulong p;int ln=1;
+    p=ul2zul(1L);
+    while(zulleq(p,x)){
+	if(zuleqto(x,p)) return(ln);
+	ln++;p=zuladd(p,p);
+    }
+    return(0);
+}
+
+/****************************************/
+/*  End of private fata and functions.	*/
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called	*/
+/*  once at the beginning and should return 0 in case of problems.	*/
+{
+    int i;
+
+    /*	Initialize some values which cannot be statically initialized	*/
+    /*	because they are stored in the target's arithmetic.             */
+    maxalign=l2zl(4L);
+    char_bit=l2zl(8L);
+    if(g_flags[6]&USEDFLAG){
+	for(i=SHORT;i<16;i++) malign[i]=4;
+    }
+    for(i=0;i<16;i++){
+	sizetab[i]=l2zl(msizetab[i]);
+	align[i]=l2zl(malign[i]);
+    }
+    for(i=1;i<= 8;i++) regsize[i]=l2zl(4L);
+    for(i=9;i<=16;i++) regsize[i]=l2zl(8L);
+
+    /*	Initialize the min/max-settings. Note that the types of the	*/
+    /*	host system may be different from the target system and you may */
+    /*	only use the smallest maximum values ANSI guarantees if you	*/
+    /*	want to be portable.						*/
+    /*	That's the reason for the subtraction in t_min[INT]. Long could */
+    /*	be unable to represent -2147483648 on the host system.		*/
+    t_min[UNSIGNED|CHAR]=t_min[UNSIGNED|SHORT]=t_min[UNSIGNED|INT]=t_min[UNSIGNED|LONG]=l2zl(0L);
+    t_min[CHAR]=l2zl(-128L);
+    t_min[SHORT]=l2zl(-32768L);
+    t_min[LONG]=zlsub(l2zl(-2147483647L),l2zl(1L));
+    t_min[INT]=t_min[LONG];
+    t_max[CHAR]=ul2zul(127L);
+    t_max[SHORT]=ul2zul(32767UL);
+    t_max[LONG]=ul2zul(2147483647UL);
+    t_max[INT]=t_max[LONG];
+    t_max[UNSIGNED|CHAR]=ul2zul(255UL);
+    t_max[UNSIGNED|SHORT]=ul2zul(65535UL);
+    t_max[UNSIGNED|LONG]=ul2zul(4294967295UL);
+    t_max[UNSIGNED|INT]=t_max[UNSIGNED|LONG];
+    /*	Reserve a few registers for use by the code-generator.	    */
+    /*	We only reserve the stack-pointer here. 		    */
+    regsa[sp]=1;
+    /*  If we are to use a framepointer also reserve %ebp.          */
+    if(g_flags[7]&USEDFLAG) regsa[7]=1;
+    /*	We need at least one free slot in the flaoting point stack  */
+    regsa[16]=1;regscratch[16]=0;
+    /*	Use l%d as labels and _%s as identifiers by default. If     */
+    /*	-elf is specified we use .l%d and %s instead.		    */
+    if(g_flags[5]&USEDFLAG) {labprefix=".L";idprefix="";}
+    return(1);
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.	    */
+{
+    if((t->flags&NQ)==FLOAT||(t->flags&NQ)==DOUBLE) return 9;
+    if((t->flags&NQ)<=POINTER) return 1;
+    return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of	*/
+/*  type t. If t==POINTER and mode!=0 then it returns	*/
+/*  non-zero only if the register can store a pointer	*/
+/*  and dereference a pointer to mode.			*/
+{
+    if(r==0) return(0);
+    t&=NQ;
+    if(r>8){
+	if(t==FLOAT||t==DOUBLE) return(1);
+	    else		return(0);
+    }
+    if(t==CHAR&&(r==si||r==di||r==bp)) return(0);
+    if(t<=LONG) return(1);
+    if(t==POINTER) return(1);
+    return(0);
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed	*/
+/*  without danger of exceptions or similar things.	*/
+/*  vbcc may generate code in which non-dangerous ICs	*/
+/*  are sometimes executed although control-flow may	*/
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).					*/
+/*  Typical ICs that generate exceptions on some	*/
+/*  machines are:					*/
+/*	- accesses via pointers 			*/
+/*	- division/modulo				*/
+/*	- overflow on signed integer/floats		*/
+{
+    int c=p->code;
+    if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+	return(0);
+    if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
+	return(1);
+    return(0);
+}
+
+int must_convert(np p,int t)
+/*  Returns zero if code for converting np to type t	*/
+/*  can be omitted.					*/
+/*  In this generic 32bit RISC cpu pointers and 32bit	*/
+/*  integers have the same representation and can use	*/
+/*  the same registers. 				*/
+{
+    int o=p->ntyp->flags,op=o&NQ,tp=t&NQ;
+    if(tp==POINTER&&op==POINTER) return(0);
+    if((t&UNSIGNED)&&(o&UNSIGNED)&&zleqto(sizetab[tp],sizetab[op])) return(0);
+    if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return(0);
+
+    return(1);
+}
+
+void gen_ds(FILE *f,zlong size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.				*/
+{
+  title(f);
+  if(newobj) fprintf(f,"%ld\n",zl2l(size));
+  else fprintf(f,"\t.space\t%ld\n",zl2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zlong align)
+/*  This function has to make sure the next data is	*/
+/*  aligned to multiples of <align> bytes.		*/
+{
+  title(f);
+  if(!zlleq(align,l2zl(1L))) fprintf(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable	*/
+/*  definition, i.e. the label and information for	*/
+/*  linkage etc.					*/
+{
+  int constflag;
+  title(f);
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+	if((v->vtyp->flags&NQ)==FUNKT) return;
+	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){fprintf(f,dataname);section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=CODE){fprintf(f,codename);section=CODE;}
+	if(!v->clist&&section!=BSS){fprintf(f,bssname);section=BSS;}
+	if(section!=BSS) fprintf(f,"\t.align\t2\n%s%ld:\n",labprefix,zl2l(v->offset));
+	    else fprintf(f,"\t.lcomm\t%s%ld,",labprefix,zl2l(v->offset));
+	newobj=1;
+    }
+    if(v->storage_class==EXTERN){
+	fprintf(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+	if(v->flags&(DEFINED|TENTATIVE)){
+	    if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){fprintf(f,dataname);section=DATA;}
+	    if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=CODE){fprintf(f,codename);section=CODE;}
+	    if(!v->clist&&section!=BSS){fprintf(f,bssname);section=BSS;}
+	    if(section!=BSS) fprintf(f,"\t.align\t2\n%s%s:\n",idprefix,v->identifier);
+		else fprintf(f,"\t.comm\t%s%s,",idprefix,v->identifier);
+	    newobj=1;
+	}
+    }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage		*/
+/*  initialized with const-list p.			*/
+{
+    title(f);
+    fprintf(f,"\t.%s\t",dct[t&NQ]);
+    if(!p->tree){
+	if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+	/*  auch wieder nicht sehr schoen und IEEE noetig   */
+	    unsigned char *ip;
+	    ip=(unsigned char *)&p->val.vdouble;
+	    fprintf(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+	    if((t&NQ)==DOUBLE){
+		fprintf(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+	    }
+	}else{
+	    printval(f,&p->val,t&NU,0);
+	}
+    }else{
+	int m=p->tree->o.flags;
+	p->tree->o.flags&=~VARADR;
+	probj2(f,&p->tree->o,t&NU);
+	p->tree->o.flags=m;
+    }
+    fprintf(f,"\n");newobj=0;
+}
+
+/*  The main code-generation routine.			*/
+/*  f is the stream the code should be written to.	*/
+/*  p is a pointer to a doubly linked list of ICs	*/
+/*  containing the function body to generate code for.	*/
+/*  v is a pointer to the function.			*/
+/*  offset is the size of the stackframe the function	*/
+/*  needs for local variables.				*/
+void gen_code(FILE *f,struct IC *p,struct Var *v,zlong offset)
+{
+    int c,t,lastcomp=0,reg;
+    int lastline=-1;
+
+    if(DEBUG&1) printf("gen_code()\n");
+    for(c=1;c<=15;c++) regs[c]=regsa[c];
+    regs[16]=0;
+    loff=((zl2l(offset)+1)/2)*2;
+    title(f);
+    function_top(f,v,loff);
+    stackoffset=notpopped=dontpop=0;
+    finit();
+    for(;p;pr(f,p),p=p->next){
+	c=p->code;t=p->typf;
+	if(c==NOP) continue;
+
+/*ADA*/
+if (lastline != p->line)
+{
+    emitdebugline(f,p->line);
+    lastline = p->line;
+}
+
+	if(c==SUBPFP) c=SUB;
+	if(c==SUBIFP) c=SUB;
+	if(c==ADDI2P) c=ADD;
+	if(c==ALLOCREG){
+	    regs[p->q1.reg]=1;
+	    continue;
+	}
+	if(c==FREEREG){
+	    if(p->q1.reg>=9){
+		for(c=0;c<8;c++)
+		    if(fst[c]==p->q1.reg) fst[c]=0;
+	    }
+	    regs[p->q1.reg]=0;
+	    continue;
+	}
+	if(notpopped&&!dontpop){
+	    int flag=0;
+	    if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+		fprintf(f,"\taddl\t$%ld,%%esp\n",notpopped);
+		stackoffset+=notpopped;notpopped=0;
+	    }
+	}
+	if(c==LABEL) {forder(f);fprintf(f,"%s%d:\n",labprefix,t);continue;}
+	if(c>=BEQ&&c<=BRA){
+	    forder(f);
+	    if(lastcomp&UNSIGNED) fprintf(f,"\tj%s\t%s%d\n",ccu[c-BEQ],labprefix,t);
+		else		  fprintf(f,"\tj%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+	    continue;
+	}
+	if(c==MOVETOREG){
+	    if(p->z.reg>8){
+		for(c=0;c<8;c++){
+		    if(fst[c]==p->z.reg) fst[c]=0;
+		}
+		fload(f,&p->q1,DOUBLE);
+		fst[0]=p->z.reg;
+		continue;
+	    }
+	    move(f,&p->q1,0,0,p->z.reg,LONG);
+	    continue;
+	}
+	if(c==MOVEFROMREG){
+	    if(p->q1.reg>8){
+		if(fst[0]!=p->q1.reg){
+		    for(c=0,reg=-1;c<8;c++){
+			if(fst[c]==p->q1.reg) reg=c;
+		    }
+		    if(reg<0) ierror(0);
+		    fxch(f,reg);
+		}
+		fprintf(f,"\tfstpl\t");probj2(f,&p->z,DOUBLE);
+		fprintf(f,"\n");fpop();
+		continue;
+	    }
+	    move(f,0,p->q1.reg,&p->z,0,LONG);
+	    continue;
+	}
+	if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ){
+	    reg=get_reg(f,p);
+	    move(f,&p->q1,0,0,reg,LONG);
+	    p->q1.flags|=REG;p->q1.reg=reg;
+	}
+	if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ){
+	    reg=get_reg(f,p);
+	    move(f,&p->q2,0,0,reg,LONG);
+	    p->q2.flags|=REG;p->q2.reg=reg;
+	}
+	if((p->z.flags&(DREFOBJ|REG))==DREFOBJ){
+	    reg=get_reg(f,p);
+	    move(f,&p->z,0,0,reg,LONG);
+	    p->z.flags|=REG;p->z.reg=reg;
+	}
+	if(c>=CONVCHAR&&c<=CONVULONG){
+	    int to;
+	    if(c==CONVCHAR) to=CHAR;
+	    if(c==CONVUCHAR) to=(UNSIGNED|CHAR);
+	    if(c==CONVSHORT) to=SHORT;
+	    if(c==CONVUSHORT) to=(UNSIGNED|SHORT);
+	    if(c==CONVINT) to=INT;
+	    if(c==CONVUINT) to=(UNSIGNED|INT);
+	    if(c==CONVLONG) to=INT;
+	    if(c==CONVULONG) to=(UNSIGNED|INT);
+	    if(c==CONVFLOAT) to=FLOAT;
+	    if(c==CONVDOUBLE) to=DOUBLE;
+	    if(c==CONVPOINTER) to=(UNSIGNED|INT);
+	    if((t&NU)==LONG) t=INT;
+	    if((t&NU)==(UNSIGNED|LONG)||(t&NU)==POINTER) t=(UNSIGNED|INT);
+	    if((to&NQ)<=INT&&(t&NQ)<=INT){
+		if(isreg(z)) reg=p->z.reg;
+		else if(isreg(q1)) reg=p->q1.reg;
+		else reg=get_reg(f,p);
+		if((to&NQ)<=SHORT){
+		    fprintf(f,"\tmov%c%cl\t",(to&UNSIGNED)?'z':'s',x_t[to&NQ]);
+		    if(isreg(q1)){
+			if((to&NQ)==SHORT){
+			    fprintf(f,"%%%s",regnames[p->q1.reg]+2);
+			}else{
+			    fprintf(f,"%%%cl",regnames[p->q1.reg][2]);
+			}
+		    }else probj2(f,&p->q1,to);
+		    fprintf(f,",%s\n",regnames[reg]);
+		}else{
+		    move(f,&p->q1,0,0,reg,to);
+		}
+		move(f,0,reg,&p->z,0,t);
+		continue;
+	    }
+	    if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+		if((to&NQ)==FLOAT||(to&NQ)==DOUBLE){
+		    if(isreg(q1)&&fst[0]==p->q1.reg){
+			if(isreg(z)){
+			    if(p->z.reg==fst[0]) continue;
+			    for(reg=0,c=7;c>=0;c--){
+				if(fst[c]==p->z.reg){reg=c;break;}
+				if(fst[c]<0) reg=c;
+			    }
+			    fst[reg]=p->z.reg;
+			}
+			fprintf(f,"\tfst%c\t",x_t[t&NQ]);
+			probj2(f,&p->z,t);fprintf(f,"\n");
+			continue;
+		    }
+		    fload(f,&p->q1,to);
+		    fstore(f,&p->z,t);
+		    continue;
+		}
+		if((to&NQ)<=SHORT){
+		    if(isreg(q1)){
+			reg=p->q1.reg;
+			if(to&UNSIGNED){
+			    fprintf(f,"\tandl\t$%ld,%s\n",(to&NQ)==CHAR?255L:65535L,regnames[reg]);
+			}else{
+/*			      fprintf(f,"\tc%ctl\t%s\n",x_t[to&NQ],regnames[reg]);*/
+			    if((to&NQ)==SHORT){
+				fprintf(f,"\tmovswl\t%%%s,%s\n",regnames[reg]+2,regnames[reg]);
+			    }else{
+				fprintf(f,"\tmovsbl\t%%%cl,%s\n",regnames[reg][2],regnames[reg]);
+			    }
+			}
+		    }else{
+			reg=get_reg(f,p);
+			if(to&UNSIGNED){
+			    fprintf(f,"\tmovz%cl\t",x_t[to&NQ]);
+			}else{
+			    fprintf(f,"\tmovs%cl\t",x_t[to&NQ]);
+			}
+			probj2(f,&p->q1,to);fprintf(f,",%s\n",regnames[reg]);
+		    }
+		    fprintf(f,"\tpushl\t%s\n",regnames[reg]);
+		    fprintf(f,"\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[sp],regnames[sp]);
+		}else{
+		    if(to&UNSIGNED){
+			fprintf(f,"\tpushl\t$0\n\tpushl\t");stackoffset-=4;
+			probj2(f,&p->q1,to);
+			fprintf(f,"\n\tfildq\t(%s)\n\taddl\t$8,%s\n",regnames[sp],regnames[sp]);
+			stackoffset+=4;
+		    }else{
+			if(isreg(q1)){
+			    fprintf(f,"\tpushl\t%s\n\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[p->q1.reg],regnames[sp],regnames[sp]);
+			}else{
+			    fprintf(f,"\tfildl\t");probj2(f,&p->q1,t);
+			    fprintf(f,"\n");
+			}
+		    }
+		}
+		fpush(f);
+		fstore(f,&p->z,t);
+		continue;
+	    }
+	    if((to&NQ)==FLOAT||(to&NQ)==DOUBLE){
+		if(isreg(q1)&&fst[0]==p->q1.reg){
+		    if((t&NQ)==CHAR){
+			if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+			fprintf(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+			move(f,0,reg,&p->z,0,t);
+		    }else{
+		      if(isreg(z)){
+			fprintf(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+			stackoffset-=4;
+			probj2(f,&p->z,t);fprintf(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+			stackoffset+=4;
+		      }else{
+			fprintf(f,"\tfist%c\t",x_t[t&NQ]);
+			probj2(f,&p->z,t);fprintf(f,"\n");
+		      }
+		    }
+		}else{
+		    fload(f,&p->q1,to);
+		    if((t&NQ)==CHAR){
+			if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+			fprintf(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+			fpop(); move(f,0,reg,&p->z,0,t);
+		    }else{
+		      if(isreg(z)){
+			fprintf(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+			stackoffset-=4;
+			probj2(f,&p->z,t);fprintf(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+			stackoffset+=4;fpop();
+		      }else{
+			fprintf(f,"\tfistp%c\t",x_t[t&NQ]);
+			probj2(f,&p->z,t);fprintf(f,"\n");fpop();
+		      }
+		    }
+		}
+		continue;
+	    }
+	    ierror(0);
+	}
+	if(c==MINUS||c==KOMPLEMENT){
+	    char *s;
+	    if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+		if(isreg(z)&&p->z.reg==9&&isreg(q1)&&p->q1.reg==9){
+		    fprintf(f,"\tfchs\n");
+		    continue;
+		}
+		fload(f,&p->q1,t);
+		fprintf(f,"\tfchs\n");
+		fprintf(f,"\tfstp%c\t",x_t[t&NQ]);
+		probj2(f,&p->z,t);fprintf(f,"\n");
+		fpop();
+		continue;
+	    }
+	    if(c==MINUS) s="neg"; else s="not";
+	    if(compare_objects(&p->q1,&p->q2)){
+		fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+		probj2(f,&p->z,t);fprintf(f,"\n");
+		continue;
+	    }
+	    if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+	    move(f,&p->q1,0,0,reg,t);
+	    fprintf(f,"\t%s%c\t%s\n",s,x_t[t&NQ],regnames[reg]);
+	    move(f,0,reg,&p->z,0,t);
+	    continue;
+	}
+	if(c==SETRETURN){
+	    if(p->z.reg){
+		if(p->z.reg==9){
+		    if(!isreg(q1)||fst[0]!=p->q1.reg)
+			fload(f,&p->q1,t);
+		}else{
+		    move(f,&p->q1,0,0,p->z.reg,t);
+		}
+	    }
+	    continue;
+	}
+	if(c==GETRETURN){
+	    if(p->q1.reg){
+		if(p->q1.reg==9){
+		    if(!isreg(z)||fst[0]!=p->z.reg)
+			fstore(f,&p->z,t);
+		}else{
+		    move(f,0,p->q1.reg,&p->z,0,t);
+		}
+	    }
+	    continue;
+	}
+	if(c==CALL){
+	    int reg;
+	    if(p->q1.flags&DREFOBJ){
+		if(!(p->q1.flags&REG)) ierror(0);
+		fprintf(f,"\tcall\t*%s\n",regnames[p->q1.reg]);
+	    }else{
+		fprintf(f,"\tcall\t");probj2(f,&p->q1,t);
+		fprintf(f,"\n");
+	    }
+	    if(!zleqto(l2zl(0L),p->q2.val.vlong)){
+		notpopped+=zl2l(p->q2.val.vlong);
+		dontpop-=zl2l(p->q2.val.vlong);
+		if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+		/*  Entfernen der Parameter verzoegern	*/
+		}else{
+		    fprintf(f,"\taddl\t$%ld,%%esp\n",zl2l(p->q2.val.vlong));
+		    stackoffset+=zl2l(p->q2.val.vlong);
+		    notpopped-=zl2l(p->q2.val.vlong);
+		}
+	    }
+	    continue;
+	}
+	if(c==ASSIGN||c==PUSH){
+	    if(c==PUSH) dontpop+=zl2l(p->q2.val.vlong);
+	    if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+		if(c==ASSIGN){
+		    prfst(f,"fassign");
+		    fload(f,&p->q1,t);
+		    fstore(f,&p->z,t);
+		    continue;
+		}else if(isreg(q1)){
+		    prfst(f,"fpush");
+		    fprintf(f,"\tsubl\t$%ld,%s\n",zl2l(sizetab[t&NQ]),regnames[sp]);
+		    stackoffset-=zl2l(sizetab[t&NQ]);
+		    if(fst[0]==p->q1.reg){
+			fprintf(f,"\tfst%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+		    }else{
+			fload(f,&p->q1,t);
+			fprintf(f,"\tfstp%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+			fpop();
+		    }
+		    continue;
+		}
+	    }
+	    if((t&NQ)>POINTER||!zleqto(p->q2.val.vlong,sizetab[t&NQ])||!zlleq(p->q2.val.vlong,l2zl(4L))){
+		int mdi=di,msi=si,m=0;long l;
+		l=zl2l(p->q2.val.vlong);
+		if(regs[cx]){m|=1;if(!cxl)cxl=++label;fprintf(f,"\tmovl\t%s,%s%d\n",regnames[cx],labprefix,cxl);}
+		if(regs[msi]||!regused[msi]){m|=2;if(!sil)sil=++label;fprintf(f,"\tmovl\t%s,%s%d\n",regnames[msi],labprefix,sil);}
+		if(regs[mdi]||!regused[mdi]){m|=4;if(!dil)dil=++label;fprintf(f,"\tmovl\t%s,%s%d\n",regnames[mdi],labprefix,dil);}
+		if((p->z.flags&REG)&&p->z.reg==msi&&(p->q1.flags&REG)&&p->q1.reg==mdi){
+		    msi=di;mdi=si;
+		    m|=8;
+		}
+		if(!(p->z.flags&REG)||p->z.reg!=msi){
+		    fprintf(f,"\tleal\t");probj2(f,&p->q1,t);
+		    fprintf(f,",%s\n",regnames[msi]);
+		}
+		if(c==PUSH){
+		    fprintf(f,"\tsubl\t$%ld,%s\n\tmovl\t%s,%s\n",l,regnames[sp],regnames[sp],regnames[mdi]);
+		    stackoffset-=l;
+		}else{
+		    fprintf(f,"\tleal\t");probj2(f,&p->z,t);
+		    fprintf(f,",%s\n",regnames[mdi]);
+		}
+		if((p->z.flags&REG)&&p->z.reg==msi){
+		    fprintf(f,"\tleal\t");probj2(f,&p->q1,t);
+		    fprintf(f,",%s\n",regnames[msi]);
+		}
+		if(m&8){
+		    msi=si;mdi=di;
+		    fprintf(f,"\txch\t%s,%s\n",regnames[msi],regnames[mdi]);
+		}
+		if((t&NQ)==ARRAY||(t&NQ)==CHAR||l<4){
+		    fprintf(f,"\tmovl\t$%ld,%s\n\trep\n\tmovsb\n",l,regnames[cx]);
+		}else{
+		    if(l>=8)
+			fprintf(f,"\tmovl\t$%ld,%s\n\trep\n",l/4,regnames[cx]);
+		    fprintf(f,"\tmovsl\n");
+		    if(l%2) fprintf(f,"\tmovsw\n");
+		    if(l%1) fprintf(f,"\tmovsb\n");
+		}
+		if(m&4) fprintf(f,"\tmovl\t%s%d,%s\n",labprefix,dil,regnames[mdi]);
+		if(m&2) fprintf(f,"\tmovl\t%s%d,%s\n",labprefix,sil,regnames[msi]);
+		if(m&1) fprintf(f,"\tmovl\t%s%d,%s\n",labprefix,cxl,regnames[cx]);
+		continue;
+	    }
+	    if(t==FLOAT) t=LONG;
+	    if(c==PUSH){
+		fprintf(f,"\tpush%c\t",x_t[t&NQ]);
+		probj2(f,&p->q1,t);fprintf(f,"\n");
+		stackoffset-=zl2l(p->q2.val.vlong);
+		continue;
+	    }
+	    if(c==ASSIGN){
+		if(p->q1.flags&KONST){
+		    move(f,&p->q1,0,&p->z,0,t);
+		    continue;
+		}
+		if(isreg(z)) reg=p->z.reg;
+		else if(isreg(q1)) reg=p->q1.reg;
+		else reg=get_reg(f,p);
+		move(f,&p->q1,0,0,reg,t);
+		move(f,0,reg,&p->z,0,t);
+		continue;
+	    }
+	    ierror(0);
+	}
+	if(c==ADDRESS){
+	    if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+	    fprintf(f,"\tleal\t");probj2(f,&p->q1,t);
+	    fprintf(f,",%s\n",regnames[reg]);
+	    move(f,0,reg,&p->z,0,POINTER);
+	    continue;
+	}
+	if(c==TEST){
+	    lastcomp=t;
+	    if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+		if(isreg(q1)&&fst[0]==p->q1.reg){
+		    fprintf(f,"\tftst\n");lastcomp|=UNSIGNED;
+		    continue;
+		}else{
+		    p->code=c=COMPARE;
+		    p->q2.flags=KONST;
+		    p->q2.val.vdouble=d2zd(0.0);
+		    if((t&NQ)==FLOAT) p->q2.val.vfloat=zd2zf(p->q2.val.vdouble);
+		    /*	fall through to COMPARE */
+		}
+	    }else{
+		fprintf(f,"\tcmp%c\t$0,",x_t[t&NQ]);
+		probj2(f,&p->q1,t);fprintf(f,"\n");
+		continue;
+	    }
+	}
+	if(c==COMPARE){
+	    lastcomp=t;
+	    if(isreg(q2)||(p->q1.flags&KONST)){
+		struct IC *b=p->next;
+		struct obj o;
+		o=p->q1;p->q1=p->q2;p->q2=o;
+		while(b&&b->code==FREEREG) b=b->next;
+		if(!b) ierror(0);
+		if(b->code==BLT) b->code=BGT;
+		else if(b->code==BLE) b->code=BGE;
+		else if(b->code==BGT) b->code=BLT;
+		else if(b->code==BGE) b->code=BLE;
+	    }
+	    if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+		prfst(f,"fcomp");
+		if(isreg(q1)&&p->q1.reg==fst[0]){
+		    fprintf(f,"\tfcom%c\t",x_t[t&NQ]);
+		    probj2(f,&p->q2,t);fprintf(f,"\n");
+		}else{
+		    fload(f,&p->q1,t);
+		    fprintf(f,"\tfcomp%c\t",x_t[t&NQ]);
+		    probj2(f,&p->q2,t);fprintf(f,"\n");
+		    fpop();
+		}
+		fprintf(f,"\tfstsw\n\tsahf\n");
+		lastcomp|=UNSIGNED;
+		continue;
+	    }
+	    if(!isreg(q1)){
+		if(!isreg(q2)){
+		    reg=get_reg(f,p);
+		    move(f,&p->q1,0,0,reg,t);
+		    p->q1.flags=REG;
+		    p->q1.reg=reg;
+		}
+	    }
+	    fprintf(f,"\tcmp%c\t",x_t[t&NQ]);
+	    probj2(f,&p->q2,t);fprintf(f,",");
+	    probj2(f,&p->q1,t);fprintf(f,"\n");
+	    continue;
+	}
+	if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+	    char s[2];
+	    prfst(f,"fmath");
+	    if(isreg(q2)) s[0]=0; else {s[0]=x_t[t&NQ];s[1]=0;}
+	    if(isreg(z)&&isreg(q1)&&p->q1.reg==fst[0]&&p->z.reg==fst[0]){
+		fprintf(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+		probj2(f,&p->q2,t); fprintf(f,"\n");continue;
+	    }
+	    fload(f,&p->q1,t);
+	    fprintf(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+	    probj2(f,&p->q2,t); fprintf(f,"\n");
+	    fstore(f,&p->z,t); continue;
+	}
+	if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&(p->q2.flags&KONST)){
+	    long ln;
+	    eval_const(&p->q2.val,t);
+	    if(zlleq(l2zl(0L),vlong)&&zulleq(ul2zul(0UL),vulong)){
+		if(ln=pof2(vulong)){
+		    if(c==MOD){
+			vlong=zlsub(vlong,l2zl(1L));
+			p->code=AND;
+		    }else{
+			vlong=l2zl(ln-1);
+			if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+		    }
+		    c=p->code;
+		    if((t&NU)==CHAR) p->q2.val.vchar=zl2zc(vlong);
+		    if((t&NU)==SHORT) p->q2.val.vshort=zl2zs(vlong);
+		    if((t&NU)==INT) p->q2.val.vint=zl2zi(vlong);
+		    if((t&NU)==LONG) p->q2.val.vlong=vlong;
+		    vulong=zl2zul(vlong);
+		    if((t&NU)==(UNSIGNED|CHAR)) p->q2.val.vuchar=zul2zuc(vulong);
+		    if((t&NU)==(UNSIGNED|SHORT)) p->q2.val.vushort=zul2zus(vulong);
+		    if((t&NU)==(UNSIGNED|INT))  p->q2.val.vuint=zul2zui(vulong);
+		    if((t&NU)==(UNSIGNED|LONG)) p->q2.val.vulong=vulong;
+		}
+	    }
+	}
+	if(c==MOD||c==DIV){
+	    int m=0;
+	    if(regs[ax]&&(!isreg(z)||p->z.reg!=ax)){
+		fprintf(f,"\tpushl\t%s\n",regnames[ax]);
+		stackoffset-=4;m|=1;
+	    }
+	    if(regs[dx]&&(!isreg(z)||p->z.reg!=dx)){
+		fprintf(f,"\tpushl\t%s\n",regnames[dx]);
+		stackoffset-=4;m|=2;
+	    }
+	    if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(p->q2.reg==ax||p->q2.reg==dx)){
+		move(f,&p->q2,0,0,dx,t);
+		fprintf(f,"\tpushl\t%s\n",regnames[dx]);
+		m|=8;stackoffset-=4;
+	    }
+	    move(f,&p->q1,0,0,ax,t);
+	    if(p->q2.flags&KONST){
+		fprintf(f,"\tpush%c\t",x_t[t&NQ]);probj2(f,&p->q2,t);
+		fprintf(f,"\n");m|=4;stackoffset-=4;
+	    }
+	    if(t&UNSIGNED) fprintf(f,"\txorl\t%s,%s\n\tdivl\t",regnames[dx],regnames[dx]);
+		else	   fprintf(f,"\tcltd\n\tidivl\t");
+	    if((m&12)||(isreg(q2)&&p->q2.reg==dx)){
+		fprintf(f,"(%s)",regnames[sp]);
+	    }else if(isreg(q2)&&p->q2.reg==ax){
+		fprintf(f,"%s(%s)",(m&2)?"4":"",regnames[sp]);
+	    }else{
+		probj2(f,&p->q2,t);
+	    }
+	    fprintf(f,"\n");
+	    if(c==DIV) move(f,0,ax,&p->z,0,t);
+		else   move(f,0,dx,&p->z,0,t);
+	    if(m&4){ fprintf(f,"\taddl\t$%ld,%s\n",zl2l(sizetab[t&NQ]),regnames[sp]);stackoffset+=4;}
+	    if(m&8){ fprintf(f,"\tpopl\t%s\n",regnames[dx]);stackoffset+=4;}
+	    if(m&2){ fprintf(f,"\tpopl\t%s\n",regnames[dx]);stackoffset+=4;}
+	    if(m&1){ fprintf(f,"\tpopl\t%s\n",regnames[ax]);stackoffset+=4;}
+	    continue;
+	}
+	if(!(p->q2.flags&KONST)&&(c==LSHIFT||c==RSHIFT)){
+	    char *s=arithmetics[c-LSHIFT];
+	    int fl=0;
+	    if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+	    if(((p->q1.flags&REG)&&p->q1.reg==cx)||((p->z.flags&REG)&&p->z.reg==cx)
+	       ||(!compare_objects(&p->q1,&p->z)&&!isreg(q1))){
+		reg=get_reg(f,p);
+		move(f,&p->q1,0,0,reg,t);
+		move(f,&p->q2,0,0,cx,t);
+		fprintf(f,"\t%s%c\t%%cl,%s\n",s,x_t[t&NQ],regnames[reg]);
+		move(f,0,reg,&p->z,0,t);
+		continue;
+	    }else{
+		if(!isreg(q2)||p->q2.reg!=cx){
+		    if(regs[cx]){fprintf(f,"\tpushl\t%s\n",regnames[cx]);fl=1;}
+		    move(f,&p->q2,0,0,cx,t);
+		}
+		if(compare_objects(&p->q1,&p->z)){
+		    fprintf(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+		    probj2(f,&p->z,t);fprintf(f,"\n");
+		}else{
+		    move(f,0,p->q1.reg,&p->z,0,t);
+		    fprintf(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+		    probj2(f,&p->z,t);fprintf(f,"\n");
+		}
+		if(fl) fprintf(f,"\tpopl\t%s\n",regnames[cx]);
+		continue;
+	    }
+	}
+	if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)){
+	    char *s;
+	    if(c>=OR&&c<=AND) s=logicals[c-OR];
+		else s=arithmetics[c-LSHIFT];
+	    if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+	    if(c!=MULT&&compare_objects(&p->q1,&p->z)){
+		if(isreg(z)||isreg(q1)||(p->q2.flags&KONST)){
+		    if((p->q2.flags&KONST)&&(c==ADD||c==SUB)){
+			eval_const(&p->q2.val,t);
+			if(zleqto(vlong,l2zl(1L))&&zuleqto(vulong,ul2zul(1UL))&&zdeqto(vdouble,d2zd(1.0))){
+			    if(c==ADD) s="inc"; else s="dec";
+			    fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+			    probj2(f,&p->z,t);fprintf(f,"\n");
+			    continue;
+			}
+		    }
+		    fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+		    probj2(f,&p->q2,t);fprintf(f,",");
+		    probj2(f,&p->z,t);fprintf(f,"\n");
+		    continue;
+		}else{
+		    if(isreg(q2)) reg=p->q2.reg; else reg=get_reg(f,p);
+		    move(f,&p->q2,0,0,reg,t);
+		    fprintf(f,"\t%s%c\t%s",s,x_t[t&NQ],regnames[reg]);
+		    fprintf(f,","); probj2(f,&p->z,t);fprintf(f,"\n");
+		    continue;
+		}
+	    }
+	    if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+	    move(f,&p->q1,0,0,reg,t);
+	    if((p->q2.flags&KONST)&&(c==ADD||c==SUB)){
+		eval_const(&p->q2.val,t);
+		if(zleqto(vlong,l2zl(1L))&&zuleqto(vulong,ul2zul(1UL))&&zdeqto(vdouble,d2zd(1.0))){
+		    if(c==ADD) s="inc"; else s="dec";
+		    fprintf(f,"\t%s%c\t%s\n",s,x_t[t&NQ],regnames[reg]);
+		}else{
+		    fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+		    probj2(f,&p->q2,t);fprintf(f,",%s\n",regnames[reg]);
+		}
+	    }else{
+		fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+		probj2(f,&p->q2,t);fprintf(f,",%s\n",regnames[reg]);
+	    }
+	    move(f,0,reg,&p->z,0,t);
+	    continue;
+	}
+	ierror(0);
+    }
+    if(notpopped){
+	fprintf(f,"\taddl\t$%ld,%%esp\n",notpopped);
+	stackoffset+=notpopped;notpopped=0;
+    }
+    function_bottom(f,v,loff);
+}
+
+int shortcut(int code,int typ)
+{
+    return(0);
+}
+
+void cleanup_cg(FILE *f)
+{
+    struct fpconstlist *p;
+    unsigned char *ip;
+
+    title(f);
+    while(p=firstfpc){
+	if(f){
+	    if(section!=CODE){fprintf(f,codename);section=CODE;}
+	    fprintf(f,"%s%d:\n\t.long\t",labprefix,p->label);
+	    ip=(unsigned char *)&p->val.vdouble;
+	    fprintf(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+	    if((p->typ&NQ)==DOUBLE){
+		fprintf(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+	    }
+	    fprintf(f,"\n");
+	}
+	firstfpc=p->next;
+	free(p);
+    }
+    if(f){
+	if(section!=BSS){fprintf(f,bssname);section=BSS;}
+	if(cxl) fprintf(f,"\t.lcomm\t%s%d,4\n",labprefix,cxl);
+	if(sil) fprintf(f,"\t.lcomm\t%s%d,4\n",labprefix,sil);
+	if(dil) fprintf(f,"\t.lcomm\t%s%d,4\n",labprefix,dil);
+    }
+}
diff --git a/machines/bi386/machine.dt b/machines/bi386/machine.dt
new file mode 100755
index 0000000..94451a4
--- /dev/null
+++ b/machines/bi386/machine.dt
@@ -0,0 +1,13 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/bi386/machine.h b/machines/bi386/machine.h
new file mode 100755
index 0000000..5970ac1
--- /dev/null
+++ b/machines/bi386/machine.h
@@ -0,0 +1,59 @@
+/*  Example of a code-generator for an Intel 386 or higher.         */
+
+#include "dt.h"
+
+#define BEI386
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+    int never_used;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 16
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 10
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 0
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#ifdef BEI386
+#define BIGENDIAN 1
+#else
+#define BIGENDIAN 0
+#endif
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#ifdef BEI386
+#define LITTLEENDIAN 0
+#else
+#define LITTLEENDIAN 1
+#endif
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+
diff --git a/machines/c16x/machine.c b/machines/c16x/machine.c
new file mode 100755
index 0000000..b80fd10
--- /dev/null
+++ b/machines/c16x/machine.c
@@ -0,0 +1,3728 @@
+/*  Code generator for SAB c16x microcontrollers.               */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for c16x V0.3 (c) in 1998-2005 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,0,0,0,
+                    0,0,0,0,
+                    0};
+char *g_flags_name[MAXGF]={"cpu","int32","no-delayed-popping","const-in-data",
+                           "merge-constants","no-peephole","mtiny","mlarge",
+                           "mhuge","tasking"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+		 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+		 "array","struct","union","enum","function"};
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[]={"noreg","R0","R1","R2","R3","R4","R5","R6","R7",
+		  "R8","R9","R10","R11","R12","R13","R14","R15",
+		  "R6/R7","R7/R8","R8/R9","R4/R5",
+		  "R14/R15","R13/R14","R12/R13",
+		  "R3/R4","R2/R3",
+		  "MAXR+1","MAXR+2","ZEROS","ONES"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1};
+
+int reg_prio[MAXR+1]={0,0,0,0,0,2,3,1,1,1,1,0,0,4,5,6,7,1,1,1,2,6,5,4,0,0};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__dpp0","__dpp1","__dpp2","__dpp3",0};
+#define INTERRUPT 1
+#define DPP0 2
+#define DPP1 4
+#define DPP2 8
+#define DPP3 16
+
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+
+static char *bregnames[]={"nobreg","RL0","RL1","RL2","RL3","RL4","RL5","RL6","RL7",
+ "e8","e9","e10","e11","e12","e13","e14","e15","e16",
+ "e17","e18","e19","e20","e21","e22"
+};
+
+static long malign[MAX_TYPE+1]=  {1,1,1,2,2,2,2,2,2,2,1,2,2,2,1,1,1,2,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,8,4,8,8,0,2,4,4,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define INT32 (g_flags[1]&USEDFLAG)
+#define TINY (g_flags[6]&USEDFLAG)
+#define LARGE (g_flags[7]&USEDFLAG)
+#define HUGE (g_flags[8]&USEDFLAG)
+#define TASKING (g_flags[9]&USEDFLAG)
+
+
+#define NDATA 0
+#define NBSS 1
+#define NCDATA 2
+#define FDATA 3
+#define FBSS 4
+#define FCDATA 5
+#define HDATA 6
+#define HBSS 7
+#define HCDATA 8
+#define CODE 9
+#define SPECIAL 10
+#define BITS 11
+
+#define SEG r2
+#define SOF r1
+
+#define MTMP1 MAXR+1
+#define MTMP2 MAXR+2
+#define ZEROS MAXR+3
+#define ONES  MAXR+4
+
+static int section=-1,newobj,scnt;
+static char *codename="SCODE\tSECTION CODE WORD PUBLIC 'CPROGRAM'\n",*ecode="SCODE\tends\n",
+            *ndataname="NDATA\tSECTION LDAT WORD PUBLIC\n",*endata="NDATA\tends\n",
+            *fdataname="FDATA\tSECTION LDAT WORD PUBLIC\n",*efdata="FDATA\tends\n",
+            *hdataname="HDATA\tSECTION LDAT WORD PUBLIC\n",*ehdata="HDATA\tends\n",
+            *nbssname="NBSS\tSECTION LDAT WORD PUBLIC\n",*enbss="NBSS\tends\n",
+            *fbssname="FBSS\tSECTION LDAT WORD PUBLIC\n",*efbss="FBSS\tends\n",
+            *hbssname="HBSS\tSECTION LDAT WORD PUBLIC\n",*ehbss="HBSS\tends\n",
+            *ncdataname="NCDATA\tSECTION LDAT WORD PUBLIC\n",*encdata="NCDATA\tends\n",
+            *fcdataname="FCDATA\tSECTION LDAT WORD PUBLIC\n",*efcdata="FCDATA\tends\n",
+            *hcdataname="HCDATA\tSECTION LDAT WORD PUBLIC\n",*ehcdata="HCDATA\tends\n",
+
+            *bitsname="BITS\tSECTION BIT BIT PUBLIC 'CBITS'\n",*ebits="BITS\tends\n";
+
+static char *even="\teven\n",*public="public",*comment="; ";
+
+#define IMM_IND  1
+#define VAR_IND  2
+#define POST_INC 3
+#define PRE_DEC  4
+
+static char sec_end[32];
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static const int sp=1,tp=2,ti=11,ti2=12,r4=5,r5=6,r4r5=20;
+static int tmp1,tmp2,tmp3,tmp4;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+static int scratchreg(int,struct IC *);
+static struct Var nvar,fvar;
+
+static char *marray[]={0,
+                       "__far=__attr(\"far\")",
+		       "__near=__attr(\"near\")",
+		       "__huge=__attr(\"huge\")",
+		       "__bit=__attr(\"bit\") unsigned char",
+                       /*"__section(x)=__vattr(\"section(\"x\")\")",*/
+                       "__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+		       "__rbank(x)=__vattr(\"rbank(\"__str(x)\")\")",
+		       "__interrupt(x)=__interrupt __vattr(\"ivec(\"__str(x)\")\")",
+		       "__sysstack(x)=__stack2(x)",
+		       "__usrstack(x)=__stack(x)",
+		       "__C16X__",
+		       "__C167__",
+		       "__ST10__",
+		       "__sfr(x)=__vattr(\"sfr(\"__str(x)\")\") extern",
+		       "__sfrbit(x,y)=__vattr(\"sfrbit(\"__str(x)\",\"__str(y)\")\") extern",
+		       "__esfr(x)=__vattr(\"sfre(\"__str(x)\")\") extern",
+		       "__esfrbit(x,y)=__vattr(\"sfrbite(\"__str(x)\",\"__str(y)\")\") extern",
+		       "__SIZE_T_INT=1",
+		       "__str(x)=#x",
+		       0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+#define issfrv(v) (v->vattr&&strstr(v->vattr,"sfr("))
+#define issfrbitv(v) (v->vattr&&strstr(v->vattr,"sfrbit("))
+#define isesfrv(v) (v->vattr&&strstr(v->vattr,"sfre("))
+#define isesfrbitv(v) (v->vattr&&strstr(v->vattr,"sfrbite("))
+#define issfr(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&issfrv(p->x.v))
+#define issfrbit(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&issfrbitv(p->x.v))
+#define isesfr(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&isesfrv(p->x.v))
+#define isesfrbit(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(p->x.v))
+
+static long loff,sysstackoffset,usrstackoffset,notpopped,dontpop,
+  usrmaxpushed,sysmaxpushed,sysstack,usrstack;
+
+static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
+static char *ccs[]={"z","nz","lt","ge","le","gt"};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"shl","shr","add","sub","mul","div","mod"};
+static char *dct[]={"","dbit","db","dw","dw","dw","dw","dw","dw","dw",
+		    "(void)","dw","dsptr","dsptr"};
+static char *vdct[]={"",".bit",".byte",".short",".short",".short",".short",".short",".short",".short",
+		    "(void)",".short",".long",".long"};
+static int pushedsize,pushorder=2;
+static char *idprefix="_",*labprefix="l";
+static int ti2_used;
+static struct rpair qp;
+static int exit_label,have_frame,stackchecklabel,stack_valid;
+static char *ret,*call,*jump;
+static int frame_used;
+
+static char *dppprefix="___DPP_";
+static int romdpp=0,ramdpp=1;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+#define STR_BADDR "baddr"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
+
+static int dppuse(struct Var *v,int section)
+{
+  if(v->tattr&DPP0) return 0;
+  if(v->tattr&DPP1) return 1;
+  if(v->tattr&DPP2) return 2;
+  if(v->tattr&DPP3) return 3;
+  if(section==NCDATA) return romdpp;
+  if(section==NDATA||section==NBSS) return ramdpp;
+  return -1;
+}
+
+static int ISFAR(struct Var *v)
+{
+  struct Typ *vt;
+  if(v==&nvar) return 0;
+  if(v==&fvar) return 1;
+  if(issfrv(v)||isesfrv(v)||issfrbitv(v)||isesfrbitv(v))
+    return 0;
+  vt=v->vtyp;
+  while(ISARRAY(vt->flags)) vt=vt->next;
+  if(vt->attr&&strstr(STR_NEAR,vt->attr))
+    return 0;
+  if(HUGE||LARGE)
+    return 1;
+  if(vt->attr&&(strstr(STR_FAR,vt->attr)||strstr(STR_HUGE,vt->attr)))
+    return 1;
+  return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec,*e;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  if(f&&TASKING){
+    emit(f,sec_end);
+    e=sec_end;
+    while(*sec&&*sec!=')') {
+      *e++=*sec;
+      emit_char(f,*sec++);
+    }
+    *e=0;
+    strcat(sec_end,"\tends\n");
+    emit(f,"\tSECTION LDAT WORD PUBLIC\n");
+  }else{
+    emit(f,"\t.section\t");
+    while(*sec&&*sec!=')') emit_char(f,*sec++);
+    emit(f,"\n");
+  }
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static struct fpconstlist {
+    struct fpconstlist *next;
+    int label,typ;
+    union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+	eval_const(&p->val,t);
+	if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+	if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+	if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+static void callee_push(long usr,long sys)
+{
+  if(usr-usrstackoffset>usrstack)
+    usrstack=usr-usrstackoffset;
+  if(sys-sysstackoffset>sysstack)
+    sysstack=sys-sysstackoffset;
+}
+static void push(long usr,long sys)
+{
+  usrstackoffset-=usr;
+  if(usrstackoffset<usrmaxpushed) 
+    usrmaxpushed=usrstackoffset;
+  if(-usrmaxpushed>usrstack) usrstack=-usrmaxpushed;
+  sysstackoffset-=sys;
+  if(sysstackoffset<sysmaxpushed) 
+    sysmaxpushed=sysstackoffset;
+  if(-sysmaxpushed>sysstack) sysstack=-sysmaxpushed;
+}
+static void pop(long usr,long sys)
+{
+  usrstackoffset+=usr;
+  sysstackoffset+=sys;
+}
+int pointer_type(struct Typ *p)
+{
+  struct Typ *merk=p;
+  if(!p) ierror(0);
+  while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+  if(p->attr){
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+  }
+  if((merk->flags&NQ)==FUNKT){
+    if(TINY)
+      return NPOINTER;
+    else
+      return HPOINTER;
+  }
+  if(LARGE)
+    return FPOINTER;
+  else if(HUGE)
+    return HPOINTER;
+  else
+    return NPOINTER;
+}
+static long voff(struct obj *p)
+{
+  if(p->v->offset<0)
+    return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-usrstackoffset+pushedsize-2;
+  return zm2l(p->v->offset)+zm2l(p->val.vmax)-usrstackoffset;
+}
+static int alignment(struct obj *o)
+{
+  if(o->flags&DREFOBJ) return 1;
+  if(!(o->flags&VAR)) ierror(0);
+  if(ISSTATIC(o->v)) return zm2l(o->val.vmax)&1;
+  return voff(o)&1;
+}
+
+static int isseg;
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/*  Gibt Objekt auf Bildschirm aus                      */
+{
+  if(p->am){
+    static struct rpair bp;
+    int base;
+    if(reg_pair(p->am->base,&bp))
+      base=bp.SOF;
+    else
+      base=p->am->base;
+    if(p->am->flags==POST_INC){
+      emit(f,"[%s+]",regnames[base]);
+      return;
+    }else if(p->am->flags==PRE_DEC){
+      emit(f,"[-%s]",regnames[base]);
+      return;
+    }else{
+      emit(f,"[%s+#%ld",regnames[base],p->am->offset);
+      if(p->am->v){
+	if(p->am->v->storage_class==STATIC)
+	  emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
+	else
+	  emit(f,"+%s%s",idprefix,p->am->v->identifier);
+      }
+      emit(f,"]");
+      return;
+    }
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"[");
+  if(p->flags&VARADR) emit(f,"#");
+  if((p->flags&(VAR|REG))==VAR){
+    if(p->v==&nvar||p->v==&fvar){
+      if(p->v==&fvar) emit(f,"SOF ");
+      emitval(f,&p->val,p->dtyp&NU);
+      return;
+    }else if(issfrv(p->v)||isesfrv(p->v)||issfrbitv(p->v)||isesfrbitv(p->v)){
+      emit(f,"%s",p->v->identifier);
+    }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      if(voff(p))
+	emit(f,"[%s+#%ld]",regnames[sp],voff(p));
+      else emit(f,"[%s]",regnames[sp]);
+    }else{
+      if(!isseg&&!ISFUNC(p->v->vtyp->flags)){
+        if(ISFAR(p->v)) 
+          emit(f,"SOF ");
+        else
+          emit(f,"DPPX:");
+      }
+      isseg=0;
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+	emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+	emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&REG){
+    if(p->reg==MTMP1||p->reg==MTMP2){
+      if(!reg_pair(p->reg,&rp)) ierror(0);
+      emit(f,"%s",regnames[rp.SOF]);
+    }else{
+      emit(f,"%s",regnames[p->reg]);
+      if((t&NQ)==BIT) emit(f,".0");
+    }
+  }
+  /* sometimes we just or a REG into a KONST */
+  if((p->flags&(KONST|REG))==KONST){
+    if(ISFLOAT(t)){
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    }else{
+      emit(f,"#");emitval(f,&p->val,t&NU);
+    }
+  }
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"]");
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+}
+static int switched_bank;
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionskopf                       */
+{
+  int i;char *tmp;
+  static int wrote_header;
+  if(f&&!wrote_header){
+    wrote_header=1;
+    if(!TASKING){
+      emit(f,"\t.sfr\tZEROS,0xfe,0x8e\n");
+      emit(f,"\t.sfr\tONES,0xfe,0x8f\n");
+      emit(f,"\t.sfr\tCP,0xfe,0x08\n");
+      emit(f,"\t.sfr\tMDH,0xfe,0x06\n");
+      emit(f,"\t.sfr\tMDL,0xfe,0x07\n");
+      emit(f,"\t.sfr\tPSW,0xfe,0x88\n");
+    }
+  }
+  have_frame=0;stack_valid=1;
+  pushedsize=0;
+  if(v->vattr&&(tmp=strstr(v->vattr,"ivec("))){
+    int vec;char c;int rc;
+    rc=sscanf(tmp+5,"%i%c",&vec,&c);
+    if(rc!=2||c!=')') error(324,"illegal vector number");
+    emit(f,"\t.section\t\".ivec%d\",\"axr\"\n",vec);
+    emit(f,"\t.global\tivec%d\nivec%d:\n",vec,vec);
+    if(v->storage_class==EXTERN)
+      emit(f,"\tjmps\t%s%s\n",idprefix,v->identifier);
+    else
+      emit(f,"\tjmps\t%s%ld\n",labprefix,zm2l(v->offset));
+    section=-1;
+  }
+  if(!special_section(f,v)&&section!=CODE){
+    if(f&&TASKING){
+      emit(f,sec_end);emit(f,codename);
+      section=CODE;
+      strcpy(sec_end,ecode);
+    }else
+      emit(f,codename);
+  }
+  if(TASKING){
+    if(v->storage_class==EXTERN){
+      if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+	emit(f,"\tpublic\t%s%s\n",idprefix,v->identifier);
+      if(TINY)
+	emit(f,"%s%s\tproc\tnear\n",idprefix,v->identifier);
+      else
+	emit(f,"%s%s\tproc\tfar\n",idprefix,v->identifier);
+    }else{
+      if(TINY)
+	emit(f,"%s%ld\tproc\tnear\n",labprefix,zm2l(v->offset));
+      else
+	emit(f,"%s%ld\tproc\tfar\n",labprefix,zm2l(v->offset));
+    }
+  }else{
+    if(v->storage_class==EXTERN){
+      if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+	emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+      emit(f,"\t.align\t1\n%s%s:\n",idprefix,v->identifier); 
+    }else{
+      emit(f,"\t.align\t1\n%s%ld:\n",labprefix,zm2l(v->offset));  
+    }
+  }
+  if(v->vattr&&(tmp=strstr(v->vattr,"rbank("))){
+    char *p;
+    tmp+=strlen("rbank(");
+    emit(f,"\tmov\t%s",idprefix);
+    for(p=tmp;*p&&*p!=')';p++) emit_char(f,*p);
+    emit(f,",%s\n",regnames[sp]);
+    emit(f,"\tscxt\tCP,#%s",idprefix);
+    for(p=tmp;*p&&*p!=')';p++) emit_char(f,*p);
+    emit(f,"\n");
+    switched_bank=1;
+  }else
+    switched_bank=0;
+  if(v->tattr&INTERRUPT){
+    /*FIXME?*/
+    emit(f,"\tpush\tMDL\n");
+    emit(f,"\tpush\tMDH\n");
+  }
+  if(stack_check){
+    stackchecklabel=++label;
+    BSET(regs_modified,tp);
+    emit(f,"\tmov\t%s,#%s%d\n",regnames[tp],labprefix,stackchecklabel);
+    emit(f,"\t%s\t%s__stack_check\n",call,idprefix);/*FIXME:usrstack*/
+  }
+  for(i=1;i<=16;i++){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[i]);
+      push(2,0);
+      have_frame=1;pushedsize+=2;
+    }
+  }
+  if(offset){
+    emit(f,"\tsub\t%s,#%ld\n",regnames[sp],offset);
+    have_frame=1;
+  }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionsende                       */
+{
+  int i;
+  if(offset) emit(f,"\tadd\t%s,#%ld\n",regnames[sp],offset);
+  for(i=16;i>0;i--){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      emit(f,"\tmov\t%s,[%s+]\n",regnames[i],regnames[sp]);
+      pop(2,0);
+    }
+  }
+  if(v->tattr&INTERRUPT){
+    emit(f,"\tpop\tMDH\n");
+    emit(f,"\tpop\tMDL\n");
+  }
+  if(switched_bank)
+    emit(f,"\tpop\tCP\n");
+  if(ret) emit(f,"\t%s\n",ret);
+  if(TASKING){
+    if(v->storage_class==EXTERN){
+      emit(f,"%s%s\tendp\n",idprefix,v->identifier);
+      if(!strcmp("main",v->identifier)) emit(f,"\textern\t__CSTART:far\n");
+    }else
+      emit(f,"%s%ld\tendp\n",labprefix,zm2l(v->offset));
+  }else{
+    if(v->storage_class==EXTERN){
+      emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+    }else{
+      emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+      emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+    }
+  }
+  if(stack_check)
+    emit(f,"%s%d\tequ\t%ld\n",labprefix,stackchecklabel,offset+pushedsize-usrmaxpushed);
+  if(stack_valid){
+    long ustack=usrstack+offset+pushedsize,sstack=sysstack;
+    if(!v->fi) v->fi=new_fi();
+    if(v->fi->flags&ALL_STACK){
+      if(v->fi->stack1!=ustack)
+        if(f) error(319,"user-",ustack,v->fi->stack1);
+      if(v->fi->stack2!=sstack)
+        if(f) error(319,"system-",sstack,v->fi->stack2);
+    }else{
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=ustack;
+      v->fi->stack2=sstack;
+    }
+#if 0
+    emit(f,"%s usrstacksize=%ld\n",comment,zm2l(v->fi->stack1));
+    emit(f,"%s sysstacksize=%ld\n",comment,zm2l(v->fi->stack2));
+#endif
+    if(TASKING){
+    }else{
+      emit(f,"\t.equ\t%s__ustack_%s,%ld\n",idprefix,v->identifier,zm2l(v->fi->stack1));
+      emit(f,"\t.equ\t%s__sstack_%s,%ld\n",idprefix,v->identifier,zm2l(v->fi->stack2));
+    }
+  }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+#define EXT_IC_CMPIA 1
+#define EXT_IC_BTST  2
+#define EXT_IC_CMPIB 3
+static void clear_ext_ic(struct ext_ic *p)
+{
+  p->flags=0;
+  p->r=0;
+  p->offset=0;
+}
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+static void peephole(struct IC *p)
+{
+  int c,c2,r,t;struct IC *p2;
+  struct AddressingMode *am;
+  frame_used=0;
+  for(;p;p=p->next){
+    c=p->code;
+    if(!frame_used){
+      if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+      if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+      if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+    }
+    /* letztes Label merken */
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+    /* and x,#const;bne/beq */
+    if(c==AND&&isconst(q2)&&isreg(z)&&!ISLWORD(ztyp(p))){
+      long bit;
+      eval_const(&p->q2.val,p->typf);
+      if(bit=pof2(vumax)){
+	struct IC *cmp=0;int fr=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==TEST){
+	    if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+	      cmp=p2;continue;
+	    }
+	  }
+	  if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf);
+	    if(ISNULL()){
+	      cmp=p2;continue;
+	    }
+	    break;
+	  }
+	  if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
+	  if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
+	    p->ext.flags=EXT_IC_BTST;
+	    p2->ext.flags=EXT_IC_BTST;
+	    p2->ext.offset=bit-1;
+	    cmp->code=NOP;
+	    cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
+	    break;
+	  }
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==p->z.reg)||((p2->q2.flags&REG)&&p2->q2.reg==p->z.reg)||((p2->z.flags&REG)&&p2->z.reg==p->z.reg)) break;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	}
+      }
+    }
+    /* [Rx+] in q1 */
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q1.reg; t=q1typ(p);
+      if((!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if((zmeqto(vmax,l2zm(1L))&&(t&NQ)==CHAR)||(zmeqto(vmax,l2zm(2L))&&ISHWORD(t))){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q1.am=mymalloc(sizeof(*am));
+	      p->q1.am->flags=POST_INC;
+	      p->q1.am->base=r;
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* [Rx+] in q2 */
+    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q2.reg; t=q2typ(p);
+      if((!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+	  if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if((zmeqto(vmax,l2zm(1L))&&(t&NQ)==CHAR)||(zmeqto(vmax,l2zm(2L))&&ISHWORD(t))){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q2.am=mymalloc(sizeof(*am));
+	      p->q2.am->flags=POST_INC;
+	      p->q2.am->base=r;
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* move x->t; add/sub x,#1/-1/2/-2-> x; test/cmp t,#0; freereg t => cmpid12 */
+    if(c==ASSIGN&&isreg(q1)&&isreg(z)&&ISHWORD(p->typf)){
+      p2=p->next;if(p2) c2=p2->code;
+      if(p2&&(c2==ADD||c2==SUB||c2==ADDI2P||c2==SUBIFP)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->q1.reg&&p2->z.reg==p2->q1.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&ISHWORD(p2->typf)){
+	long l;
+	eval_const(&p2->q2.val,p2->typf);
+	l=zm2l(vmax);
+	if((l==1||l==2||l==-1||l==-2)&&p2->next){
+	  struct IC *p3=p2->next;
+	  if((p3->code==TEST||(p3->code==COMPARE&&(p3->q2.flags&(KONST|DREFOBJ))==KONST))&&(p3->q1.flags&(REG|DREFOBJ))==REG&&p3->q1.reg==p->z.reg&&scratchreg(p->z.reg,p3)&&ISHWORD(p3->typf)){
+	    if(c2==SUB||c2==SUBIFP) l=-l;
+	    p3->q1=p->q1;
+	    p->code=c=NOP;
+	    p->q1.flags=p->q2.flags=p->z.flags=0;
+	    p2->code=NOP;
+	    p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	    p3->ext.flags=EXT_IC_CMPIB;
+	    p3->ext.offset=l;
+	    p3->ext.r=p->q1.reg;
+	  }
+	}
+      }
+    }
+    /* add/sub x,#1/2/-1/-2 ->x; cmp x,#c => cmpid12 x,#c+-12 */
+    if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&isconst(q2)&&ISHWORD(p->typf)&&!reg_pair(p->q1.reg,&rp)){
+      eval_const(&p->q2.val,p->typf);
+      if(zmeqto(vmax,l2zm(-1L))||zmeqto(vmax,l2zm(-2L))||zmeqto(vmax,l2zm(1L))||zmeqto(vmax,l2zm(2L))){
+	long l=zm2l(vmax);
+	if(c==SUB||c==SUBIFP) l=-l;
+	r=p->q1.reg;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(c2==TEST||(c2==COMPARE&&(p2->q2.flags&(KONST|DREFOBJ))==KONST))&&ISHWORD(p2->typf)){
+	    unsigned long ul;
+	    eval_const(&p2->q2.val,q2typ(p2));
+	    ul=zum2ul(vumax);
+	    if(ul<65534){
+	      p2->ext.flags=EXT_IC_CMPIA;
+	      p2->ext.offset=l;
+	      p2->ext.r=r;
+	      p->code=c=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	    }
+	    break;
+
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	}
+      }
+    }
+    /* [Rx+#const] */
+    if((c==ADDI2P||c==SUBIFP)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(p->q1.flags&VARADR))){
+      int base;zmax of;struct obj *o;struct Var *v;
+      if(p->q1.flags&VARADR){
+	v=p->q1.v;
+	of=p->q1.val.vmax;
+	r=p->z.reg;
+	if(isreg(q2)) base=p->q2.reg; else base=r;
+      }else{
+	eval_const(&p->q2.val,p->typf);
+	if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+	v=0;
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+      }
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+	c2=p2->code;
+	if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	    if(o) break;
+	    o=&p2->q1;
+	  }
+	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	    if(o) break;
+	    o=&p2->q2;
+	  }
+	  if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	    if(o) break;
+	    o=&p2->z;
+	  }
+	}
+	if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	  int m;
+	  if(c2==FREEREG) 
+	    m=p2->q1.reg;
+	  else
+	    m=p2->z.reg;
+	  if(m==r){
+	    if(o){
+	      o->am=am=mymalloc(sizeof(*am));
+	      am->flags=IMM_IND;
+	      am->base=base;
+	      am->offset=zm2l(of);
+	      am->v=v;
+	      if(!v){
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }else{
+		if(isreg(q2)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
+		  p->q2.val.vmax=sizetab[p->typf&NQ];
+		}
+	      }
+	    }
+	    break;
+	  }
+	  if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
+	  continue;
+	}
+      }
+    }      
+  }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/*  Initializes an addressing-mode structure and returns a pointer to   */
+/*  that object. Will not survive a second call!                        */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  am.v=v;
+  return &obj;
+}
+/* prints label types used by tasking assembler */
+static void emit_label_type(FILE *f,struct Var *v)
+{
+  if(TASKING){
+    if(ISFUNC(v->vtyp->flags)){
+      if(TINY)
+	emit(f,"near");
+      else
+	emit(f,"far");
+    }else{
+      if((v->vtyp->flags&NQ)==BIT)
+	emit(f,"bit");
+      else if((v->vtyp->flags&NQ)==CHAR)
+	emit(f,"byte");
+      else
+	emit(f,"word");
+    }
+  }
+}
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/*  Generates code to move object q (or register qr) into object z (or  */
+/*  register zr). One must be a register and DREFOBJ only allowed with  */
+/*  registers.                                                          */
+{
+  long l=0;
+  t&=NQ;
+  if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+  if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+  if(qr&&qr==zr) return;
+  if((t&NQ)==BIT){
+    if(!zr&&((z->flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(z->v))) ierror(0);
+    if(q&&(q->flags&(KONST|DREFOBJ))==KONST){
+      if(z&&(z->flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(z->v))
+	emit(f,"\textr\t#1\n");
+      eval_const(&q->val,BIT);
+      if(zmeqto(vmax,l2zm(0L)))
+	emit(f,"\tbclr\t");
+      else
+	emit(f,"\tbset\t");
+      if(zr) emit(f,"%s.0",regnames[zr]); else emit_obj(f,z,t);
+      emit(f,"\n");
+    }else{
+      if(!qr&&((q->flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(q->v))) ierror(0);
+      if((q->flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(q->v)){
+	if(!zr&&((z->flags&(VAR|DREFOBJ))!=VAR||!isesfrbitv(z->v))){
+	  emit(f,"\textr\t#1\n");
+	  emit(f,"\tbmov\t%s.0,",regnames[ti]);
+	  if(qr) emit(f,"%s.0",regnames[qr]); else emit_obj(f,q,t);
+	  emit(f,"\n");
+	  emit(f,"\tbmov\t");
+	  if(zr) emit(f,"%s.0",regnames[zr]); else emit_obj(f,z,t);
+	  emit(f,",%s.0\n",regnames[ti]);
+	  return;
+	}else
+	  emit(f,"\textr\t#1\n");
+      }else if(z&&(z->flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(z->v)){
+	if(!qr){
+	  emit(f,"\tbmov\t%s.0,",regnames[ti]);
+	  if(qr) emit(f,"%s.0",regnames[qr]); else emit_obj(f,q,t);
+	  emit(f,"\n");
+	  emit(f,"\textr\t#1\n");
+	  emit(f,"\tbmov\t");emit_obj(f,z,t);
+	  emit(f,",%s.0\n",regnames[ti]);
+	  return;
+	}else
+	  emit(f,"\textr\t#1\n");
+      }
+      emit(f,"\tbmov\t");
+      if(zr) emit(f,"%s.0",regnames[zr]); else emit_obj(f,z,t);
+      emit(f,",");
+      if(qr) emit(f,"%s.0",regnames[qr]); else emit_obj(f,q,t);
+      emit(f,"\n");
+    }
+    return;
+  }
+  if(q){
+    if(!zr) ierror(0);
+    if(q->am&&reg_pair(q->am->base,&rp)){
+      l=rp.SOF;
+      if(zr>16)
+	emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+      else
+	emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+    }else if((q->flags&DREFOBJ)&&reg_pair(q->reg,&rp)){
+      l=rp.SOF;
+      if(zr>16)
+	emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+      else
+	emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+    }else if((q->flags&(VAR|REG|VARADR))==VAR&&ISSTATIC(q->v)&&ISFAR(q->v)){
+      emit(f,"\texts\t#SEG ");
+      isseg=1;emit_obj(f,q,INT);
+      if(zr>16)
+	emit(f,",#2\n");
+      else
+	emit(f,",#1\n");
+    }
+    if(reg_pair(zr,&rp)){
+      if(q->am){
+	emit(f,"\tmov\t%s,",regnames[rp.r1]);
+	emit_obj(f,q,t);emit(f,"\n");
+	q->am->offset+=2;
+	emit(f,"\tmov\t%s,",regnames[rp.r2]);
+	emit_obj(f,q,t);emit(f,"\n");
+	q->am->offset-=2;
+	return;
+      }else if(q->flags&DREFOBJ){
+	int tmp=0;
+	if(!(q->flags&REG)) ierror(0);
+	if(!l) l=q->reg;
+	if(l==rp.r1){
+	  tmp=rp.r1;
+	  /*FIXME: tp hier immer frei? */
+	  BSET(regs_modified,tp);
+	  rp.r1=tp;
+	}
+	/*FIXME: test auf scratchreg*/
+	if(q->reg>MAXR){
+	  emit(f,"\tmov\t%s,[%s+]\n",regnames[rp.r1],regnames[l]);
+	  emit(f,"\tmov\t%s,[%s]\n",regnames[rp.r2],regnames[l]);
+	}else{
+	  emit(f,"\tmov\t%s,[%s]\n",regnames[rp.r1],regnames[l]);
+	  emit(f,"\tmov\t%s,[%s+#2]\n",regnames[rp.r2],regnames[l]);
+	}
+	if(tmp) emit(f,"\tmov\t%s,%s\n",regnames[tmp],regnames[rp.r1]);
+	return;
+      }else if(q->flags&VARADR){
+	q->flags&=~VARADR;
+	emit(f,"\tmov\t%s,#",regnames[rp.r1]);emit_obj(f,q,t);emit(f,"\n");
+	emit(f,"\tmov\t%s,#SEG ",regnames[rp.r2]);isseg=1;emit_obj(f,q,t);emit(f,"\n");
+	q->flags|=VARADR;
+	return;
+      }else if((q->flags&(KONST|DREFOBJ))==KONST){
+	long l2;
+	if(ISFLOAT(t)) ierror(0);
+	eval_const(&q->val,t);
+	l=zm2zl(zmand(vmax,l2zm(65535L)));
+	emit(f,"\tmov\t%s,#%ld\n",regnames[rp.r1],l);
+	l2=zm2l(zmrshift(vmax,l2zm(16L)));
+	if(l2==l) emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[rp.r1]);
+	else emit(f,"\tmov\t%s,#%ld\n",regnames[rp.r2],l2);
+	return;
+      }else if(qr){
+	if(!reg_pair(qr,&qp)) ierror(0);
+	emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[qp.r1]);
+	emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[qp.r2]);
+	return;
+      }else{
+	if(!(q->flags&VAR)) ierror(0);
+	if(q->v->storage_class==AUTO||q->v->storage_class==REGISTER){
+	  l=voff(q);
+	  if(l)
+	    emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[rp.r1],regnames[sp],l);
+	  else
+	    emit(f,"\tmov\t%s,[%s]\n",regnames[rp.r1],regnames[sp]);
+	  emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[rp.r2],regnames[sp],l+2);
+	  return;
+	}else{
+	  emit(f,"\tmov\t%s,",regnames[rp.r1]);emit_obj(f,q,t);emit(f,"\n");
+	  emit(f,"\tmov\t%s,",regnames[rp.r2]);emit_obj(f,q,t);emit(f,"+2\n");
+	  return;
+	}
+      }
+      ierror(0);
+    }else{
+      emit(f,"\tmov%s\t%s,",x_t[t&NQ],(t==CHAR?bregnames[zr]:regnames[zr]));
+      if(qr&&t==CHAR)
+	emit(f,"%s",bregnames[qr]); 
+      else if(!q->am&&(q->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&reg_pair(q->reg,&rp))
+	emit(f,"[%s]",regnames[rp.SOF]);
+      else
+	emit_obj(f,q,t);
+      emit(f,"\n");
+      return;
+    }
+  }
+  if(z){
+    if(!qr) ierror(0);
+    if(z->am&&reg_pair(z->am->base,&rp)){
+      l=rp.SOF;
+      if(qr>16)
+	emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+      else
+	emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);      
+    }else if((z->flags&DREFOBJ)&&reg_pair(z->reg,&rp)){
+      l=rp.SOF;
+      if(qr>16)
+	emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+      else
+	emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+    }else if((z->flags&(VAR|REG|VARADR))==VAR&&ISSTATIC(z->v)&&ISFAR(z->v)){
+      emit(f,"\texts\t#SEG ");
+      isseg=1;emit_obj(f,z,INT);
+      if(qr>16)
+	emit(f,",#2\n");
+      else
+	emit(f,",#1\n");
+    }
+    if(reg_pair(qr,&rp)){
+      if(z->am){
+	emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,",%s\n",regnames[rp.r1]);
+	z->am->offset+=2;
+	emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,",%s\n",regnames[rp.r2]);
+	z->am->offset-=2;
+	return;
+      }else if(z->flags&DREFOBJ){
+	if(!(z->flags&REG)) ierror(0);
+	if(!l) l=z->reg;
+	/*FIXME: test auf scratchreg statt >MAXR*/
+	if(z->reg>MAXR&&l!=rp.r2){
+	  emit(f,"\tmov\t[%s+],%s\n",regnames[l],regnames[rp.r1]);
+	  emit(f,"\tmov\t[%s],%s\n",regnames[l],regnames[rp.r2]);
+	}else{
+	  emit(f,"\tmov\t[%s],%s\n",regnames[l],regnames[rp.r1]);
+	  emit(f,"\tmov\t[%s+#2],%s\n",regnames[l],regnames[rp.r2]);
+	}
+	return;
+      }else if(zr){
+	if(!reg_pair(zr,&qp)) ierror(0);
+	emit(f,"\tmov\t%s,%s\n",regnames[qp.r1],regnames[rp.r1]);
+	emit(f,"\tmov\t%s,%s\n",regnames[qp.r2],regnames[rp.r2]);
+	return;
+      }else{
+	if(!(z->flags&VAR)) ierror(0);
+	if(z->v->storage_class==AUTO||z->v->storage_class==REGISTER){
+	  l=voff(z);
+	  if(l)
+	    emit(f,"\tmov\t[%s+#%ld],%s\n",regnames[sp],l,regnames[rp.r1]);
+	  else
+	    emit(f,"\tmov\t[%s],%s\n",regnames[sp],regnames[rp.r1]);
+	  emit(f,"\tmov\t[%s+#%ld],%s\n",regnames[sp],l+2,regnames[rp.r2]);
+	  return;
+	}else{
+	  emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,",%s\n",regnames[rp.r1]);
+	  emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,"+2,%s\n",regnames[rp.r2]);
+	  return;
+	}
+      }
+      ierror(0);
+    }else{
+      emit(f,"\tmov%s\t",x_t[t&NQ]);
+      if(!z->am&&(z->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&reg_pair(z->reg,&rp))
+	emit(f,"[%s]",regnames[rp.SOF]);
+      else if(zr&&t==CHAR)
+	emit(f,"%s",bregnames[zr]);
+      else
+	emit_obj(f,z,t);
+      emit(f,",%s\n",((t==CHAR)?bregnames[qr]:regnames[qr]));
+      return;
+    }
+  }
+  /*reg->reg*/
+  if(t==CHAR){
+    emit(f,"\tmovb\t%s,%s\n",bregnames[zr],bregnames[qr]);
+  }else if(ISLWORD(t)){
+    if(!reg_pair(qr,&qp)) ierror(0);
+    if(!reg_pair(zr,&rp)) ierror(0);
+    emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[qp.r1]);
+    emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[qp.r2]);
+  }else{
+    emit(f,"\tmov\t%s,%s\n",regnames[zr],regnames[qr]);
+  }
+}
+
+static int get_reg(FILE *f,struct IC *p)
+{
+  int i;
+  for(i=1;i<=16;i++){
+    if(!regs[i]&&regscratch[i]){
+      BSET(regs_modified,i);
+      return i;
+    }
+  }
+  ierror(0);
+}
+
+static void save_result(FILE *f,int r,struct IC *p,int t)
+/*  Saves result in register r to object o. May use tp or ti. */ 
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ){
+    BSET(regs_modified,tp);
+    if(ISLWORD(p->z.dtyp)){
+      if(!ti2_used) tmp4=ti2; else tmp4=get_reg(f,p);
+      BSET(regs_modified,tmp3);
+      tmp3=tp;
+      p->z.flags&=~DREFOBJ;
+      move(f,&p->z,0,0,MTMP2,FPOINTER);
+      p->z.flags=(DREFOBJ|REG);
+      p->z.reg=MTMP2;
+    }else if(!(p->z.flags&KONST)){
+      int tmp=(r==tp)?ti:tp;
+      BSET(regs_modified,tmp);
+      p->z.flags&=~DREFOBJ;
+      move(f,&p->z,0,0,tmp,NPOINTER);
+      p->z.flags=(DREFOBJ|REG);
+      p->z.reg=tmp;
+    }
+  }
+  move(f,0,r,&p->z,0,t);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+  int c;
+  if(r==tp||r==ti||r==ti2||r==MTMP1||r==MTMP2)
+    return 1;
+  while(1){
+    p=p->next;
+    if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+    if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+    if((p->q1.flags&REG)&&p->q1.reg==r) return 0;
+    if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
+    if((p->z.flags&REG)&&p->z.reg==r) return 0;
+  }
+}
+
+static char *longcmd(char *s)
+{
+  if(!strcmp(s,"add")) return "addc";
+  if(!strcmp(s,"sub")) return "subc";
+  /*FIXME*/
+  return s;
+}
+
+/* perform long arithmetic using library functions */
+/* the functions take arguments in r4/r5 and r10/r11 */
+/* giving the result in r4/r5 */
+/* returns , if the operation was performed, 0 if */
+/* the IC should be handled by inline-code */
+static int lib_larith(FILE *f,struct IC *p)
+{
+  int r4p,r5p,c=p->code,t=ztyp(p);char *s;
+  if(regs[r4]&&(!isreg(z)||p->z.reg==r4r5)){
+    emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[r4]);
+    push(2,0);
+    r4p=1;
+  }else
+    r4p=0;
+  if(regs[r5]&&(!isreg(z)||p->z.reg==r4r5)){
+    emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[r5]);
+    push(2,0);
+    r5p=1;
+  }else
+    r5p=0;
+  if(!p->q1.am&&(p->q1.flags&DREFOBJ)){
+    if(!(p->q1.flags&(REG))){
+      if(ISLWORD(p->q1.dtyp)){
+	tmp3=ti2;tmp4=ti;ti2_used=1;
+	BSET(regs_modified,ti);
+	BSET(regs_modified,ti2);
+	p->q1.flags&=~DREFOBJ;
+	move(f,&p->q1,0,0,MTMP2,FPOINTER);
+	p->q1.reg=MTMP2;
+	p->q1.flags=(REG|DREFOBJ);
+      }else if(!(p->q1.flags&KONST)){
+	BSET(regs_modified,ti);
+	p->q1.flags&=~DREFOBJ;
+	move(f,&p->q1,0,0,ti,NPOINTER);
+	p->q1.reg=ti;
+	p->q1.flags=(REG|DREFOBJ);
+      }
+    }
+  }
+  BSET(regs_modified,r4r5);
+  move(f,&p->q1,0,0,r4r5,q1typ(p));
+  if(!p->q2.am&&(p->q2.flags&DREFOBJ)){
+    if(!(p->q2.flags&(REG))){
+      if(ISLWORD(p->q2.dtyp)){
+	BSET(regs_modified,ti); 
+	BSET(regs_modified,ti2);
+	tmp3=ti2;tmp4=ti;ti2_used=1;
+	p->q2.flags&=~DREFOBJ;
+	move(f,&p->q2,0,0,MTMP2,FPOINTER);
+	p->q2.reg=MTMP2;
+	p->q2.flags=(REG|DREFOBJ);
+      }else if(!(p->q2.flags&KONST)){
+	BSET(regs_modified,ti);
+	p->q2.flags&=~DREFOBJ;
+	move(f,&p->q2,0,0,ti,NPOINTER);
+	p->q2.reg=ti;
+	p->q2.flags=(REG|DREFOBJ);
+      }
+    }
+  }  
+  /* ti/ti2 must be r10/r11 */
+  tmp3=ti;tmp4=ti2;ti2_used=1;
+  BSET(regs_modified,ti); 
+  BSET(regs_modified,ti2);
+  move(f,&p->q2,0,0,MTMP2,q2typ(p));
+  if(c==MULT)
+    s="_mul";
+  else if(c==DIV&&(t&UNSIGNED))
+    s="_udil";
+  else if(c==DIV&&!(t&UNSIGNED))
+    s="_sdil";
+  else if(c==MOD&&(t&UNSIGNED))
+    s="_umol";
+  else if(c==MOD&&!(t&UNSIGNED))
+    s="_smol";
+  else
+    ierror(0);
+  if(TASKING){
+    emit(f,"\textern\t%s%s:%s\n",idprefix,s,TINY?"near":"far");
+    emit(f,"\t%s\t%s%s\n",call,idprefix,s);
+  }
+  save_result(f,r4r5,p,ztyp(p));
+  if(r5p){
+    emit(f,"\tmov\t%s,[%s+]\n",regnames[r5],regnames[sp]);
+    pop(2,0);
+  }
+  if(r4p){
+    emit(f,"\tmov\t%s,[%s+]\n",regnames[r4],regnames[sp]);
+    pop(2,0);
+  }  
+  return 1;
+}
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+int emit_peephole(void)
+{
+  int entries,i;long x,y,z;
+  char *asmline[EMIT_BUF_DEPTH];
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+  if(entries>=1){
+    if(sscanf(asmline[0],"\tshl\tR%ld,#%ld\n",&x,&y)==2&&(y<0||y>15)){
+      sprintf(asmline[0],"\tmov\tR%ld,#0\n",x);
+      return 1;
+    }
+    if(sscanf(asmline[0],"\tshr\tR%ld,#%ld\n",&x,&y)==2&&(y<0||y>15)){
+      sprintf(asmline[0],"\tmov\tR%ld,#0\n",x);
+      return 1;
+    }
+  }
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+    if(sscanf(asmline[0],"\tadd\tR0,#%ld",&x)==1&&sscanf(asmline[1],"\tadd\tR0,#%ld",&y)==1){
+      sprintf(asmline[1],"\tadd\tR0,#%ld\n",x+y);
+      remove_asm();
+      return 1;
+    }
+    if(sscanf(asmline[1],"\tmov\tR11,#%ld",&x)==1&&sscanf(asmline[0],"\texts\tR11,#%ld",&y)==1){
+      sprintf(asmline[1],"\texts\t#%ld,#%ld\n",x,y);
+      remove_asm();
+      return 1;
+    }
+  }
+  if(entries>=3){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[2]=emit_buffer[i];
+    if(sscanf(asmline[2],"\tmov\tR1,#%ld",&x)==1&&sscanf(asmline[1],"\texts\t#%ld,#1",&y)==1&&sscanf(asmline[0],"\tmov\t[R1],R%ld",&z)==1){
+      strcpy(asmline[2],asmline[1]);
+      sprintf(asmline[1],"\tmov\t%ld,R%ld\n",x,z);
+      remove_asm();
+      return 1;
+    }
+  }
+  return 0;
+}
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(2L);
+  char_bit=l2zm(8L);
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i=1;i<=MAXR;i++){
+    if(i<=16){
+      regsize[i]=l2zm(2L);regtype[i]=&ityp;
+    }else{
+      regsize[i]=l2zm(4L);regtype[i]=&ltyp;
+    }
+  }	
+  
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=t_min[SHORT];
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=t_max[SHORT];
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=tu_max[SHORT];
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  regsa[sp]=regsa[tp]=regsa[ti]=regsa[ti2]=1;
+  regscratch[sp]=regscratch[tp]=regscratch[ti]=regscratch[ti2]=0;
+  target_macros=marray;
+  if(TINY) marray[0]="__TINY__";
+  else if(LARGE) marray[0]="__LARGE__";
+  else if(HUGE) marray[0]="__HUGE__";
+  else marray[0]="__MEDIUM__";
+
+  if(!TASKING){
+    codename="\t.section\t.text,\"carx1\"\n";
+    ndataname="\t.section\t.ndata,\"darw1\"\n";
+    fdataname="\t.section\t.fdata,\"darw1\"\n";
+    hdataname="\t.section\t.hdata,\"darw1\"\n";
+    nbssname="\t.section\t.nbss,\"uarw1\"\n";
+    fbssname="\t.section\t.fbss,\"uarw1\"\n";
+    hbssname="\t.section\t.hbss,\"uarw1\"\n";
+    ncdataname="\t.section\t.ncdata,\"dar1\"\n";
+    fcdataname="\t.section\t.fcdata,\"dar1\"\n";
+    hcdataname="\t.section\t.hcdata,\"dar1\"\n";
+    bitsname="\t.section\t.bits,\"darw0\"\n";
+    even="\t.align\t1\n";
+    public=".global";
+    comment="; ";
+  }
+
+  nvar.storage_class=STATIC;
+  fvar.storage_class=STATIC;
+
+
+  /* TODO: set argument registers */
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);
+
+  declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+  return 1;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+  int f=t->flags&NQ;
+  if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+    return 0;
+  if(ISSCALAR(f)){
+    if(f==LONG||f==FPOINTER||f==HPOINTER)
+      return 20;
+    else
+      return 5;
+  }
+  return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  t&=NQ;
+  if(r==0) return(0);
+  if(mode>0&&!ISPOINTER(t)) return 0;
+  if(t==NPOINTER&&mode>0){
+    if(r<=4) return 1; else return 0;
+  }
+  if(t<=CHAR&&r>8) return 0;
+  if((t<LONG||t==NPOINTER)&&r<=16) return 1;
+  if(t==LONG||t==FLOAT||t==FPOINTER||t==HPOINTER){
+    if(r>16) return 1;
+  }
+  return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r<=16) return 0;
+  if(p){
+    switch(r){
+    case 17: p->r1=7;p->r2=8;break;
+    case 18: p->r1=8;p->r2=9;break;
+    case 19: p->r1=9;p->r2=10;break;
+    case 20: p->r1=5;p->r2=6;break;
+    case 21: p->r1=15;p->r2=16;break;
+    case 22: p->r1=14;p->r2=15;break;
+    case 23: p->r1=13;p->r2=14;break;
+    case 24: p->r1=4;p->r2=5;break;
+    case 25: p->r1=3;p->r2=4;break;
+	
+    /* pseudos */
+    case MTMP1: p->r1=tmp1;p->r2=tmp2;break;
+    case MTMP2: p->r1=tmp3;p->r2=tmp4;break;
+    case ZEROS: return 0;
+    case ONES: return 0;
+    default: ierror(0);
+    }
+  }
+  return 1;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if((o->flags&DREFOBJ)){
+    if(o->flags&VKONST) return 1;
+    if(r<=4&&p->q2.flags&&o!=&p->z)
+      return 6;
+    else
+      return 4;
+  }else if(o->flags&VKONST){
+    struct obj *co=&o->v->cobj;
+    if((p->code==ASSIGN&&(p->z.flags&DREFOBJ))||p->code==PUSH)
+      return 4;
+    if(co->flags&VARADR)
+      return 4;
+    if(o==&p->q1)
+      eval_const(&co->val,q1typ(p));
+    else
+      eval_const(&co->val,q2typ(p));
+    /*FIXME*/
+    return 0;
+  }else if(c==GETRETURN&&p->q1.reg==r){
+    return 4;
+  }else if(c==SETRETURN&&p->z.reg==r){
+    return 4;
+  }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&&regok(r,CHAR,0)){
+    return 3;
+  }
+  return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  In this generic 32bit RISC cpu pointers and 32bit   */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if(op==tp) return 0;
+  if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+  if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+  if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+#if 0
+  emit(f,"\tds\t%ld\n",zm2l(size));
+#endif
+  /*FIXME: we currently do not use ds because of initialization */
+  long l=zm2l(size);
+  if(TASKING){
+    if(t&&(t->flags&NQ)==BIT){
+      emit(f,"\tdbit\n");
+      return;
+    }
+    /*FIXME:alignment while(size>=4) {emit(f,"\tddw\t0\n");size-=4;}*/
+    while(size--) emit(f,"\tdb\t0\n");
+  }else{
+    if(newobj&&section!=SPECIAL)
+      emit(f,"%ld\n",zm2l(size));
+    else
+      emit(f,"\t.space\t%ld\n",zm2l(size));
+    newobj=0; 
+  }
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(section!=BITS&&!zmleq(align,l2zm(1L)))
+    emit(f,even);
+}
+static void new_section(FILE *f,int nsec)
+{
+  if(!f||section==nsec) return;
+  if(TASKING)
+    emit(f,sec_end);
+  section=nsec;
+  if(nsec==HDATA){
+    emit(f,hdataname);
+    strcpy(sec_end,ehdata);
+  }else if(nsec==FDATA){
+    emit(f,fdataname);
+    strcpy(sec_end,efdata);
+  }else if(nsec==NDATA){
+    emit(f,ndataname);
+    strcpy(sec_end,endata);
+  }else if(nsec==HCDATA){
+    emit(f,hcdataname);
+    strcpy(sec_end,ehcdata);
+  }else if(nsec==FCDATA){
+    emit(f,fcdataname);
+    strcpy(sec_end,efcdata);
+  }else if(nsec==NCDATA){
+    emit(f,ncdataname);
+    strcpy(sec_end,encdata);
+  }else if(nsec==HBSS){
+    emit(f,hbssname);
+    strcpy(sec_end,ehbss);
+  }else if(nsec==FBSS){
+    emit(f,fbssname);
+    strcpy(sec_end,efbss);
+  }else if(nsec==NBSS){
+    emit(f,nbssname);
+    strcpy(sec_end,enbss);
+  }else if(nsec==BITS){
+    emit(f,bitsname);
+    strcpy(sec_end,ebits);
+  }
+}
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  char *attr;struct Typ *tv;
+  tv=v->vtyp;
+  while(tv->flags==ARRAY) tv=tv->next;
+  attr=tv->attr;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!TASKING){
+      emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+      emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+    }
+    if(!special_section(f,v)){
+      if((v->vtyp->flags&NQ)==BIT){
+	new_section(f,BITS);
+      }else{
+	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HDATA);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FDATA);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NDATA);
+	  else{
+	    if(HUGE)
+	      new_section(f,HDATA);
+	    else if(LARGE)
+	      new_section(f,FDATA);
+	    else
+	      new_section(f,NDATA);
+	  }
+	}
+	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HCDATA);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FCDATA);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NCDATA);
+	  else{
+	    if(HUGE)
+	      new_section(f,HCDATA);
+	    else if(LARGE)
+	      new_section(f,FCDATA);
+	    else
+	      new_section(f,NCDATA);
+	  }
+	}
+	if(!v->clist){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HBSS);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FBSS);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NBSS);
+	  else{
+	    if(HUGE)
+	      new_section(f,HBSS);
+	    else if(LARGE)
+	      new_section(f,FBSS);
+	    else
+	      new_section(f,NBSS);
+	  }
+	}
+      }
+    }
+    gen_align(f,falign(v->vtyp));
+    if(TASKING){
+      emit(f,"%s%ld\tlabel\t",labprefix,zm2l(v->offset));
+      emit_label_type(f,v);
+      emit(f,"\n");
+    }else{
+      if(dppuse(v,section)>=0)
+        emit(f,"\t.set\t%s%s%ld,%d\n",dppprefix,labprefix,zm2l(v->offset),dppuse(v,section));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }
+  }
+  if(v->storage_class==EXTERN){
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!TASKING){
+	emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+	emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+      }
+      emit(f,"\t%s\t%s%s\n",public,idprefix,v->identifier);
+      if(!special_section(f,v)){
+	if((v->vtyp->flags&NQ)==BIT){
+	  if(f&&section!=BITS){
+	    if(TASKING)
+	      emit(f,sec_end);
+	    strcpy(sec_end,ebits);
+	    emit(f,bitsname);
+	    section=BITS;	  
+	  }
+	}else{
+	  if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+	    if(attr&&strstr(attr,STR_HUGE))
+	      new_section(f,HDATA);
+	    else if(attr&&strstr(attr,STR_FAR))
+	      new_section(f,FDATA);
+	    else if(attr&&strstr(attr,STR_NEAR))
+	      new_section(f,NDATA);
+	    else{
+	      if(HUGE)
+		new_section(f,HDATA);
+	      else if(LARGE)
+		new_section(f,FDATA);
+	      else
+		new_section(f,NDATA);
+	    }
+	  }
+	  if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+	    if(attr&&strstr(attr,STR_HUGE))
+	      new_section(f,HCDATA);
+	    else if(attr&&strstr(attr,STR_FAR))
+	      new_section(f,FCDATA);
+	    else if(attr&&strstr(attr,STR_NEAR))
+	      new_section(f,NCDATA);
+	    else{
+	      if(HUGE)
+		new_section(f,HCDATA);
+	      else if(LARGE)
+		new_section(f,FCDATA);
+	      else
+		new_section(f,NCDATA);
+	    }
+	  }
+	  if(!v->clist){
+	    if(attr&&strstr(attr,STR_HUGE))
+	      new_section(f,HBSS);
+	    else if(attr&&strstr(attr,STR_FAR))
+	      new_section(f,FBSS);
+	    else if(attr&&strstr(attr,STR_NEAR))
+	      new_section(f,NBSS);
+	    else{
+	      if(HUGE)
+		new_section(f,HBSS);
+	      else if(LARGE)
+		new_section(f,FBSS);
+	      else
+		new_section(f,NBSS);
+	    }
+	  }
+	}
+      }
+      gen_align(f,falign(v->vtyp));
+      if(TASKING){
+	emit(f,"%s%s\tlabel\t",idprefix,v->identifier);
+	emit_label_type(f,v);
+	emit(f,"\n");
+      }else{
+        if(dppuse(v,section)>=0){
+          emit(f,"\t.global\t%s%s%s\n",dppprefix,idprefix,v->identifier);
+          emit(f,"\t.set\t%s%s%s,%d\n",dppprefix,idprefix,v->identifier,dppuse(v,section));
+        }
+	emit(f,"%s%s:\n",idprefix,v->identifier);
+      }
+    }else if(strcmp(v->identifier,"__va_start")&&!issfrv(v)&&!isesfrv(v)&&!issfrbitv(v)&&!isesfrbitv(v)){
+      if(TASKING){
+	emit(f,"\textern\t%s%s:",idprefix,v->identifier);
+	emit_label_type(f,v);
+	emit(f,"\n");
+      }else{
+	emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+      }
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if(ISPOINTER(t)){
+    if(p->tree)
+      emit(f,"\t%s\t",TASKING?dct[t&NQ]:vdct[t&NQ]); 
+    if(ISLWORD(t))
+      t=UNSIGNED|LONG;
+    else
+      t=UNSIGNED|SHORT;
+    if(!p->tree)
+      emit(f,"\t%s\t",TASKING?dct[t&NQ]:vdct[t&NQ]);
+  }else{
+    emit(f,"\t%s\t",TASKING?dct[t&NQ]:vdct[t&NQ]);
+  }
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+      if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+      }
+    }else{
+      if(ISLWORD(t)){
+	long l;
+	eval_const(&p->val,t);
+	l=zm2l(zmand(p->val.vmax,l2zm(65535L)));
+	emit(f,"%ld",l);
+	l=zm2l(zmand(zmrshift(p->val.vmax,l2zm(16L)),l2zm(65535L)));
+	emit(f,",%ld",l);
+      }else if((t&NQ)!=BIT)
+	/*FIXME: initialization of bits impossible */
+	emitval(f,&p->val,(t&NU)|UNSIGNED);
+    }
+  }else{
+    int m=p->tree->o.flags;
+    p->tree->o.flags&=~VARADR;
+    emit_obj(f,&p->tree->o,t&NU);
+    p->tree->o.flags=m;
+  }
+  emit(f,"\n");
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+  int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
+  struct obj *bit_obj;char *bit_reg;
+  static int idone;
+  struct obj o,*cc=0;int cc_t;
+  struct IC *p2;
+  if(TINY){
+    ret="ret";
+    call="calla\tcc_uc,";
+    jump="jmpa\tcc_uc,";
+  }else{
+    ret="rets";
+    call="calls";
+    jump="jmps\t";
+  }
+  if(v->tattr&INTERRUPT)
+    ret="reti";
+  if(DEBUG&1) printf("gen_code()\n");
+  if(!v->fi) v->fi=new_fi();
+  v->fi->flags|=ALL_REGS;
+  if(f&&TASKING&&!idone){
+    emit(f,"$EXTEND\n");
+    emit(f,"$MODEL(SMALL)\n");
+    idone=1;
+  }
+  for(p2=p;p2;p2=p2->next) clear_ext_ic(&p2->ext);
+  if(!(g_flags[5]&USEDFLAG)){
+    peephole(p);
+    if(!frame_used) offset=l2zm(0L);
+  }
+  for(c=1;c<=15;c++) regs[c]=regsa[c];
+  regs[16]=0;
+  for(c=1;c<=MAXR;c++){
+    if(regscratch[c]&&(regsa[c]||regused[c])){
+      BSET(regs_modified,c);
+    }
+  }
+  loff=((zm2l(offset)+1)/2)*2;
+  function_top(f,v,loff);
+  usrstackoffset=sysstackoffset=notpopped=dontpop=usrmaxpushed=sysmaxpushed=0;
+  sysstack=usrstack=0;
+  for(;p;pr(f,p),p=p->next){
+    if((p->q1.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      p->q1.flags=VAR;
+      p->q1.v=ISLWORD(p->q1.dtyp)?&fvar:&nvar;
+    }
+    if((p->q2.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      p->q2.flags=VAR;
+      p->q2.v=ISLWORD(p->q2.dtyp)?&fvar:&nvar;
+    }
+    if((p->z.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      p->z.flags=VAR;
+      p->z.v=ISLWORD(p->z.dtyp)?&fvar:&nvar;
+    }
+    if(!TASKING){
+      int rn,rb;char *rs;
+      if(issfr(q1)){
+	rs=strstr(p->q1.v->vattr,"sfr(");
+	sscanf(rs+4,"%i",&rn);
+	if(rn<=255) rn=0xfe00+2*rn;
+	emit(f,"\t.sfr\t%s,%d\n",p->q1.v->identifier,rn);
+      }
+      if(issfr(q2)){
+	rs=strstr(p->q2.v->vattr,"sfr(");
+	sscanf(rs+4,"%i",&rn);
+	if(rn<=255) rn=0xfe00+2*rn;
+	emit(f,"\t.sfr\t%s,%d\n",p->q2.v->identifier,rn);
+      }
+      if(issfr(z)){
+	rs=strstr(p->z.v->vattr,"sfr(");
+	sscanf(rs+4,"%i",&rn);
+	if(rn<=255) rn=0xfe00+2*rn;
+	emit(f,"\t.sfr\t%s,%d\n",p->z.v->identifier,rn);
+      }
+      if(issfrbit(q1)){
+	rs=strstr(p->q1.v->vattr,"sfrbit(");
+	sscanf(rs+7,"%i,%i",&rn,&rb);
+	if(rn<=255) rn=0xfe00+2*rn;
+	emit(f,"\t.sfr\t%s,%d,%d\n",p->q1.v->identifier,rn,rb);
+      }
+      if(issfrbit(q2)){
+	rs=strstr(p->q2.v->vattr,"sfrbit(");
+	sscanf(rs+7,"%i,%i",&rn,&rb);
+	if(rn<=255) rn=0xfe00+2*rn;
+	emit(f,"\t.sfr\t%s,%d,%d\n",p->q2.v->identifier,rn,rb);
+      }
+      if(issfrbit(z)){
+	rs=strstr(p->z.v->vattr,"sfrbit(");
+	sscanf(rs+7,"%i,%i",&rn,&rb);
+	if(rn<=255) rn=0xfe00+2*rn;
+	emit(f,"\t.sfr\t%s,%d,%d\n",p->z.v->identifier,rn,rb);
+      }
+      if(isesfr(q1)){
+	rs=strstr(p->q1.v->vattr,"sfre(");
+	sscanf(rs+5,"%i",&rn);
+	if(rn<=255) rn=0xf000+2*rn;
+	emit(f,"\t.equ\t%s,%d\n",p->q1.v->identifier,rn);
+      }
+      if(isesfr(q2)){
+	rs=strstr(p->q2.v->vattr,"sfre(");
+	sscanf(rs+5,"%i",&rn);
+	if(rn<=255) rn=0xf000+2*rn;
+	emit(f,"\t.equ\t%s,%d\n",p->q2.v->identifier,rn);
+      }
+      if(isesfr(z)){
+	rs=strstr(p->z.v->vattr,"sfre(");
+	sscanf(rs+5,"%i",&rn);
+	if(rn<=255) rn=0xf000+2*rn;
+	emit(f,"\t.equ\t%s,%d\n",p->z.v->identifier,rn);
+      }
+      if(isesfrbit(q1)){
+	rs=strstr(p->q1.v->vattr,"sfrbite(");
+	sscanf(rs+8,"%i,%i",&rn,&rb);
+	if(rn<=255) rn=0xf000+2*rn;
+	emit(f,"\t.sfr\t%s,%d,%d\n",p->q1.v->identifier,rn,rb);
+      }
+      if(isesfrbit(q2)){
+	rs=strstr(p->q2.v->vattr,"sfrbite(");
+	sscanf(rs+8,"%i,%i",&rn,&rb);
+	if(rn<=255) rn=0xf000+2*rn;
+	emit(f,"\t.sfr\t%s,%d,%d\n",p->q2.v->identifier,rn,rb);
+      }
+      if(isesfrbit(z)){
+	rs=strstr(p->z.v->vattr,"sfrbite(");
+	sscanf(rs+8,"%i,%i",&rn,&rb);
+	if(rn<=255) rn=0xf000+2*rn;
+	emit(f,"\t.sfr\t%s,%d,%d\n",p->z.v->identifier,rn,rb);
+      }      
+    }
+
+    c=p->code;t=p->typf;
+    ti2_used=0; short_add=0;
+    if(c==NOP) continue;
+    if(c==ALLOCREG){
+      regs[p->q1.reg]=1;
+      if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=1;
+      BSET(regs_modified,p->q1.reg);
+      continue;
+    }
+    if(c==FREEREG){
+      regs[p->q1.reg]=0;
+      if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=0;
+      continue;
+    }
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+	emit(f,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+	pop(notpopped,0);notpopped=0;cc=0;
+      }
+    }
+    if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
+    if(c==BRA){
+      if(p->typf==exit_label&&!have_frame){
+	emit(f,"\t%s\n",ret);
+      }else{
+	if(t==exit_label) need_return=1;
+	emit(f,"\tjmpr\tcc_uc,%s%d\n",labprefix,t);
+      }
+      cc=0;continue;
+    }
+    if(c==BEQ||c==BNE){
+      if(p->ext.flags==EXT_IC_BTST){
+	if(bit_reg){
+	  emit(f,"\tj%sb\t%s.%ld,%s%d\n",(c==BEQ)?"n":"",bit_reg,p->ext.offset,labprefix,t);
+	}else{
+	  if(!bit_obj) ierror(0);
+	  emit(f,"\tj%sb\t",(c==BEQ)?"n":"");
+	  emit_obj(f,bit_obj,t);emit(f,".%ld,%s%d\n",p->ext.offset,labprefix,t);
+	}
+      }else if(lastcomp==BIT){
+	if(c==BEQ) bit_reverse=1-bit_reverse;
+	emit(f,"\tj%sb\t",(bit_reverse==1)?"n":"");
+	if(bit_obj)
+	  emit_obj(f,bit_obj,t);
+	else
+	  emit(f,"%s",bit_reg);
+	emit(f,",%s%d\n",labprefix,t);
+      }else
+	emit(f,"\tjmpr\tcc_%s,%s%d\n",ccs[c-BEQ],labprefix,t);
+      cc=0;continue;
+    }
+    if(c>BNE&&c<BRA){      
+      if(p->ext.flags==EXT_IC_BTST||lastcomp==BIT) ierror(0);
+      if(lastcomp&UNSIGNED) emit(f,"\tjmpr\tcc_u%s,%s%d\n",ccs[c-BEQ],labprefix,t);
+      else              emit(f,"\tjmpr\tcc_s%s,%s%d\n",ccs[c-BEQ],labprefix,t);
+      cc=0;continue;
+    }
+    if(c==MOVETOREG){
+      move(f,&p->q1,0,0,p->z.reg,SHORT);
+      cc=&p->q1;cc_t=SHORT;continue;
+    }
+    if(c==MOVEFROMREG){
+      move(f,0,p->q1.reg,&p->z,0,SHORT);
+      cc=&p->z;cc_t=SHORT;continue;
+    }
+    
+    if((t&NQ)==DOUBLE) {pric2(stdout,p);ierror(0);}
+    if((t&NQ)==BIT){
+      cc=0;
+      if(c==ASSIGN){
+	if(!isreg(z)&&((p->z.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->z.v))) ierror(0);
+	move(f,&p->q1,0,&p->z,0,t);
+	continue;
+      }
+      if(c==COMPARE){
+	if(!isconst(q2)){
+	  if(!isreg(q2)&&((p->q2.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->q2.v))) ierror(0);
+	  bit_reg="PSW.1";bit_obj=0;lastcomp=BIT;bit_reverse=1;
+	  if(isesfrbit(q1)){
+	    if(!isesfrbit(q2)&&!isreg(q2)){
+	      move(f,&p->q1,0,0,ti,t);
+	      emit(f,"\tbcmp\t%s.0,",regnames[ti]);
+	      emit_obj(f,&p->q2,t);emit(f,"\n");
+	      continue;
+	    }else
+	      emit(f,"\textr\t#1\n");
+	  }else if(isesfrbit(q2)){
+	    if(!isreg(q1)){
+	      move(f,&p->q2,0,0,ti,t);
+	      emit(f,"\tbcmp\t");
+	      emit_obj(f,&p->q1,t);
+	      emit(f,",%s.0\n",regnames[ti]);
+	      continue;
+	    }else
+	      emit(f,"\textr\t#1\n");
+	  }
+	  emit(f,"\tbcmp\t");emit_obj(f,&p->q1,t);
+	  emit(f,",");emit_obj(f,&p->q2,t);emit(f,"\n");
+	}else{
+	  bit_reg=0;bit_obj=&p->q1;lastcomp=BIT;
+	  eval_const(&p->q2.val,t);
+	  if(ISNULL())
+	    bit_reverse=0;
+	  else
+	    bit_reverse=1;
+	  if(isesfrbit(q1)) emit(f,"\textr\t#1\n");
+	}
+	continue;
+      }
+      if(c==TEST){
+	bit_reg=0;bit_obj=&p->q1;bit_reverse=0;lastcomp=BIT;
+	if(isesfrbit(q1)) emit(f,"\textr\t#1\n");
+	continue;
+      }
+      if(c==AND||c==OR||c==XOR){
+	char *s;
+	if(compare_objects(&p->z,&p->q2)){
+	  struct obj m;
+	  m=p->q1;p->q1=p->q2;p->q2=m;
+	}
+	if(!compare_objects(&p->q1,&p->z))
+	  move(f,&p->q1,0,&p->z,0,t);
+	/*FIXME: const, esfr etc. */
+	if(c==AND) s="band";
+	else if(c==OR) s="bor";
+	else s="bxor";
+	if(isesfrbit(q2)&&!isesfrbit(z)&&!isreg(z)){
+	  move(f,&p->q2,0,0,ti,t);
+	  emit(f,"\t%s\t",s);
+	  emit_obj(f,&p->z,t);
+	  emit(f,",%s.0\n",regnames[ti]);
+	}else if(isesfrbit(z)&&!isesfrbit(q2)&&!isreg(q2)){
+	  move(f,&p->q2,0,0,ti,t);
+	  emit(f,"\textr\t#1\n");
+	  emit(f,"\t%s\t",s);
+	  emit_obj(f,&p->z,t);
+	  emit(f,",%s.0\n",regnames[ti]);
+	}else{
+	  if(isesfrbit(z)) emit(f,"\textr\t#1\n");
+	  emit(f,"\t%s\t",s);
+	  emit_obj(f,&p->z,t);emit(f,",");
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+	continue;
+      }
+      if(c!=CONVERT) ierror(0);
+    }
+
+    if(c==TEST){
+      lastcomp=t;
+      if(p->ext.flags==EXT_IC_CMPIA){
+	if(p->ext.offset<0)
+	  emit(f,"\tsub\t%s,#%ld\n",regnames[p->ext.r],-p->ext.offset);
+	else
+	  emit(f,"\tadd\t%s,#%ld\n",regnames[p->ext.r],p->ext.offset);
+	cc=0;continue;
+      }
+      if(p->ext.flags==EXT_IC_CMPIB){
+	if(p->ext.offset<0)
+	  emit(f,"\tcmpd%ld\t%s,#0\n",-p->ext.offset,regnames[p->ext.r]);
+	else
+	  emit(f,"\tcmpi%ld\t%s,#0\n",p->ext.offset,regnames[p->ext.r]);
+	cc=0;continue;
+      }
+      if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+	continue;
+      }
+      p->code=c=COMPARE;
+      gval.vmax=l2zm(0L);
+      p->q2.flags=KONST;
+      eval_const(&gval,MAXINT);
+      insert_const(&p->q2.val,t);
+    } 
+    if(c==COMPARE&&isconst(q1)){
+      struct IC *p2;
+      o=p->q1;p->q1=p->q2;p->q2=o;
+      p2=p->next;
+      while(p2&&p2->code==FREEREG) p2=p2->next;
+      if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+      if(p2->code==BLT) p2->code=BGT;
+      else if(p2->code==BGT) p2->code=BLT;
+      else if(p2->code==BLE) p2->code=BGE;
+      else if(p2->code==BGE) p2->code=BLE;
+    }
+    if(c==COMPARE&&p->ext.flags==EXT_IC_CMPIA){
+      long l;
+      if(!isconst(q2)) ierror(0);
+      eval_const(&p->q2.val,t);
+      l=zm2l(vmax);
+      if(p->ext.offset<0)
+	emit(f,"\tcmpd%ld\t%s,#%ld\n",-p->ext.offset,regnames[p->ext.r],l-p->ext.offset);
+      else
+	emit(f,"\tcmpi%ld\t%s,#%ld\n",p->ext.offset,regnames[p->ext.r],l-p->ext.offset);
+      cc=0;lastcomp=t;continue;
+    }
+    if(c==COMPARE&&p->ext.flags==EXT_IC_CMPIB){
+pric2(stdout,p);
+      if(p->ext.offset<0)
+	emit(f,"\tcmpd%ld\t%s,",-p->ext.offset,regnames[p->ext.r]);
+      else
+	emit(f,"\tcmpi%ld\t%s,",p->ext.offset,regnames[p->ext.r]);
+      emit_obj(f,&p->q2,t);emit(f,"\n");
+      cc=0;lastcomp=t;continue;
+    }
+    if(c==COMPARE&&isconst(q2)){
+      eval_const(&p->q2.val,t);
+      if(ISNULL()){
+	if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+	  lastcomp=t;continue;
+	}
+      }
+    }
+
+    if(c==SUBPFP){
+      p->code=c=SUB;
+      if((p->typf2&NQ)==NPOINTER) p->typf=t=INT;
+      else if((p->typf2&NQ)==HPOINTER) p->typf=t=LONG;
+      else ierror(0);
+      if((p->typf2&NQ)==NPOINTER){
+	cc=&p->z;cc_t=NPOINTER;
+      }else{
+	cc=0;
+      }
+    }
+
+    if(c==ADDI2P||c==SUBIFP){
+      /*if(c==ADDI2P) p->code=c=ADD; else p->code=c=SUB;*/
+      if((p->typf2&NQ)!=HPOINTER){
+	p->typf=t=(UNSIGNED|SHORT);
+	short_add=2;
+	if(isreg(q2)&&reg_pair(p->q2.reg,&rp)){
+	  /*FIXME:warning*/
+	  p->q2.reg=rp.r1;
+	}
+      }else if(ISHWORD(t)){
+	p->typf=t=(UNSIGNED|LONG);
+	short_add=1;
+      }
+      if((p->typf2&NQ)==NPOINTER){
+	cc=&p->z;cc_t=NPOINTER;
+      }else{
+	cc=0;
+      }      
+    }
+    /* try to avoid z==q2 */
+    if((c==ADD||c==AND||c==OR||c==XOR||(c==ADDI2P&&!short_add))&&compare_objects(&p->q2,&p->z)){
+      o=p->q1;p->q1=p->q2;p->q2=o;
+    }    
+    /* DREFOBJs nach q2, um evtl. op reg,[ri] zu nutzen */
+    if(c==ADD||c==MULT||c==OR||c==AND||c==XOR){
+      if(isreg(q2)&&scratchreg(p->q2.reg,p)){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+      }
+      if((p->q1.flags&DREFOBJ)&&(!(p->q1.flags&REG)||p->q1.reg<=4)&&(!p->q1.am||p->q1.am->flags!=IMM_IND)){
+	if(!((p->q2.flags&DREFOBJ)&&(!p->q2.am||p->q2.am->flags!=IMM_IND))){
+	  struct obj o;
+	  o=p->q1;p->q1=p->q2;p->q2=o;
+	}
+      }
+    }
+    /*FIXME: ICs mit mehreren Typen*/
+    if(switch_IC(p)&&isreg(z)){
+      reg=p->z.reg;
+    }else if(isreg(q1)&&(!ISLWORD(t)||reg_pair(p->q1.reg,&rp))&&(scratchreg(p->q1.reg,p)||(isreg(z)&&p->z.reg==p->q1.reg)||(!ISLWORD(t)&&c==COMPARE))){
+      reg=p->q1.reg;
+    }else{
+      if(ISLWORD(ztyp(p))){
+	tmp1=ti;tmp2=ti2;ti2_used=1;
+	BSET(regs_modified,ti);
+	BSET(regs_modified,ti2);
+	reg=MTMP1;
+      }else{
+	if((t&NQ)==CHAR){
+	  BSET(regs_modified,tp);
+	  reg=tp;
+	}else{
+	  BSET(regs_modified,ti);
+	  reg=ti;
+	}
+      }
+    }
+    /* op reg,mem/const */
+    if(issfr(z)&&(c==ADD||c==SUB||c==AND||c==OR||c==XOR||c==ADDI2P)&&(compare_objects(&p->q1,&p->z)||((c!=SUB&&c!=SUBIFP)&&compare_objects(&p->q2,&p->z)))){
+      char *s;
+      if(!compare_objects(&p->q1,&p->z)){o=p->q1;p->q1=p->q2;p->q2=o;}
+      if((p->q2.flags&(KONST|DREFOBJ))==KONST||((p->q2.flags&(VAR|DREFOBJ))==VAR&&ISSTATIC(p->q2.v))){
+	if(c>=OR&&c<=AND){
+	  s=logicals[c-OR];
+	}else{
+	  if(c==ADDI2P)
+	    s=arithmetics[ADD-LSHIFT];
+	  else if(c==SUBIFP)
+	    s=arithmetics[SUB-LSHIFT];
+	  else
+	    s=arithmetics[c-LSHIFT];
+	}
+	if((p->q2.flags&VAR)&&ISFAR(p->q2.v)){
+	  emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->q2,t);emit(f,",#1\n");
+	}
+	emit(f,"\t%s%s\t",s,(t&NQ)==CHAR?"b":"");
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+	emit_obj(f,&p->q2,t);
+	emit(f,"\n");
+	cc=&p->z;cc_t=t;
+	continue;
+      }
+    }
+    /* op mem,reg */
+    if((c==ADD||c==SUB||c==AND||c==OR||c==XOR||c==ADDI2P)&&(compare_objects(&p->q1,&p->z)||((c!=SUB&&c!=SUBIFP)&&compare_objects(&p->q2,&p->z)))&&(p->z.flags&(VAR|VARADR|DREFOBJ|REG))==VAR&&ISSTATIC(p->z.v)){
+      char *s;
+      if(!compare_objects(&p->q1,&p->z)){o=p->q1;p->q1=p->q2;p->q2=o;}
+      cc=&p->z;cc_t=t;
+      if(isreg(q2)){
+	reg=p->q2.reg;
+      }else if(issfr(q2)){
+	reg=0;
+      }else if(isconst(q2)){
+	eval_const(&p->q2.val,t);
+	if(ISLWORD(t)){
+	  unsigned long ul;
+	  reg=MTMP1;
+	  if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&zumeqto(vumax,ul2zum(1UL))){
+	    if(c==ADD) c=SUB;
+	    else if(c==SUB) c=ADD;
+	    else if(c==ADDI2P) c=SUBIFP;
+	    else c=ADDI2P;
+	    tmp1=ONES;tmp2=ONES;
+	  }else{
+	    ul=zum2ul(zumand(vumax,ul2zum(65535UL)));
+	    if(ul==0) tmp1=ZEROS;
+	    else if(ul==0xffff) tmp1=ONES;
+	    else{
+	      BSET(regs_modified,ti);
+	      tmp1=ti;
+	      emit(f,"\tmov\t%s,#%lu\n",regnames[ti],ul);
+	    }
+	    ul=zum2ul(zumand(zumrshift(vumax,ul2zum(16UL)),ul2zum(65535UL)));
+	    if(ul==0) tmp2=ZEROS;
+	    else if(ul==0xffff) tmp2=ONES;
+	    else{
+	      BSET(regs_modified,ti2);
+	      tmp2=ti2;
+	      emit(f,"\tmov\t%s,#%lu\n",regnames[ti2],ul);
+	    }
+	  }
+	}else{
+	  long l;
+	  if(c==OR&&(l=pof2(vumax))&&ISBADDR(p->z.v)){
+	    emit(f,"\tbset\t");emit_obj(f,&p->z,t);
+	    emit(f,".%ld\n",l-1);
+	    cc=0;continue;
+	  }else if(c==AND&&(l=pof2(zumkompl(vumax)))&&ISBADDR(p->z.v)){
+	    emit(f,"\tbclr\t");emit_obj(f,&p->z,t);
+	    emit(f,".%ld\n",l-1);
+	    cc=0;continue;
+	  }else if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&zumeqto(vumax,ul2zum(1UL))){
+	    if(c==ADD) c=SUB; 
+	    else if(c==SUB) c=ADD;
+	    else if(c==ADDI2P) c=SUBIFP;
+	    else c=ADDI2P;
+	    reg=ONES;
+	  }else{
+	    if(zumeqto(vumax,ul2zum(0UL))) reg=ZEROS;
+	    else if(zumeqto(vumax,ul2zum(0xffffUL))) reg=ONES;
+	    else{
+	      BSET(regs_modified,tp);
+	      reg=tp;
+	      move(f,&p->q2,0,0,reg,t);
+	    }
+	  }
+	}
+      }else{
+	/*FIXME:ones/zeros nutzen*/
+	if(ISLWORD(t)){
+	  tmp1=ti;tmp2=ti2;
+	  BSET(regs_modified,ti);
+	  BSET(regs_modified,ti2);
+	  reg=MTMP1;
+	}else{
+	  BSET(regs_modified,tp);
+	  reg=tp;
+	}
+	if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ){
+	  if(ISLWORD(p->q2.dtyp)){
+	    tmp3=ti2;tmp4=ti;
+	    BSET(regs_modified,ti);
+	    BSET(regs_modified,ti2);
+	    p->q2.flags&=~DREFOBJ;
+	    move(f,&p->q2,0,0,MTMP2,HPOINTER);
+	    p->q2.flags=(REG|DREFOBJ);p->q2.reg=MTMP2;
+	  }else if(!(p->q2.flags&KONST)){
+	    BSET(regs_modified,ti);
+	    move(f,&p->q2,0,0,ti,NPOINTER);
+	    p->q2.flags=REG;p->q2.reg=ti;
+	  }
+	}
+	move(f,&p->q2,0,0,reg,t);
+      }
+      if(c>=OR&&c<=AND){
+	s=logicals[c-OR];
+      }else{
+	if(c==ADDI2P)
+	  s=arithmetics[ADD-LSHIFT];
+	else if(c==SUBIFP)
+	  s=arithmetics[SUB-LSHIFT];
+	else
+	  s=arithmetics[c-LSHIFT];
+      }
+      if(reg&&reg_pair(reg,&rp)){
+	if(ISFAR(p->z.v)){
+	  emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->z,t);emit(f,",#2\n");
+	}
+	emit(f,"\t%s\t",s);
+	emit_obj(f,&p->q1,t);emit(f,",%s\n",regnames[rp.r1]);
+	s=longcmd(s);
+	p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm(2L));
+	emit(f,"\t%s\t",s);
+	emit_obj(f,&p->q1,t);emit(f,",%s\n",regnames[rp.r2]);
+	p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm(2L));
+      }else{
+	if(ISFAR(p->z.v)){
+	  emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->z,t);emit(f,",#1\n");
+	}
+	emit(f,"\t%s%s\t",s,(t&NQ)==CHAR?"b":"");
+	emit_obj(f,&p->q1,t);
+	if(reg)
+	  emit(f,",%s\n",((t&NQ)==CHAR&&reg<=MAXR)?bregnames[reg]:regnames[reg]);
+	else{
+	  emit(f,",");
+	  emit_obj(f,&p->q2,t);
+	  emit(f,"\n");
+	}
+      }
+      cc=&p->z;cc_t=t;
+      continue;
+    }
+    if(p->ext.flags==EXT_IC_BTST){
+      if(isreg(q1)){bit_reg=regnames[p->q1.reg];continue;}
+      if((p->q1.flags&(VAR|VARADR|DREFOBJ|REG))==VAR&&ISSTATIC(p->q1.v)&&ISBADDR(p->q1.v)){
+	bit_reg=0;bit_obj=&p->q1;
+	continue;
+      }
+    }
+
+    if((c==MULT||((c==DIV||c==MOD)&&(p->typf&UNSIGNED)))&&isconst(q2)){
+      long ln;
+      eval_const(&p->q2.val,t);
+      if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	if(ln=pof2(vumax)){
+	  if(c==MOD){
+	    vmax=zmsub(vmax,l2zm(1L));
+	    p->code=AND;
+	  }else{
+	    vmax=l2zm(ln-1);
+	    if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+	  }
+	  c=p->code;
+	  gval.vmax=vmax;
+	  eval_const(&gval,MAXINT);
+	  if(c==AND){
+	    insert_const(&p->q2.val,t);
+	  }else{
+	    insert_const(&p->q2.val,INT);
+	    p->typf2=INT;
+	  }
+	}
+      }
+    }
+    if(ISLWORD(t)&&(c==MULT||c==DIV||c==MOD)){
+      if(lib_larith(f,p)) continue;
+    }
+
+    if(!p->q1.am&&(p->q1.flags&DREFOBJ)){
+      if(!(p->q1.flags&(REG))){
+	if(ISLWORD(p->q1.dtyp)){
+	  tmp3=ti2;tmp4=ti;ti2_used=1;
+	  BSET(regs_modified,ti);
+	  BSET(regs_modified,ti2);
+	  p->q1.flags&=~DREFOBJ;
+	  move(f,&p->q1,0,0,MTMP2,FPOINTER);
+	  p->q1.reg=MTMP2;
+	  p->q1.flags=(REG|DREFOBJ);
+	}else if(!(p->q1.flags&KONST)){
+	  BSET(regs_modified,ti);
+	  p->q1.flags&=~DREFOBJ;
+	  move(f,&p->q1,0,0,ti,NPOINTER);
+	  p->q1.reg=ti;
+	  p->q1.flags=(REG|DREFOBJ);
+	}
+      }
+      if(p->q2.flags){
+	move(f,&p->q1,0,0,reg,q2typ(p));/*FIXME*/
+	if((!isreg(q1)||p->q1.reg!=reg)&&c==COMPARE&&!ISLWORD(t)&&isconst(q2)){
+	  /* avoid cmp, if not needed */
+	  eval_const(&p->q2.val,t);
+	  if(ISNULL()){
+	    lastcomp=t;continue;
+	  }
+	}
+      }
+    }else{
+      if(p->q2.flags){
+	move(f,&p->q1,0,0,reg,q1typ(p));/*FIXME*/
+	if((!isreg(q1)||p->q1.reg!=reg)&&c==COMPARE&&!ISLWORD(t)&&isconst(q2)){
+	  /* avoid cmp, if not needed */
+	  eval_const(&p->q2.val,t);
+	  if(ISNULL()){
+	    lastcomp=t;continue;
+	  }
+	}
+      }
+    }
+    if(p->ext.flags==EXT_IC_BTST){ bit_reg=regnames[reg];continue;}
+    if(!p->q2.am&&(p->q2.flags&DREFOBJ)){
+      if(!(p->q2.flags&(REG))||p->q2.reg>4){
+	if(ISLWORD(p->q2.dtyp)){
+	  if(ti2_used) tmp4=get_reg(f,p); else tmp4=ti2;
+	  tmp3=tp;
+	  BSET(regs_modified,tmp3);
+	  BSET(regs_modified,tmp4);
+	  p->q2.flags&=~DREFOBJ;
+	  move(f,&p->q2,0,0,MTMP2,FPOINTER);
+	  p->q2.reg=MTMP2;
+	  p->q2.flags=(REG|DREFOBJ);
+	}else if(!(p->q2.flags&KONST)){
+	  BSET(regs_modified,tp);
+	  p->q2.flags&=~DREFOBJ;
+	  move(f,&p->q2,0,0,tp,NPOINTER);
+	  p->q2.flags=(REG|DREFOBJ);
+	  p->q2.reg=tp;
+	}
+      }
+    }
+    if(c==CONVERT&&!must_convert(p->typf,p->typf2,0)){
+      p->code=c=ASSIGN;
+      p->q2.val.vmax=sizetab[p->typf&NQ];
+    }
+
+    if(c==CONVERT){
+      int to=p->typf2&NU;
+      if(to==INT) to=SHORT;
+      if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
+      if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+      if((t&NU)==INT) t=SHORT;
+      if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+      if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+      if((to&NQ)<=LONG&&(t&NQ)<=LONG){
+	if((to&NQ)<=(t&NQ)){
+	  if((to&NQ)==(t&NQ)) ierror(0);
+	  if((to&NQ)==BIT){
+	    cc=0;
+	    if((p->q1.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->q1.v)) ierror(0);
+	    if(reg_pair(reg,&rp)){
+	      emit(f,"\tmov\t%s,#0\n",regnames[rp.r1]);
+	      emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+	      emit(f,"\tbmov\t%s.0,",regnames[rp.r1]);
+	      emit_obj(f,&p->q1,t);emit(f,"\n");
+	    }else{
+	      emit(f,"\tmov\t%s,#0\n",regnames[reg]);
+	      emit(f,"\tbmov\t%s.0,",regnames[reg]);
+	    }
+	    emit_obj(f,&p->q1,t);emit(f,"\n");
+	    save_result(f,reg,p,t);
+	    continue;
+	  }
+	  if((p->q1.flags&(VAR|REG|VARADR))==VAR&&ISSTATIC(p->q1.v)&&ISFAR(p->q1.v)){
+	    emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->q1,t);
+	    emit(f,",#1\n");
+	  }
+	  qp.SEG=0;
+	  if(!p->q1.am&&(p->q1.flags&DREFOBJ)&&reg_pair(p->q1.reg,&qp))
+	    emit(f,"\texts\t%s,#1\n",regnames[qp.SEG]);
+	  if(p->q1.am&&reg_pair(p->q1.am->base,&qp))
+	    emit(f,"\texts\t%s,#1\n",regnames[qp.SEG]);
+	  if(reg_pair(reg,&rp)){
+	    cc=0;
+	    if((to&NQ)==CHAR){
+	      if(isreg(q1)||((p->q1.flags&(VAR|VARADR|DREFOBJ))==VAR&&ISSTATIC(p->q1.v))){
+		emit(f,"\tmovb%c\t%s,",(to&UNSIGNED)?'z':'s',regnames[rp.r1]);
+		if((to&NQ)==CHAR&&isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+		else if(qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+		else emit_obj(f,&p->q1,to);
+		emit(f,"\n");
+	      }else{
+		BSET(regs_modified,tp);
+		emit(f,"\tmovb\t%s,",bregnames[tp]);
+		if(isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+		else if(!p->q1.am&&qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+		else emit_obj(f,&p->q1,to);
+		emit(f,"\n");
+		emit(f,"\tmovb%c\t%s,%s\n",(to&UNSIGNED)?'z':'s',regnames[rp.r1],bregnames[tp]);
+	      }
+	    }else{
+	      emit(f,"\tmov\t%s,",regnames[rp.r1]);
+	      if(qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+	      else emit_obj(f,&p->q1,to);
+	      emit(f,"\n");
+	    }
+	    if(to&UNSIGNED)
+	      emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+	    else
+	      emit(f,"\tmov\t%s,%s\n\tashr\t%s,#15\n",regnames[rp.r2],regnames[rp.r1],regnames[rp.r2]);
+
+	  }else{
+	    cc=&p->z;cc_t=t;
+	    if(isreg(q1)||((p->q1.flags&(VAR|VARADR|DREFOBJ))==VAR&&ISSTATIC(p->q1.v))){
+	      emit(f,"\tmovb%c\t%s,",(to&UNSIGNED)?'z':'s',regnames[reg]);
+	      if((to&NQ)==CHAR&&isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+	      else if(qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+	      else emit_obj(f,&p->q1,to);
+	      emit(f,"\n");
+	    }else{
+	      BSET(regs_modified,tp);
+	      emit(f,"\tmovb\t%s,",bregnames[tp]);
+	      if(isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+	      else if(!p->q1.am&&qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+	      else emit_obj(f,&p->q1,to);
+	      emit(f,"\n");
+	      emit(f,"\tmovb%c\t%s,%s\n",(to&UNSIGNED)?'z':'s',regnames[reg],bregnames[tp]);
+	    }	    
+	  }
+	  save_result(f,reg,p,t);
+	  continue;
+	}else{
+	  if((t&NQ)==BIT){
+	    if(!isreg(z)&&((p->z.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->z.v))) ierror(0);
+	    if(isreg(q1)){
+	      reg=p->q1.reg;
+	    }else{
+	      if(ISLWORD(to)){
+		tmp1=ti;tmp2=ti2;
+		BSET(regs_modified,ti);
+		BSET(regs_modified,ti2);
+		reg=MTMP1;
+	      }
+	    }
+	    move(f,&p->q1,0,0,reg,to);
+	    if(reg_pair(reg,&rp)){
+	      if(isreg(q1)&&!scratchreg(reg,p)){
+		BSET(regs_modified,ti);
+		emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[rp.r1]);
+		emit(f,"\tor\t%s,%s\n",regnames[ti],regnames[rp.r2]);
+	      }else
+		emit(f,"\tor\t%s,%s\n",regnames[rp.r1],regnames[rp.r2]);
+	    }else{
+	      if(isreg(q1)) emit(f,"\tcmp%s\t%s,#0\n",(to&NQ)==CHAR?"b":"",(to&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+	    }
+	    emit(f,"\tbmovn\t");
+	    if(isesfrbit(z))
+	      emit(f,"%s.0",regnames[ti]);
+	    else
+	      emit_obj(f,&p->z,t);
+	    emit(f,",PSW.3\n");
+	    if(isesfrbit(z)){
+	      emit(f,"\textr\t#1\n");
+	      emit(f,"\tbmov\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",%s.0\n",regnames[ti]);
+	    }
+	    cc=0;continue;
+	  }
+	  cc=&p->z;cc_t=t;
+	  if(ISLWORD(to)){
+	    if(isreg(q1)) {reg_pair(p->q1.reg,&rp);p->q1.reg=rp.r1;}
+	    to=SHORT;
+	  }
+	  if(isreg(q1)&&regok(p->q1.reg,t,0)) reg=p->q1.reg;
+	  if(isreg(z)) reg=p->z.reg;
+	  if(!regok(reg,t,0)){
+	    reg=tp;
+	    BSET(regs_modified,tp);
+	  }
+	  move(f,&p->q1,0,0,reg,to);
+	  save_result(f,reg,p,t);
+	}
+	continue;
+      }
+      ierror(0);
+    }
+    if(c==MINUS||c==KOMPLEMENT){
+      move(f,&p->q1,0,0,reg,t);
+      if(reg_pair(reg,&rp)){
+	emit(f,"\t%s\t%s\n",(c==MINUS?"neg":"cpl"),regnames[rp.r1]);
+	if(c==MINUS) emit(f,"\taddc\t%s,#0\n",regnames[rp.r2]);
+	emit(f,"\t%s\t%s\n",(c==MINUS?"neg":"cpl"),regnames[rp.r2]);
+	cc=0;
+      }else{
+	emit(f,"\t%s%s\t%s\n",(c==MINUS?"neg":"cpl"),x_t[t&NQ],regnames[reg]);
+	cc=&p->z;cc_t=t;
+      }
+      save_result(f,reg,p,t);
+      continue;
+    }
+    if(c==SETRETURN){
+      if(p->z.reg){
+	move(f,&p->q1,0,0,p->z.reg,t);
+	BSET(regs_modified,p->z.reg);
+      }
+      cc=0; /* probably not needed */
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+	if(!isreg(z)||p->z.reg!=p->q1.reg){ cc=&p->z;cc_t=t;}
+	save_result(f,p->q1.reg,p,t);
+      }
+      continue;
+    }
+    if(c==CALL){
+      int reg,jmp=0;long csstack=0,custack=0;
+      cc=0;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	long va_off=loff-usrstackoffset+pushedsize+zm2l(va_offset(v));
+	emit(f,"\tmov\t%s,%s\n",regnames[r4],regnames[sp]);
+	if(va_off)
+	  emit(f,"\tadd\t%s,#%ld\n",regnames[r4],va_off);
+	BSET(regs_modified,r4);
+	if(LARGE||HUGE){
+	  emit(f,"\tmov\t%s,#0\n",regnames[r5]);
+	  BSET(regs_modified,r5);
+	}
+	continue;
+      }
+      if(stack_valid){
+        int i;
+        if(p->call_cnt<=0){
+          err_ic=p;if(f) error(320);
+          stack_valid=0;
+        }
+        for(i=0;stack_valid&&i<p->call_cnt;i++){
+          if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+	    if(p->call_list[i].v->fi->stack1>custack) custack=p->call_list[i].v->fi->stack1;
+	    if(p->call_list[i].v->fi->stack2>csstack) csstack=p->call_list[i].v->fi->stack2;
+          }else{
+            err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+            stack_valid=0;
+          }
+        }
+      }
+      if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	callee_push(custack,csstack);
+      }else{
+	if(usrstackoffset==0&&!have_frame&&!(v->tattr&INTERRUPT)){
+	  struct IC *p2;
+	  jmp=1;
+	  for(p2=p->next;p2;p2=p2->next){
+	    if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL&&
+	       (p2->code!=GETRETURN||(p2->z.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)&&
+	       (p2->code!=SETRETURN||(p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)){
+	      jmp=0;break;
+	    }
+	  }
+	}
+	if(p->q1.flags&DREFOBJ){
+	  int clabel=++label;
+	  if(ISLWORD(p->q1.dtyp)){
+	    int tmp;
+	    if(!ti2_used) tmp=ti2; else tmp=tp;
+	    BSET(regs_modified,tmp);
+	    emit(f,"\tmov\t%s,#SEG %s%d\n",regnames[tmp],labprefix,clabel);
+	    emit(f,"\tpush\t%s\n",regnames[tmp]);
+	    emit(f,"\tmov\t%s,#SOF %s%d\n",regnames[tmp],labprefix,clabel);
+	    emit(f,"\tpush\t%s\n",regnames[tmp]);
+	    push(0,4);
+	  }
+	  if(!(p->q1.flags&REG)) ierror(0);
+	  reg=p->q1.reg;
+	  p->q1.flags&=~DREFOBJ;
+	  if(!ISLWORD(p->q1.dtyp)){
+	    emit(f,"\tcalli\tcc_uc,[%s]\n",regnames[reg]);
+	    push(0,2);
+	    callee_push(custack,csstack);
+	    pop(0,2);
+	  }else{
+	    if(!reg_pair(reg,&rp)) ierror(0);
+	    emit(f,"\tpush\t%s\n",regnames[rp.r2]);
+	    emit(f,"\tpush\t%s\n",regnames[rp.r1]);
+	    push(0,4);
+	    callee_push(custack,csstack);
+	    emit(f,"\trets\n");
+	    emit(f,"%s%d:\n",labprefix,clabel);
+	    pop(0,8);
+	  }
+	}else{
+	  if(jmp){
+	    emit(f,"\t%s",jump);
+	    if(!need_return) ret=TASKING?"retv":"";
+	    callee_push(custack,csstack);
+	  }else{
+	    emit(f,"\t%s\t",call);
+	    if(TINY)
+	      push(0,2);
+	    else
+	      push(0,4);
+	    callee_push(custack,csstack);
+	    if(TINY)
+	      pop(0,2);
+	    else
+	      pop(0,4);
+	  }
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+      }
+      if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+	notpopped+=zm2l(p->q2.val.vmax);
+	dontpop-=zm2l(p->q2.val.vmax);
+	if(!(g_flags[2]&USEDFLAG)&&usrstackoffset==-notpopped){
+	  /*  Entfernen der Parameter verzoegern  */
+	}else{
+	  emit(f,"\tadd\t%s,#%ld\n",regnames[sp],zm2l(p->q2.val.vmax));
+	  pop(zm2l(p->q2.val.vmax),0);
+	  notpopped-=zm2l(p->q2.val.vmax);cc=0;
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+      if(!ISSCALAR(t)||!zmeqto(p->q2.val.vmax,sizetab[t&NQ])||!zmleq(p->q2.val.vmax,l2zm(4L))){
+	int alq,alz,rq,rz;unsigned long size;
+	cc=0;
+	size=zm2l(p->q2.val.vmax);
+	/*FIXME: check for (s)huge */
+	if(malign[t&NQ]==1){
+	  alq=alignment(&p->q1);
+	  alz=alignment(&p->z);
+	}else{
+	  alq=alz=0;
+	}
+	if(size==1||(size==2&&alq==0&&alz==0)){
+	  if(c==PUSH&&zm2l(p->z.val.vmax)==1){
+	    emit(f,"\tsub\t%s,#1\n",regnames[sp]);
+	    push(1,0);size=1;
+	  }
+	  BSET(regs_modified,tp);
+	  move(f,&p->q1,0,0,tp,size==1?CHAR:SHORT);
+	  if(c==PUSH){
+	    emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[tp]);
+	    push(size,0);
+	  }else
+	    save_result(f,tp,p,size==1?CHAR:SHORT);
+	  continue;
+	}
+	if(size==4&&alq==0&&alz==0){
+	  tmp1=ti;tmp2=ti2;
+	  BSET(regs_modified,ti);
+	  BSET(regs_modified,ti2);
+	  move(f,&p->q1,0,0,MTMP1,LONG);
+	  if(c==PUSH){
+	    emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[tmp2]);
+	    emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[tmp1]);
+	    push(4,0);
+	  }else
+	    save_result(f,MTMP1,p,LONG);
+	  continue;
+	}
+	if(p->q1.am){
+	  if(p->q1.am->flags!=IMM_IND) ierror(0);
+	  if(!scratchreg(p->q1.am->base,p)){
+	    BSET(regs_modified,ti);
+	    emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[p->q1.am->base]);
+	    rq=ti;
+	  }else
+	    rq=p->q1.am->base;
+	  emit(f,"\tadd\t%s,#%ld",regnames[rq],p->q1.am->offset);
+	  if(p->q1.am->v){
+	    if(p->q1.am->v->storage_class==EXTERN)
+	      emit(f,"+%s%s\n",idprefix,p->q1.am->v->identifier);
+
+	    else
+	      emit(f,"+%s%ld\n",labprefix,zm2l(p->q1.am->v->offset));
+	  }
+	  emit(f,"\n");
+	}else if(p->q1.flags&REG){
+	  if(scratchreg(p->q1.reg,p)){
+	    rq=p->q1.reg;
+	  }else{
+	    BSET(regs_modified,ti);
+	    emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[p->q1.reg]);
+	    rq=ti;
+	  }
+	}else if((p->q1.flags&VAR)&&ISSTATIC(p->q1.v)){
+	  int m=p->q1.flags;
+	  rq=ti;
+	  BSET(regs_modified,ti);
+	  if(p->q1.flags&DREFOBJ)
+	    p->q1.flags&=~DREFOBJ;
+	  else
+	    p->q1.flags|=VARADR;
+	  move(f,&p->q1,0,0,ti,NPOINTER);
+	  p->q1.flags&=~VARADR;
+	}else{
+	  BSET(regs_modified,ti);
+	  rq=ti;
+	  emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[sp]);
+	  if(voff(&p->q1))
+	    emit(f,"\tadd\t%s,#%ld\n",regnames[ti],voff(&p->q1));
+	}
+	if(!p->z.flags){
+	  /* PUSH */
+	  emit(f,"\tsub\t%s,#%lu\n",regnames[sp],size);
+	  emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[sp]);
+	  rz=ti2;
+	  push(size,0);
+	  BSET(regs_modified,ti2);
+	}else if(p->z.am){
+	  if(p->z.am->flags!=IMM_IND) ierror(0);
+	  if(!scratchreg(p->z.am->base,p)){
+	    BSET(regs_modified,ti2);
+	    emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[p->z.am->base]);
+	    rz=ti2;
+	  }else
+	    rz=p->z.am->base;
+	  emit(f,"\tadd\t%s,#%ld",regnames[rz],p->z.am->offset);
+	  if(p->z.am->v){
+	    if(p->z.am->v->storage_class==EXTERN)
+	      emit(f,"+%s%s",idprefix,p->z.am->v->identifier);
+	    else
+	      emit(f,"%+s%ld",labprefix,zm2l(p->z.am->v->offset));
+
+	  }
+	  emit(f,"\n");
+	}else if(p->z.flags&REG){
+	  if(scratchreg(p->z.reg,p)){
+	    rz=p->z.reg;
+	  }else{
+	    BSET(regs_modified,ti2);
+	    emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[p->z.reg]);
+	    rz=ti2;
+	  }
+	}else if(ISSTATIC(p->z.v)){
+	  int m=p->z.flags;
+	  rz=ti2;
+	  BSET(regs_modified,ti2);
+	  if(p->z.flags&DREFOBJ)
+	    p->z.flags&=~DREFOBJ;
+	  else
+	    p->z.flags|=VARADR;
+	  move(f,&p->z,0,0,ti2,NPOINTER);
+	  p->z.flags=m;
+	}else{
+	  BSET(regs_modified,ti2);
+	  rz=ti2;
+	  emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[sp]);
+	  if(voff(&p->z))
+	    emit(f,"\tadd\t%s,#%ld\n",regnames[ti2],voff(&p->z));
+	}	
+	if(alq==0&&alz==0){
+	  if(optspeed){
+	    if((size/8)>1){ 
+	      BSET(regs_modified,tp);
+	      emit(f,"\tmov\t%s,#%lu\n",regnames[tp],size/8);
+	      emit(f,"%s%d:\n",labprefix,++label);
+	    }
+	    if(size>=8){
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      emit(f,"\tadd\t%s,#2\n",regnames[rz]);	    
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      emit(f,"\tadd\t%s,#2\n",regnames[rz]);	    
+	    }
+	    if((size/8)>1){
+	      emit(f,"\tsub\t%s,#1\n",regnames[tp]);
+	      emit(f,"\tjmpr\tcc_nz,%s%d\n",labprefix,label);	      
+	    }
+	    size&=7;
+	    if(size>=4){
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      if(size>4) emit(f,"\tadd\t%s,#2\n",regnames[rz]);	      
+	    }
+	    size&=3;
+	    if(size>=2){
+	      emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	      if(size>2) emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+	    }	      
+	    if(size&1)
+	      if(size&1) emit(f,"\tmovb\t[%s],[%s]\n",regnames[rz],regnames[rq]);
+	  }else{
+	    BSET(regs_modified,tp);
+	    emit(f,"\tmov\t%s,#%lu\n",regnames[tp],size/2);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	    emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+	    emit(f,"\tsub\t%s,#1\n",regnames[tp]);
+	    emit(f,"\tjmpr\tcc_nz,%s%d\n",labprefix,label);
+	    if(size&1) emit(f,"\tmovb\t[%s],[%s]\n",regnames[rz],regnames[rq]);
+	  }
+	}else{
+	  BSET(regs_modified,tp);
+	  emit(f,"\tmov\t%s,#%lu\n",regnames[tp],size);
+	  emit(f,"%s%d:\n",labprefix,++label);
+	  emit(f,"\tmovb\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+	  emit(f,"\tadd\t%s,#1\n",regnames[rz]);
+	  emit(f,"\tsub\t%s,#1\n",regnames[tp]);
+	  emit(f,"\tjmpr\tcc_nz,%s%d\n",labprefix,label);
+	}
+	continue;
+      }
+      /* mov [rx],[ry] ; mov [rx+],[ry] ; mov [rx],[ry+] */
+      if(!ISLWORD(t)&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(!p->z.am||p->z.am->flags==POST_INC)&&(!p->q1.am||p->q1.am->flags==POST_INC)&&!reg_pair(p->q1.reg,&rp)&&!reg_pair(p->z.reg,&rp)){
+	emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+	emit_obj(f,&p->z,t);emit(f,",");
+	emit_obj(f,&p->q1,t);emit(f,"\n");
+	cc=&p->z;cc_t=t;continue;
+      }
+      /* mov mem,[rx]/reg */
+      if(!ISLWORD(t)&&(issfr(q1)||(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ))&&(p->z.flags&(REG|DREFOBJ|VAR))==VAR&&!p->q1.am&&(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
+	emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+	emit_obj(f,&p->z,t);emit(f,",");
+	emit_obj(f,&p->q1,t);emit(f,"\n");
+	cc=&p->z;cc_t=t;continue;
+      } 
+      /* mov [rx]/reg,mem */
+      if(!ISLWORD(t)&&(issfr(z)||(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ))&&(p->q1.flags&(REG|DREFOBJ|VAR))==VAR&&!p->z.am&&(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)){
+	emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+	emit_obj(f,&p->z,t);emit(f,",");
+	emit_obj(f,&p->q1,t);emit(f,"\n");
+	cc=&p->z;cc_t=t;continue;
+      }     
+      /* mov reg,op */
+      if(issfr(z)&&(p->q1.flags&KONST)){
+	emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+	emit_obj(f,&p->z,t);emit(f,",");
+	emit_obj(f,&p->q1,t);emit(f,"\n");
+	cc=&p->z;cc_t=t;continue;
+      }
+
+      if(isreg(q1)){
+	reg=p->q1.reg;
+      }else if(isreg(z)){
+	reg=p->z.reg;
+      }else{
+	BSET(regs_modified,ti);
+	if(ISLWORD(t)){
+	  BSET(regs_modified,ti2);
+	  tmp1=ti;tmp2=ti2;
+	  reg=MTMP1;
+	}else
+	  reg=ti;
+      }
+      if(c==PUSH){
+	move(f,&p->q1,0,0,reg,t);
+	if(reg_pair(reg,&rp)){
+	  emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[rp.r2]);
+	  emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[rp.r1]);
+	  cc=0;
+	}else{
+	  emit(f,"\tmov%s\t[-%s],%s\n",x_t[t&NQ],regnames[sp],regnames[reg]);
+	  cc=&p->q1;cc_t=t;
+	}
+	push(zm2l(p->z.val.vmax),0);
+	continue;
+      }
+      if(c==ASSIGN){
+	if((p->z.flags&(VAR|REG|DREFOBJ))==VAR&&ISSTATIC(p->z.v)&&isconst(q1)){
+	  /*FIXME: long und ones */
+	  eval_const(&p->q1.val,t);
+	  if(ISNULL()&&!ISLWORD(t)){
+	    emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");emit_obj(f,&p->z,t);
+	    emit(f,",ZEROS\n");
+	    cc=&p->z;cc_t=t;continue;
+	  }
+	}
+	if((t&NQ)==CHAR&&!regok(reg,CHAR,0)){
+	  reg=tp;
+	  BSET(regs_modified,tp);
+	}
+	move(f,&p->q1,0,0,reg,t);
+	save_result(f,reg,p,t);
+	if(ISLWORD(t)){
+	  cc=0;
+	}else{
+	  cc=&p->z;cc_t=t;
+	}
+	continue;
+      }
+      ierror(0);
+    }
+    if(c==ADDRESS){
+      if(reg_pair(reg,&rp)){
+	emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[sp]);
+	emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+	if(voff(&p->q1))
+	  emit(f,"\tadd\t%s,#%ld\n",regnames[rp.r1],voff(&p->q1)&0xffff);
+      }else{
+	emit(f,"\tmov\t%s,%s\n",regnames[reg],regnames[sp]);
+	if(voff(&p->q1)) emit(f,"\tadd\t%s,#%ld\n",regnames[reg],voff(&p->q1));
+      }
+      save_result(f,reg,p,p->typf2);
+      cc=0;
+      continue;
+    }
+
+    if(c==MOD||c==DIV){
+      if(ISLWORD(t)) ierror(0);
+      /*FIXME:suboptimal*/
+      emit(f,"\tmov\tMDL,%s\n",regnames[reg]);
+      move(f,&p->q2,0,0,reg,t);
+      emit(f,"\tdiv%s\t%s\n",(t&UNSIGNED)?"u":"",regnames[reg]);
+      if(c==MOD) 
+	emit(f,"\tmov\t%s,MDH\n",regnames[reg]);
+      else
+	emit(f,"\tmov\t%s,MDL\n",regnames[reg]);
+      save_result(f,reg,p,t);
+      cc=&p->z;cc_t=t;
+      continue;
+    }
+    if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==COMPARE||c==ADDI2P||c==SUBIFP){
+      char *s;
+      /*FIXME: nicht immer besser*/
+/* rfi: better performed in LSHIFT code generation
+      if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
+	eval_const(&p->q2.val,t);
+	if(zm2l(vmax)==1&&!p->q1.am){
+	  p->code=c=ADD;
+	  p->q2=p->q1;
+	}
+      }
+*/
+      if(ISLWORD(t)&&c==MULT) ierror(0);
+      if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
+/* rfi: we now handle constant value greater than 16 in const shift generation
+	if(isconst(q2))	
+	  eval_const(&p->q2.val,q2typ(p));
+	if(!isconst(q2)||zmleq(l2zm(16L),vmax)){
+*/
+	if(!isconst(q2)){
+	  int cnt,lab1,lab2;
+	  if(isreg(q2)&&scratchreg(p->q2.reg,p)){
+	    cnt=p->q2.reg;
+	  }else{
+	    BSET(regs_modified,tp);
+	    cnt=tp;
+	    if(isreg(q2)&&reg_pair(p->q2.reg,&rp))
+	      move(f,0,rp.r1,0,tp,INT);
+	    else
+	      move(f,&p->q2,0,0,tp,INT);
+	  }
+	  if(reg_pair(cnt,&rp))
+	    cnt=rp.r1;
+	  /*move(f,&p->q1,0,0,reg,ztyp(p));*/
+	  lab1=++label;lab2=++label;
+	  if(!reg_pair(reg,&rp)) ierror(0);
+	  if(c==LSHIFT){
+	    emit(f,"\tjmpr\tcc_uc,%s%d\n",labprefix,lab2);
+	    emit(f,"%s%d:\n",labprefix,lab1);
+	    emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+	    emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+	    emit(f,"%s%d:\n",labprefix,lab2);
+/* rfi: fix off by one and handle negative shift value
+		emit(f,"\tsub\t%s,#1\n",regnames[cnt]);
+	    emit(f,"\tjmpr\tcc_ne,%s%d\n",labprefix,lab1);
+*/
+	    emit(f,"\tcmpd1\t%s,#1\n",regnames[cnt]);
+	    emit(f,"\tjmpr\tcc_sge,%s%d\n",labprefix,lab1);
+	  }else{
+	    emit(f,"\tjmpr\tcc_uc,%s%d\n",labprefix,lab2);
+	    emit(f,"%s%d:\n",labprefix,lab1);
+		emit(f,"\tshr\t%s,#1\n",regnames[rp.r1]);
+	    emit(f,"\tbmov\t%s.15,%s.0\n",regnames[rp.r1],regnames[rp.r2]);
+/* rfi: use ashr for signed shift
+		emit(f,"\tshr\t%s,#1\n",regnames[rp.r2]);
+*/
+	    emit(f,"\t%sshr\t%s,#1\n",(t&UNSIGNED)?"":"a",regnames[rp.r2]);
+	    emit(f,"%s%d:\n",labprefix,lab2);
+/* rfi: fix off by one and handle negative shift value
+		emit(f,"\tsub\t%s,#1\n",regnames[cnt]);
+	    emit(f,"\tjmpr\tcc_ne,%s%d\n",labprefix,lab1);
+*/
+	    emit(f,"\tcmpd1\t%s,#1\n",regnames[cnt]);
+	    emit(f,"\tjmpr\tcc_sge,%s%d\n",labprefix,lab1);
+	  }
+	  save_result(f,reg,p,ztyp(p));
+	  continue;
+	}
+      }
+      if(c>=OR&&c<=AND){
+	s=logicals[c-OR];
+      }else{
+	if(c==ADDI2P)
+	  s=arithmetics[ADD-LSHIFT];
+	else if(c==SUBIFP)
+	  s=arithmetics[SUB-LSHIFT];
+	else
+	  s=arithmetics[c-LSHIFT];
+      }
+      if(c==RSHIFT&&!(t&UNSIGNED)) s="ashr";
+      if(c==COMPARE){
+	lastcomp=t;
+	if(ISLWORD(t)) s="sub"; else s="cmp";
+      }
+      if((c==MULT&&!isreg(q2))){
+	BSET(regs_modified,tp);
+	move(f,&p->q2,0,0,tp,t);
+	p->q2.flags=REG;
+	p->q2.reg=tp;
+      }
+      if((c==LSHIFT||c==RSHIFT)&&!isconst(q2)&&!isreg(q2)){
+	BSET(regs_modified,tp);
+	move(f,&p->q2,0,0,tp,t);
+	p->q2.flags=REG;
+	p->q2.reg=tp;
+      }
+      if(isreg(q2)){
+	if(reg_pair(reg,&rp)){
+	  if(!reg_pair(p->q2.reg,&qp)) qp.r1=p->q2.reg;
+	  emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r1],regnames[qp.r1]);
+	  s=longcmd(s);
+	  if(!short_add) emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[qp.r2]);
+	}else{
+	  emit(f,"\t%s%s\t%s,%s\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],(t&NQ)==CHAR?bregnames[p->q2.reg]:regnames[p->q2.reg]);
+	}	    
+      }else if(p->q2.am){
+	if(reg_pair(p->q2.am->base,&rp)){
+	  int seg=rp.SEG;
+	  if(!short_add&&reg_pair(reg,&rp))
+	    emit(f,"\texts\t%s,#3\n",regnames[seg]);
+	  else
+	    emit(f,"\texts\t%s,#1\n",regnames[seg]);
+	}
+	if(reg_pair(reg,&rp)){
+	  BSET(regs_modified,tp);
+	  emit(f,"\tmov\t%s,",regnames[tp]);emit_obj(f,&p->q2,t);emit(f,"\n");
+	  emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r1],regnames[tp]);
+	  s=longcmd(s);
+	  if(!short_add){
+	    p->q2.am->offset+=2;
+	    emit(f,"\tmov\t%s,",regnames[tp]);emit_obj(f,&p->q2,t);emit(f,"\n");
+	    emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[tp]);
+	    p->q2.am->offset-=2;
+	  }
+	}else{
+	  if(p->q2.am->flags==POST_INC&&p->q2.am->base<=4){
+	    emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+	    emit_obj(f,&p->q2,t);emit(f,"\n");
+	  }else{
+	    BSET(regs_modified,tp);
+	    emit(f,"\tmov%s\t%s,",x_t[t&NQ],(t&NQ)==CHAR?bregnames[tp]:regnames[tp]);
+	    emit_obj(f,&p->q2,t);emit(f,"\n");
+	    emit(f,"\t%s%s\t%s,%s\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],(t&NQ)==CHAR?bregnames[tp]:regnames[tp]);
+	  }
+	}
+      }else if((p->q2.flags&(VAR|VARADR|REG))==VAR&&ISSTATIC(p->q2.v)){
+	if(ISFAR(p->q2.v)){
+	  emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->q2,t);
+	  emit(f,",#%d\n",(reg_pair(reg,&rp)?2:1));
+	}
+	if(reg_pair(reg,&rp)){
+	  emit(f,"\t%s\t%s,",s,regnames[rp.r1]);
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	  s=longcmd(s);
+	  if(!short_add){
+	    emit(f,"\t%s\t%s,",s,regnames[rp.r2]);
+	    emit_obj(f,&p->q2,t);emit(f,"+2\n");
+	  }
+	}else{
+	  emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+      }else if(isconst(q2)){
+	if(ISFLOAT(t)) ierror(0);
+	if(reg_pair(reg,&rp)){
+	  long l;
+/* rfi: shift constant must be evaluated according to own type
+	  eval_const(&p->q2.val,t);
+*/
+	  eval_const(&p->q2.val,q2typ(p));
+	  if(c==RSHIFT){
+	    l=zm2l(vmax);
+/* rfi: new generation for constant right shift */
+		if( l < 0) {
+		/* TODO: we should raise a warning */
+		/* Implementation dependent: negative shift is same as null shift */
+		/* avoid shift generation */
+		} else if( l > 31) {
+		/* TODO: we should raise a warning */
+		/* Implementation dependent: same behaviour as non const shift */
+			if( t & UNSIGNED)
+				emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+			else
+	    		emit(f,"\t%s\t%s,#15\n",s,regnames[rp.r2]);
+
+		   	emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[rp.r2]);
+		} else if( l > 15) {
+	    	emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[rp.r2]);
+			if( t & UNSIGNED)
+				emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+			else
+	    		emit(f,"\t%s\t%s,#15\n",s,regnames[rp.r2]);
+
+			l -= 16 ;
+			if( l > 0)
+	    		emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r1],l);
+		} else if( l == 0) {
+		/* avoid shift generation */
+		} else if( l == 1) {
+			emit(f,"\tshr\t%s,#1\n",regnames[rp.r1]);
+	    	emit(f,"\tbmov\t%s.15,%s.0\n",regnames[rp.r1],regnames[rp.r2]);
+	    	emit(f,"\t%s\t%s,#1\n",s,regnames[rp.r2]);
+		} else {
+/* rfi: warning should be raised in corresponding case (see TODO above)
+	    if(l<1||l>15) ierror(0);
+*/
+	    BSET(regs_modified,tp);
+	    emit(f,"\tmov\t%s,%s\n",regnames[tp],regnames[rp.r2]);
+	    emit(f,"\tshr\t%s,#%ld\n",regnames[rp.r1],l);
+	    emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r2],l);
+	    emit(f,"\tshl\t%s,#%ld\n",regnames[tp],16-l);
+	    emit(f,"\tor\t%s,%s\n",regnames[rp.r1],regnames[tp]);
+		}
+	  }else if(c==LSHIFT){
+	    l=zm2l(vmax);
+/* rfi: new generation for constant left shift */
+		if( l < 0) {
+		/* TODO: we should raise a warning */
+		/* Implementation dependent: negative shift is same as null shift */
+		/* avoid shift generation */
+		} else if( l > 31) {
+		/* TODO: we should raise a warning */
+		/* Implementation dependent: same behaviour as non const shift */
+			emit(f,"\tmov\t%s,#0\n",regnames[rp.r1]);
+		   	emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[rp.r1]);
+		} else if( l > 15) {
+	   		emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[rp.r1]);
+	   		emit(f,"\tmov\t%s,#0\n",regnames[rp.r1]);
+			l -= 16 ;
+			if( l > 0)
+	      		emit(f,"\tshl\t%s,#%ld\n",regnames[rp.r2],l);
+		} else if( l == 0) {
+		/* avoid shift generation */
+		} else if( l == 1) {
+	      emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+	      emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+		} else
+/* rfi: warning should be raised in corresponding case (see TODO above)
+	    if(l<1||l>15) ierror(0);
+*/
+	    if(l==2){
+	      emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+	      emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+	      emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+	      emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+	    }else{
+	      BSET(regs_modified,tp);
+	      emit(f,"\tmov\t%s,%s\n",regnames[tp],regnames[rp.r1]);
+	      emit(f,"\tshl\t%s,#%ld\n",regnames[rp.r1],l);
+	      emit(f,"\tshl\t%s,#%ld\n",regnames[rp.r2],l);
+	      emit(f,"\tshr\t%s,#%ld\n",regnames[tp],16-l);
+	      emit(f,"\tor\t%s,%s\n",regnames[rp.r2],regnames[tp]);
+	    }
+	  }else{
+	    l=zm2l(zmand(vmax,l2zm(65535L)));
+	    emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r1],l);
+	    l=zm2l(zmrshift(vmax,l2zm(16L)));
+	    s=longcmd(s);
+	    if(!short_add) emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r2],l);
+	  }
+	}else{
+	  emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+      }else if(p->q2.flags&VARADR){
+	p->q2.flags&=~VARADR;
+	if(reg_pair(reg,&rp)){
+	  emit(f,"\t%s\t%s,#SOF ",s,regnames[rp.r1]);emit_obj(f,&p->q2,t);emit(f,"\n");
+	  s=longcmd(s);
+	  if(!short_add)
+	    emit(f,"\t%s\t%s,#SEG ",s,regnames[rp.r2]);isseg=1;emit_obj(f,&p->q2,t);emit(f,"\n");
+	}else{
+	  emit(f,"\t%s\t%s,#",s,regnames[reg]);emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+	p->q2.flags|=VARADR;
+      }else if(p->q2.flags&DREFOBJ){
+	int seg=0,sof=0;
+        /*	if(!(p->q2.flags&REG)) ierror(0);*/
+	if(reg_pair(p->q2.reg,&rp)){
+	  seg=rp.SEG;sof=rp.SOF;
+	  if(!short_add&&reg_pair(reg,&rp)){
+	    emit(f,"\texts\t%s,#2\n",regnames[seg]);
+	  }else
+	    emit(f,"\texts\t%s,#1\n",regnames[seg]);
+	}
+	if(reg_pair(reg,&rp)){
+	  if(scratchreg(p->q2.reg,p)){
+	    emit(f,"\t%s\t%s,[%s+]\n",s,regnames[rp.r1],regnames[sof?sof:p->q2.reg]);
+	    s=longcmd(s);
+	    if(!short_add) emit(f,"\t%s\t%s,[%s]\n",s,regnames[rp.r2],regnames[sof?sof:p->q2.reg]);
+	  }else{
+	    emit(f,"\t%s\t%s,[%s]\n",s,regnames[rp.r1],regnames[sof?sof:p->q2.reg]);
+	    s=longcmd(s);
+	    if(!short_add){
+	      BSET(regs_modified,tp);
+	      emit(f,"\tmov\t%s,[%s+#2]\n",regnames[tp],regnames[sof?sof:p->q2.reg]);
+	      emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[tp]);
+	    }
+	  }
+	}else{
+	  emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+      }else if((p->q2.flags&(VAR|DREFOBJ))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)){
+	long l=voff(&p->q2);
+	if(reg_pair(reg,&rp)){
+	  if(l){
+	    BSET(regs_modified,tp);
+	    emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[tp],regnames[sp],l);
+	    emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r1],regnames[tp]);
+	  }else
+	    emit(f,"\t%s\t%s,[%s]\n",s,regnames[rp.r1],regnames[sp]);
+	  s=longcmd(s);
+	  if(!short_add){
+	    BSET(regs_modified,tp);
+	    emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[tp],regnames[sp],l+2);
+	    emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[tp]);
+	  }
+	}else{
+	  if(l){
+	    BSET(regs_modified,tp);
+	    emit(f,"\tmov%s\t%s,[%s+#%ld]\n",x_t[t&NQ],(t&NQ)==CHAR?bregnames[tp]:regnames[tp],regnames[sp],l);
+	    emit(f,"\t%s%s\t%s,%s\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],(t&NQ)==CHAR?bregnames[tp]:regnames[tp]);
+	  }else
+	    emit(f,"\t%s%s\t%s,[%s]\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],regnames[sp]);
+	}
+      }else
+	ierror(0);
+      if(c==MULT) emit(f,"\tmov\t%s,MDL\n",regnames[reg]);
+      /*FIXME:signed*/
+      if(short_add==1) emit(f,"\t%s\t%s,#0\n",s,regnames[rp.r2]);
+      if(c!=COMPARE) save_result(f,reg,p,t);
+      if(!ISLWORD(t)||((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&!short_add)){
+	cc=&p->z;cc_t=t;
+      }else
+	cc=0;
+      continue;
+    }
+    ierror(0);
+  }
+  if(notpopped){
+    emit(f,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+    pop(notpopped,0);notpopped=0;
+  }
+  function_bottom(f,v,loff);
+}
+
+int shortcut(int c,int t)
+{
+  if(c==COMPARE||c==AND||c==OR||c==XOR) return 1;
+  if((t&NQ)!=BIT&&(c==ADD||c==SUB)) return 1;
+  return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+  if(f&&stack_check){
+    emit(f,"\t%s\t%s__stack_check\n",public,idprefix);
+  }
+  while(p=firstfpc){
+    if(f){
+      new_section(f,NDATA);
+      emit(f,even);
+      emit(f,"%s%d:\n\t%s\t",labprefix,p->label,TASKING?dct[SHORT]:vdct[SHORT]);
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+      if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+  if(f&&TASKING) emit(f,"%s\tREGDEF R0-R15\n\tend\n",sec_end);
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+  int f=t->flags&NQ;
+  if(!ISSCALAR(f)) return 0;
+  if(p->gpr>3||mode) return 0;
+  if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+    return 0;
+  else if(f==LONG||f==FPOINTER||f==HPOINTER){
+    if(p->gpr==0) {p->gpr=2;return 23;}
+    if(p->gpr==1) {p->gpr=3;return 22;}
+    if(p->gpr==2) {p->gpr=4;return 21;}
+    return 0;
+  }else
+    return 13+p->gpr++;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+/*  *p = (union atyps) 0 ; /* rfi: clear unused bits */
+  t&=NU;
+  if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}  
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==NPOINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==BIT){
+	if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
+      }else if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==BIT){
+	if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
+      }else if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==NPOINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==BIT){fprintf(f,"B");vmax=zc2zm(p->vchar);fprintf(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){fprintf(f,"UB");vumax=zuc2zum(p->vuchar);fprintf(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vumax,ul2zum(0UL)));}
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+	if(strstr(attr,STR_NEAR))
+	  p->flags=((p->flags&~NU)|NPOINTER);
+	if(strstr(attr,STR_FAR))
+	  p->flags=((p->flags&~NU)|FPOINTER);
+	if(strstr(attr,STR_HUGE))
+	  p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+      p->flags=((p->flags&~NU)|BIT);
+    p=p->next;
+  }
+}
+
+void init_db(FILE *f)
+{
+}
+
+void cleanup_db(FILE *f)
+{
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0,*tt;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)&&(t&NU)==LLONG){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+	if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%suint64",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+        }else{
+	  sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+	}
+      }
+    }
+  }
+
+
+  return ret;
+}
diff --git a/machines/c16x/machine.dt b/machines/c16x/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/c16x/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/c16x/machine.h b/machines/c16x/machine.h
new file mode 100755
index 0000000..be6dbdd
--- /dev/null
+++ b/machines/c16x/machine.h
@@ -0,0 +1,184 @@
+/*  Example of a code-generator for SAB c16x 16bit microcontrollers.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them:      */
+/* - #define HAVE_EXT_TYPES
+   - #undef all standard types
+   - #define all standard types plus new types
+   - write eval_const and insert_const
+   - write typedefs for zmax and zumax
+   - write typname[]
+   - write conv_typ()
+   - optionally #define ISPOINTER, ISARITH, ISINT etc.
+   - optionally #define HAVE_TGT_PRINTVAL and write printval
+   - optionally #define POINTER_TYPE
+   - optionally #define HAVE_TGT_FALIGN and write falign
+   - optionally #define HAVE_TGT_SZOF and write szof
+   - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+#define BOOL 19
+
+#define MAXINT 20
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+    struct Var *v;
+};
+
+/* This type will be added to every IC. Can be used by the cg.      */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+  int flags;
+  int r;
+  long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 25
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 10
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+  int gpr;
+};
+
+/*  We use unsigned int as size_t rather than unsigned long which   */
+/*  is the default setting.                                         */
+#define HAVE_INT_SIZET 1
+
+/*  We have register pairs.                                         */
+#define HAVE_REGPAIRS 1
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
diff --git a/machines/dv/machine.c b/machines/dv/machine.c
new file mode 100755
index 0000000..264d677
--- /dev/null
+++ b/machines/dv/machine.c
@@ -0,0 +1,1112 @@
+/*
+    Dalvik backend for vbcc
+*/                                                                             
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc dalvik code-generator V0.1 (c) in 2012 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+		    VALFLAG,VALFLAG,VALFLAG,
+		    0,0,
+		    VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+			   "volatile-gprs","volatile-fprs","volatile-ccrs",
+			   "imm-ind","gpr-ind",
+			   "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS   ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS   ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND    ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND    ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS   ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+#ifdef DV_BYTE8
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,8,0,0,0,4,0};
+#else
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,1,1,1,2,1,2,2,0,2,0,0,0,1,0};
+#endif
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__GENERIC__",
+		       0};
+
+/* special registers */
+static int sp;                     /*  Stackpointer                        */
+static int t1,t2,t3;               /*  temporary gprs */
+static int f1,f2,f3;               /*  temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+  *dataname="\t.data\n",
+  *bssname="",
+  *rodataname="\t.section\t.rodata\n";
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix=":",*idprefix="";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+   a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    ierror(0);
+  }
+
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if(!(o->flags&VAR)) ierror(0);
+  if(!reg_pair(r,&rp)) ierror(0);
+
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    emit(f,"\tmove-int\t%s,%s\n",mregnames[rp.r2],mregnames[fp]);
+    emit(f,"\tconst-int\t%s,%ld\n",mregnames[rp.r1],loff);
+  }else{
+    emit(f,"\tconst-int\t%s,%s\n",mregnames[rp.r2],gp);
+    emit(f,"\tconst-int\t%s,",mregnames[rp.r1]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+   general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NU;
+  if(o->flags&VARADR){
+    load_address(f,r,o,POINTER);
+  }else{
+    if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+      return;
+#ifdef DV_BYTE8
+    ierror(0);
+#else
+    ierror(0);
+#endif
+  }
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NQ;
+  emit(f,"\tmov.%s\t",dt(type));
+  emit_obj(f,o,type);
+  emit(f,",%s\n",regnames[r]);
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+
+  if(isreg(z)){
+    zreg=p->z.reg;
+  }else{
+    if(ISFLOAT(ztyp(p)))
+      zreg=f1;
+    else
+      zreg=t1;
+  }
+  
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q1,q1typ(p));
+    p->q1.reg=t1;
+    p->q1.flags|=(REG|DREFOBJ);
+  }
+  if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+    if(ISFLOAT(q1typ(p)))
+      q1reg=f1;
+    else
+      q1reg=t1;
+    load_reg(f,q1reg,&p->q1,q1typ(p));
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q2,q2typ(p));
+    p->q2.reg=t1;
+    p->q2.flags|=(REG|DREFOBJ);
+  }
+  if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+    if(ISFLOAT(q2typ(p)))
+      q2reg=f2;
+    else
+      q2reg=t2;
+    load_reg(f,q2reg,&p->q2,q2typ(p));
+    p->q2.reg=q2reg;
+    p->q2.flags=REG;
+  }
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->z,POINTER);
+    p->z.reg=t2;
+    p->z.flags|=(REG|DREFOBJ);
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    ierror(0);
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) ierror(0);
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      ierror(0);
+      emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  /*if(p->flags&DREFOBJ) emit(f,")");*/
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  return;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=zm2l(of);
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=GPR_IND;
+              am->base=base;
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  rsavesize=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  emit(f,ret);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(4);
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  regnames[0]="noreg";
+  for(i=1;i<=GPRS;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"v%d",i-1);
+#ifdef DV_BYTE8
+    regsize[i]=l2zm(4L);
+#else
+    regsize[i]=l2zm(1L);
+#endif
+    regtype[i]=&ltyp;
+  }
+  for(i=GPRS+1;i<=GPRS+PAIRS+1;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"v%d/v%d",i-GPRS-1,i-GPRS);
+#ifdef DV_BYTE8
+    regsize[i]=l2zm(8L);
+#else
+    regsize[i]=l2zm(2L);
+#endif
+    regtype[i]=&llong;
+  }
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+#ifdef DV_BYTE8
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+#else
+  t_min[CHAR]=t_min[SHORT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_max[CHAR]=t_max[SHORT]=ul2zum(2147483647UL);
+  tu_max[CHAR]=tu_max[SHORT]=ul2zum(4294967295UL);
+#endif
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  sp=FIRST_GPR;
+  t1=FIRST_GPR+1;
+  t2=FIRST_GPR+2;
+  f1=FIRST_FPR;
+  f2=FIRST_FPR+1;
+  regsa[t1]=regsa[t2]=1;
+  regsa[f1]=regsa[f2]=1;
+  regsa[sp]=1;
+  regscratch[t1]=regscratch[t2]=0;
+  regscratch[f1]=regscratch[f2]=0;
+  regscratch[sp]=0;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+    regscratch[i]=1;
+
+  target_macros=marray;
+
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) 
+    return FIRST_FPR+2;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 
+    return 0;
+  if(zmleq(szof(t),l2zm(4L))) 
+    return FIRST_GPR+3;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    if(!LOAD_STORE)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  t&=NQ;
+  if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+    return 1;
+  if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+    return 1;
+  if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(v->clist||section==SPECIAL){
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||section==SPECIAL){
+	gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\tdc.%s\t",dt(t&NQ));
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *m;
+  argsize=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  maxpushed=0;
+
+  /*FIXME*/
+  ret="\trts\n";
+
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+    /* convert MULT/DIV/MOD with powers of two */
+    if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  p->typf2=INT;
+	}
+      }
+    }
+#if FIXED_SP
+    if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+  }
+  peephole(p);
+
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+
+  localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+  /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+  function_top(f,v,localsize);
+
+#if FIXED_SP
+  pushed=0;
+#endif
+
+  for(;p;p=p->next){
+    c=p->code;t=p->typf;
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(0/*t==exit_label&&framesize==0*/)
+	emit(f,ret);
+      else
+	emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      emit(f,"\tb%s\t",ccs[c-BEQ]);
+      if(isreg(q1)){
+	emit_obj(f,&p->q1,0);
+	emit(f,",");
+      }
+      emit(f,"%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      ierror(0);
+    }
+    p=preload(f,p);
+    c=p->code;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+      if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+	if(q1typ(p)&UNSIGNED)
+	  emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+	else
+	  emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+      }
+      save_result(f,p);
+      continue;
+    }
+    if(c==KOMPLEMENT){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==SETRETURN){
+      load_reg(f,p->z.reg,&p->q1,t);
+      BSET(regs_modified,p->z.reg);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+	save_result(f,p);
+      }else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      int reg;
+      /*FIXME*/
+#if 0      
+      if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	  stack=framesize+zum2ul(p->q1.v->fi->stack1);
+      }else
+	stack_valid=0;
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+	emit(f,"\tcall\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      /*FIXME*/
+#if FIXED_SP
+      pushed-=zm2l(p->q2.val.vmax);
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+	int i;
+	for(i=1;i<=MAXR;i++){
+	  if(regscratch[i]) BSET(regs_modified,i);
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(c==PUSH){
+#if FIXED_SP
+	emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	pushed+=zm2l(p->q2.val.vmax);
+#else
+	emit(f,"\tpush.%s\t",dt(t));
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	push(zm2l(p->q2.val.vmax));
+#endif
+	continue;
+      }
+      if(c==ASSIGN){
+	load_reg(f,zreg,&p->q1,t);
+	save_result(f,p);
+      }
+      continue;
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      save_result(f,p);
+      continue;
+    }
+    if(c==MINUS){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==TEST){
+      emit(f,"\ttst.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if(c==COMPARE){
+      emit(f,"\tcmp.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,",");
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+      if(!THREE_ADDR)
+	load_reg(f,zreg,&p->q1,t);
+      if(c>=OR&&c<=AND)
+	emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+      else
+	emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+      if(THREE_ADDR){
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+      }
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      save_result(f,p);
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  function_bottom(f,v,localsize);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=stack;
+  }
+  emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+  f=t->flags&NQ;
+  if(f<=LONG||f==POINTER){
+    if(m->gregs>=GPR_ARGS)
+      return 0;
+    else
+      return FIRST_GPR+3+m->gregs++;
+  }
+  if(ISFLOAT(f)){
+    if(m->fregs>=FPR_ARGS)
+      return 0;
+    else
+      return FIRST_FPR+2+m->fregs++;
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
diff --git a/machines/dv/machine.dt b/machines/dv/machine.dt
new file mode 100755
index 0000000..fa79dba
--- /dev/null
+++ b/machines/dv/machine.dt
@@ -0,0 +1,16 @@
+S32BSLE
+S32BULE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S64BULE S64BUBE
+
+
diff --git a/machines/dv/machine.h b/machines/dv/machine.h
new file mode 100755
index 0000000..cc49371
--- /dev/null
+++ b/machines/dv/machine.h
@@ -0,0 +1,127 @@
+/*  
+    Dalvik backend for vbcc
+*/
+
+#include "dt.h"
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define GPRS 256
+#define PAIRS (GPRS/2)
+#define MAXR (GPRS + PAIRS)
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#ifndef DV_BYTE8
+#define MINADDI2P CHAR
+#else
+#define MINADDI2P INT
+#endif
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long regs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we need register-pairs */
+##define HAVE_REGPAIRS
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
diff --git a/machines/falco16/machine.c b/machines/falco16/machine.c
new file mode 100755
index 0000000..91ada14
--- /dev/null
+++ b/machines/falco16/machine.c
@@ -0,0 +1,2470 @@
+/* 
+   FALCO16 v3
+*/                                                                             
+
+/* TO DO
+
+- If a FREEREG follows an IC for Q1, the register can be used as temporary.
+e.g if we get a = R0 + c, and there's a FREEREG R0 following the IC, we can generate
+add r0, [c]
+mov [a], r0
+instead of
+mov r1, r0
+add r1, [c]
+mov [a], r1
+
+-- floating point capability must also be implemented
+
+- data alignement doesn't work, g1 should be aligned below.
+-- Is this supposed to be handled by the assembler?
+char global = 4;
+int g1 = 5;
+
+-- conditional branching for LONG works, but temporary register handling is not ideal.
+   Register are loaded more than required.
+
+-- inline optimization must be done, e.g shift by const, mul/div by 2
+
+-- call ptr not implemented.
+
+-- register parameter passing
+
+-- 1arg operation are currently only using reg arguments
+
+-- could take advantage of [reg+ofs] addressing mode by combining IC
+
+-- IRQs should only save registers which are actually used, in case of function call all regs must be saved
+-- implement "naked" keyword for RTOS use.
+
+-- right now lib_mov is done by messing with the IC operands changing them into pointers. It is probably better to
+   use ptr_push instead of messign around with val_push.
+
+-- must update arg_push to support double, long long and such, not using more temperary registers
+
+-- compare with KONST not correct when KONST = maxint
+
+*/
+
+#include "supp.h"
+#include "vbc.h"
+
+//static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="falco16_v3 code generator v0.1 by Daniel Schoch";
+
+// command line
+//--------------
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF] = {VALFLAG, VALFLAG, VALFLAG};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"regs", "rsave", "rtmp"};
+/* Description of command line options:
+regs=<val>
+DEFAULT = 6
+Specify the number of registers to use. Must be >=3 and <= 14.
+The value should match the actual CPU implementation, the default is 6.
+Values < 6 don't make much practical sense since there won't be
+enough registers available for efficient code generation.
+
+rsave=<val>
+DEFAULT = automatic
+0 <= val <= regs-rtmp
+Specify the number of non-scratch registers to use.
+Non-scratch registers are registers that are saved across
+function calls. They are used for efficient register
+variable implementation.
+
+rtmp=<val>
+DEFAULT = 0
+0 <= val <= 3
+Specify the number of temporary registers to reserve.
+Temporary registers are used by the code generator.
+In situation where there is no free register is available
+a register must be saved and restored.
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+
+
+// data types
+//======================
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[MAX_TYPE+1];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+// registers
+//==========================
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle	empty_reg_handle = {0, 0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define ISCOMPOSITE(t)	(ISARRAY(t) || ISSTRUCT(t) || ISUNION(t))
+
+// number of registers to use, this can be a ny value from 3 to 14.
+// A value < 6 is not recommended as it does not leave any registers for
+// efficient code generation.
+// The default is 6.
+int nregs;
+
+// register names
+#define REG_FLAGS	1
+#define REG_SP		2
+#define REG_R0		3
+#define REG_R1		4
+#define REG_R2		5
+#define REG_R3		6
+#define REG_R4		7
+#define REG_R5		8
+#define REG_R6		9
+#define REG_R7		10
+#define REG_R8		11
+#define REG_R9		12
+#define REG_R10		13
+#define REG_R11		14
+#define REG_R12		15
+#define REG_R13		16
+
+// register usage tracking system
+// Allocated by ALLOCEG IC
+#define TRACK_ALLOCREG	1
+// used by IC, not available as temporary
+#define TRACK_IC		2
+// allocated as temporary by tracker
+#define TRACK_TMP		4
+// saved 
+#define TRACK_SAVED		8
+// not usable as indicated by CPU register layout
+#define TRACK_OFFLIMITS		16
+// dedicated temporary register
+#define TRACK_DEDICATED		32
+// bits indicating register is used and cannot be used no matter what
+#define TRACK_NOGO		(TRACK_IC | TRACK_TMP | TRACK_OFFLIMITS)
+int track_status[MAXR+1];
+
+// We provide 3 slots for temporary registers.
+// In here we keep track if which slot contains which register.
+#define TRACK_SLOTS		3
+int track_slot[TRACK_SLOTS];
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp = { INT };
+
+/* macros defined by the backend */
+// extended data types attribute strings
+#define EXTDATA_INTERRUPT	"interrupt"
+
+static char 		*marray[] = {
+   "__FALCO16__",
+   "__interrupt(x)=__vattr(\"interrupt(\"#x\")\")",
+   0
+};
+
+/* sections */
+#define SEC_TEXT	0		// code
+#define SEC_RODATA	1		// constant data
+#define SEC_DATA	2		// initialized data
+#define SEC_BSS		3		// data initialized to 0
+#define SEC_VECTOR	4		// irq vectors
+static int		section = -1;
+static char 		*sec_textname = "code",
+  			*sec_rodataname = "const",
+  			*sec_dataname = "idata",
+  			*sec_bssname = "zdata",
+  			*sec_vectorname = "vector";
+
+/* assembly-prefixes for labels and external identifiers */
+static char 		*label_prefix = "p";
+static char		*ident_prefix = "_";
+static int			label_count;
+
+
+// assemly data storage strings
+static char 		*dct[] = {"", "db", "dw", "dw", "dd", "dd", "dd", "dd", "dd"};
+
+
+static long		loff;
+static long		stackoffset;
+static int		newobj;
+
+
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+   zumax	p;
+   int		ln = 1;
+    
+   p = ul2zum(1UL);
+   while (ln <= 32 && zumleq(p, x)) {
+      if (zumeqto(x, p)) return ln;
+      ln++; p = zumadd(p, p);
+   }
+   return 0;
+}
+
+static long const_get(struct obj *x, int typ, int n)
+{
+   long	       ret;
+   
+   eval_const(&x->val, typ);
+   ret = (vmax >> (n * char_bit)) & 0xffff;
+   
+   return ret;
+}   
+
+static long ofs_get(struct obj *x)
+{
+   long	    ret;
+   
+   ret = 0;
+   if (x->flags & VAR) {
+      if (x->v->offset < 0) {
+         ret = (long)(loff-(x->v->offset+2)+(x->val.vmax))-stackoffset+2;
+      } else {
+         ret = (long)((x->v->offset)+(x->val.vmax)-stackoffset);
+      }
+   }  
+   return ret;
+}
+
+
+static void emit_object(FILE *f, struct obj *x, int n, int typ)
+{
+   long		ofs;
+
+// calculate offset into stack
+   ofs = ofs_get(x);
+
+// access mode
+   eval_const(&x->val, typ);
+
+   if (x->flags & REG) {
+      if (x->flags & DREFOBJ) {
+// register pointer '[reg+ofs]'
+         emit(f, "[%s+%ld]", regnames[x->reg], n);
+      } else {
+// register 'reg'
+         emit(f, "%s", regnames[x->reg]);
+      }
+   } else if (x->flags & KONST) {
+      if (x->flags & VARADR) {
+// This is the special case for which the address of a constant must be generated.
+// KONST| VARADR is never generated by the front-end, but it's a modified
+// object by the back-end. The address of a constant is used for FLOAT/DOUBLE
+// library call operations involving a constant. An address to a constant is generated by
+// placing the constant into section SEC_RODATA and generating a pointer to
+// the object.
+// NOT COMPLETE, must have some kind of konst counter.
+// 1st nject konst into ROM section         
+         emit(f, "__KONST_");
+      } else if (x->flags & DREFOBJ) {
+// constant address, e.g. mov [123], r0
+         emit(f, "[%ld]", const_get(x, typ, n));      
+      } else {
+// regular KONST value
+         emit(f, "%ld", const_get(x, typ, n));
+      }
+   } else if (x->flags & VAR) {
+// REGULAR VARIABLE ACCESS      
+      if (isauto(x->v->storage_class)) {
+         if (x->flags & VARADR) {
+// this is a special case not generated by the front-end, it's a modified object
+// by the back end needing to generate the address of a auto variable.
+// This is used by 'ptr_push'. What eventually must be generated is
+// mov reg, sp
+// add reg, ofs+n
+// Since this is the emit_object function we only generate sp here, the
+// add reg, ofs+n must be generated by the callee.
+            emit(f, "sp");
+         } else {
+// stack based value '[sp+ofs]'      
+            emit(f, "[sp+%ld]", (long)ofs + n);
+         } 
+      } else if (isextern(x->v->storage_class)) {
+         if (x->flags & VARADR) {
+// address of global variable
+            emit(f, "%s%s+%ld", ident_prefix, (long)x->v->identifier, (long)x->val.vmax + n);
+         } else {
+// value of global '[ident+ofs]'        
+            emit(f, "[%s%s+%ld]", ident_prefix, (long)x->v->identifier, (long)x->val.vmax + n);
+         }
+      } else if (isstatic(x->v->storage_class)) {
+         if (x->flags & VARADR) {
+// address of static variable         
+            emit(f, "%s%ld+%ld", label_prefix, (long)x->v->offset, (long)x->val.vmax + n);
+         } else {
+// value of static variable         
+            emit(f, "[%s%ld+%ld]", label_prefix, (long)x->v->offset, (long)x->val.vmax + n);
+         }
+      } else terror("-- emit_object: unexpected storage class");
+   } else {   
+      terror("-- emit_object: unexpected access mode");
+   }  
+}
+
+/*
+Load a temporary ptr register to be used by the main emit_load
+function.
+returns 1, if code was generated to load the pointer.
+returns 0, if no code was necessary since no temporary ptr is required.
+*/
+static int emit_tmpptr(FILE *f, struct obj *x, int n)
+{
+   struct AddressingMode *am;
+   char		*regptr_name;
+   int		ret;
+
+   ret = 0;
+   am = x->am;
+   if (am && am->regptr) {
+      ret = 1;
+      regptr_name =  regnames[x->am->regptr];         
+      if (n == 0) {
+	 emit(f, "\tmov\t%s, ", regptr_name);
+         emit_object(f, x, 0, POINTER);
+	 emit(f, "\n");
+      } else {
+	  //  emit(f, "\tadd\t%s, %d\n", regptr_name, n);
+      }    
+   }
+   return ret;
+}
+
+
+// Generate code to perform a given operation.
+// The code generated is:
+//    op  t, s
+// typ = operand type (e.g CHAR, POINTER, INT ...)
+// n   = the offset when dealing with multi-world objects (e.g long, float)
+// EITHER t OR s MUST BE A REGISTER!
+// For the non-register operand, temporaries are used and loaded
+// according to am-data.
+static void emit_op(FILE *f, struct obj *t, struct obj *s, int typ, int n, char *op)
+{
+   long		ofs;
+   char		*mode;
+
+// calculate offset into stack
+   ofs = ofs_get(t);
+
+// determine access mode (8-bit or 16-bit instruction)
+   mode = "";
+   if (sizetab[typ&NQ] == 1) mode = ".8";
+
+   if (emit_tmpptr(f, s, n)) {
+// we use a temporary pointer and it's loaded in register s->am->regptr
+// Now we have to generate the code to load the data using the temporary pointer.      
+      emit(f, "\t%s%s\t%s, [%s+%d]\n", op, mode, regnames[t->reg], regnames[s->am->regptr], n);      
+   } else if (emit_tmpptr(f, t, n)) {
+// get value into target register
+      emit(f, "\t%s%s\t[%s+%d], %s\n", op, mode, regnames[t->am->regptr], n, regnames[s->reg]);      
+   } else {
+      emit(f, "\t%s%s\t", op, mode);
+      emit_object(f, t, n, typ);
+      emit(f, ", ");
+      emit_object(f, s, n, typ);
+      emit(f, "\n");
+   }      
+}
+
+// Generate register loading code in the following format:
+//    op  reg, x
+// Meaning it is always code generated, which loads into a register.
+// typ = operand type (e.g CHAR, POINTER, INT ...)
+// n   = the offset when dealing with multi-world objects (e.g long, float)
+static void emit_load(FILE *f, int reg, struct obj *s, int typ, int n, char *op)
+{
+   struct obj	*x;
+   int		ofs;
+
+// if target register is blank, we quit
+   if (reg == 0) return;
+
+   x = mymalloc(sizeof(struct obj));
+
+// build a target register object
+   x->flags = REG;
+   x->reg = reg;
+   x->dtyp = 0;
+   x->v = 0;
+   x->am = 0;
+
+// generate operation
+   emit_op(f, x, s, typ, n, op);
+// we have to take care of the speical case of address of auto variable
+   if ((s->flags & (VAR|VARADR)) == (VAR|VARADR)) {
+      if (isauto(s->v->storage_class)) {
+// calculate offset into stack
+         ofs = ofs_get(s) + n;
+         if (ofs) {       
+	 emit(f, "\tadd\t%s, %d\n", regnames[reg], ofs);
+         } 
+      }
+   }
+
+   myfree(x);
+}
+ 
+// Generate the following code:
+//    mov t, reg
+// typ = operand type (e.g CHAR, POINTER, INT ...)
+// n   = the offset when dealing with multi-world objects (e.g long, float)
+static void emit_store(FILE *f, struct obj *t, int reg, int typ, int n)
+{
+   struct obj	*x;
+
+// if source register is blank, we quit
+   if (reg == 0) return;
+
+   x = mymalloc(sizeof(struct obj));
+
+// build a source register object
+   x->flags = REG;
+   x->reg = reg;
+   x->dtyp = 0;
+   x->v = 0;
+   x->am = 0;
+
+// generate operation
+   emit_op(f, t, x, typ, n, "mov");
+
+   myfree(x);
+}
+
+void am_alloc(struct obj *x)
+{
+// if no object, return
+   if (x == 0) return;
+// if already allocated, return
+   if (x->am) return;
+
+   x->am = mymalloc(sizeof(struct AddressingMode));
+   x->am->regptr = 0;
+   x->am->regval[0] = 0;
+   x->am->regval[1] = 0;
+}
+
+// Compare if 2 objects are the same.
+int obj_eq(struct obj *x1, struct obj *x2)
+{
+   int		ret;
+
+// we assume the objects are equal to start with
+   ret = 1;
+
+   if (x1==0 || x2==0) {
+      ret = 0;
+   } else {
+      if (x1->flags != x2->flags) ret = 0;
+      if (x1->reg != x2->reg) ret = 0;
+   }
+
+   return ret;
+}
+
+/*
+Initialize register tracking system.
+The tracking systemis is used to keep track of what register is used and holds
+what at any given time. Depending on availability, temporary registers can be
+allocated with best efficiency.
+*/
+static void track_init(void)
+{
+   int		i;
+
+// pre-fill
+   for(i = 1; i <= MAXR; i++) {
+// clear all unnecessary bits
+      track_status[i] &= (TRACK_OFFLIMITS | TRACK_DEDICATED);
+   }
+
+// all slots are empty at the beginning.
+   for (i = 0; i < TRACK_SLOTS; i++) {
+// indicate slot is not used      
+     track_slot[i] = 0;
+   }
+}
+
+
+// Mark any register used by the IC
+static void track_obj_claim(struct obj *x)
+{
+// analyze object and flag already used registers as 'no-go'
+   if (x && (x->flags & REG)) {
+      track_status[x->reg] |= TRACK_IC;
+   }
+}
+
+/* 
+Allocate the required temporary registers
+to be able to generate code for the given IC.
+Each operand gets an 'am' datastructure, which
+is filled with the temporary registers to use.
+
+And it works like this
+z   =   q1 <op> q2
+ptr     ptr     ptr
+val     val
+
+There's only one ptr that satisfies all three operand.
+There's only one val that is used for both q1 and z.
+
+So for example in if we have q1(ptr, val) that means:
+Use register ptr to get q1 into register val.
+
+Or for z(ptr, val): Use register ptr to store register val
+to the target location.
+*/
+
+
+/*
+0. determine if we need to free previously allocated temps
+a. we do this if we got a branch or if the current IC uses any temp reg
+1. determine how many temporaries we need
+2. check if we can reuse previously reserved temps
+3. reserve temps if necessary (and make it smart, pick the ones that are not used in the next IC)
+*/
+
+static int track_alloc(FILE *f)
+{
+   int		reg;
+   int		i;
+   int		save;
+
+   reg = 0;
+   save = 0;
+// try to find a register
+// If we can't find one, there's some serious issue.
+   for (i = 1; i < MAXR+1; i++) {
+      if ((track_status[i] & (TRACK_NOGO|TRACK_ALLOCREG|TRACK_SAVED)) == TRACK_ALLOCREG) {
+// found a register, but it must be saved, keep looking maybe
+// we find a better one, only use this if we haven't found anything useful yet
+         if (reg == 0) {
+            reg = i;
+            save = 1;
+         }  
+      } else if ((track_status[i] & (TRACK_NOGO|TRACK_ALLOCREG|TRACK_SAVED)) == (TRACK_ALLOCREG|TRACK_SAVED)) {
+// found a register, it's in use by ALLOCREG, but it has already been saved
+// We use it and quit.
+         reg = i;
+	 save = 0;
+	 break;
+      } else if ((track_status[i] & (TRACK_NOGO|TRACK_ALLOCREG|TRACK_SAVED|TRACK_DEDICATED)) == 0) {
+// found an unallocated register which is not a dedicated temp, we use it
+         reg = i;
+	 save = 0;
+	 break;
+      } else if ((track_status[i] & (TRACK_NOGO|TRACK_DEDICATED)) == TRACK_DEDICATED) {
+// found a dedicated temporary, we could use it, but we try to find a better one
+         reg = i;
+	 save = 0;
+      }
+   }
+   if (reg == 0) terror("-- track_alloc: can't find temporary register");
+
+// flag register as taken
+   track_status[reg] |= TRACK_TMP;
+   emit(f, "; allocate temporary: %s\n", regnames[reg]);
+   if (save) {
+      track_status[reg] |= TRACK_SAVED;
+// find an unused storage slot
+      for (i = 0; i < TRACK_SLOTS; i++) {
+         if (!track_slot[i]) break;
+      }
+      if (i >= TRACK_SLOTS) terror("--track_alloc: out of storage slots");
+      track_slot[i] = reg;      
+      emit(f, "\tmov\t[_TSLOT+%d], %s\n", i*2, regnames[reg]);
+   }
+
+   return reg;
+}
+
+
+/*
+Temporary register tracking and assignement.
+*/
+/*
+Check if access to object x requires temporary registers.
+Allocate all required temporary registers.
+*/
+static void track_obj(FILE *f, struct obj *x, int typ)
+{
+   int		i;
+   int		reg, reg2;
+   int		need_tmpval;
+   int		size;
+
+
+// object must have 'am' structure.
+   am_alloc(x);
+
+// determine if we need to free previously allocated temporaries
+// claim registers used by object  
+   track_obj_claim(x);
+// see if one of them was allocated, and free it if necessary
+   for (i = 0; i < TRACK_SLOTS; i++) {
+      reg = track_slot[i];
+      if ((track_status[reg] & (TRACK_IC|TRACK_SAVED)) == (TRACK_IC|TRACK_SAVED)) {
+         track_status[reg] &= ~TRACK_SAVED;
+         track_slot[i] = 0;
+         emit(f, "; restore temporary\n");
+         emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[reg], i*2);
+      }
+   }
+
+// determine how many temporary registers we need
+   need_tmpval = 1;
+   if (x && (x->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+
+   if (need_tmpval) {
+// we need temporary value register, allocate one
+      reg = track_alloc(f);    
+// In case this is a 32-bit operand we need 2 temporaries
+      size = sizetab[typ&NQ];     
+      reg2 = 0;
+      if (size == 4) {
+         reg2 = track_alloc(f);
+      }
+      x->am->regval[0] = reg;
+      x->am->regval[1] = reg2;
+   }
+
+// next step is to check if pointer memory access requires a register
+   if (x && (x->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+      reg = track_alloc(f);
+      x->am->regptr = reg;
+   }
+}
+
+/*
+Check the IC for temporary register requirements.
+Allocate all required temporaries and save them if required.
+*/
+static void track_ic(FILE *f, struct IC *p) 
+{
+   struct obj	*z;
+   struct obj	*q1;
+   struct obj	*q2;
+   int		i;
+   int		reg, reg2;
+   int		need_tmpval;
+   int		size;
+   int		code;
+
+// get objects
+   z = &p->z;
+   q1 = &p->q1;
+   q2 = &p->q2;
+
+// get instruction code
+   code = p->code;
+
+// each object must have 'am' structure.
+   am_alloc(z);
+   am_alloc(q1);
+   am_alloc(q2);
+
+
+// determine if we need to free previously allocated temporaries
+// claim registers used by IC   
+   track_obj_claim(z);
+   track_obj_claim(q1);
+   track_obj_claim(q2);
+
+// see if one of them was allocated, and free it if necessary
+   for (i = 0; i < TRACK_SLOTS; i++) {
+      reg = track_slot[i];
+      if ((track_status[reg] & (TRACK_IC|TRACK_SAVED)) == (TRACK_IC|TRACK_SAVED)) {
+         track_status[reg] &= ~TRACK_SAVED;
+	 track_slot[i] = 0;
+	 emit(f, "; restore temporary\n");
+	 emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[reg], i*2);
+      }
+   }
+
+// determine how many temporary registers we need
+   need_tmpval = 1;
+   if (z && (z->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+   if (q1 && (q1->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+   if (q2 && (q2->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+
+// if target Z is NOT the same as Q1 we will always need a temporary   
+   if (code == ASSIGN || code == CONVERT) {
+      ;
+   } else if (code == COMPARE) {
+// in case of COMPARE we need a temporary if Q1 == KONST
+      if (q1 && (q1->flags & KONST) == KONST) need_tmpval = 1;
+   } else {
+      if (!obj_eq(z, q1)) {
+         need_tmpval = 1;
+      }
+   }
+
+   if (need_tmpval) {
+      reg = 0;
+// check if we can use target register as temporary
+// We can do so if Q2 is not the same as Z      
+      if (z) {   
+         if (((z->flags & (REG|DREFOBJ)) == REG) && !obj_eq(z, q2)) {
+            reg = z->reg;
+	    track_status[reg] |= TRACK_TMP;
+         } else {
+// we need temporary value register, allocate one
+            reg = track_alloc(f);
+         }
+// In case this is a 32-bit operand we need 2 temporaries
+         size = sizetab[ztyp(p)&NQ];     
+         reg2 = 0;
+         if (size >= 4) {
+            reg2 = track_alloc(f);
+         }
+         z->am->regval[0] = reg;
+         z->am->regval[1] = reg2;
+      }
+// Q1 need the same temp as Z, but maybe only 16-bit
+      if (q1) {
+         if (!reg) {
+	    reg = track_alloc(f);
+         }
+         q1->am->regval[0] = reg;
+         if (sizetab[q1typ(p)&NQ] <= 2) {
+            reg2 = 0;
+         }
+        q1->am->regval[1] = reg2;
+      }
+   }
+
+// next step is to check if pointer memory access requires a register
+   reg = 0; 
+   if (z && (z->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+      if (!reg) reg = track_alloc(f);
+      z->am->regptr = reg;
+   } 
+   if (q1 && (q1->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+      if (!reg) reg = track_alloc(f);
+      q1->am->regptr = reg;
+   } 
+   if (q2 && (q2->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+      if (!reg) reg = track_alloc(f);
+      q2->am->regptr = reg;
+   }
+
+}
+
+static void track_release(void)
+{
+   int		i;
+
+   for (i = 1; i <= MAXR; i++) {
+      track_status[i] &= ~(TRACK_TMP|TRACK_IC);
+   }
+}
+
+/*
+Restores all saved temporary registers.
+This must be executed before any branch, call
+or function exit.
+*/
+static void track_restore(FILE *f)
+{
+   int		i;
+
+   track_release();
+   for (i = 0; i < TRACK_SLOTS; i++) {
+      if (track_slot[i]) {
+         track_status[track_slot[i]] &= ~(TRACK_SAVED);
+	 emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[track_slot[i]], i*2);
+	 track_slot[i] = 0;
+      }
+   }
+}
+// same as above, but don't clear TRACK_SAVED and don't release the temps.
+// This is used in branch instructions.
+static void track_restore2(FILE *f)
+{
+   int		i;
+
+   for (i = 0; i < TRACK_SLOTS; i++) {
+      if (track_slot[i]) {
+	 emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[track_slot[i]], i*2);
+      }
+   }
+}
+
+
+
+/* generates the function entry code */
+static void cd_function_entry(FILE *f, struct Var *v, long offset)
+{
+   int		i;
+
+   if (section != SEC_TEXT) {
+      emit(f, "\n\tsection\t%s\n", sec_textname);
+      section = SEC_TEXT;
+   }
+
+   if (v->storage_class == EXTERN) emit(f,"\tpublic\t%s%s\n", ident_prefix, v->identifier);
+   emit(f,"%s%s:\n", ident_prefix,v->identifier);
+
+   if (v->vattr && strstr(v->vattr, EXTDATA_INTERRUPT)) {     
+// interrupt service routine
+      emit(f, "\tpush\tflags\n");
+      for (i = REG_R0; i < REG_R0+nregs; i++) {
+         emit(f, "\tpush\t%s\n", regnames[i]);
+      }
+   }   
+            
+// allocate required stack
+   if (offset > 0) emit(f,"\tsub\tsp, %ld\n", offset);
+
+// store non-scratch register used in function
+   for (i = 1; i <= MAXR; i++) {
+      if (!regsa[i] && !regscratch[i] && regused[i]) {
+         emit(f, "\tpush\t%s\n", regnames[i]);
+// adjust stack offset
+         stackoffset -= 2;
+      }
+   }
+}
+
+/* generates the function exit code */
+static void cg_function_exit(FILE *f, struct Var *v, long offset)
+{
+   int		i;
+
+// restore any saved temporary registers
+// I don't think this is necessary as long as we don't have global register variables.
+// What does vbcc do? Global regs?
+   track_restore(f);
+
+// restore non-scratch register used in function
+   for (i = MAXR; i >= 1; i--) {
+      if (!regsa[i] && !regscratch[i] && regused[i]) {
+         emit(f, "\tpop\t%s\n", regnames[i]);
+         stackoffset += 2;
+      }
+   }
+
+   if (offset > 0) {
+      emit(f,"\tadd\tsp, %ld\n", offset);
+   }
+   
+   if (v->vattr && strstr(v->vattr, EXTDATA_INTERRUPT)) {
+// interrupt service routine
+      for (i = REG_R0+nregs-1; i >= REG_R0; i--) {
+         emit(f, "\tpop\t%s\n", regnames[i]);
+      }
+      emit(f, "\tpop\tflags\n");
+      emit(f, "\tiret\n\n");
+   } else {   
+      emit(f, "\tret\n\n");
+   }
+}
+
+/* 
+some blurp:
+There's an IC, which contains a target(z), and 2 sources(q1 and q2).
+Macros ztyp, q1typ and q2typ return the type of the operands
+e.g. (char, int, short, double, struct, array....).
+Also contains the qualifiers UNSIGNED, CONST
+Most of the time it's the same for all operands. Exceptions are
+CONVERT or adding int to pointer.
+Using NU and NQ will remove qualifiers and only leave base type.
+
+Of interest are:
+ISPOINTER, ISINT, ISFLOAT, ISFUNC, ISSTRUCT, ISUNION, ISARRAY,
+ISSCALAR, ISARITH
+
+Each operand can be one of the following:
+----------------------------------------
+KONST			constant number
+KONST|DREFOBJ		absolute pointer
+REG			register
+VAR			variable (can be auto, register, static, extern)
+VAR|REG			a variable which was put in a register
+REG|DREFOBJ		indirect [reg]
+VAR|DREFOBJ		indirect [var]
+VAR|REG|DREFOBJ		indirect [reg], where the register is a variable
+VAR|VARADR		address of a variable
+
+Temporaries generated by the compiler don't have the VAR flag set.
+It is only a VAR if it is so in the source code.
+
+Each variable then has information regarding the storage class,
+so each VAR is on of the following:
+AUTO
+REGISTER
+STATIC
+EXTERN
+
+Macros of interest:
+isauto, isextern, isstatic.
+
+*/
+/* val_push
+Pushing the value of the object onto the stack.
+*/
+static void val_push(FILE *f, struct obj *x, int typ)
+{
+// handle required temporaries	   
+   track_obj(f, x, typ); 
+
+   emit(f, "; push val\n");
+   
+// Load Q1 into temporary register val if necessary.
+// Automatically use temporary x->am->regptr if necessary.
+   emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+   emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+
+// emit operation
+  if (x->am->regval[1]) {
+      emit(f, "\tpush\t%s\n", regnames[x->am->regval[1]]);
+      stackoffset -= 2;
+   }
+   if (x->am->regval[0]) {
+// operation is performed on temporaries
+      emit(f, "\tpush\t%s\n", regnames[x->am->regval[0]]);
+      stackoffset -= 2;
+    } else {
+// operation is performed directly on target (z == q1 for this to work)
+      emit(f, "\tpush\t%s\n", regnames[x->reg]);
+      stackoffset -= 2;
+   }
+
+// release temporaries
+   track_release();
+}
+/* ptr_push
+Pushing the ptr to the object onto the stack.
+In case the object is a KONST, a copy of the KONST is made
+in romsection and a pointer to the constant is pushed.
+WARNING WARNING WARNING
+This function MODIFIES the object *x.
+*/
+static void ptr_push(FILE *f, struct obj *x)
+{
+// handle required temporaries	   
+   track_obj(f, x, POINTER); 
+
+   emit(f, "; push ptr to object\n");
+   
+// modify the IC such that we can generate code from it
+
+// what we should do here is: if DREFOBJ is set, clear it. If DREFOBJ is not set, set VARADR.
+      if (x->flags & DREFOBJ) {
+         x->flags &= ~DREFOBJ;
+     } else {    
+	 x->flags |= VARADR;
+      }
+      x->dtyp = POINTER;
+
+// Load object into temporary register val if necessary.
+// Automatically use temporary x->am->regptr if necessary.
+   emit_load(f, x->am->regval[0], x, POINTER, 0, "mov");
+
+// emit operation
+   if (x->am->regval[0]) {
+// operation is performed on temporaries
+      emit(f, "\tpush\t%s\n", regnames[x->am->regval[0]]);
+      stackoffset -= 2;
+    } else {
+// operation is performed directly on target (z == q1 for this to work)
+      emit(f, "\tpush\t%s\n", regnames[x->reg]);
+      stackoffset -= 2;
+   }
+
+// release temporaries
+   track_release();
+}
+
+/*
+Get the object from the stack. It is assumed the object is
+located at [sp]. It is subsequently transfered to x
+[sp] --> x
+This function can be implemented either using 'pop' or using '[sp+xx]'.
+Either one has advantage or disadvantage, also depending on CPU
+implementation.
+*/
+void val_pop(FILE *f, struct obj *x, int typ)
+{
+   emit(f, "; pop val\n");
+
+// handle required temporaries	   
+   track_obj(f, x, typ); 
+   
+// Load [sp] value into temporary register val if necessary.
+   if (x->am->regval[0]) {
+// operation is performed on temporaries
+      emit(f, "\tpop\t%s\n", regnames[x->am->regval[0]]);
+      stackoffset += 2;
+      if (x->am->regval[1]) {
+         emit(f, "\tpop\t%s\n", regnames[x->am->regval[1]]);
+         stackoffset += 2;
+      }
+   } else {
+// operation is performed directly on target (z == q1 for this to work)
+      emit(f, "\tpop\t%s\n", regnames[x->reg]);
+      stackoffset += 2;
+   }
+
+// store to target
+   emit_store(f, x, x->am->regval[0], typ, 0);
+   emit_store(f, x, x->am->regval[1], typ, 2);
+
+// release temporaries
+   track_release();
+}
+
+/*
+Library call for ALU functions.
+*/
+static void lib_alu(FILE *f, struct IC *p, char *call)
+{
+   char		*modifier;
+   char		*dtype;
+   int		size;
+
+   // do some checking first
+   if (q1typ(p) != q2typ(p)) terror("--lib_alu: type mismatch");
+
+   modifier = "S";
+   if (q1typ(p) & UNSIGNED) {
+      modifier = "U";
+   }
+
+   switch (q1typ(p)) {
+      case CHAR: 
+         dtype = "I8"; break;
+      case SHORT:
+      case INT:
+         dtype = "I16"; break;
+      case LONG:
+         dtype = "I32"; break;
+      case FLOAT:
+         dtype = "F32"; break;
+      case DOUBLE:
+         dtype = "F64"; break;
+      default:
+         dtype = ""; break;
+         terror("--lib_alu: data type not supported");
+	 break;
+   }
+// handle required temporaries
+// temporary allocation is handled in val_push instead.
+// The idea here is to allocate all required temporaries now,
+// such that the return value can be easily grabbed.
+// This is not implemented right now due to complications.
+//   track_ic(f, p);
+
+// push the spaceholder for the result
+   size = sizetab[ztyp(p)&NQ];
+   if (size <= 2) {
+// stack is 2-byte minimum
+   if (size < 2) size = 2;
+   emit(f, "\tsub\tsp, %d\n", size);
+   stackoffset -= size;
+// Push all arguments
+   val_push(f, &p->q2, q2typ(p));
+   val_push(f, &p->q1, q1typ(p));
+   } else {
+      ptr_push(f, &p->q2);
+      ptr_push(f, &p->q1);
+   }
+   track_restore(f);
+// emit call to library function
+   emit(f, "\tcall\t_%s_%s%s\n", call, modifier, dtype);
+
+// restore stack state
+// use 2*size in case 'val_pop' actually pops,
+// use 3*size in case 'val_pop uses [sp+xx]
+    emit(f, "\tadd\tsp, %d\n", (int)2*size);
+    stackoffset += 2*size;
+
+// last step is to grab the return value
+// Return value is at [sp].
+   val_pop(f, &p->z, ztyp(p));
+
+} 
+
+
+/*
+Library call for mempry copy functions.
+*/
+static void lib_mov(FILE *f, struct IC *p)
+{
+
+// modify the IC such that we can generate code from it      
+   p->q2.flags = KONST;
+
+// Push Q2 (number of bytes to copy)
+   emit(f, "; push array size\n");
+   val_push(f, &p->q2, INT);
+// Push pointer to Q1 (source)
+   emit(f, "; push source pointer\n");
+   ptr_push(f, &p->q1);
+// push pointer to target (Z)
+   emit(f, "; push target pointer\n");
+   ptr_push(f, &p->z);
+
+   track_restore(f);
+// emit call to library function
+   emit(f, "\tcall\t_MOV\n");
+
+// stack cleanup, we should use callee clean-up
+    emit(f, "\tadd\tsp, %d\n", (int)6);
+    stackoffset += 6;
+} 
+/*
+
+*/
+static void cg_assign(FILE *f, struct IC *p)
+{
+   struct obj	*x;
+   int		typ;
+   int		size;
+
+// any struct or array goes to library function
+// anything > 4 bytes goes to library
+// size is only possible with ASSIGN, not CONVERT.
+   if (p->code == ASSIGN) {
+      size = opsize(p);
+      if (size > 4 || ISCOMPOSITE(ztyp(p))) {
+
+         lib_mov(f, p);
+         return;
+      }
+   }
+
+// handle required temporaries   
+   track_ic(f, p);
+
+   // We also get here for CONVERT, so test don't work.
+  // if (q1typ(p) != ztyp(p)) terror(0);
+   emit(f, "; mov\n");
+
+// emit operation
+   typ = q1typ(p);
+   x = &p->q1;
+   if (x->am->regval[0]) {
+// operation is performed on temporaries
+      emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+      emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+   } else {
+// operation is performed directly, no temporaries involved
+      emit_op(f, &p->z, x, typ, 0, "mov");
+   }
+
+// check if this is a CONVERT operation and inject sign extension
+// if necessary.
+   if (p->code == CONVERT) {
+// if Q1 is CHAR we need to blow it up to INT      
+      if (sizetab[q1typ(p) & NQ] == 1) {
+         if (typ & UNSIGNED) {
+// clear high byte            
+            if (p->z.am->regval[0]) {
+	       emit(f, "\tand\t%s, 0xff\n", regnames[p->z.am->regval[0]]);
+            } else {
+	       emit(f, "\tand\t%s, 0xff\n", regnames[p->z.reg]);
+	    }
+         } else {
+// SXT high byte
+            if (p->z.am->regval[0]) {
+               emit(f, "\tsxt.8\t%s\n", regnames[p->z.am->regval[0]]);
+            } else {
+	       emit(f, "\tsxt.8\t%s\n", regnames[p->z.reg]);
+	    }
+	 }
+      }         
+// if Z is LONG we need to blow it up from INT to LONG      
+      if (sizetab[ztyp(p) & NQ] == 4) {      
+         if (typ & UNSIGNED) {
+            emit(f, "\tmov\t%s, 0\n", regnames[p->z.am->regval[1]]);
+         } else {
+            emit(f, "\tmov\t%s, %s\n", regnames[p->z.am->regval[1]], regnames[p->z.am->regval[0]]);
+            emit(f, "\tsxt\t%s\n", regnames[p->z.am->regval[1]]);
+         } 
+      }
+   }
+// emit store if necessary
+   typ = ztyp(p);
+   x = &p->z;
+   emit_store(f, x, x->am->regval[0], typ, 0);
+   emit_store(f, x, x->am->regval[1], typ, 2);
+
+// release temporaries
+   track_release();
+}   
+
+
+static void cg_push(FILE *f, struct IC *p)
+{
+   int		size;
+
+// any object larger than 4 bytes goes to a library function
+   size = opsize(p); // might need to use pushsize here instead of opsize?
+   if (size > 4 || ISCOMPOSITE(q1typ(p))) {
+// allocate required stack
+      emit(f, "\tsub\tsp, %d\n", size);
+      stackoffset -= size;
+
+// Push Z (number of bytes to push)
+      emit(f, "; push array size\n");
+// modify z such that it becomes a KONST      
+      p->z.flags = KONST;
+      val_push(f, &p->z, INT);
+// Push pointer to Q1 (source)
+      emit(f, "; push source pointer\n");
+      ptr_push(f, &p->q1);
+
+// emit call to library function
+      emit(f, "\tcall\t_PUSH\n");
+
+// stack cleanup, we should use callee clean-up
+      emit(f, "\tadd\tsp, %d\n", (int)4);
+      stackoffset += 4;
+      return;
+   }
+// handle required temporaries of 1op instructions	   
+  // track_push(f, p); // this must go, needs to be part of val_push
+
+   val_push(f, &p->q1, q1typ(p));
+
+} 
+
+static void cg_call(FILE *f, struct IC *p) 
+{
+   long		size = pushedargsize(p);
+   long		ofs;
+   
+// calculate offset into stack
+   ofs = ofs_get(&p->q1);
+   
+   emit(f, "; call\n");
+  
+// restore any temporaries
+   track_restore(f);
+
+   if ((p->q1.flags & (VAR|DREFOBJ)) == VAR) {
+// call to label      
+      emit(f, "\tcall\t%s%s\n", ident_prefix, p->q1.v->identifier);
+   } else if ((p->q1.flags & (VAR|DREFOBJ)) == (VAR|DREFOBJ) && p->q1.dtyp == POINTER) {
+      terror("-- call:  pointer argument not yet supported");
+   } else terror("-- call: unexpected call mode\n");   
+   if (size > 0) {
+      emit(f,"\tadd\tsp, %ld\n", size);
+      stackoffset += size;
+   }    
+}
+
+
+static void cg_alu(FILE *f, struct IC *p)
+{
+   struct obj	*x;
+   int		typ;
+   int		c;
+   char		*instr1, *instr2;
+
+   c = p->code;
+   switch (c) {
+      case ADD: instr1 = "add"; instr2 = "addc"; break;
+      case SUB: instr1 = "sub"; instr2 = "subc"; break;
+      case ADDI2P: instr1 = "add"; instr2 = "addc"; break;
+      case SUBIFP: instr1 = "sub"; instr2 = "subc"; break;
+      case OR: instr1 = instr2 = "or"; break;
+      case AND: instr1 = instr2 = "and"; break;
+      case XOR: instr1 = instr2 = "xor"; break;
+      default: instr1 = "xxx"; break;
+   };   
+      
+   emit(f, "; %s\n", instr1);
+
+   // get type of argument
+   typ = ztyp(p);   
+
+// try to get z and q1 the same, if possible
+   switch_IC(p); 
+// handle required temporaries of 2op instructions	  
+   track_ic(f, p);
+
+
+   if (!ISINT(typ) && !ISPOINTER(typ)) terror("-- addsub: unexpected operands");
+ 
+// Load Q1 into temporary register val if necessary.
+// Automatically use temporary x->am->regptr if necessary.
+   x = &p->q1;
+   emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+   emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+
+// emit operation
+   x = &p->z;
+   if (x->am->regval[0]) {
+// operation is performed on temporaries
+      emit_load(f, x->am->regval[0], &p->q2, typ, 0, instr1);
+      emit_load(f, x->am->regval[1], &p->q2, typ, 2, instr2);
+   } else {
+// operation is performed directly on target (z == q1 for this to work)
+      emit_op(f, x, &p->q2, typ, 0, instr1);
+   }
+
+// emit store if necessary
+   x = &p->z;
+   if (x->am->regval[0]) {
+      if (((x->flags & (REG|DREFOBJ)) != REG) && x->reg != x->am->regval[0]) { 
+// only write store if target is not a register or in case it is a register it
+// is not the same as the source.
+         emit_store(f, x, x->am->regval[0], typ, 0);
+         emit_store(f, x, x->am->regval[1], typ, 2);
+      }
+   }
+// release temporaries
+   track_release();
+}                   	 
+
+
+static void cg_lshift(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+   lib_alu(f, p, "SHL");
+}  
+      
+static void cg_rshift(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+   lib_alu(f, p, "SHR");
+}        
+        
+
+static void cg_mult(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+   lib_alu(f, p, "MUL");
+}        
+
+static void cg_div(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+   lib_alu(f, p, "DIV");
+}        
+
+static void cg_mod(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+   lib_alu(f, p, "MOD");
+} 
+/*
+modify IC such that we get
+z = q1 xor 0xffff
+*/
+static void cg_komplement(FILE *f, struct IC *p)
+{
+   struct obj	*x;
+
+   emit(f, "; komplement\n");
+
+   p->code = XOR;
+
+// change q2 to const 0
+   x = &p->q2;
+   x->flags = KONST;
+   x->reg = 0;
+   x->dtyp = 0;
+// insert 0xffff
+   gval.vmax = -1;
+   eval_const(&gval, MAXINT);
+   insert_const(&x->val, ztyp(p));
+
+// transfer to alu
+   cg_alu(f, p);
+}    
+
+/*
+modify IC such that we get
+z = 0 - q1
+*/
+static void cg_minus(FILE *f, struct IC *p)
+{
+   struct obj	*x;
+
+   emit(f, "; minus\n");
+
+   p->code = SUB;
+   p->q2 = p->q1;
+
+// change q1 to const 0
+   x = &p->q1;
+   x->flags = KONST;
+   x->reg = 0;
+   x->dtyp = 0;
+// is this the right way of generating a constant?
+   gval.vmax = 0;
+   eval_const(&gval, MAXINT);
+   insert_const(&x->val, ztyp(p));
+
+// transfer to alu
+   cg_alu(f, p);
+
+}    
+
+static void cg_address(FILE *f, struct IC *p)
+{
+   struct obj	*x;
+   int		typ;
+   long		ofs;
+   int		reg;
+   
+// calculate offset into stack
+   ofs = ofs_get(&p->q1);
+
+// handle required temporaries of 1op instructions	   
+   track_ic(f, p);
+
+   emit(f, "; address\n");
+   
+// emit operation
+   typ = ztyp(p);
+   x = &p->z;
+   reg = x->reg;
+   if (x->am->regval[0]) {
+      reg = x->am->regval[0];
+   }
+// emit operation
+   emit(f, "\tmov\t%s, sp\n", regnames[reg]);
+   if (ofs != 0) emit(f, "\tadd\t%s, %ld\n", regnames[reg], ofs);
+
+// emit store if necessary
+   typ = ztyp(p);
+   x = &p->z;
+   if (x->am->regval[0]) {
+      if ((x->flags & (REG|DREFOBJ)) != REG) { 
+// only write store if target is not a register 
+         emit_store(f, x, x->am->regval[0], typ, 0);
+      }
+   }
+// release temporaries
+   track_release();
+}
+
+/*
+modify IC such that we get
+COMPARE q1, 0
+*/
+static void cg_test(FILE *f, struct IC *p)
+{
+   struct obj	*x;
+
+   emit(f, "; test\n");
+
+   p->code = COMPARE;
+
+// change q2 to const 0
+   x = &p->q2;
+   x->flags = KONST;
+   x->reg = 0;
+   x->dtyp = 0;
+// insert 0
+   gval.vmax = 0;
+   eval_const(&gval, MAXINT);
+   insert_const(&x->val, ztyp(p));
+
+}  
+
+/*
+Swap operands q1 <-> q2 of an IC. This is used by the branch IC
+to map the operation to the available comaprisons.
+*/
+static void swap_operands(struct IC *p)
+{
+   struct obj y;
+   y = p->q1;
+   p->q1 = p->q2;
+   p->q2 = y;
+}
+
+static void cg_branch_modify(struct IC *cmp, struct IC *p)
+{
+   int		c;
+   int		q2_inc;
+   int		swap;
+   int		q2_konst;  
+
+   
+// grab the branch instruction
+   c = p->code;
+   
+/*
+In case Q1 == KONST we need to swap operands, however
+this only makes a difference in case Q2 == REG.
+This whole logic here might not be necessary if the front-end
+always puts KONST in Q2. Test seem to confirm this, however for
+the time being we leave the code in.
+*/
+   if (((cmp->q1.flags & (KONST|DREFOBJ)) == KONST) && ((cmp->q2.flags & (REG|DREFOBJ)) == REG)) {
+// swap operands      
+      swap_operands(cmp);
+// modify branch condition to match operand swap
+      switch (c) {
+         case BLT: c = BGT; break;
+         case BGE: c = BLE; break;
+         case BLE: c = BGE; break;
+         case BGT: c = BLT; break;
+      }
+   }
+
+// Check if Q2 is a KONST. If it is we shouldn't swap operands.
+   q2_konst = 0;
+   if ((cmp->q2.flags & (KONST|DREFOBJ)) == KONST) {
+      q2_konst = 1;
+   }
+
+// initialize modification falgs
+   swap = 0;
+   q2_inc = 0;
+
+// decode jump and decide what modifications must be undertaken.
+   switch (c) {
+// equal ==, generate 'je'
+      case BEQ: break;
+// not equal !=, generate 'jne'      
+      case BNE: break;
+// less than '<'
+      case BLT: break;
+// greater equal '>='      
+      case BGE: break;
+// less equal '<=' 
+// This must be changed into BLT or BGE     
+      case BLE:
+	 if (q2_konst) {
+// Q2 is KONST, can't swap operands but must modify the constant
+	    c = BLT;
+	    q2_inc = 1;
+	 } else {
+// must swap operands to map to available comparison instructions
+            c = BGE;
+	    swap = 1;
+	 }   
+	 break;
+// greater than '>'
+      case BGT:
+	 if (q2_konst) {
+// Q2 is KONST, can't swap operands but must modify the constant
+	    c = BGE;
+	    q2_inc = 1;
+	 } else {
+// must swap operands to map to available comparison instructions
+            c = BLT;
+	    swap = 1;
+	 }   
+	 break;
+   }
+
+/* 
+MODIFY IC if neccessary.
+Modification looks like this:
+If q2_inc == 1, we increment KONST q2 by 1.
+If swap == 1, we swap operands.
+Either way, we replace the  exisiting condition code with the new one.
+*/
+   if (swap) swap_operands(cmp);
+   if (q2_inc) {
+// partial constant
+      struct obj *x; 
+// increment Q2
+      x = &cmp->q2;
+// not sure if this is the way I'm supposed to do this
+      eval_const(&x->val, q2typ(cmp));
+      gval.vmax = zmadd(vmax, 1);
+      eval_const(&gval, MAXINT);
+      insert_const(&x->val, q2typ(cmp));
+   }
+// insert new condition code
+   p->code = c;
+}
+
+//static void cg_branch
+
+static void cg_branch(FILE *f, struct IC *p)
+{
+   struct IC	*cmp;
+   int		c;
+// size in bytes   
+   long		size;
+   int		typ;
+   char		*sign;
+// jump target
+// The target in case the condition is satisfied
+   long		target_true;
+// the target in case the condition is violated
+   long		target_false; 
+// partial constant
+   struct obj	*x; 
+   
+      
+   if (q1typ(p) != q2typ(p)) terror(0);
+ 
+   emit(f, "; compare\n");
+   
+
+// try to find compare IC
+   cmp = p->prev;
+   while (cmp && cmp->code == FREEREG) cmp = cmp->prev;
+   if (!cmp || (cmp->code != COMPARE && cmp->code != TEST)) terror("-- cg_branch: compare not found");   
+
+   typ = q1typ(cmp);
+   size = sizetab[typ&NQ];
+
+   if (!ISINT(typ)) terror("-- cg_branch: unexpected object type");
+   
+// get jump target
+   target_true = (long)p->typf;
+   target_false = label_count++;
+
+   cg_branch_modify(cmp, p);
+
+// grab the branch instruction
+   c = p->code;
+
+// determine sign/unsigned modifier
+   sign = "s";
+   if (typ & UNSIGNED) {
+      sign = "u";
+   }
+
+// 1. step we allcoate necessay temporaries	  
+   track_ic(f, cmp);
+
+// We need to distinguish different operand sizes
+   if (size <= 2) {
+// First case takes care of CHAR and INT/SHORT
+      x = &cmp->q1;
+      emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+// emit operation
+      if (x->am->regval[0]) {
+// operation is performed on temporaries
+         emit_load(f, x->am->regval[0], &cmp->q2, typ, 0, "cmp");
+      } else {
+// operation is performed directly on target (z == q1 for this to work)
+         emit_op(f, x, &cmp->q2, typ, 0, "cmp");
+      }
+// must restore temporaries here,
+      track_restore(f);
+
+      switch (c) {
+         case BLT:
+            emit(f, "\tj%sl\t%s%ld\n", sign, label_prefix, target_true);
+	    break;
+         case BGE:
+            emit(f, "\tj%sge\t%s%ld\n", sign, label_prefix, target_true);
+	    break;
+         case BEQ:
+            emit(f, "\tje\t%s%ld\n", label_prefix, target_true);
+	    break;
+         case BNE:
+            emit(f, "\tjne\t%s%ld\n", label_prefix, target_true);
+	    break;
+      }
+
+   } else if (size == 4) {
+// LONG
+      x = &cmp->q1;
+      emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+      emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+// emit operation
+      if (x->am->regval[1]) {
+// operation is performed on temporaries
+         emit_load(f, x->am->regval[1], &cmp->q2, typ, 2, "cmp");
+      } else {
+// operation is performed directly on target (z == q1 for this to work)
+         emit_op(f, x, &cmp->q2, typ, 2, "cmp");
+      }
+// must restore temporaries here,
+      track_restore2(f);// (but don't release)
+      switch (c) {
+         case BLT:
+            emit(f, "\tj%sl\t%s%ld\n", sign, label_prefix, target_true);
+            emit(f, "\tjne\t%sn%ld\n", label_prefix, target_false);
+	    break;
+         case BGE:
+            emit(f, "\tj%sl\t%sn%ld\n", sign, label_prefix, target_false);
+            emit(f, "\tjne\t%s%ld\n", label_prefix, target_true);
+	    break;
+         case BEQ:
+            emit(f, "\tjne\t%sn%ld\n", label_prefix, target_false);
+	    break;
+         case BNE:
+            emit(f, "\tjne\t%sn%ld\n", label_prefix, target_true);
+	    break;
+      }
+// here we have to reallocate temporary. HOWEVER if done cleverly we don't have
+// to reload it, I have to think about the whole thing a litte bit.
+  // (reload what is needed, use same temps as above)
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+
+      // emit operation
+      if (x->am->regval[0]) {
+// operation is performed on temporaries
+         emit_load(f, x->am->regval[0], &cmp->q2, typ, 0, "cmp");
+      } else {
+// operation is performed directly on target (z == q1 for this to work)
+         emit_op(f, x, &cmp->q2, typ, 0, "cmp");
+      }
+      track_restore(f); 
+     switch (c) {
+         case BLT:
+            emit(f, "\tjuge\t%s%ld\n", label_prefix, target_true);
+	    break;
+         case BGE:
+            emit(f, "\tjul\t%s%ld\n", label_prefix, target_true);
+	    break;
+         case BEQ:
+            emit(f, "\tje\t%s%ld\n", label_prefix, target_true);
+	    break;
+         case BNE:
+            emit(f, "\tjne\t%s%ld\n", label_prefix, target_true);
+	    break;
+      }
+              
+      
+   } else {
+      terror("branch size not supported");
+   }
+
+// emit "not taken" label
+   emit(f, "%sn%ld:\n", label_prefix, target_false);
+
+// release temporaries
+   track_release();
+}
+
+static void cg_setreturn(FILE *f, struct IC *p)
+{
+   emit(f, "; set return\n");
+   
+   if (sizetab[ztyp(p)&NQ] > regsize[p->z.reg]) terror("-- cg_setreturn: size mismatch");
+   emit_load(f, REG_R0, &p->q1, q1typ(p), 0, "mov");
+}
+
+static void cg_getreturn(FILE *f, struct IC *p)
+{
+   emit(f, "; get return\n");
+   
+   if (p->q1.reg) {
+      emit_store(f, &p->z, p->q1.reg, ztyp(p), 0);
+   }
+}
+
+static void cg_movefromreg(FILE *f, struct IC *p)
+{
+   emit_store(f, &p->z, p->q1.reg, ztyp(p), 0);
+}
+
+static void cg_movetoreg(FILE *f, struct IC *p)
+{
+   emit_load(f, p->z.reg, &p->q1, ztyp(p), 0, "mov");
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+   int		i;
+   int		nregs;
+   int		rtmp;
+   int		rsave;
+   
+/*  Initialize some values which cannot be statically initialized   */
+ /*  because they are stored in the target's arithmetic.             */
+   maxalign = l2zm(2L);
+   char_bit = l2zm(8L);
+
+   sizetab[0] = 1; typname[0] = "strange"; align[0] = 1;
+   sizetab[CHAR] = 1; typname[CHAR] = "char"; align[CHAR] = 1;
+   sizetab[SHORT] = 2; typname[SHORT] = "short"; align[SHORT] = 2;
+   sizetab[INT] = 2; typname[INT] = "int"; align[INT] = 2;
+   sizetab[LONG] = 4; typname[LONG] = "long"; align[LONG] = 2;
+   sizetab[LLONG] = 8; typname[LLONG] = "long long"; align[LLONG] = 2;
+   sizetab[FLOAT] = 4; typname[FLOAT] = "float"; align[FLOAT] = 2;
+   sizetab[DOUBLE] = 8; typname[DOUBLE] = "double"; align[DOUBLE] = 2;
+   sizetab[LDOUBLE] = 8; typname[LDOUBLE] = "long double"; align[LDOUBLE] = 2;
+   sizetab[VOID] = 0; typname[VOID] = "void"; align[VOID] = 1;
+   sizetab[POINTER] = 2; typname[POINTER] = "pointer"; align[POINTER] = 2;
+   sizetab[ARRAY] = 0; typname[ARRAY] = "array"; align[ARRAY] = 1;
+   sizetab[STRUCT] = 0; typname[STRUCT] = "struct"; align[STRUCT] = 1;
+   sizetab[UNION] = 0; typname[UNION] = "union"; align[UNION] = 1;
+   sizetab[ENUM] = 2; typname[ENUM] = "enum"; align[ENUM] = 2;
+   sizetab[FUNKT] = 0; typname[FUNKT] = "function"; align[FUNKT] = 1;
+   sizetab[MAXINT] = 0;
+
+// fill in the default register description
+   regnames[0] = "noreg";
+   regnames[REG_R0] = "r0";
+   regnames[REG_R1] = "r1";
+   regnames[REG_R2] = "r2";
+   regnames[REG_R3] = "r3";
+   regnames[REG_R4] = "r4";   
+   regnames[REG_R5] = "r5";
+   regnames[REG_R6] = "r6";
+   regnames[REG_R7] = "r7";
+   regnames[REG_R8] = "r8";
+   regnames[REG_R9] = "r9";
+   regnames[REG_R10] = "r10";
+   regnames[REG_R11] = "r11";
+   regnames[REG_R12] = "r12";
+   regnames[REG_R13] = "r13";
+
+   for (i = 1; i < MAXR+1; i++) {
+      regsize[i] = l2zm(2L);
+      regtype[i] = &ltyp;
+      regscratch[i] = 1;
+      regsa[i] = 0;
+      reg_prio[i] = 1;
+// private register tracking system
+// Indicate register is available as temporary.
+      track_status[i] = 0;
+   }
+
+// default numbers of registers to use
+   nregs = 6;
+// check command line flags for number of registers
+   if (g_flags[0] & USEDFLAG) {
+      nregs = g_flags_val[0].l;
+   }
+   if (nregs < 3) nregs = 3;
+   if (nregs > 14) nregs = 14;  
+// limit available registers to 'nregs'
+   for (i = REG_R0+nregs; i <= REG_R13; i++) {
+      regsa[i] = 1;
+      regscratch[i] = 0;
+      track_status[i] |= TRACK_OFFLIMITS;
+   }
+
+// get the number of temporary registers to reserve
+   if (g_flags[2] & USEDFLAG) {
+      rtmp = g_flags_val[1].l;
+   } else {
+      rtmp = 0;
+      if (nregs >= 6) rtmp = 1;
+      if (nregs >= 9) rtmp = 2;
+      if (nregs >= 12) rtmp = 3;
+   }
+   if (rtmp < 0) rtmp = 0;
+   if (rtmp > 3) rtmp = 3;
+
+// remove temporary registers from code generator pool (on the top side)
+   for (i = nregs-rtmp; i < nregs; i++) {
+      regsa[REG_R0+i] = 1;
+      regscratch[REG_R0+i] = 0;
+// indicate to tracked that this is a dedicated temporary register
+      track_status[REG_R0+i] |= TRACK_DEDICATED;
+   }
+
+// get numbers of registers to save across function calls
+   if (g_flags[1] & USEDFLAG) {
+      rsave = g_flags_val[1].l;
+   } else {
+      rsave = 0;
+// automatically select 
+      if (nregs >= 6) rsave = 2;
+      if (nregs >= 10) rsave = 4;
+   }
+   if (rsave < 0) rsave = 0;
+   if (rsave > nregs-rtmp) rsave = nregs-rtmp;
+
+   for (i = 0; i < rsave; i++) {
+      regscratch[REG_R0+nregs-rtmp-rsave+i] = 0;
+   }
+   
+// SP is special
+   regnames[REG_SP] = "sp";
+   regscratch[REG_SP] = 0;
+   regsa[REG_SP] = 1;
+   track_status[REG_SP] |= TRACK_OFFLIMITS;
+// and FLAGS is special
+   regnames[REG_FLAGS] = "flags";
+   regscratch[REG_FLAGS] = 0;
+   regsa[REG_FLAGS] = 1;
+   track_status[REG_FLAGS] |= TRACK_OFFLIMITS;
+
+// print some status to the screen
+   printf("Falco16 CPU information\n");
+   printf("   GP registers: %d\n", nregs);
+   printf("   temporaries:  %d\n", rtmp);
+   printf("   saves:        %d\n", rsave);
+
+
+
+  /*  Don't use multiple ccs.   */
+  multiple_ccs = 0;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=t_min(SHORT);
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=t_max(SHORT);
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=t_max(UNSIGNED|SHORT);
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+
+  target_macros=marray;
+
+// local label counter
+  label_count = 0;
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+   int	       ret;
+   int	       p;
+   
+   ret = 0;
+   p = t->flags & NQ;
+   
+   if (sizetab[p] <= regsize[REG_R0]) ret = REG_R0;
+  
+   return ret;
+}
+
+int reg_pair(int r, struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}
+
+
+int regok(int r, int t, int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+// simple paramtere check   
+   if(r == 0) return 0;
+
+// if floating point, we don't keep them in registers at all
+   if (ISFLOAT(t)) return 0;
+
+// Must be integer or pointer, keep them in register if possible. 
+   t &= NQ;
+   if (sizetab[t] <= regsize[r]) return 1;
+   
+   return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+
+  return 0;
+}
+
+int must_convert(int src, int dst, int const_expr)
+{
+   int		srcp = src & NQ;
+   int		dstp = dst & NQ;
+
+   if (ISINT(src) && ISINT(dst)) {
+      if (sizetab[srcp] >= sizetab[dstp]) return 0;
+     // if (sizetab[srcp] == 1 && sizetab[dstp] == 2) return 0;        
+   } else if (ISINT(src) && ISPOINTER(dst)) {
+      if (sizetab[srcp] >= sizetab[dstp]) return 0;
+     // if (sizetab[srcp] == 1 && sizetab[dstp] == 2) return 0;        
+   } else if (ISPOINTER(src) && ISINT(dst)) {
+      if (sizetab[srcp] >= sizetab[dstp]) return 0;
+    //  if (sizetab[srcp] == 1 && sizetab[dstp] == 2) return 0;        
+   } 
+   
+// no conversion when src and dst are same type   
+   if (src == dst) return 0;
+
+   
+   return 1;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(np p)
+{
+
+/*
+   following operations go into library
+
+N - native
+L - library call (some paramters are implemented native)
+A - library call (all the time)
+X - not supported
+- - not valid (not generated by front-end)
+? - what to do?
+
+            CHAR  SHORT/INT  LONG  LLONG  FLOAT  DOUBLE  LDOUBLE
+
+CMP          N        N        N     X      ?      X       X
+OR           N        N        N     X      -      -       -
+XOR          N        N        N     X      -      -       -
+AND          N        N        N     X      -      -       -
+LSHIFT       L        L        L     X      -      -       -
+RSHIFT       L        L        L     X      -      -       -
+ADD          N        N        N     X      A      X       X
+SUB          N        N        N     X      A      X       X
+MULT         L        L        L     X      A      X       X
+DIV          L        L        L     X      A      X       X
+MOD          L        L        L     X      A      X       X
+*/
+
+   static char	fname[16];
+   char		*ret;
+   int		f;
+   char		*sign;
+   char		*dtype;
+   int		code;
+
+   if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
+   extern struct Typ *arith_typ();
+    struct Typ *t=arith_typ(p->left->ntyp,p->right->ntyp);
+    f=t->flags&NU;
+    freetyp(t);
+    if((f&NQ)==LLONG){
+      sprintf(fname,"__cmp%s%sll",ename[p->flags],(f&UNSIGNED)&&p->flags!=EQUAL&&p->flags!=INEQUAL?"u":"");
+      ret=fname;
+    }else if((f&NQ)==FLOAT){
+      sprintf(fname,"__cmp%s%sf",ename[p->flags],(f&UNSIGNED)&&p->flags!=EQUAL&&p->flags!=INEQUAL?"u":"");
+      ret=fname;
+    }else if((f&NQ)==DOUBLE||(f&NQ)==LDOUBLE){
+      sprintf(fname,"__cmp%s%sd",ename[p->flags],(f&UNSIGNED)&&p->flags!=EQUAL&&p->flags!=INEQUAL?"u":"");
+      ret=fname;
+    }
+   }else{
+// get code of operation
+      code = p->flags;
+// get data type
+      f = p->ntyp->flags & NU;
+
+      sign = "s";
+      if (f & UNSIGNED) {
+         sign = "u";
+      }
+
+      switch (f & NQ) {
+         case CHAR: dtype = "i8"; break;
+         case SHORT:
+         case INT: dtype = "i16"; break;
+         case LONG: dtype = "i32"; break;
+         case FLOAT: dtype = "f32"; break;
+         case DOUBLE: dtype = "f64"; break;
+         default: dtype = ""; break;
+            terror("--use_libcall: data type not supported");
+	    break;
+      }
+// default is no function
+      ret = 0;
+      switch (code) {
+         case LSHIFT: sprintf(fname, "__shl_%s%s", sign, dtype); ret = fname; break;
+         case RSHIFT: sprintf(fname, "__shr_%s%s", sign, dtype); ret = fname; break;
+         case ADD:
+	    if (ISFLOAT(f)) { sprintf(fname, "__add_%s", dtype); ret = fname; }
+	    break;
+	 case SUB:
+	    if (ISFLOAT(f)) { sprintf(fname, "__sub_%s", dtype); ret = fname; }
+	    break;
+	 case MINUS:
+	    if (ISFLOAT(f)) { sprintf(fname, "__neg_%s", dtype); ret = fname; }
+	    break;
+	 case MULT: sprintf(fname, "__mul_%s%s", sign, dtype); ret = fname; break;
+	 case DIV:
+	    sprintf(fname, "__div_%s%s", sign, dtype); ret = fname;
+	    break;
+	 case MOD:
+	    sprintf(fname, "__mod_%s%s", sign, dtype); ret = fname;
+	    break;
+      }
+   }
+  
+   if(ret){
+/* declare function if necessary */
+      struct struct_declaration *sd;struct Typ *t;
+      if(!find_ext_var(ret)){
+         sd = mymalloc(sizeof(*sd));
+         sd->count = 0;
+         t = new_typ();
+         t->flags = FUNKT;
+         t->exact = add_sd(sd, FUNKT);
+         t->next = clone_typ(p->ntyp);
+         add_var(ret, t, EXTERN, 0);
+      }
+   }
+   return ret;
+}
+
+
+
+void gen_ds(FILE *f, zmax size, struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+   if (newobj) {
+      emit(f, "\tdb\tdup(%ld, 0)\n", zm2l(size));
+   } else {
+      emit (f, "-- somehting's wrong\n");
+   }     
+   newobj = 0;
+}
+
+void gen_align(FILE *f, zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+   int p;
+   p = p; 
+}
+
+void gen_var_head(FILE *f, struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+   int		constflag;
+
+   if (v->clist) constflag = is_const(v->vtyp);
+   if (v->storage_class == STATIC) {
+      if ((v->vtyp->flags&NQ) == FUNKT) return;
+      if (v->clist && (!constflag) && section != SEC_DATA) {
+         emit(f, "\n\tsection\t%s\n", sec_dataname);
+         if (f) section = SEC_DATA;
+      }
+      if (v->clist && constflag && section != SEC_RODATA) {
+         emit(f, "\n\tsection\t%s\n", sec_rodataname);
+         if (f) section = SEC_RODATA;
+      }
+      if (!v->clist && section != SEC_BSS) {
+         emit(f, "\n\tsection\t%s\n", sec_bssname);
+         if (f) section = SEC_BSS;
+      }
+      emit(f, "%s%ld:", label_prefix, zm2l(v->offset));
+
+      newobj = 1;
+   }
+   if (v->storage_class == EXTERN) {
+      if (v->flags & (DEFINED|TENTATIVE)) {
+         if (v->clist && (!constflag) && section != SEC_DATA) {
+            emit(f, "\n\tsection\t%s\n", sec_dataname);
+            if (f) section=SEC_DATA;
+         }
+         if (v->clist && constflag && section != SEC_RODATA) {
+            emit(f, "\n\tsection\t%s\n", sec_rodataname); 
+            if(f) section = SEC_RODATA;
+         }
+         if (!v->clist && section != SEC_BSS) {
+            emit(f, "\n\tsection\t%s\n", sec_bssname);
+            if (f) section = SEC_BSS;
+         }
+         emit(f, "\tpublic\t%s%s\n", ident_prefix, v->identifier);
+         emit(f, "%s%s:", ident_prefix, v->identifier);
+         newobj = 1;
+      }
+   }
+}
+
+void gen_dc(FILE *f, int t, struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+   emit(f, "\t%s\t", dct[t&NQ]);
+   if (!p->tree) {
+      if ((t&NQ) == FLOAT || (t&NQ) == DOUBLE) {
+         emit(f, "-- floating point not supported\n");
+      } else {
+	 emitval(f, &p->val, t&NU);
+      }
+   } else {
+         emit(f, "-- gen_dc: what the hell\n");
+   }
+   emit(f, "\n");
+   newobj = 0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f, struct IC *p, struct Var *v, zmax offset)
+/*  The main code-generation.                                           */
+{
+   struct IC	*head;
+   int		c;
+  
+   if (DEBUG&1) printf("gen_code()\n");
+   
+   loff = ((zm2l(offset) + 1) / 2) * 2;
+   stackoffset = 0;
+   cd_function_entry(f, v, loff);
+   
+// initialize temporary register tracking
+   track_init();
+
+   head = p;
+   for(; p; p = p->next){
+// print: this doesn't work right, due to emit buffer
+   printic(f, p);
+   emit(f, "; stackoffset: %d\n", stackoffset);
+
+// get operation code      
+      c = p->code;
+      
+      switch (c) {
+         case NOP: 
+            break;
+            
+         case ASSIGN:
+	 case CONVERT:
+            cg_assign(f, p);
+            break; 
+         
+         case LSHIFT:
+            cg_lshift(f, p);
+            break;
+         case RSHIFT:
+            cg_rshift(f, p);
+            break;
+            
+         case ADD:
+         case ADDI2P:
+         case SUB:
+         case SUBIFP:
+         case OR:
+         case XOR:
+         case AND:
+            cg_alu(f, p);
+            break;
+         
+         case MULT:
+            cg_mult(f, p);
+            break;
+
+         case DIV:
+            cg_div(f, p);
+            break;
+
+         case MOD:
+            cg_mod(f, p);
+            break;
+         
+         case KOMPLEMENT:
+            cg_komplement(f, p);
+            break;
+
+         case MINUS:
+            cg_minus(f, p);
+            break;
+            
+         case ADDRESS:
+            cg_address(f, p);
+            break;   
+            
+         case TEST:
+// change TEST into COMPARE
+            cg_test(f, p);
+            break;
+	 
+         case COMPARE:
+// This is handled by the branch IC. Nothing to do here.
+            break;     
+               
+         case LABEL:
+// must restore all temporaries before any label
+// This is not good, as vbcc seems to be generating more labels than necessaty,
+// pretty much defeating our clever system. We must do some more processing here.
+            track_restore(f);
+            emit(f, "%s%ld:\n", label_prefix, (long)p->typf);
+            break;
+            
+         case BEQ:
+         case BNE:
+         case BLT:
+         case BGE:
+         case BLE:
+         case BGT:
+            cg_branch(f, p);
+            break;      
+         case BRA:
+// restore temporaries
+            track_restore(f);
+            emit(f, "\tjmp\t%s%ld\n", label_prefix, (long)p->typf);
+            break;
+               
+         case PUSH:
+            cg_push(f, p);
+            break;
+
+         case CALL:
+            cg_call(f, p);
+            break;
+            
+         case SETRETURN:
+            cg_setreturn(f, p);
+            break;   
+
+         case GETRETURN:
+            cg_getreturn(f, p);
+            break;
+            
+         case ALLOCREG:
+// register is being used, indicate it can only be used if saved
+            track_status[p->q1.reg] |= TRACK_ALLOCREG;
+            break;
+            
+         case FREEREG:
+// register is again free
+            track_status[p->q1.reg] &= ~(TRACK_ALLOCREG);
+            break; 
+        
+         case MOVEFROMREG:
+            cg_movefromreg(f, p);       
+	    break;
+            
+         case MOVETOREG:
+	    cg_movetoreg(f, p);
+            break;
+            
+            
+         default:
+            emit(f, "unhandled IC\n");
+      }
+      emit(f, "\n");   
+   }   
+   cg_function_exit(f, v, loff);
+
+}
+
+int shortcut(int code, int typ)
+{
+   if (sizetab[typ&NQ] > 2) return 0;
+   return 1;
+}
+
+
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+
+}
diff --git a/machines/falco16/machine.dt b/machines/falco16/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/falco16/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/falco16/machine.h b/machines/falco16/machine.h
new file mode 100755
index 0000000..bdebc42
--- /dev/null
+++ b/machines/falco16/machine.h
@@ -0,0 +1,142 @@
+/* 
+   FALCO16 v3
+*/
+
+/*#include "supp.h"*/
+#include "dt.h"
+
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+struct AddressingMode {
+// register to be used as temporary pointer   
+   int			regptr;
+// register to be used as temporary value
+// We support long and float and therfore need potentially 2 registers   
+   int			regval[2];
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR		16
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF		3
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 4
+
+/*  Parameter push order */
+#undef ORDERED_PUSH
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+//#define HAVE_REGPARMS 1
+#undef HAVE_REGPARMS
+
+/* use library calls for some basic ICs */
+#define HAVE_LIBCALLS 1
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+/* select size_t. unsigned int or unsigned long, the default */
+#undef HAVE_INT_SIZET
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 1
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+
+/*  We have some target-specific variable attributes.               */
+#undef HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#undef HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#undef HAVE_REGS_MODIFIED
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#undef HAVE_TARGET_RALLOC
+
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we do need extra elements in the IC */
+#define HAVE_EXT_IC 1
+struct Regtmp {
+// register number   
+   int		reg;
+// must be saved before used?
+   int		save;
+};
+#define MAX_TMPREG		3
+struct ext_ic {
+// temporary ptr register to use with this IC
+   struct Regtmp	reg_tmp[MAX_TMPREG];
+};
+
+/* We have extended types! What we have to do to support them:      */
+/* - #define HAVE_EXT_TYPES
+   - #undef all standard types
+   - #define all standard types plus new types
+   - write eval_const and insert_const
+   - write typedefs for zmax and zumax
+   - define atyps union
+   - write typname[]
+   - write conv_typ()
+   - optionally #define ISPOINTER, ISARITH, ISINT etc.
+   - optionally #define HAVE_TGT_PRINTVAL and write printval
+   - optionally #define POINTER_TYPE
+   - optionally #define HAVE_TGT_FALIGN and write falign
+   - optionally #define HAVE_TGT_SZOF and write szof
+   - optionally add functions for attribute-handling
+*/
+#undef HAVE_TGT_PRINTVAL
+#undef HAVE_EXT_TYPES
+
+
+
diff --git a/machines/fire16/machine.c b/machines/fire16/machine.c
new file mode 100644
index 0000000..e838c11
--- /dev/null
+++ b/machines/fire16/machine.c
@@ -0,0 +1,2280 @@
+/*
+ * Backend for the Fire16 iCE40 SoftCore
+ * (c) 2019 by Sylvain Munaut
+ */
+
+#define DBG
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for fire16 v0.1 (c) 2019 by Sylvain Munaut";
+
+/*  Commandline-flags the code-generator accepts                */
+char *g_flags_name[MAXGF]={"tiny-dmem", "tiny-pmem"};
+int g_flags[MAXGF]={0, 0};
+union ppi g_flags_val[MAXGF];
+
+/*  Extended type names */
+char *typname[]={"n/a", "char","short","int","long","long long",
+                 "float","double","long double","void",
+                 "dmem-pointer","pmem-pointer",
+                 "array","struct","union","enum","function"};
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]   = {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1] = {0,1,1,1,2,4,2,4,4,1,1,1,1,1,1,1,1,1,1};
+
+/* Macros */
+static char *marray[] = {
+	"__pmem=__attr(\"pmem\")",
+	0
+};
+
+/* Register types */
+struct Typ ityp={SHORT}, ltyp={LONG};
+
+/* Registers num */
+enum {
+	R_NONE = 0,
+	R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7,
+	R_R8, R_R9, R_RA, R_RB, R_RC, R_RD, R_RE, R_RF,
+	R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7,
+	R_S8, R_S9, R_SA, R_SB, R_SC, R_SD, R_SE, R_SF,
+	R_R0P, R_R2P, R_R4P, R_R6P, R_R8_P, R_RAP, R_RCP, R_REP,
+	R_S0P, R_S2P, R_S4P, R_S6P, R_S8_P, R_SAP, R_SCP, R_SEP,
+	R_A, R_X, R_Y, R_I
+};
+
+#define isgpr(r) ((r) >= R_R0 && (r) <= R_SEP)
+
+/* Identifier prefixes */
+static const char *idprefix="_", *labprefix="l";
+
+#define isreg(x) (((x)->flags&(REG|DREFOBJ))==REG)
+#define isconst(x) (((x)->flags&(KONST|DREFOBJ))==KONST)
+
+#define ISTSHORT(t) (((t)&NQ)==CHAR || ((t)&NQ)==SHORT || ((t)&NQ)==INT || ((t)&NQ)==DPOINTER || ((t)&NQ)==PPOINTER)
+#define ISTLONG(t)  (((t)&NQ)==LONG || ((t)&NQ)==FLOAT)
+
+#define STR_PMEM "pmem"
+
+#define TINY_DMEM (g_flags[0] & USEDFLAG)
+#define TINY_PMEM (g_flags[1] & USEDFLAG)
+#define TINY_IMM(i) ( (((i) & 0xff00) == 0xff00) || (((i) & 0xff00) == 0x0000) )
+
+static char *sym_name(struct Var *var)
+{
+	static char sym[128];	/* fixme ? */
+
+	if (isstatic(var->storage_class))
+		snprintf(sym, sizeof(sym)-1, "%s%ld", labprefix, zm2l(var->offset));
+	else
+		snprintf(sym, sizeof(sym)-1, "%s%s", idprefix, var->identifier);
+
+	return sym;
+}
+
+static long const2long(struct obj *o, int dtyp)
+{
+	if (!(o->flags & KONST))
+		ierror(0);
+	eval_const(&o->val, dtyp);
+	return zm2l(vmax);
+}
+
+struct gc_state
+{
+	FILE *f;
+
+	int reg_busy[MAXR+1];	/* Track used registers */
+
+	int op_save;		/* Saved register to restore before op end */
+	long val_rv;		/* Return Value immediate (must be small enough) */
+	int reg_rv;		/* Return Value register, 0=none */
+	int reg_lw;		/* Register written in the last emitted op code */
+
+	int s_argsize;
+	int s_localsize;
+	int s_savesize;
+
+	int cmp_signed;		/* Last comparison was signed */
+	int cmp_cur_z;		/* Current state of z flag */
+};
+
+static int
+_gc_find_reg(struct gc_state *gc, int pair)
+{
+	int min, max, r;
+
+	min = pair ? R_R0P : R_R0;
+	max = pair ? R_SEP : R_SF;
+
+	/* Try for a scratch reg first */
+	for (r=min; r<=max; r++)
+		if (!gc->reg_busy[r] && !regsa[r] && regscratch[r])
+			return r;
+
+	/* Ok ... anything will do */
+	for (r=min; r<=max; r++)
+		if (!gc->reg_busy[r] && !regsa[r])
+			return r;
+
+	/* Nothing :/ */
+	return 0;
+}
+
+
+/* Stack layout: (grows toward 0)
+ *
+ *       ,------------------------------------------------,
+ *   Y   | (next available word)                          |  <- Y pointer
+ *       | arguments to called functions [size=s_argsize] |
+ *       | local variables [size=s_localsize]             |
+ *       | saved register [size=s_savesize]               |
+ *       | return-address save [size=1]                   |
+ *   Y+N | arguments to this function [size=?]            |
+ *       `------------------------------------------------'
+ */
+static long
+_gc_real_offset(struct gc_state *gc, struct Var *v, long add_offset)
+{
+	long off = zm2l(v->offset);
+
+	if (off < 0) {
+		/* function parameter */
+		off = gc->s_localsize + gc->s_savesize + 1 - (off + zm2l(maxalign));
+	}
+
+	off += gc->s_argsize;
+	off += add_offset;
+	off += 1; /* Because we point to the next available word */
+
+	return off;
+}
+
+#define _gc_emit(gc, ...) do {		\
+	(gc)->reg_lw = 0;		\
+	emit((gc)->f,  __VA_ARGS__ );	\
+} while (0)
+
+static void
+_gc_emit_nop(struct gc_state *gc)
+{
+	gc->reg_lw = 0;
+	gc->cmp_cur_z = 0;
+	emit(gc->f, "\tnop\n" );
+}
+
+/* Emit a IMM opcode prefix if the constant requires it */
+static long
+_gc_emit_imm(struct gc_state *gc, long v)
+{
+	v = v & 0xffff;
+
+	if ((v & 0xff00) == 0) {
+		return v;
+	} else if ((v & 0xff00) == 0xff00) {
+		return - ((v ^ 0xffff) + 1);
+	} else {
+		gc->reg_lw = 0;
+		emit(gc->f, "\timm\t$%d\n", (v >> 8) & 0xff);
+		return v & 0xff;
+	}
+}
+
+/* Emit movs between any register pairs and any single GPR & A */
+static void
+_gc_emit_mov(struct gc_state *gc, int dst, int src)
+{
+	if (src == dst)
+		return;
+
+	if ((src == gc->reg_lw) && isgpr(src))
+		emit(gc->f, "\tnop\n");
+
+	emit(gc->f, "\tmov\t%s, %s\n", regnames[dst], regnames[src]);
+
+	BSET(regs_modified, dst);
+
+	gc->reg_lw = isgpr(dst) ? dst : 0;
+}
+
+/* Emit opcode and checks for depencies */
+static void
+_gc_emit_alu(struct gc_state *gc, const char *opcode,
+             int dst, int src1, int src2, long imm)
+{
+	int dep1 = (src1 == gc->reg_lw) && isgpr(src1);
+	int dep2 = (src2 == gc->reg_lw) && isgpr(src2);
+	char dst_str[16], *op1_str, op2_str[16], imm_str[16];
+
+	if ((dep1 || dep2) && (src1 != R_I) && (src2 != R_I))
+		emit(gc->f, "\tnop\n");
+
+	if ((src1 == R_I) || (src2 == R_I)) {
+		imm = _gc_emit_imm(gc, imm);
+		if ((dst && (dst != R_A)) ||
+		    ((src1 != R_I) && (src1 != R_A)) ||
+		    ((src2 != R_I) && (src2 != R_A))) {
+			emit(gc->f, "\timm\t$%d\n", imm);
+			snprintf(imm_str, sizeof(imm_str)-1, "%s", regnames[R_I]);
+		} else {
+			snprintf(imm_str, sizeof(imm_str)-1, "$%ld", imm);
+		}
+	}
+
+	dst_str[0] = op2_str[0] = 0;
+	op1_str = (src1 != R_I) ? regnames[src1] : imm_str;
+	if (dst)  snprintf(dst_str, sizeof(dst_str)-1, "%s, ", regnames[dst]);
+	if (src2) snprintf(op2_str, sizeof(op2_str)-1, ", %s", (src2 != R_I) ? regnames[src2] : imm_str);
+
+	emit(gc->f, "\t%s\t%s%s%s\n", opcode, dst_str, op1_str, op2_str);
+
+	BSET(regs_modified, dst);
+
+	gc->reg_lw = isgpr(dst) ? dst : 0;
+	gc->cmp_cur_z = gc->reg_lw;
+}
+
+static void
+_gc_move_gpr(struct gc_state *gc, int dst, int src)
+{
+	struct rpair rp_src, rp_dst;
+	int ip_src, ip_dst;
+
+	if (src == dst)
+		return;
+
+	ip_dst = reg_pair(dst, &rp_dst);
+	ip_src = reg_pair(src, &rp_src);
+	if ((regsize[dst] != regsize[src]) || (ip_dst != ip_src))
+		ierror(0);	/* Shouldn't happen */
+
+	if (ip_dst) {
+		if (gc->reg_lw == rp_src.r1) {
+			_gc_emit_mov(gc, R_A, rp_src.r2);
+			_gc_emit_mov(gc, rp_dst.r2, R_A);
+			_gc_emit_mov(gc, R_A, rp_src.r1);
+			_gc_emit_mov(gc, rp_dst.r1, R_A);
+		} else {
+			_gc_emit_mov(gc, R_A, rp_src.r1);
+			_gc_emit_mov(gc, rp_dst.r1, R_A);
+			_gc_emit_mov(gc, R_A, rp_src.r2);
+			_gc_emit_mov(gc, rp_dst.r2, R_A);
+		}
+	} else {
+		/* _gc_emit_mov will handle if src or dst is R_A */
+		_gc_emit_mov(gc, R_A, src);
+		_gc_emit_mov(gc, dst, R_A);
+	}
+}
+
+static void
+_gc_store_to_mem(struct gc_state *gc, int val_reg, int dtyp,
+                 long ptr_const, int ptr_reg, struct Var *var)
+{
+	struct rpair rp;
+	char *opcode;
+	int tiny;
+	int is_pair;
+
+	if (dtyp == DPOINTER) {
+		opcode = "std";
+		tiny = TINY_DMEM;
+	} else if (dtyp == PPOINTER) {
+		opcode = "stp";
+		tiny = TINY_PMEM;
+	} else {
+		ierror(0);
+	}
+
+	is_pair = reg_pair(val_reg, &rp);
+
+	if (var)
+	{
+		/* Variable */
+		if (isauto(var->storage_class)) {
+			/* Stack variable always in data mem */
+			if (dtyp != DPOINTER)
+				ierror(1);
+
+			long sp_offset = _gc_real_offset(gc, var, ptr_const);
+
+			if (sp_offset <= 15) {
+				/* Offset is small enough for indexed Y access */
+				if (is_pair) {
+					/* 32 bit */
+					_gc_emit_mov(gc, R_A, rp.r1);
+					_gc_emit(gc, "\t%s\tA, [Y++, $%d]\n", opcode, sp_offset);
+					_gc_emit_mov(gc, R_A, rp.r2);
+					_gc_emit(gc, "\t%s\tA, [Y--, $%d]\n", opcode, sp_offset);
+				} else {
+					/* 16 bit */
+					_gc_emit_mov(gc, R_A, val_reg);
+					_gc_emit(gc, "\t%s\tA, [Y, $%d]\n", opcode, sp_offset);
+				}
+			} else {
+				/* Offset is too large ... load address in A and fall back to code below */
+				_gc_emit(gc, "\tmov\tA, Y\n");
+				_gc_emit(gc, "\tadd A, A, $%d\n", sp_offset);
+				ptr_reg = R_A;
+			}
+		} else if (isextern(var->storage_class) || isstatic(var->storage_class)) {
+			/* Symbol name */
+			char *sym = sym_name(var);
+
+			/* Make access using absolute immediate addressing */
+			if (reg_pair(val_reg, &rp)) {
+				/* 32 bit */
+				_gc_emit_mov(gc, R_A, rp.r1);
+				if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+				_gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+				_gc_emit_mov(gc, R_A, rp.r2);
+				if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const+1);
+				_gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const+1);
+			} else {
+				/* 16 bit */
+				_gc_emit_mov(gc, R_A, val_reg);
+				if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+				_gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+			}
+		} else {
+			ierror(0);
+		}
+	}
+
+	if (ptr_reg)
+	{
+		/* Register pointer */
+		_gc_emit_mov(gc, R_A, ptr_reg);
+		_gc_emit_mov(gc, R_X, R_A);
+
+		if (is_pair) {
+			/* 32 bit */
+			_gc_emit_mov(gc, R_A, rp.r1);
+			_gc_emit(gc, "\t%s\tA, [X++]\n", opcode);
+			_gc_emit_mov(gc, R_A, rp.r2);
+			_gc_emit(gc, "\t%s\tA, [X--]\n", opcode);
+		} else {
+			/* 16 bit */
+			_gc_emit_mov(gc, R_A, val_reg);
+			_gc_emit(gc, "\t%s\tA, [X]\n", opcode);
+		}
+	}
+
+	if (!ptr_reg && !var)
+	{
+		/* Constant immediate pointer */
+		if (is_pair) {
+			/* 32 bit access */
+			_gc_emit_mov(gc, R_A, rp.r1);
+			_gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+				tiny ? (ptr_const+0) : _gc_emit_imm(gc, ptr_const+0));
+			_gc_emit_mov(gc, R_A, rp.r2);
+			_gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+				tiny ? (ptr_const+1) : _gc_emit_imm(gc, ptr_const+1));
+		} else {
+			/* 16 bit access */
+			_gc_emit_mov(gc, R_A, val_reg);
+			_gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+				tiny ? ptr_const : _gc_emit_imm(gc, ptr_const));
+		}
+	}
+}
+
+static void
+_gc_load_from_mem(struct gc_state *gc, int val_reg, int dtyp,
+                 long ptr_const, int ptr_reg, struct Var *var)
+{
+	struct rpair rp;
+	char *opcode;
+	int tiny;
+	int is_pair;
+
+	if (dtyp == DPOINTER) {
+		opcode = "ldd";
+		tiny = TINY_DMEM;
+	} else if (dtyp == PPOINTER) {
+		opcode = "ldp";
+		tiny = TINY_PMEM;
+	} else {
+		ierror(0);
+	}
+
+	is_pair = reg_pair(val_reg, &rp);
+
+	if (var)
+	{
+		/* Variable */
+		if (isauto(var->storage_class)) {
+			/* Stack variable always in data mem */
+			if (dtyp != DPOINTER)
+				ierror(1);
+
+			long sp_offset = _gc_real_offset(gc, var, ptr_const);
+
+			if (sp_offset <= 15) {
+				/* Offset is small enough for indexed Y access */
+				if (is_pair) {
+					/* 32 bit */
+					_gc_emit(gc, "\t%s\tA, [Y++, $%d]\n", opcode, sp_offset);
+					_gc_emit_mov(gc, rp.r1, R_A);
+					_gc_emit(gc, "\t%s\tA, [Y--, $%d]\n", opcode, sp_offset);
+					_gc_emit_mov(gc, rp.r2, R_A);
+				} else {
+					/* 16 bit */
+					_gc_emit(gc, "\t%s\tA, [Y, $%d]\n", opcode, sp_offset);
+					_gc_emit_mov(gc, val_reg, R_A);
+				}
+			} else {
+				/* Offset is too large ... load address in A and fall back to code below */
+				_gc_emit(gc, "\tmov\tA, Y\n");
+				_gc_emit(gc, "\tadd A, A, $%d\n", sp_offset);
+				ptr_reg = R_A;
+			}
+		} else if (isextern(var->storage_class) || isstatic(var->storage_class)) {
+			/* Symbol name */
+			char *sym = sym_name(var);
+
+			/* Make access using absolute immediate addressing */
+			if (is_pair) {
+				/* 32 bit */
+				if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+				_gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+				if (dtyp == PPOINTER) _gc_emit_nop(gc);
+				_gc_emit_mov(gc, rp.r1, R_A);
+				if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const+1);
+				_gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const+1);
+				if (dtyp == PPOINTER) _gc_emit_nop(gc);
+				_gc_emit_mov(gc, rp.r2, R_A);
+			} else {
+				/* 16 bit */
+				if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+				_gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+				if (dtyp == PPOINTER) _gc_emit_nop(gc);
+				_gc_emit_mov(gc, val_reg, R_A);
+			}
+		} else {
+			ierror(0);
+		}
+	}
+
+	if (ptr_reg)
+	{
+		/* Register pointer */
+		_gc_emit_mov(gc, R_A, ptr_reg);
+		_gc_emit_mov(gc, R_X, R_A);
+
+		if (is_pair) {
+			/* 32 bit access */
+			_gc_emit(gc, "\t%s\tA, [X++]\n", opcode);
+			if (dtyp == PPOINTER) _gc_emit_nop(gc);
+			_gc_emit_mov(gc, rp.r1, R_A);
+			_gc_emit(gc, "\t%s\tA, [X--]\n", opcode);
+			if (dtyp == PPOINTER) _gc_emit_nop(gc);
+			_gc_emit_mov(gc, rp.r2, R_A);
+		} else {
+			/* 16 bit access */
+			_gc_emit(gc, "\t%s\tA, [X]\n", opcode);
+			if (dtyp == PPOINTER) _gc_emit_nop(gc);
+			_gc_emit_mov(gc, val_reg, R_A);
+		}
+	}
+
+	if (!ptr_reg && !var)
+	{
+		/* Constant immediate pointer */
+		if (is_pair) {
+			/* 32 bit access */
+			_gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+				tiny ? (ptr_const+0) : _gc_emit_imm(gc, ptr_const+0));
+			if (dtyp == PPOINTER) _gc_emit_nop(gc);
+			_gc_emit_mov(gc, rp.r1, R_A);
+			_gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+				tiny ? (ptr_const+1) : _gc_emit_imm(gc, ptr_const+1));
+			if (dtyp == PPOINTER) _gc_emit_nop(gc);
+			_gc_emit_mov(gc,rp.r2, R_A);
+		} else {
+			/* 16 bit access */
+			_gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+				tiny ? ptr_const : _gc_emit_imm(gc, ptr_const));
+			if (dtyp == PPOINTER) _gc_emit_nop(gc);
+			_gc_emit_mov(gc, val_reg, R_A);
+		}
+	}
+}
+
+/* Selects a register for the result to be computed in */
+static int
+_gc_store_sel(struct IC *p)
+{
+	int t;
+
+	/* Register destination ? */
+	if (isreg(&p->z))
+		return p->z.reg;
+
+	/* If not, use the scratch registers as temporaries */
+	/* (ideally we should find some free scratch ones and use that
+	 *  instead of having 'reserved' ones ...) */
+	t = ztyp(p) & NQ;
+	if (ISSCALAR(t) && (msizetab[t] == 1))
+		return R_RF;
+	if (ISSCALAR(t) && (msizetab[t] == 2))
+		return R_REP;
+
+	/* Couldn't find a fit ? */
+	ierror(0);
+}
+
+static void
+_gc_op_pre(struct gc_state *gc, struct IC *p, int n_op,
+           int *r_z, int *r_q1, int *r_q2, long *k)
+{
+	int is32b;
+	int t = q1typ(p) & NQ;
+	int z;
+
+	/* Init */
+	gc->op_save = 0;
+
+	/* Type */
+	if (ISSCALAR(t) && (msizetab[t] == 1))
+		is32b = 0;
+	else if (ISSCALAR(t) && (msizetab[t] == 2))
+		is32b = 1;
+	else
+		ierror(0);
+
+	/* Where to place the destination ? */
+	if (r_z && isreg(&p->z))
+		z = p->z.reg;
+	else
+		z = is32b ? R_REP : R_RF;	/* R_A is needed for the store_op */
+
+	if (r_z) *r_z = z;
+
+	/* Where can we load q1 ? */
+	if (isreg(&p->q1))
+		*r_q1 = p->q1.reg;
+	else if (isconst(&p->q1)) {
+		*r_q1 = R_I;
+		*k = const2long(&p->q1, q1typ(p));
+	} else {
+		if (isreg(&p->q2) || isconst(&p->q2) || (n_op < 2))
+			*r_q1 = R_A;
+		else
+			*r_q1 = z;
+	}
+
+	/* q2 ? */
+	if (n_op != 2)
+		return;
+
+	if (isreg(&p->q2))
+		*r_q2 = p->q2.reg;
+	else if (isconst(&p->q2)) {
+		*r_q2 = R_I;
+		*k = const2long(&p->q2, q2typ(p));
+	} else if (*r_q1 != z) {
+		*r_q2 = z;
+	} else if (!is32b) {
+		*r_q2 = (*r_q1 == R_A) ? R_RE : R_A;
+	} else if (z != R_REP) {
+		*r_q2 = R_REP;
+	} else {
+		/* At this point we have nowhere safe to load a 32b q2 :/ */
+		*r_q2 = _gc_find_reg(gc, 1);
+		if (!*r_q2)
+			*r_q2 = R_RCP;
+		gc->op_save = !regscratch[*r_q2] ? *r_q2 : 0;
+	}
+
+	if (gc->op_save) {
+		struct rpair rp;
+		reg_pair(gc->op_save, &rp);
+		_gc_emit_mov(gc, R_A, rp.r1);
+		_gc_emit(gc, "\tstd\tA, [Y--]\n");
+		_gc_emit_mov(gc, R_A, rp.r2);
+		_gc_emit(gc, "\tstd\tA, [Y--]\n");
+	}
+}
+
+static void
+_gc_op_post(struct gc_state *gc, struct IC *p)
+{
+	if (gc->op_save) {
+		struct rpair rp;
+		reg_pair(gc->op_save, &rp);
+		_gc_emit(gc, "\tldd\tA, [Y++, $1]\n");
+		_gc_emit_mov(gc, rp.r2, R_A);
+		_gc_emit(gc, "\tldd\tA, [Y++, $1]\n");
+		_gc_emit_mov(gc, rp.r1, R_A);
+	}
+
+	gc->op_save = 0;
+}
+
+/* Load an object into a register */
+static void
+_gc_load_op(struct gc_state *gc, struct obj *q, int dst, int typf)
+{
+	struct rpair rp;
+
+	/* Source already in register ? */
+	if (isreg(q))
+	{
+		_gc_move_gpr(gc, dst, q->reg);
+		return;
+	}
+
+	/* Is this a dereference ? */
+	if (q->flags & DREFOBJ)
+	{
+		long ptr_imm = 0;
+		int ptr_reg = 0;
+
+		if (q->flags & KONST) {
+			/* Constant address load */
+			ptr_imm = const2long(q, pointer_type(q->v->vtyp));
+		} else if (q->flags & REG) {
+			/* Dereference value in register */
+			ptr_reg = q->reg;
+		} else {
+			/* Load variable content */
+			ptr_reg = R_A;
+			_gc_load_from_mem(gc, R_A, pointer_type(q->v->vtyp), zm2l(zl2zm(q->val.vlong)), 0, q->v);
+		}
+
+		/* Execute dereference */
+		_gc_load_from_mem(gc, dst, q->dtyp, ptr_imm, ptr_reg, NULL);
+	}
+	else
+	{
+		if (q->flags & KONST) {
+			/* Constant load */
+			long k = const2long(q, typf);
+
+			if (reg_pair(dst, &rp)) {
+				/* 32 bit */
+				long v = k & 0xffff;
+				v = _gc_emit_imm(gc, v);
+				_gc_emit(gc, "\tmov\tA, $%d\n", v);
+				_gc_emit_mov(gc, rp.r1, R_A);
+				v = (k >> 16) & 0xffff;
+				v = _gc_emit_imm(gc, v);
+				_gc_emit(gc, "\tmov\tA, $%d\n", v);
+				_gc_emit_mov(gc, rp.r2, R_A);
+			} else {
+				/* 16 bit */
+				k = _gc_emit_imm(gc, k);
+				_gc_emit(gc, "\tmov\tA, $%d\n", k);
+				_gc_emit_mov(gc, dst, R_A);
+			}
+		} else if (q->flags & VARADR) {
+			/* Variable address load */
+			int tiny = (pointer_type(q->v->vtyp) == DPOINTER) ? TINY_DMEM : TINY_PMEM;
+			long ofs = zm2l(zl2zm(q->val.vlong));
+			char *sym = sym_name(q->v);
+
+			if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ofs);
+			_gc_emit(gc, "\tmov\tA, [$(lo(%s+%d))]\n", sym, ofs);
+			_gc_emit_mov(gc, dst, R_A);
+		} else if (!(q->flags & REG)) {
+			/* Variable load */
+			_gc_load_from_mem(gc, dst, pointer_type(q->v->vtyp), zm2l(zl2zm(q->val.vlong)), 0, q->v);
+		}
+	}
+}
+
+/* Store a register into its final destination */
+static void
+_gc_store_op(struct gc_state *gc, struct obj *z, int src, int typf)
+{
+	struct rpair rp;
+	int reg;
+
+	/* Register destination ? */
+	if (isreg(z))
+	{
+		_gc_move_gpr(gc, z->reg, src);
+		return;
+	}
+
+	/* Is this a dereference ? */
+	if (z->flags & DREFOBJ)
+	{
+		long ptr_imm = 0;
+		int ptr_reg = 0;
+
+		if (z->flags & KONST) {
+			/* Constant address load */
+			ptr_imm = const2long(z, pointer_type(z->v->vtyp));
+		} else if (z->flags & REG) {
+			/* Dereference value in register */
+			ptr_reg = z->reg;
+		} else {
+			/* Load variable content */
+			ptr_reg = R_A;
+			_gc_load_from_mem(gc, R_A, pointer_type(z->v->vtyp), zm2l(zl2zm(z->val.vlong)), 0, z->v);
+		}
+
+		/* Execute dereference */
+		_gc_store_to_mem(gc, src, z->dtyp, ptr_imm, ptr_reg, NULL);
+	}
+	else if (z->flags & VAR)
+	{
+		/* Variable store */
+		_gc_store_to_mem(gc, src, pointer_type(z->v->vtyp), zm2l(zl2zm(z->val.vlong)), 0, z->v);
+	}
+	else
+	{
+		/* huh ? */
+		ierror(0);
+	}
+}
+
+
+static void
+gc_func_begin(struct gc_state *gc,
+              FILE *f, struct IC *p, struct Var *v, zmax offset)
+{
+	int i;
+
+	/* Reset state */
+	memset(gc, 0x00, sizeof(struct gc_state));
+
+	gc->f = f;
+
+	/* Init register usage */
+	for (i=1; i<=MAXR; i++)
+		gc->reg_busy[i] = regsa[i];
+
+	/* Section and symbol setup */
+	if (isextern(v->storage_class))
+		emit(f, "\t.text\n%s%s:\n", idprefix, v->identifier);
+	else
+		emit(f, "\t.text\n%s%d:\n", labprefix, zm2l(v->offset));
+
+	/* Debug */
+#ifdef DBG
+	emit(gc->f, "\t; Function prologue\n");
+#endif
+
+	/* Function prologue */
+		/* Save return address */
+	emit(f, "\tmov\tA, X\n");
+	emit(f, "\tstd\tA, [Y--]\n");
+
+		/* Save all registers need saving */
+	for (i=1; i<=MAXR; i++) {
+		if (regused[i] && !regscratch[i] && !regsa[i])
+		{
+			struct rpair rp;
+			if (reg_pair(i, &rp)) {
+				if (!regused[rp.r1]) {
+					emit(f, "\tmov\tA, %s\n", regnames[rp.r1]);
+					emit(f, "\tstd\tA, [Y--]\n");
+					gc->s_savesize += 1;
+				}
+				if (!regused[rp.r2]) {
+					emit(f, "\tmov\tA, %s\n", regnames[rp.r2]);
+					emit(f, "\tstd\tA, [Y--]\n");
+					gc->s_savesize += 1;
+				}
+			} else {
+				emit(f, "\tmov\tA, %s\n", regnames[i]);
+				emit(f, "\tstd\tA, [Y--]\n");
+				gc->s_savesize += 1;
+			}
+		}
+	}
+
+		/* Adjust SP for local variables */
+	gc->s_localsize = zm2l(offset);
+
+	if (gc->s_localsize <= 2) {
+		for (i=0; i<gc->s_localsize; i++)
+			emit(f, "\tldd\tA, [Y--]\n");	/* Useless op */
+	} else {
+		emit(f, "\tmov\tA, Y\n");
+		emit(f, "\tadd\tA, A, $%d\n", -gc->s_localsize);
+		emit(f, "\tmov\tY, A\n");
+	}
+
+	/* Modifieds regs in all cases */
+	BSET(regs_modified, R_A);
+	BSET(regs_modified, R_X);
+	BSET(regs_modified, R_Y);
+}
+
+static void
+gc_func_end(struct gc_state *gc,
+            FILE *f, struct IC *p, struct Var *v, zmax offset)
+{
+	int i;
+
+	/* Debug */
+#ifdef DBG
+	emit(gc->f, "\n\t; Function epilogue\n");
+#endif
+
+	/* Function epilogue */
+		/* Re-adjust SP */
+	if (gc->s_localsize <= 2) {
+		for (i=0; i<gc->s_localsize; i++)
+			emit(f, "\tldd\tA, [Y++]\n");	/* Useless op */
+	} else {
+		emit(f, "\tmov\tA, Y\n");
+		emit(f, "\tadd\tA, A, $%d\n", gc->s_localsize);
+		emit(f, "\tmov\tY, A\n");
+	}
+
+		/* Restore saved registers */
+	for (i=MAXR; i>=1; i--) {
+		if (regused[i] && !regscratch[i] && !regsa[i])
+		{
+			struct rpair rp;
+			if (reg_pair(i, &rp)) {
+				if (!regused[rp.r2]) {
+					emit(f, "\tldd\tA, [Y++, $1]\n");
+					emit(f, "\tmov\t%s, A\n", regnames[rp.r2]);
+				}
+				if (!regused[rp.r1]) {
+					emit(f, "\tldd\tA, [Y++, $1]\n");
+					emit(f, "\tmov\t%s, A\n", regnames[rp.r1]);
+				}
+			} else {
+				emit(f, "\tldd\tA, [Y++, $1]\n");
+				emit(f, "\tmov\t%s, A\n", regnames[i]);
+			}
+		}
+	}
+
+		/* Return address */
+	emit(f, "\tldd\tA, [Y++, $1]\n");
+	emit(f, "\tmov\tX, A\n");
+
+		/* Return value */
+	emit(f, "\tbax\n");
+	if (gc->reg_rv)
+		emit(f, "\tmov\tA, %s\n", regnames[gc->reg_rv]);
+	else
+		emit(f, "\tmov\tA, $%d\n", gc->val_rv);
+
+	/* Bit of spacing */
+	emit(gc->f, "\n\n");
+}
+
+static void
+gc_func_assign(struct gc_state *gc, struct IC *node)
+{
+	/* FIXME: Only works for size=1 | size=2 ... */
+	int v_reg;
+
+	if (isreg(&node->q1)) {
+		v_reg = node->q1.reg;
+	} else {
+		v_reg = _gc_store_sel(node);
+		_gc_load_op(gc, &node->q1, v_reg, q1typ(node));
+	}
+
+	_gc_store_op(gc, &node->z, v_reg, ztyp(node));
+}
+
+static void
+gc_func_convert(struct gc_state *gc, struct IC *node)
+{
+	struct rpair rp;
+	int qt = q1typ(node) & NQ;
+	int zt = ztyp(node)  & NQ;
+	int sext = !(q1typ(node) & UNSIGNED);
+	int v_reg;
+
+	if ((zt == LONG) && (qt >= CHAR) && (qt <= INT)) {
+		/* Convert from short to long */
+		v_reg = _gc_store_sel(node);
+
+		if (!reg_pair(v_reg, &rp))
+			ierror(0);
+
+		_gc_load_op(gc, &node->q1, rp.r1, q1typ(node));
+
+		if (sext) {
+			_gc_emit_alu(gc, "rol", R_A, rp.r1, 0, 0);
+			_gc_emit_alu(gc, "and", R_A, R_A, R_I, 1);
+			_gc_emit_alu(gc, "sub", R_A, R_A, R_I, 0);
+			_gc_emit_mov(gc, rp.r2, R_A);
+		} else {
+			_gc_emit(gc, "\tmov\tA, $0\n");
+			_gc_emit_mov(gc, rp.r2, R_A);
+		}
+	} else if ((zt >= CHAR) && (zt <= INT) && (qt == LONG)) {
+		/* Convert from long to short */
+		if (isreg(&node->q1)) {
+			/* Long already in register, so get the LSB from pair and do store */
+			if (!reg_pair(node->q1.reg, &rp))
+				ierror(0);
+
+			v_reg = rp.r1;
+		} else {
+			/* Perform a load as if it was a short. Because of Little-Endian, it works */
+			v_reg = _gc_store_sel(node);
+			_gc_load_op(gc, &node->q1, v_reg, q1typ(node));
+		}
+	} else if (ISPOINTER(zt) && ISPOINTER(qt)) {
+		/* No way to convert between pointer types to different spaces ... */
+		ierror(1);
+	} else {
+		/* Shouldn't happen, all other conversions are lib_call */
+		ierror(0);
+	}
+
+	_gc_store_op(gc, &node->z, v_reg, ztyp(node));
+}
+
+static void
+gc_func_alu_2op(struct gc_state *gc, struct IC *node)
+{
+	const char *opcode, *opcode2;
+	struct rpair rpz, rp1, rp2;
+	int regz, reg1, reg2, regt;
+	long k;
+	int is32b, issub, isadd;
+
+	is32b = ISTLONG(ztyp(node));
+	isadd = (node->code == ADD) || (node->code == ADDI2P);
+	issub = (node->code == SUB) || (node->code == SUBIFP) || (node->code == SUBPFP);
+
+	/* Load operands */
+	_gc_op_pre(gc, node, 2, &regz, &reg1, &reg2, &k);
+
+	if (!isreg(&node->q1) && !isconst(&node->q1))
+		_gc_load_op(gc, &node->q1, reg1, q1typ(node));
+
+	if (!isreg(&node->q2) && !isconst(&node->q2))
+		_gc_load_op(gc, &node->q2, reg2, q2typ(node));
+
+	/* We can only have immediate in reg2. Also 'sub' is swapped vs hw */
+	if (issub) {
+		if (reg2 == R_I) {
+			node->code = ADD;
+			k = -k;
+		} else {
+			regt = reg1;
+			reg1 = reg2;
+			reg2 = regt;
+		}
+	} else if (reg1 == R_I) {
+		regt = reg1;
+		reg1 = reg2;
+		reg2 = regt;
+	}
+
+	/* Solve reg-pairs */
+	reg_pair(regz, &rpz);
+	reg_pair(reg1, &rp1);
+	reg_pair(reg2, &rp2);
+
+	if (reg2 == R_I)
+		rp2.r1 = rp2.r2 = R_I;
+
+	/* Select opcode */
+	switch (node->code) {
+	case OR:  opcode = "or";  opcode2 = "or";   break;
+	case XOR: opcode = "xor"; opcode2 = "xor";   break;
+	case AND: opcode = "and"; opcode2 = "and";   break;
+	case ADD: opcode = "add"; opcode2 = "addcy"; break;
+	case SUB: opcode = "sub"; opcode2 = "subcy"; break;
+	case ADDI2P: opcode = "add"; opcode2 = NULL; break;
+	case SUBIFP: opcode = "sub"; opcode2 = NULL; break;
+	case SUBPFP: opcode = "sub"; opcode2 = NULL; break;
+	default: ierror(0);
+	}
+
+	/* Do the operation */
+	if (is32b) {
+		if (regz == reg1) {
+			if (reg2 == R_I) {
+				/* 1 single GPR (reg1 == regz) and one immediate */
+				_gc_emit_alu(gc, opcode,  rpz.r1, rp1.r1, R_I, k & 0xffff);
+				_gc_emit_alu(gc, opcode2, rpz.r2, rp1.r2, R_I, (k >> 16) & 0xffff);
+			} else {
+				/* 2 different GPRs, reg1 == regz */
+				_gc_emit_mov(gc, R_A, rp2.r1);
+				_gc_emit_alu(gc, opcode,  rpz.r1, rp1.r1, R_A, 0);
+				_gc_emit_mov(gc, R_A, rp2.r2);
+				_gc_emit_alu(gc, opcode2, rpz.r2, rp1.r2, R_A, 0);
+			}
+		} else if (regz == reg2) {
+			/* 2 different GPRs, reg2 == regz */
+			_gc_emit_mov(gc, R_A, rp1.r1);
+			_gc_emit_alu(gc, opcode,  rpz.r1, R_A, rp2.r1, 0);
+			_gc_emit_mov(gc, R_A, rp1.r2);
+			_gc_emit_alu(gc, opcode2, rpz.r2, R_A, rp2.r2, 0);
+		} else if (reg2 == R_I) {
+			/* 2 different GPRs and one immediate */
+			_gc_emit_mov(gc, R_A, rp1.r1);
+			_gc_emit_alu(gc, opcode,  rpz.r1, R_A, rp2.r1, k & 0xffff);
+			_gc_emit_mov(gc, R_A, rp1.r2);
+			_gc_emit_alu(gc, opcode2, rpz.r2, R_A, rp2.r2, (k >> 16) & 0xffff);
+		} else {
+			/* 3 different GPRs pair */
+			_gc_emit_mov(gc, R_A, rp1.r1);
+			_gc_emit_alu(gc, opcode,  R_A, R_A, rp2.r1, 0);
+			_gc_emit_mov(gc, rpz.r1, R_A);
+			_gc_emit_mov(gc, R_A, rp1.r2);
+			_gc_emit_alu(gc, opcode2, R_A, R_A, rp2.r2, 0);
+			_gc_emit_mov(gc, rpz.r2, R_A);
+		}
+	} else {
+		/* Count GPRs */
+		int ngpr = isgpr(regz) + isgpr(reg1) + isgpr(reg2);
+
+		/* Detect INC / DEC */
+		if ((reg2 == R_I) && ((k == 1) || (k == -1)) && (isadd || issub))
+		{
+			opcode = ((k == -1) ^ (node->code == SUB)) ? "dec" : "inc";
+
+			if ((regz == reg1) || (regz == R_A) || (reg1 == R_A)) {
+				_gc_emit_alu(gc, opcode, regz, reg1, 0, 0);
+			} else {
+				_gc_emit_alu(gc, opcode, R_A, reg1, 0, 0);
+				_gc_emit_mov(gc, regz, R_A);
+			}
+		}
+
+		/* Classic ALU */
+		else if (ngpr < 2) {
+			_gc_emit_alu(gc, opcode, regz, reg1, reg2, k);
+		} else if (ngpr == 2) {
+			if (regz == R_A) {
+				_gc_emit_mov(gc, R_A, reg1);
+				_gc_emit_alu(gc, opcode, R_A, R_A, reg2, k);
+			} else if ((regz == reg1) || (regz == reg2)) {
+				_gc_emit_alu(gc, opcode, regz, reg1, reg2, k);
+			} else {
+				_gc_emit_alu(gc, opcode, R_A, reg1, reg2, k);
+				_gc_emit_mov(gc, regz, R_A);
+			}
+		} else {
+			if (regz == reg1) {
+				_gc_emit_mov(gc, R_A, reg2);
+				_gc_emit_alu(gc, opcode, regz, regz, R_A, 0);
+			} else if (regz == reg2) {
+				_gc_emit_mov(gc, R_A, reg1);
+				_gc_emit_alu(gc, opcode, regz, regz, R_A, 0);
+			} else {
+				_gc_emit_mov(gc, R_A, reg1);
+				_gc_emit_alu(gc, opcode, R_A, R_A, reg2, 0);
+				_gc_emit_mov(gc, regz, R_A);
+			}
+		}
+	}
+
+	/* Store result */
+	_gc_store_op(gc, &node->z, regz, ztyp(node));
+
+	/* Allow 'test' optimization */
+	gc->cmp_cur_z = regz;
+
+	/* Clean up */
+	_gc_op_post(gc, node);
+}
+
+static void
+gc_func_not(struct gc_state *gc, struct IC *node)
+{
+	struct rpair rp;
+	int l_reg, z_reg, is32b;
+
+	z_reg = _gc_store_sel(node);
+	is32b = reg_pair(z_reg, &rp);
+	l_reg = (is32b || (isreg(&node->q1) && (node->q1.reg != z_reg))) ? z_reg : R_A;
+
+	_gc_load_op(gc, &node->q1, l_reg, q1typ(node));
+
+	if (is32b) {
+		_gc_emit(gc, "\tmov\tA, $0xffff\n");
+		_gc_emit_alu(gc, "xor", rp.r1, rp.r1, R_A, 0);
+		_gc_emit_alu(gc, "xor", rp.r2, rp.r2, R_A, 0);
+	} else {
+		_gc_emit_alu(gc, "xor", z_reg, l_reg, R_I, 0xffff);
+	}
+
+	_gc_store_op(gc, &node->z, z_reg, ztyp(node));
+}
+
+static void
+gc_func_neg(struct gc_state *gc, struct IC *node)
+{
+	struct rpair rp;
+	int l_reg, z_reg, is32b;
+
+	z_reg = _gc_store_sel(node);
+	is32b = reg_pair(z_reg, &rp);
+	l_reg = (is32b || (isreg(&node->q1) && (node->q1.reg != z_reg))) ? z_reg : R_A;
+
+	_gc_load_op(gc, &node->q1, l_reg, q1typ(node));
+
+	if (is32b) {
+		_gc_emit(gc, "\tmov\tA, $0\n");
+		_gc_emit_alu(gc, "sub",  rp.r1, rp.r1, R_A, 0);
+		_gc_emit_alu(gc, "subcy", rp.r2, rp.r2, R_A, 0);
+	} else {
+		_gc_emit_alu(gc, "sub", z_reg, l_reg, R_I, 0);
+	}
+
+	_gc_store_op(gc, &node->z, z_reg, ztyp(node));
+}
+
+static void
+gc_func_shift(struct gc_state *gc, struct IC *node)
+{
+	/* FIXME */
+}
+
+static void
+gc_func_allocreg(struct gc_state *gc, struct IC *node)
+{
+	struct rpair rp;
+	int reg = node->q1.reg;
+
+	if (reg_pair(reg, &rp)) {
+		gc->reg_busy[rp.r1] = 1;
+		gc->reg_busy[rp.r2] = 1;
+	}
+	gc->reg_busy[reg] = 1;
+}
+
+static void
+gc_func_freereg(struct gc_state *gc, struct IC *node)
+{
+	int reg = node->q1.reg;
+	if (regsa[reg])
+		return;
+
+	if (reg_pair(reg, &rp)) {
+		gc->reg_busy[rp.r1] = 0;
+		gc->reg_busy[rp.r2] = 0;
+	}
+	gc->reg_busy[reg] = 0;
+}
+
+static void
+gc_func_cmp_test(struct gc_state *gc, struct IC *node)
+{
+	struct rpair rp1, rp2;
+	int reg1, reg2;
+	long k;
+	int istest, is32b;
+
+	istest = (node->code == TEST);
+	is32b = ISTLONG(q1typ(node));
+
+	/* Can this be optimized out ? */
+	if (istest && isreg(&node->q1) && (node->q1.reg == gc->cmp_cur_z))
+		return;
+
+	/* Load operands */
+	_gc_op_pre(gc, node, istest?1:2, NULL, &reg1, &reg2, &k);
+
+	if (!isreg(&node->q1) && !isconst(&node->q1))
+		_gc_load_op(gc, &node->q1, reg1, q1typ(node));
+
+	if (!istest && !isreg(&node->q2) && !isconst(&node->q2))
+		_gc_load_op(gc, &node->q2, reg2, q2typ(node));
+
+	reg_pair(reg1, &rp1);
+	reg_pair(reg2, &rp2);
+
+	if (reg2 == R_I)
+		rp2.r1 = rp2.r2 = R_I;
+
+	/* Do the compare */
+	if (is32b) {
+		/* 32b compare */
+		if (istest) {
+			_gc_emit_mov(gc, R_A, rp1.r2);
+			_gc_emit_alu(gc, "or", R_A, R_A, rp1.r1, 0);
+		} else {
+			_gc_emit_mov(gc, R_A, rp1.r1);
+			_gc_emit_alu(gc, "sub", R_A, R_A, rp2.r1, k & 0xffff);
+			_gc_emit_mov(gc, R_A, rp1.r2);
+			_gc_emit_alu(gc, "subcy", R_A, R_A, rp2.r2, (k >> 16) & 0xffff);
+		}
+	} else {
+		/* 16b compare */
+		if (node->code == TEST) {
+			_gc_emit_alu(gc, "test", 0, reg1, R_I, 0xffff);
+		} else {
+			_gc_emit_alu(gc, "cmp", 0, reg1, reg2, k);
+		}
+	}
+
+	/* Clean up */
+	_gc_op_post(gc, node);
+}
+
+static void
+gc_func_branch(struct gc_state *gc, struct IC *node)
+{
+	const char *cc, *ecc;
+	char label[16];
+
+	/* If q1 exists, it's the result of an lib_call compare */
+	if (node->q1.flags) {
+		int r;
+		if (isreg(&node->q1)) {
+			r = node->q1.reg;
+		} else {
+			_gc_load_op(gc, &node->q1, R_A, q1typ(node));
+			r = R_A;
+		}
+		_gc_emit_alu(gc, "cmp", 0, r, -1, 0);
+		gc->cmp_signed = 1;
+	}
+
+	/* Select condition code */
+	switch (node->code) {
+		case BRA: ecc = NULL; cc = ""; break;
+		case BEQ: ecc = NULL; cc = ".z"; break;
+		case BNE: ecc = NULL; cc = ".nz"; break;
+		case BLT: ecc = gc->cmp_signed ? "gt" : "hi"; cc = ".z"; break;
+		case BGE: ecc = gc->cmp_signed ? "gt" : "hi"; cc = ".nz"; break;
+		case BLE: ecc = gc->cmp_signed ? "ge" : "hs"; cc = ".z"; break;
+		case BGT: ecc = gc->cmp_signed ? "ge" : "hs"; cc = ".nz"; break;
+		default: ierror(0);
+	}
+
+	if (ecc)
+		_gc_emit(gc, "\tcc\t%s\n", ecc);
+
+	snprintf(label, sizeof(label)-1, "%s%d", labprefix, node->typf);
+	_gc_emit(gc, "\timm\t$hi(%s)\n", label);
+	_gc_emit(gc, "\tba%s\t$lo(%s)\n", cc, label);
+	_gc_emit_nop(gc);
+}
+
+static void
+gc_func_label(struct gc_state *gc, struct IC *node)
+{
+	_gc_emit(gc, "%s%d:\n", labprefix, node->typf);
+}
+
+static void
+gc_func_call(struct gc_state *gc, struct IC *node)
+{
+	if ((node->q1.flags & (VAR | DREFOBJ)) == VAR &&
+	     node->q1.v->fi && node->q1.v->fi->inline_asm)
+	{
+		emit_inline_asm(gc->f, node->q1.v->fi->inline_asm);
+	}
+	else if (node->q1.flags & DREFOBJ)
+	{
+		/* Function pointer */
+		if (node->q1.dtyp != PPOINTER)
+			ierror(1);
+
+		if (node->q1.flags & KONST) {
+			/* Constant, do immediate jump */
+			long k = const2long(&node->q1, node->q1.dtyp);
+			k = _gc_emit_imm(gc, k);
+			_gc_emit(gc, "\tbal\t$%d\n", k);
+		} else {
+			/* Load variable into A */
+			if (node->q1.flags & REG)
+				_gc_emit_mov(gc, R_A, node->q1.reg);
+			else
+				_gc_load_from_mem(gc, R_A, pointer_type(node->q1.v->vtyp), zm2l(zl2zm(node->q1.val.vlong)), 0, node->q1.v);
+
+			/* Do the jump */
+			_gc_emit_mov(gc, R_X, R_A);
+			_gc_emit(gc, "\tbalx\tX\n");
+		}
+
+		_gc_emit_nop(gc);
+	}
+	else
+	{
+		char *sym = sym_name(node->q1.v);
+
+		if (!TINY_PMEM) _gc_emit(gc, "\timm\t$(hi(%s))\n", sym);
+		_gc_emit(gc, "\tbal\t$(lo(%s))\n", sym);
+
+		_gc_emit_nop(gc);
+	}
+
+	/* FIXME: fixup stack pointer after the call ?!? */
+}
+
+static void
+gc_func_push(struct gc_state *gc, struct IC *node)
+{
+	/* FIXME */
+}
+
+static void
+gc_func_getreturn(struct gc_state *gc, struct IC *node)
+{
+	int dst_reg;
+
+	/* Is it relevant at all ? */
+	if (!node->q1.reg) {
+		ierror(0);
+		return;
+	}
+
+	/* Is the target a register ? */
+	if (isreg(&node->z))
+	{
+		/* Yes, need move */
+		_gc_move_gpr(gc, node->z.reg, node->q1.reg);
+	} else {
+		/* Nope, not supported */
+		ierror(0);
+	}
+}
+
+static void
+gc_func_setreturn(struct gc_state *gc, struct IC *node)
+{
+	int src_reg;
+
+	/* Is it relevant at all ? */
+	if (!node->z.reg) {
+		ierror(0);
+		return;
+	}
+
+	/* Special case for small constants */
+	if ((node->z.reg == R_A) && isconst(&node->q1)) {
+		gc->val_rv = const2long(&node->q1, q1typ(node));
+		return;
+	}
+
+	/* Load value into register */
+	src_reg = node->z.reg;
+	_gc_load_op(gc, &node->q1, src_reg, q1typ(node));
+
+	/* If the target is R_A, we need to defer */
+	if (node->z.reg == R_A) {
+		if ((regscratch[src_reg] || regsa[src_reg]) && (src_reg != R_A)) {
+			gc->reg_rv = src_reg;
+		} else {
+			_gc_emit_mov(gc, R_A, src_reg);
+			_gc_emit_mov(gc, R_R0, R_A);
+			gc->reg_rv = R_R0;
+			gc->reg_lw = R_R0;
+			BSET(regs_modified, R_R0);
+		}
+	} else {
+		_gc_move_gpr(gc, node->z.reg, src_reg);
+	}
+}
+
+static void
+gc_func_movefromreg(struct gc_state *gc, struct IC *node)
+{
+	_gc_store_op(gc, &node->z, node->q1.reg, ztyp(node));
+}
+
+static void
+gc_func_movetoreg(struct gc_state *gc, struct IC *node)
+{
+	_gc_load_op(gc, &node->q1, node->z.reg, q1typ(node));
+}
+
+static void
+gc_func_address(struct gc_state *gc, struct IC *node)
+{
+	long sp_offset;
+
+	/* q1 is always an 'auto' (stack object) */
+	if (ztyp(node) != DPOINTER)
+		ierror(1);
+
+	if (!isauto(node->q1.v->storage_class))
+		ierror(0);
+
+	/* Compute real offset */
+	sp_offset = _gc_real_offset(gc, node->q1.v, zm2l(zl2zm(node->q1.val.vlong)));
+
+	_gc_emit_mov(gc, R_A, R_Y);
+	_gc_emit_alu(gc, "add", R_A, R_A, R_I, sp_offset);
+
+	/* Store it where we were asked */
+	_gc_store_op(gc, &node->z, R_A, ztyp(node));
+}
+
+static void
+gc_func_ic(struct gc_state *gc, struct IC *node)
+{
+	/* If nop, abort early */
+	if (node->code == NOP)
+		return;
+
+	/* Un-needed converts */
+	if (node->code == CONVERT && !must_convert(node->typf,node->typf2,0)) {
+		node->code = ASSIGN;
+		node->q2.val.vmax = sizetab[node->typf&NQ];
+	}
+
+	/* Debug */
+#ifdef DBG
+	emit(gc->f, "\n\t; %s\n", ename[node->code]);
+#endif
+
+	/* Main dispatch */
+#define GC_OP(c,n) case c: gc_func_ ## n (gc, node); break;
+
+	switch (node->code)
+	{
+	GC_OP(ASSIGN,		assign)
+	GC_OP(CONVERT,		convert)
+	GC_OP(OR,		alu_2op)
+	GC_OP(XOR,		alu_2op)
+	GC_OP(AND,		alu_2op)
+	GC_OP(ADD,		alu_2op)
+	GC_OP(SUB,		alu_2op)
+	GC_OP(KOMPLEMENT,	not)
+	GC_OP(MINUS,		neg)
+	GC_OP(LSHIFT,		shift)
+	GC_OP(RSHIFT,		shift)
+	GC_OP(ALLOCREG, 	allocreg)
+	GC_OP(FREEREG,		freereg)
+	GC_OP(COMPARE,		cmp_test)
+	GC_OP(TEST,		cmp_test)
+	GC_OP(BEQ ... BRA,	branch)
+	GC_OP(LABEL,		label)
+	GC_OP(CALL,		call)
+	GC_OP(PUSH,		push)
+	GC_OP(GETRETURN,	getreturn)
+	GC_OP(SETRETURN,	setreturn)
+	GC_OP(MOVEFROMREG,	movefromreg)
+	GC_OP(MOVETOREG,	movetoreg)
+	GC_OP(ADDRESS,		address)
+	GC_OP(ADDI2P,		alu_2op)
+	GC_OP(SUBIFP,		alu_2op)
+	GC_OP(SUBPFP,		alu_2op)
+
+		/* Those are always handled with libcall */
+	case MULT:
+	case DIV:
+	case MOD:
+	default:
+		break;//ierror(0);
+	}
+
+#undef GC_OP
+}
+
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+	int i, j;
+
+	/* Macros */
+	target_macros = marray;
+
+	/* Alignement / size for types */
+	stackalign = l2zm(1L);
+	maxalign   = l2zm(1L);
+	char_bit   = l2zm(16L);
+
+	for (i=0; i<=MAX_TYPE; i++) {
+		sizetab[i]=l2zm(msizetab[i]);
+		align[i]=l2zm(malign[i]);
+	}
+
+	/* Registers */
+	regnames[0] = "noreg";
+
+		/* Defaults */
+	memset(regscratch, 0x00, sizeof(regscratch));
+	memset(regsa,      0x00, sizeof(regsa));
+	memset(reg_prio,   0x00, sizeof(reg_prio));
+
+		/* GPRs rX:  1-16 */
+	for (i=0; i<16; i++)
+	{
+		j = R_R0 + i;
+		regnames[j] = mymalloc(3);
+		sprintf(regnames[j], "r%x", i);
+		regsize[j] = l2zm(1L);
+		regtype[j] = &ityp;
+	}
+
+		/* GPRs sX: 17-32 */
+	for (i=0; i<16; i++)
+	{
+		j = R_S0 + i;
+		regnames[j] = mymalloc(3);
+		sprintf(regnames[j], "s%x", i);
+		regsize[j] = l2zm(1L);
+		regtype[j] = &ityp;
+	}
+
+		/* GPRs pair rXp: 33-40 */
+	for (i=0; i<8; i++)
+	{
+		j = R_R0P + i;
+		regnames[j] = mymalloc(3);
+		sprintf(regnames[j], "r%xp", 2*i);
+		regsize[j] = l2zm(2L);
+		regtype[j] = &ltyp;
+	}
+
+		/* GPRs pair sXp: 41-48 */
+	for (i=0; i<8; i++)
+	{
+		j = R_S0P + i;
+		regnames[j] = mymalloc(3);
+		sprintf(regnames[j], "s%xp", 2*i);
+		regsize[j] = l2zm(2L);
+		regtype[j] = &ltyp;
+	}
+
+		/* Use the first 8 registers as scratch
+		 * registers */
+	for (i=0; i<8; i++) {
+		regscratch[R_R0 + i] = 1;
+		regscratch[R_S0 + i] = 1;
+	}
+
+	for (i=0; i<4; i++) {
+		regscratch[R_R0P + i] = 1;
+		regscratch[R_S0P + i] = 1;
+	}
+
+		/* Code gen internally uses re/rf pair */
+	regsa[R_RE] = regsa[R_RF] = regsa[R_REP] = 1;
+
+		/* Priority */
+	/* FIXME: TODO */
+
+		/* SPRs: 49-51 */
+	regnames[R_A] = "A";
+	regsize[R_A]  = l2zm(1L);
+	regtype[R_A]  = &ityp;
+	regsa[R_A]    = 1;		/* Special, used by codegen */
+
+	regnames[R_X] = "X";
+	regsize[R_X]  = l2zm(1L);
+	regtype[R_X]  = &ityp;
+	regsa[R_X]    = 1;		/* Link Register */
+
+	regnames[R_Y] = "Y";
+	regsize[R_Y]  = l2zm(1L);
+	regtype[R_Y]  = &ityp;
+	regsa[R_Y]    = 1;		/* Used as Stack pointer */
+
+	regnames[R_I] = "I";
+	regsize[R_I]  = l2zm(1L);
+	regtype[R_I]  = &ityp;
+	regsa[R_I]    = 1;		/* Virtual Immediate register */
+
+	/*  Initialize the min/max-settings. Note that the types of the     */
+	/*  host system may be different from the target system and you may */
+	/*  only use the smallest maximum values ANSI guarantees if you     */
+	/*  want to be portable.                                            */
+	/*  That's the reason for the subtraction in t_min[INT]. Long could */
+	/*  be unable to represent -2147483648 on the host system.          */
+	t_min[CHAR]=l2zm(-32768L);
+	t_min[SHORT]=l2zm(-32768L);
+	t_min[INT]=t_min[SHORT];
+	t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+	t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+	t_min[MAXINT]=t_min(LLONG);
+	t_max[CHAR]=ul2zum(32767UL);
+	t_max[SHORT]=ul2zum(32767UL);
+	t_max[INT]=t_max[SHORT];
+	t_max[LONG]=ul2zum(2147483647UL);
+	t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+	t_max[MAXINT]=t_max(LLONG);
+	tu_max[CHAR]=ul2zum(65535UL);
+	tu_max[SHORT]=ul2zum(65535UL);
+	tu_max[INT]=tu_max[SHORT];
+	tu_max[LONG]=ul2zum(4294967295UL);
+	tu_max[LLONG]=zumkompl(ul2zum(0UL));
+	tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+	/* Built-ins */
+#define UINT	(UNSIGNED|INT)
+#define ULONG	(UNSIGNED|LONG)
+#define ULLONG	(UNSIGNED|LLONG)
+
+		/* 16 bit ops: lsl/lsr + mul/div/mod done in libcall */
+	declare_builtin("__lslint16",  INT,  INT,  R_R0, INT,  R_R1, 1, 0);
+	declare_builtin("__lsrint16",  INT,  INT,  R_R0, INT,  R_R1, 1, 0);
+	declare_builtin("__lsruint16", UINT, UINT, R_R0, INT,  R_R1, 1, 0);
+
+	declare_builtin("__mulint16",  INT,  INT,  R_R0, INT,  R_R1, 1, 0);
+	declare_builtin("__divint16",  INT,  INT,  R_R0, INT,  R_R1, 1, 0);
+	declare_builtin("__divuint16", UINT, UINT, R_R0, UINT, R_R1, 1, 0);
+	declare_builtin("__modint16",  INT,  INT,  R_R0, INT,  R_R1, 1, 0);
+	declare_builtin("__moduint16", UINT, UINT, R_R0, UINT, R_R1, 1, 0);
+
+		/* 32 bit ops: lsl/lsr + mul/div/mod done in libcall */
+	declare_builtin("__lslint32",  LONG,  LONG,  R_R0P, INT,   R_R2,  1, 0);
+	declare_builtin("__lsrint32",  LONG,  LONG,  R_R0P, INT,   R_R2,  1, 0);
+	declare_builtin("__lsruint32", ULONG, ULONG, R_R0P, INT,   R_R2,  1, 0);
+
+	declare_builtin("__mulint32",  LONG,  LONG,  R_R0P, LONG,  R_R2P, 1, 0);
+	declare_builtin("__divint32",  LONG,  LONG,  R_R0P, LONG,  R_R2P, 1, 0);
+	declare_builtin("__divuint32", ULONG, ULONG, R_R0P, ULONG, R_R2P, 1, 0);
+	declare_builtin("__modint32",  LONG,  LONG,  R_R0P, LONG,  R_R2P, 1, 0);
+	declare_builtin("__moduint32", ULONG, ULONG, R_R0P, ULONG, R_R2P, 1, 0);
+
+		/* 64 bits ops: everything done in libcall */
+	declare_builtin("__orint64",   LLONG,  LLONG, 0,  LLONG,  0, 1, 0);
+	declare_builtin("__eorint64",  LLONG,  LLONG, 0,  LLONG,  0, 1, 0);
+	declare_builtin("__andint64",  LLONG,  LLONG, 0,  LLONG,  0, 1, 0);
+
+	declare_builtin("__lslint64",  LLONG,  LLONG,  0, INT,    0, 1, 0);
+	declare_builtin("__lsrint64",  LLONG,  LLONG,  0, INT,    0, 1, 0);
+	declare_builtin("__lsruint64", ULLONG, ULLONG, 0, INT,    0, 1, 0);
+
+	declare_builtin("__addint64",  LLONG,  LLONG, 0,  LLONG,  0, 1, 0);
+	declare_builtin("__subint64",  LLONG,  LLONG, 0,  LLONG,  0, 1, 0);
+
+	declare_builtin("__mulint64",  LLONG,  LLONG,  0, LLONG,  0, 1, 0);
+	declare_builtin("__divint64",  LLONG,  LLONG,  0, LLONG,  0, 1, 0);
+	declare_builtin("__divuint64", ULLONG, ULLONG, 0, ULLONG, 0, 1, 0);
+	declare_builtin("__modint64",  LLONG,  LLONG,  0, LLONG,  0, 1, 0);
+	declare_builtin("__moduint64", ULLONG, ULLONG, 0, ULLONG, 0, 1, 0);
+
+	declare_builtin("__negint64",  LLONG,  LLONG,  0, 0,      0, 1, 0);
+	declare_builtin("__notint64",  LLONG,  LLONG,  0, 0,      0, 1, 0);
+
+	declare_builtin("__cmpint64",  INT,    LLONG,  0, LLONG,  0, 1, 0);
+	declare_builtin("__cmpuint64", INT,    ULLONG, 0, ULLONG, 0, 1, 0);
+
+		/* 64 bits conversions */
+	declare_builtin("__uint64touint16", ULLONG,  UINT, R_R0,  0, 0, 1, 0);
+	declare_builtin("__uint64tosint16", ULLONG,   INT, R_R0,  0, 0, 1, 0);
+	declare_builtin("__uint64touint32", ULLONG, ULONG, R_R0P, 0, 0, 1, 0);
+	declare_builtin("__uint64tosint32", ULLONG,  LONG, R_R0P, 0, 0, 1, 0);
+
+	declare_builtin("__sint64touint16",  LLONG,  UINT, R_R0,  0, 0, 1, 0);
+	declare_builtin("__sint64tosint16",  LLONG,   INT, R_R0,  0, 0, 1, 0);
+	declare_builtin("__sint64touint32",  LLONG, ULONG, R_R0P, 0, 0, 1, 0);
+	declare_builtin("__sint64tosint32",  LLONG,  LONG, R_R0P, 0, 0, 1, 0);
+
+	declare_builtin("__uint16touint64",  UINT, ULLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__sint16touint64",   INT, ULLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__uint32touint64", ULONG, ULLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__sint32touint64",  LONG, ULLONG, 0, 0, 0, 1, 0);
+
+	declare_builtin("__uint16tosint64",  UINT,  LLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__sint16tosint64",   INT,  LLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__uint32tosint64", ULONG,  LLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__sint32tosint64",  LONG,  LLONG, 0, 0, 0, 1, 0);
+
+		/* Float / Int conversions */
+			/* int16 */
+	declare_builtin("__sint16toflt32", FLOAT,  INT,  R_R0,  0, 0, 1, 0);
+	declare_builtin("__uint16toflt32", FLOAT,  UINT, R_R0,  0, 0, 1, 0);
+	declare_builtin("__sint16toflt64", DOUBLE, INT,  R_R0,  0, 0, 1, 0);
+	declare_builtin("__uint16toflt64", DOUBLE, UINT, R_R0,  0, 0, 1, 0);
+
+	declare_builtin("__flt32tosint16", INT,  FLOAT,  R_R0P, 0, 0, 1, 0);
+	declare_builtin("__flt32touint16", UINT, FLOAT,  R_R0P, 0, 0, 1, 0);
+	declare_builtin("__flt64tosint16", INT,  DOUBLE, 0,     0, 0, 1, 0);
+	declare_builtin("__flt64touint16", UINT, DOUBLE, 0,     0, 0, 1, 0);
+
+			/* int32 */
+	declare_builtin("__sint32toflt32", FLOAT,  LONG,  R_R0P, 0, 0, 1, 0);
+	declare_builtin("__uint32toflt32", FLOAT,  ULONG, R_R0P, 0, 0, 1, 0);
+	declare_builtin("__sint32toflt64", DOUBLE, LONG,  R_R0P, 0, 0, 1, 0);
+	declare_builtin("__uint32toflt64", DOUBLE, ULONG, R_R0P, 0, 0, 1, 0);
+
+	declare_builtin("__flt32tosint32", LONG,  FLOAT,  R_R0P, 0, 0, 1, 0);
+	declare_builtin("__flt32touint32", ULONG, FLOAT,  R_R0P, 0, 0, 1, 0);
+	declare_builtin("__flt64tosint32", LONG,  DOUBLE, 0,     0, 0, 1, 0);
+	declare_builtin("__flt64touint32", ULONG, DOUBLE, 0,     0, 0, 1, 0);
+
+			/* int64 */
+	declare_builtin("__sint64toflt32", FLOAT,  LLONG,  0, 0, 0, 1, 0);
+	declare_builtin("__uint64toflt32", FLOAT,  ULLONG, 0, 0, 0, 1, 0);
+	declare_builtin("__sint64toflt64", DOUBLE, LLONG,  0, 0, 0, 1, 0);
+	declare_builtin("__uint64toflt64", DOUBLE, ULLONG, 0, 0, 0, 1, 0);
+
+	declare_builtin("__flt32tosint64", LLONG,  FLOAT,  0, 0, 0, 1, 0);
+	declare_builtin("__flt32touint64", ULLONG, FLOAT,  0, 0, 0, 1, 0);
+	declare_builtin("__flt64tosint64", LLONG,  DOUBLE, 0, 0, 0, 1, 0);
+	declare_builtin("__flt64touint64", ULLONG, DOUBLE, 0, 0, 0, 1, 0);
+
+		/* Inter-Float conversions */
+	declare_builtin("__flt32toflt64", DOUBLE, FLOAT,  0, 0, 0, 1, 0);
+	declare_builtin("__flt64toflt32", FLOAT,  DOUBLE, 0, 0, 0, 1, 0);
+
+		/* Floating point math */
+			/* float */
+	declare_builtin("__addflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+	declare_builtin("__subflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+	declare_builtin("__mulflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+	declare_builtin("__divflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+	declare_builtin("__negflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+
+	declare_builtin("__cmpflt32", INT,   FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+
+			/* double */
+	declare_builtin("__addflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+	declare_builtin("__subflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+	declare_builtin("__mulflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+	declare_builtin("__divflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+	declare_builtin("__negflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+
+	declare_builtin("__cmpflt64", INT,    DOUBLE, 0, DOUBLE, 0, 1, 0);
+
+#undef UINT
+#undef ULONG
+#undef ULLONG
+
+	return 1;
+}
+
+void cleanup_cg(FILE *f)
+{
+	/* Nothing to do */
+}
+
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+int freturn(struct Typ *t)
+{
+	int f = t->flags & NQ;
+
+	/* Any scalar that fits in 16 bits uses A as return register */
+	if (ISSCALAR(f) && (msizetab[f] == 1))
+		return R_A;
+
+	/* Any scalar that fits in 32 bits used R0/R1 as return register */
+	if (ISSCALAR(f) && (msizetab[f] == 2))
+		return R_R0P;
+}
+
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+int regok(int r, int t, int mode)
+{
+	if (r == 0)
+		return 0;
+
+	if (ISTSHORT(t)) {
+		if (r >= R_R0 && r <= R_RF)
+			return 1;
+		if (r >= R_S0 && r <= R_SF)
+			return 1;
+		if (r == R_A || r == R_X || r == R_Y)
+			return 1;
+	}
+
+	if (ISTLONG(t)) {
+		if (r >= R_R0P && r <= R_REP)
+			return 1;
+		if (r >= R_S0P && r <= R_SEP)
+			return 1;
+	}
+
+	return 0;
+}
+
+int dangerous_IC(struct IC *p)
+{
+	/* Only memory accesses are 'dangerous' */
+	int c=p->code;
+	if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+		return 1;
+	return 0;
+}
+
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+int must_convert(int o,int t, int const_expr)
+{
+	int op=o&NQ,tp=t&NQ;
+
+	if (op==tp) return 0;
+
+	if (ISPOINTER(op) && ISPOINTER(tp))
+		return 1; /* No conversion actually possible between pointer types ! */
+
+	if (ISTSHORT(op) && ISTSHORT(tp))
+		return 0; /* All 'short' types are compatible */
+
+	return 1;
+}
+
+int shortcut(int code, int t)
+{
+	t &= NQ;
+	if (t == CHAR || t == SHORT || t == INT)
+		return 1;
+	return 0;
+}
+
+void gen_code(FILE *f, struct IC *p, struct Var *v, zmax offset)
+{
+	struct gc_state gc;
+	struct IC *node;
+
+	gc_func_begin(&gc, f, p, v, offset);
+	for (node=p; node; node=node->next)
+		gc_func_ic(&gc, node);
+	gc_func_end(&gc, f, p, v, offset);
+}
+
+void gen_ds(FILE *f, zmax size, struct Typ *t)
+{
+	long s = zm2l(size);
+	emit(f, "\t.space %ld\n", s);
+}
+
+void gen_align(FILE *f, zmax align)
+{
+	long a = zm2l(align);
+
+	if (a > 1)
+		emit(f, "\t.align %ld\n", a);
+}
+
+void gen_var_head(FILE *f, struct Var *v)
+{
+	const char*section_names[] = { /* bit 2: pmem, bit 1: init, bit 0: const */
+		"bss", NULL, "data", "rodata",
+		"pmem_bss", NULL, "pmem_data", "pmem_rodata",
+	};
+	int section_type;
+	struct Typ *tv;
+	char *attr;
+
+	tv = v->vtyp;
+	while (tv->flags==ARRAY)
+		tv = tv->next;
+	attr = tv->attr;
+
+	if (isstatic(v->storage_class) || isextern(v->storage_class))
+	{
+		/* Select section */
+		section_type  = (attr && strstr(attr, STR_PMEM)) ? 4 : 0;
+		section_type |= v->clist ? 2 : 0;
+		section_type |= (v->clist && is_const(v->vtyp)) ? 1 : 0;
+
+		emit(f, "\t.section %s\n", section_names[section_type]);
+
+		/* Symbol name */
+		if (isstatic(v->storage_class))
+			emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
+		else
+			emit(f, "%s%s:\n", idprefix, v->identifier);
+
+		/* FIXME: export global symbols */
+	}
+	else
+	{
+		ierror(0);
+	}
+}
+
+void gen_dc(FILE *f, int t, struct const_list *p)
+{
+	const char *dct[] = { "", "byte", "short",  "short", "long", "long", "long", "long" };
+	int tb;
+
+	if (ISPOINTER(t))
+		t = UNSIGNED|SHORT;
+	tb = t & NQ;
+
+	if (tb > LDOUBLE)
+		ierror(0);
+
+	emit(f, "\t.%s\t", dct[t&NQ]);
+
+	if (!p->tree)
+	{
+		if (ISFLOAT(tb)) {
+			unsigned char *ip;
+			emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+			if(tb != FLOAT){
+				emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+			}
+		} else if (tb == LLONG) {
+			/* Init */
+			zumax tmp;
+			eval_const(&p->val,t);
+			tmp = vumax;
+
+			/* Lower 32b */
+			vumax = zumand(tmp,ul2zum(0xffffffff));
+			gval.vulong = zum2zul(vumax);
+			emitval(f, &gval, UNSIGNED|LONG);
+
+			emit(f, ",");
+
+			/* Upper 32b */
+			vumax = zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+			gval.vulong = zum2zul(vumax);
+			emitval(f, &gval, UNSIGNED|LONG);
+		} else {
+			emitval(f, &p->val, (t&NU)|UNSIGNED);
+		}
+	}
+	else
+	{
+		if ((p->tree->o.flags & (VAR | VARADR)) == (VAR | VARADR)) {
+			emit(f, "%s", sym_name(p->tree->o.v));
+		} else {
+			/* Not supported ... no idea what to do here */
+			ierror(0);
+		}
+	}
+
+	emit(f,"\n");
+}
+
+void init_db(FILE *f)
+{
+	/* not supported */
+}
+
+void cleanup_db(FILE *f)
+{
+	/* not supported */
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+	static const char *names[] = { "na", "int16", "int16", "int16", "int32", "int64", "flt32", "flt64" };
+	static const struct {
+		int code;
+		int use_sign;
+		int types;
+	} lib_ops[] = {
+#define TB(x) (1 << (x))
+		{ OR,      0, TB(LLONG) },
+		{ XOR,     0, TB(LLONG) },
+		{ AND,     0, TB(LLONG) },
+		{ LSHIFT,  0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+		{ RSHIFT,  1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+		{ ADD,     0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) },
+		{ SUB,     0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) },
+		{ MULT,    0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+		{ DIV,     1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+		{ MOD,     1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+		{ COMPARE, 1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) },
+		{ -1 }
+	};
+#undef TB
+	static char fname[20];
+	const char *n, *n2, *s, *s2;
+	int i;
+
+	/* We don't really support long doubles */
+	if (t==LDOUBLE)  t=DOUBLE;
+	if (t2==LDOUBLE) t2=DOUBLE;
+
+	/* Safety */
+	if (((t&NQ) < CHAR) || ((t&NQ) > DOUBLE))
+		return NULL;
+	if ((t2&NQ) > DOUBLE)
+		return NULL;
+
+	/* Get name string for t/t2 and sign char */
+	n  = names[t  & NQ]; s  = ISFLOAT(t)  ? "" : ((t  & UNSIGNED) ? "u" : "s");
+	n2 = names[t2 & NQ]; s2 = ISFLOAT(t2) ? "" : ((t2 & UNSIGNED) ? "u" : "s");
+
+	/* Conversions */
+	if (c == CONVERT)
+	{
+		/* Build name */
+		snprintf(fname, sizeof(fname)-1, "__%s%sto%s%s", s, n, s2, n2);
+
+		/* All conversion with float are library */
+		if (ISFLOAT(t) || ISFLOAT(t2))
+			return fname;
+
+		/* No match */
+		return NULL;
+	}
+
+	/* Scan for supported operations */
+	for (i=0; lib_ops[i].code > 0; i++)
+	{
+		/* Match op */
+		if (lib_ops[i].code != c)
+			continue;
+
+		/* Supported type ? */
+		if ((lib_ops[i].types & (1 << (t&NQ))) == 0)
+			return NULL;
+
+		/* Build name */
+		if (lib_ops[i].use_sign)
+			snprintf(fname, sizeof(fname)-1, "__%s%s%s", ename[c], s, n);
+		else
+			snprintf(fname, sizeof(fname)-1, "__%s%s", ename[c], n);
+
+		return fname;
+	}
+
+	return NULL;
+}
+
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+int reg_pair(int r,struct rpair *p)
+{
+	if ((r >= R_R0P) && (r <= R_REP))
+	{
+		p->r1 = R_R0 + 2 * (r -  R_R0P);
+		p->r2 = R_R1 + 2 * (r -  R_R0P);
+		return 1;
+	}
+
+	if ((r >= R_S0P) && (r <= R_SEP))
+	{
+		p->r1 = R_S0 + 2 * (r -  R_S0P);
+		p->r2 = R_S1 + 2 * (r -  R_S0P);
+		return 1;
+	}
+
+	return 0;
+}
+
+int reg_parm(struct reg_handle *p, struct Typ *t,int vararg,struct Typ *d)
+{
+	int f = t->flags & NQ;
+
+	/* Exclusions */
+	if (!ISSCALAR(f)) return 0;
+	if (p->gpr >= 4 || vararg) return 0;
+	if (f==LLONG || f==DOUBLE || f==LDOUBLE) return 0;
+
+	/* Pairs (possibly 'loosing' one reg if misaligned) */
+	if (f==LONG || f==FLOAT) {
+		p->gpr += (p->gpr & 1);	/* align */
+		if (p->gpr >= 4)
+			return 0;
+		p->gpr += 2;
+		return R_R0P + (p->gpr / 2) - 1;
+	}
+
+	/* Normal */
+	return R_R0 + p->gpr++;
+}
+
+int pointer_type(struct Typ *p)
+{
+	while (ISARRAY(p->flags))
+		p=p->next;
+	if (ISFUNC(p->flags))
+		return PPOINTER;
+	if (p->attr && strstr(p->attr, STR_PMEM))
+		return PPOINTER;
+	return DPOINTER;
+}
+
+void conv_typ(struct Typ *p)
+{
+	char *attr;
+	while(p) {
+		if (ISPOINTER(p->flags)) {
+			p->flags = ((p->flags&~NU)|POINTER_TYPE(p->next));
+			if(attr=p->next->attr){
+				if(strstr(attr,STR_PMEM))
+					p->flags=((p->flags&~NU)|PPOINTER);
+			}
+		}
+		p=p->next;
+	}
+}
+
+/* Below is mostly copied from supp.c */
+void printval(FILE *f,union atyps *p,int t)
+{
+	t&=NU;
+	if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+	if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+	if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+	if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+	if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+	if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+	if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+	if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+	if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+	if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+	if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+	if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+	if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+	if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);}
+	if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);}
+	if(t==DPOINTER){fprintf(f,"Pd");vumax=zul2zum(p->vushort);printzum(f,vumax);}
+	if(t==PPOINTER){fprintf(f,"Pp");vumax=zul2zum(p->vushort);printzum(f,vumax);}
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+{
+	t&=NU;
+	if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+	if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+	if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+	if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+	if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+	if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+	if(t==LDOUBLE){emitzld(f,p->vldouble);}
+	if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+	if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+	if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+	if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+	if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+	if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+	if(t==MAXINT){emitzm(f,p->vmax);}
+	if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);}
+	if(t==DPOINTER){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+	if(t==PPOINTER){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+}
+
+void insert_const(union atyps *p,int t)
+{
+	if(!p) ierror(0);
+	t&=NU;
+	if(t==CHAR) {p->vchar=vchar;return;}
+	if(t==SHORT) {p->vshort=vshort;return;}
+	if(t==INT) {p->vint=vint;return;}
+	if(t==LONG) {p->vlong=vlong;return;}
+	if(t==LLONG) {p->vllong=vllong;return;}
+	if(t==MAXINT) {p->vmax=vmax;return;}
+	if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+	if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+	if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+	if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+	if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+	if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+	if(t==FLOAT) {p->vfloat=vfloat;return;}
+	if(t==DOUBLE) {p->vdouble=vdouble;return;}
+	if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+	if(t==DPOINTER) {p->vushort=vushort;return;}
+	if(t==PPOINTER) {p->vushort=vushort;return;}
+}
+
+void eval_const(union atyps *p,int t)
+{
+	int f=t&NQ;
+	if(!p) ierror(0);
+	if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+		if(!(t&UNSIGNED)){
+			if(f==CHAR) vmax=zc2zm(p->vchar);
+			else if(f==SHORT)vmax=zs2zm(p->vshort);
+			else if(f==INT)  vmax=zi2zm(p->vint);
+			else if(f==LONG) vmax=zl2zm(p->vlong);
+			else if(f==LLONG) vmax=zll2zm(p->vllong);
+			else if(f==MAXINT) vmax=p->vmax;
+			else ierror(0);
+			vumax=zm2zum(vmax);
+			vldouble=zm2zld(vmax);
+		}else{
+			if(f==CHAR) vumax=zuc2zum(p->vuchar);
+			else if(f==SHORT)vumax=zus2zum(p->vushort);
+			else if(f==INT)  vumax=zui2zum(p->vuint);
+			else if(f==LONG) vumax=zul2zum(p->vulong);
+			else if(f==LLONG) vumax=zull2zum(p->vullong);
+			else if(f==MAXINT) vumax=p->vumax;
+			else ierror(0);
+			vmax=zum2zm(vumax);
+			vldouble=zum2zld(vumax);
+		}
+	}else{
+		if(ISPOINTER(f)){
+			vumax=zus2zum(p->vushort);
+			vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+		}else{
+			if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+			else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+			else vldouble=p->vldouble;
+			vmax=zld2zm(vldouble);
+			vumax=zld2zum(vldouble);
+		}
+	}
+	vfloat=zld2zf(vldouble);
+	vdouble=zld2zd(vldouble);
+	vuchar=zum2zuc(vumax);
+	vushort=zum2zus(vumax);
+	vuint=zum2zui(vumax);
+	vulong=zum2zul(vumax);
+	vullong=zum2zull(vumax);
+	vchar=zm2zc(vmax);
+	vshort=zm2zs(vmax);
+	vint=zm2zi(vmax);
+	vlong=zm2zl(vmax);
+	vllong=zm2zll(vmax);
+}
diff --git a/machines/fire16/machine.dt b/machines/fire16/machine.dt
new file mode 100644
index 0000000..fa60647
--- /dev/null
+++ b/machines/fire16/machine.dt
@@ -0,0 +1,16 @@
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/fire16/machine.h b/machines/fire16/machine.h
new file mode 100644
index 0000000..f723321
--- /dev/null
+++ b/machines/fire16/machine.h
@@ -0,0 +1,189 @@
+/* 
+ * Backend for the Fire16 iCE40 SoftCore
+ * (c) 2019 by Sylvain Munaut
+ */
+
+#include "dt.h"
+
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+struct AddressingMode {
+	int not_used_yet;	// FIXME
+};
+
+/*  The number of registers of the target machine.                  */
+	/* - 16 rN GPR + 8 pairs
+	 * - 16 sN GPR + 8 pairs
+	 * - A, X, Y, I
+	 */
+#define MAXR 52
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P CHAR
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MAXADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 16
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gpr;
+};
+
+/*  We have register pairs.                                         */
+#define HAVE_REGPAIRS 1
+
+/*  We use unsigned int as size_t rather than unsigned long which   */
+/*  is the default setting.                                         */
+#define HAVE_INT_SIZET 1
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0	/* FIXME: not yet */
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We do not have target-specific pragmas */
+#undef HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+   register-allocation */
+#if 0 /* FIXME */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y)  XXX
+#define cost_load_reg(x,y)  XXX
+#define cost_save_reg(x,y)  XXX
+#define cost_pushpop_reg(x) XXX
+#endif
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we need extended types (for pmem/dmem pointers) */
+#define HAVE_EXT_TYPES 1
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define DPOINTER 10
+#define PPOINTER 11
+#define ARRAY 12
+#define STRUCT 13
+#define UNION 14
+#define ENUM 15
+#define FUNKT 16
+#define BOOL 17
+#define MAXINT 18
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=DPOINTER&&(x&NQ)<=PPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=PPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) (INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+
+/* we need our own printval */
+#define HAVE_TGT_PRINTVAL 1
+
+/* we want to replace some ICs with libcalls */
+#define HAVE_LIBCALLS 1
+
+/* we much prefer BNE */
+#define HAVE_WANTBNE 1
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
diff --git a/machines/generic/machine.c b/machines/generic/machine.c
new file mode 100755
index 0000000..f7b86ac
--- /dev/null
+++ b/machines/generic/machine.c
@@ -0,0 +1,1166 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+    CPU.
+ 
+    Configurable at build-time are:
+    - number of (32bit) general-purpose-registers
+    - number of (64bit) floating-point-registers
+    - number of (8bit) condition-code-registers
+    - mechanism for stack-arguments (moving ot fixed sp)
+ 
+    It allows to select as run-time-options:
+    - two- or three-address code
+    - memory operands or load-store-architecture
+    - number of register-arguments
+    - number of caller-save-registers
+*/                                                                             
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc generic code-generator V0.1b (c) in 2001 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+		    VALFLAG,VALFLAG,VALFLAG,
+		    0,0,
+		    VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+			   "volatile-gprs","volatile-fprs","volatile-ccrs",
+			   "imm-ind","gpr-ind",
+			   "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS   ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS   ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND    ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND    ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS   ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__GENERIC__",
+		       0};
+
+/* special registers */
+static int sp;                     /*  Stackpointer                        */
+static int t1,t2,t3;               /*  temporary gprs */
+static int f1,f2,f3;               /*  temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+  *dataname="\t.data\n",
+  *bssname="",
+  *rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+   a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | return-address [size=4]                      |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize+4-off-zm2l(maxalign);
+  }
+
+#if FIXED_SP
+  off+=argsize;
+#else
+  off+=stackoffset;
+#endif
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if(!(o->flags&VAR)) ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    if(THREE_ADDR){
+      emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+    }else{
+      emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+      if(off)
+	emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+    }
+  }else{
+    emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+   general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NU;
+  if(o->flags&VARADR){
+    load_address(f,r,o,POINTER);
+  }else{
+    if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+      return;
+    emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NQ;
+  emit(f,"\tmov.%s\t",dt(type));
+  emit_obj(f,o,type);
+  emit(f,",%s\n",regnames[r]);
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+
+  if(isreg(z)&&(THREE_ADDR||!compare_objects(&p->q2,&p->z))){
+    zreg=p->z.reg;
+  }else{
+    if(ISFLOAT(ztyp(p)))
+      zreg=f1;
+    else
+      zreg=t1;
+  }
+  
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q1,q1typ(p));
+    p->q1.reg=t1;
+    p->q1.flags|=(REG|DREFOBJ);
+  }
+  if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+    if(p->code==ASSIGN&&isreg(z))
+      q1reg=p->z.reg;
+    else if(ISFLOAT(q1typ(p)))
+      q1reg=f1;
+    else
+      q1reg=t1;
+    load_reg(f,q1reg,&p->q1,q1typ(p));
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q2,q2typ(p));
+    p->q2.reg=t1;
+    p->q2.flags|=(REG|DREFOBJ);
+  }
+  if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+    if(ISFLOAT(q2typ(p)))
+      q2reg=f2;
+    else
+      q2reg=t2;
+    load_reg(f,q2reg,&p->q2,q2typ(p));
+    p->q2.reg=q2reg;
+    p->q2.flags=REG;
+  }
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->z,POINTER);
+    p->z.reg=t2;
+    p->z.flags|=(REG|DREFOBJ);
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+    if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=zm2l(of);
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=GPR_IND;
+              am->base=base;
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  rsavesize=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  emit(f,ret);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(4);
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  regnames[0]="noreg";
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+    regsize[i]=l2zm(4L);
+    regtype[i]=&ltyp;
+  }
+  for(i=FIRST_FPR;i<=LAST_FPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+    regsize[i]=l2zm(8L);
+    regtype[i]=&ldbl;
+  }
+  for(i=FIRST_CCR;i<=LAST_CCR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+    regsize[i]=l2zm(1L);
+    regtype[i]=&lchar;
+  }
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  sp=FIRST_GPR;
+  t1=FIRST_GPR+1;
+  t2=FIRST_GPR+2;
+  f1=FIRST_FPR;
+  f2=FIRST_FPR+1;
+  regsa[t1]=regsa[t2]=1;
+  regsa[f1]=regsa[f2]=1;
+  regsa[sp]=1;
+  regscratch[t1]=regscratch[t2]=0;
+  regscratch[f1]=regscratch[f2]=0;
+  regscratch[sp]=0;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+    regscratch[i]=1;
+
+  target_macros=marray;
+
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) 
+    return FIRST_FPR+2;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 
+    return 0;
+  if(zmleq(szof(t),l2zm(4L))) 
+    return FIRST_GPR+3;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    if(!LOAD_STORE)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  t&=NQ;
+  if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+    return 1;
+  if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+    return 1;
+  if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(v->clist||section==SPECIAL){
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||section==SPECIAL){
+	gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\tdc.%s\t",dt(t&NQ));
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *m;
+  argsize=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  maxpushed=0;
+
+  /*FIXME*/
+  ret="\trts\n";
+
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+    /* convert MULT/DIV/MOD with powers of two */
+    if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  p->typf2=INT;
+	}
+      }
+    }
+#if FIXED_SP
+    if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+  }
+  peephole(p);
+
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+
+  localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+  /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+  function_top(f,v,localsize);
+
+#if FIXED_SP
+  pushed=0;
+#endif
+
+  for(;p;p=p->next){
+    c=p->code;t=p->typf;
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(0/*t==exit_label&&framesize==0*/)
+	emit(f,ret);
+      else
+	emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      emit(f,"\tb%s\t",ccs[c-BEQ]);
+      if(isreg(q1)){
+	emit_obj(f,&p->q1,0);
+	emit(f,",");
+      }
+      emit(f,"%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      ierror(0);
+    }
+    /* switch commutative operands if suitable */
+    if(c==ADD||c==MULT||c==AND||c==XOR||c==OR){
+      if(compare_objects(&p->q2,&p->z)){
+	struct obj tmp;
+	tmp=p->q1;
+	p->q1=p->q2;
+	p->q2=tmp;
+      }
+    }
+
+    p=preload(f,p);
+    c=p->code;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+      if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+	if(q1typ(p)&UNSIGNED)
+	  emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+	else
+	  emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+      }
+      save_result(f,p);
+      continue;
+    }
+    if(c==KOMPLEMENT){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==SETRETURN){
+      load_reg(f,p->z.reg,&p->q1,t);
+      BSET(regs_modified,p->z.reg);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+	save_result(f,p);
+      }else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      int reg;
+      /*FIXME*/
+#if 0      
+      if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	  stack=framesize+zum2ul(p->q1.v->fi->stack1);
+      }else
+	stack_valid=0;
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+	emit(f,"\tcall\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      /*FIXME*/
+#if FIXED_SP
+      pushed-=zm2l(p->q2.val.vmax);
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+	int i;
+	for(i=1;i<=MAXR;i++){
+	  if(regscratch[i]) BSET(regs_modified,i);
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(c==PUSH){
+#if FIXED_SP
+	emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	pushed+=zm2l(p->q2.val.vmax);
+#else
+	emit(f,"\tpush.%s\t",dt(t));
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	push(zm2l(p->q2.val.vmax));
+#endif
+	continue;
+      }
+      if(c==ASSIGN){
+	load_reg(f,zreg,&p->q1,t);
+	save_result(f,p);
+      }
+      continue;
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      save_result(f,p);
+      continue;
+    }
+    if(c==MINUS){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==TEST){
+      emit(f,"\ttst.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if(c==COMPARE){
+      emit(f,"\tcmp.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,",");
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+      if(!THREE_ADDR)
+	load_reg(f,zreg,&p->q1,t);
+      if(c>=OR&&c<=AND)
+	emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+      else
+	emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+      if(THREE_ADDR){
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+      }
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      save_result(f,p);
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  function_bottom(f,v,localsize);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=stack;
+  }
+  emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+  f=t->flags&NQ;
+  if(f<=LONG||f==POINTER){
+    if(m->gregs>=GPR_ARGS)
+      return 0;
+    else
+      return FIRST_GPR+3+m->gregs++;
+  }
+  if(ISFLOAT(f)){
+    if(m->fregs>=FPR_ARGS)
+      return 0;
+    else
+      return FIRST_FPR+2+m->fregs++;
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
diff --git a/machines/generic/machine.dt b/machines/generic/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/generic/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/generic/machine.h b/machines/generic/machine.h
new file mode 100755
index 0000000..118a4d7
--- /dev/null
+++ b/machines/generic/machine.h
@@ -0,0 +1,151 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+    CPU.
+
+    Configurable at build-time are:
+    - number of (32bit) general-purpose-registers
+    - number of (64bit) floating-point-registers
+    - number of (8bit) condition-code-registers
+    - mechanism for stack-arguments (moving ot fixed sp)
+
+    It allows to select as run-time-options:
+    - two- or three-address code
+    - memory operands or load-store-architecture
+    - number of register-arguments
+    - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 32
+#define NUM_FPRS 32
+#define NUM_CCRS 8
+#define FIXED_SP 1
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
diff --git a/machines/hc12/machine.c b/machines/hc12/machine.c
new file mode 100755
index 0000000..c6bc237
--- /dev/null
+++ b/machines/hc12/machine.c
@@ -0,0 +1,3872 @@
+/*  Code generator for Motorola 68hc12 microcontrollers.               */
+
+/*TODO:
+  regs_modified bei struct-copy
+  savings verfeinern
+  4-Byte Copy
+  [static] testen
+  peephole-Pass um ALLOCREGs zu entfernen
+  ACC_IND (Achtung?)
+  struct-copy Problemfälle
+  banked
+  bit
+  long long, float, double, long double
+
+*/
+
+#include "supp.h"
+#include "vbc.h" /* nicht schoen, aber ... */
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for 6809/6803/68hc12 V1.0 (c) in 2000-2021 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+                    0,0,0,0,
+		    0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+                           "merge-constants","no-peephole","mem-cse","acc-glob",
+			   "pcrel","drel","no-char-addi2p","nodx","nou","double64"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+		 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+		 "array","struct","union","enum","function"};
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[]={"noreg","d","x","y","sp","u","d/x"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,0,1,0,1};
+
+int reg_prio[MAXR+1]={0,0,1,1,0,0,1};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__dpage",0};
+#define INTERRUPT 1
+#define DPAGE     2
+
+int MINADDI2P=CHAR;
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,4,4,4,4,0,2,4,4,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static int section=-1,newobj,scnt,pushed_acc;
+static char *codename="\t.text\n",
+            *dataname="\t.data\n",
+            *bssname="\t.section\t.bss\n",
+            *rodataname="\t.section\t.rodata\n";
+
+#define IMM_IND  1
+#define VAR_IND  2
+#define POST_INC 3
+#define POST_DEC 4
+#define PRE_INC  5
+#define PRE_DEC  6
+#define ACC_IND  7
+#define KONSTINC 8
+
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static int acc=1,ix=2,iy=3,sp=4,iu=5,dx=6;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+		       "__HC12__",
+		       "__SIZE_T_INT=1",
+		       "__direct=__vattr(\"section(\\\"dpage\\\")\")",
+		       0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static long loff,roff,stackoffset,notpopped,dontpop,maxpushed,stack;
+
+static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
+static char *ccs[]={"eq","ne","lt","ge","le","gt"};
+static char *uccs[]={"eq","ne","lo","hs","ls","hi"};
+static char *logicals[]={"ora","eor","and"};
+static char *dct[]={"",".bit",".byte",".2byte",".2byte",".4byte",".8byte",".4byte",".4byte",".4byte",
+		    "(void)",".2byte",".34byte",".34byte"};
+static char *idprefix="",*labprefix=".l";
+static int exit_label,have_frame;
+static char *ret;
+static int stackchecklabel;
+static int frame_used,stack_valid;
+static int CPU=6812;
+static int pcrel,drel;
+static int skip_rel;
+static char *jsrinst="jsr";
+static char *jmpinst="jmp";
+static int nodx,nou;
+int switchsubs;
+
+static int cc_t;
+static struct obj *cc;
+
+static struct obj mobj;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+#define STR_BADDR "baddr"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||ISFLOAT(t&NQ))
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
+#define ISCHWORD(t) ((t&NQ)==CHAR||ISHWORD(t))
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
+/*FIXME*/
+#define ISFAR(v) ((v)->vtyp->attr&&(strstr(STR_FAR,(v)->vtyp->attr)||strstr(STR_HUGE,(v)->vtyp->attr)))
+
+#define ISACC(x) ((x)==acc)
+#define ISX(x) ((x)==ix)
+#define ISY(x) ((x)==iy)
+#define ISU(x) ((x)==iu)
+#define ISIDX(x) (ISX(x)||ISY(x)||(ISU(x)&&CPU!=6812))
+#define ISRACC(x) (isreg(x)&&ISACC(p->x.reg))
+#define ISRX(x) (isreg(x)&&ISX(p->x.reg))
+#define ISRY(x) (isreg(x)&&ISY(p->x.reg))
+#define ISRU(x) (isreg(x)&&ISU(p->x.reg))
+#define ISRIDX(x) (isreg(x)&&ISIDX(p->x.reg))
+
+#define CPUOPT ((g_flags[0]&USEDFLAG)?g_flags_val[0].l:6812)
+
+#define SPUSH(x) (CPU==6812?"\tpsh" x "\n":"\tpshs\t" x "\n")
+#define SPUSHD   (CPU==6812?"\tpshd\n":"\tpshs\tb,a\n")
+#define SPULL(x) (CPU==6812?"\tpul" x "\n":"\tpuls\t" x "\n")
+#define SPULLD   (CPU==6812?"\tpuld\n":"\tpuls\ta,b\n")
+#define SCMP(x)  (CPU==6812?"\tcp" x "\t":"\tcmp" x "\t")
+#define SEX      (CPU==6812?"\tsex\tb,d\n":"\tsex\n")
+#define EXTEND(t) (((t)&UNSIGNED)?"\tclra\n":SEX)
+
+#define SGN16(x) (zm2l(zi2zm(zm2zi(l2zm((long)(x))))))
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2, ALLOWSFX = 4};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+static int check_sfx(char *s)
+{
+  if(!*s) return 0;
+  s+=strlen(s)-1;
+  if(*s=='+'||*s=='-') return 1;
+  if(*s!='s'&&*s!='x'&&*s!='y'&&*s!='u') return 0;
+  s--;
+  if(*s!=',') return 0;
+  s--;
+  if(*s=='+'||*s=='-') return 1;
+  return 0;
+}
+
+static int setszflag(char *op,char r)
+{
+  static char *zb[]={"adcb","addb","andb","aslb","asrb","clrb","comb","decb","eorb","incb",
+		"ldab","ldb","lslb","lsrb","negb","orb","orab","rolb","rorb","sbcb",
+		"stb","stab","subb","tstb"};
+  static char *zd[]={"addd","ldd","sex","std","subd"};
+
+  int i;
+
+  if(r=='b'){
+    for(i=0;i<sizeof(zb)/sizeof(*zb);i++)
+      if(!strcmp(op,zb[i]))
+	return 1;
+  }
+  if(r=='d'){
+    for(i=0;i<sizeof(zd)/sizeof(*zd);i++)
+      if(!strcmp(op,zd[i]))
+	return 1;
+  }
+  if(r=='x'&&(!strcmp(op,"leax")||!strcmp(op,"ldx"))) return 1;
+  if(r=='y'&&(!strcmp(op,"leay")||!strcmp(op,"ldy"))) return 1;
+  if(CPU==6812){
+    if(r=='x'&&(!strcmp(op,"dex")||!strcmp(op,"inx"))) return 1;
+    if(r=='y'&&(!strcmp(op,"dey")||!strcmp(op,"iny"))) return 1;
+  }
+  return 0;
+}
+
+int emit_peephole(void)
+{
+  int entries,i,j,v1,v2;
+  char *asmline[EMIT_BUF_DEPTH];
+  char buf1[1024],buf2[1024];
+  char op1[8],op2[8];
+
+
+  /* TODO: adapt better */
+  static struct peeps elim[]={
+    "lda","sta",0,NEEDSAME,
+    "ldb","stb",0,NEEDSAME,
+    "ldaa","staa",0,NEEDSAME,
+    "ldab","stab",0,NEEDSAME,
+    "ldd","std",0,NEEDSAME,
+    "ldx","stx",0,NEEDSAME,
+    "ldy","sty",0,NEEDSAME,
+    "ldu","stu",0,NEEDSAME,
+    "sta","sta",0,NEEDSAME,
+    "stb","stb",0,NEEDSAME,
+    "staa","staa",0,NEEDSAME,
+    "stab","stab",0,NEEDSAME,
+    "std","std",0,NEEDSAME,
+    "stx","stx",0,NEEDSAME,
+    "sty","sty",0,NEEDSAME,
+    "stu","stu",0,NEEDSAME,
+    "sta","lda",0,NEEDSAME,
+    "stb","ldb",0,NEEDSAME,
+    "staa","ldaa",0,NEEDSAME,
+    "stab","ldab",0,NEEDSAME,
+    "std","ldd",0,NEEDSAME,
+    "stx","ldx",0,NEEDSAME,
+    "sty","ldy",0,NEEDSAME,
+    "stu","ldu",0,NEEDSAME,
+#if 0
+    "lda","lda",0,REMOVE1ST,
+    "ldaa","ldaa",0,REMOVE1ST,
+    "ldab","ldab",0,REMOVE1ST,
+    "ldb","ldb",0,REMOVE1ST,
+    "ldd","ldd",0,REMOVE1ST,
+    "ldx","ldx",0,REMOVE1ST,
+    "ldy","ldy",0,REMOVE1ST,
+    "ldu","ldu",0,REMOVE1ST,
+    "lda","pla",0,REMOVE1ST,
+    "lda","txa",0,REMOVE1ST,
+    "lda","tya",0,REMOVE1ST,
+    "ldx","tax",0,REMOVE1ST,
+    "ldy","tay",0,REMOVE1ST,
+    "tay","ldy",0,REMOVE1ST,
+    "tax","ldx",0,REMOVE1ST,
+    "txa","lda",0,REMOVE1ST,
+    "tya","lda",0,REMOVE1ST,
+#endif
+  };
+
+
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpb")&&!strcmp(buf1,"#0"))
+    strcpy(asmline[0],"\ttstb\n");
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpd")&&!strcmp(buf1,"#0"))
+    strcpy(asmline[0],"\tsubd\t#0\n");
+
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+
+    for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+      if(elim[j].flags&NEEDSAME){
+	if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+	   sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+	   !strcmp(buf1,buf2)){
+	  if(!check_sfx(buf1)&&!check_sfx(buf2)){
+	    if(elim[j].r){
+	      strcpy(asmline[0],elim[j].r);
+	    }else{
+	      if(elim[j].flags&REMOVE1ST)
+		strcpy(asmline[1],asmline[0]);
+	      remove_asm();
+	    }
+	    return 1;
+	  }
+	}
+      }else{
+	*buf1=0;*buf2=0;
+	if(sscanf(asmline[1]," %6s %999s",op1,buf1)>=1&&
+	   sscanf(asmline[0]," %6s %999s",op2,buf2)>=1&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+	  if((elim[j].flags&ALLOWSFX)||(!check_sfx(buf1)&&!check_sfx(buf2))){
+	    if(elim[j].flags&REMOVE1ST)
+	      strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+      }
+    }
+
+    if(!strcmp(asmline[0],"\trts\n")&&sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"puls")){
+      sprintf(asmline[1]+strlen(asmline[1])-1,",pc\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tstb\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-1,s\n")){
+      strcpy(asmline[1],"\tpshs\tb\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tstd\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-2,s\n")){
+      strcpy(asmline[1],"\tpshs\tb,a\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tldb\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb\n")){
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tldd\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb,a\n")){
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tpshs\tb,a\n")&&!strcmp(asmline[1],"\tpuls\ta,b\n")){
+      strcpy(asmline[1],"\tldd\t0,s\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(sscanf(asmline[1]," ldd %999s",op1)>=1&&sscanf(asmline[0]," ldd %999s",op2)>=1){
+      if(!((op2[0]=='a'||op2[0]=='b'||op2[0]=='d')&&op2[1]==',')){
+	strcpy(asmline[1],asmline[0]);
+	remove_asm();
+	return 1;
+      }
+    }
+
+    if(!strcmp(asmline[0],"\ttfr\tx,d\n")&&!strcmp(asmline[1],"\ttfr\td,x\n")){
+      remove_asm();
+      return 1;
+    }
+    if(!strcmp(asmline[0],"\ttfr\ty,d\n")&&!strcmp(asmline[1],"\ttfr\td,y\n")){
+      remove_asm();
+      return 1;
+    }
+    if(!strcmp(asmline[0],"\tstd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+      remove_asm();
+      return 1;
+    }
+    if(!strcmp(asmline[0],"\tldd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+      remove_asm();
+      return 1;
+    }
+
+    if(sscanf(asmline[0]," leas %d,s",&v1)==1&&sscanf(asmline[1]," leas %d,s",&v2)==1){
+      sprintf(asmline[1],"\tleas\t%ld,s\n",SGN16(v1+v2));
+      remove_asm();
+      return 1;
+    }
+
+    if(CPU!=6812&&sscanf(asmline[0]," tfr %c,%c",buf1,buf2)==2){
+      if((*buf1=='x'||*buf1=='y'||*buf1=='u'||*buf1=='s')&&
+	 (*buf2=='x'||*buf2=='y'||*buf2=='u'||*buf2=='s')){
+	sprintf(asmline[0],"\tlea%c\t,%c\n",*buf2,*buf1);
+      }
+    }
+    if(CPU==6812&&(!strcmp(asmline[1],"\tdex\n")||!strcmp(asmline[1],"\tdey\n")||!strcmp(asmline[1],"\tsubd\t#1\n"))&&
+       (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+      char r=asmline[1][3];
+      if(r=='b') r='d';
+      strcpy(asmline[1],"\td");
+      strncpy(asmline[1]+2,asmline[0]+1,4);
+      asmline[1][6]=r;asmline[1][7]=',';
+      strcpy(asmline[1]+8,asmline[0]+5);
+      remove_asm();
+      return 1;
+    }
+    if(CPU==6812&&(!strcmp(asmline[1],"\tinx\n")||!strcmp(asmline[1],"\tiny\n")||!strcmp(asmline[1],"\taddd\t#1\n"))&&
+       (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+      char r=asmline[1][3];
+      strcpy(asmline[1],"\ti");
+      strncpy(asmline[1]+2,asmline[0]+1,4);
+      asmline[1][6]=r;asmline[1][7]=',';
+      strcpy(asmline[1]+8,asmline[0]+5);
+      remove_asm();
+      return 1;
+    }
+  }
+  if(entries>=3){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[2]=emit_buffer[i];
+    if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(!strcmp(asmline[1],"\ttstb\n")||!strcmp(asmline[1],"\tcpb\t#0\n")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'b')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   (!strcmp(op2,"subd")||!strcmp(op2,"cpd"))&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'d')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,(CPU==6812)?"cpx":"cmpx")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'x')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,(CPU==6812)?"cpy":"cmpy")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'y')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(v->tattr&DPAGE){
+    emit(f,"\t.section\t.dpage\n");
+  }else{
+    if(!v->vattr) return 0;
+    sec=strstr(v->vattr,"section(");
+    if(!sec) return 0;
+    sec+=strlen("section(");
+    emit(f,"\t.section\t");
+    while(*sec&&*sec!=')') emit_char(f,*sec++);
+    emit(f,"\n");
+  }
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static struct fpconstlist {
+    struct fpconstlist *next;
+    int label,typ;
+    union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+	eval_const(&p->val,t);
+	if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+	if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+	if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+int pointer_type(struct Typ *p)
+{
+  if(!p) ierror(0);
+  while((p->flags&NQ)==ARRAY) p=p->next;
+  if((p->flags&NQ)==FUNKT) return NPOINTER; /*FIXME: banked*/
+  if(p->attr){
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+  }
+  /*FIXME*/
+  return NPOINTER;
+}
+static long voff(struct obj *p)
+{
+  if(zm2l(p->v->offset)<0) 
+    return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+1;
+  else
+    return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/*  Gibt Objekt auf Bildschirm aus                      */
+{
+  if(p->am){
+    int flags=p->am->flags;
+    if(flags==ACC_IND){
+      emit(f,"%s,%s",regnames[acc],regnames[p->am->base]);
+      return;
+    }
+    if(flags==KONSTINC){
+      eval_const(&p->val,p->am->base);
+      if(ISFLOAT(p->am->base)){
+	unsigned char *m=(unsigned char *)&p->val.vfloat;
+	if(zm2l(p->am->offset)==2)
+	  emit(f,"#0x%02x%02x",m[2],m[3]);
+	else
+	  emit(f,"#0x%02x%02x",m[0],m[1]);
+	return;
+      }else if((t&NQ)==CHAR){
+	vumax=zumrshift(vumax,24-8*p->am->offset);
+	vumax=zumand(vumax,ul2zum(255UL));
+      }else{
+	vumax=zumrshift(vumax,16-8*p->am->offset);
+	vumax=zumand(vumax,ul2zum(0xFFFFUL));
+      }
+      emit(f,"#%lu",zum2ul(vumax));
+      return;
+    }
+    if(flags<POST_INC||flags>PRE_DEC||CPU==6812)
+      emit(f,"%ld",p->am->offset&0xffff);
+    if(p->am->v){
+      if(p->am->v->storage_class==STATIC)
+	emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
+      else
+	emit(f,"+(%s%s)",idprefix,p->am->v->identifier);
+    }
+    emit(f,",");
+    if(flags==PRE_INC){
+      emit(f,"+");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+    }else if(flags==PRE_DEC){
+      emit(f,"-");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+    }
+    emit(f,"%s",regnames[p->am->base]);
+    if(flags==POST_INC){
+      emit(f,"+");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+    }else if(flags==POST_DEC){
+      emit(f,"-");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+    }
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&VARADR) emit(f,"#");
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"0,");
+  if((p->flags&(DREFOBJ|REG))==DREFOBJ) emit(f,"[");
+  if((p->flags&(VAR|REG))==VAR){
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      emit(f,"%ld,%s",voff(p),regnames[sp]);
+    }else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){
+	emit(f,"%ld",zm2l(zi2zm(zm2zi(p->val.vmax))));
+	emit(f,"+");
+      }
+      if(p->v->storage_class==STATIC){
+	emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+	emit(f,"(%s%s)",idprefix,p->v->identifier);
+      }
+      if(pcrel&&!(p->flags&VARADR)&&ISFUNC(p->v->vtyp->flags))
+	emit(f,",pc");
+      if(drel&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)){
+	if(CPU==6812) ierror(0);
+	emit(f,",%s",regnames[iu]);
+      }
+    }
+  }
+  if(p->flags&REG){
+    if(ISACC(p->reg)&&(t&NQ)==CHAR)
+      emit(f,"b");
+    else
+      emit(f,"%s",regnames[p->reg]);
+  }
+  if(p->flags&KONST){
+    if(ISFLOAT(t)){
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    }else{
+      emit(f,"#");emitval(f,&p->val,t&NU);
+    }
+  }
+  if((p->flags&(DREFOBJ|REG))==DREFOBJ){
+    if(p->v->storage_class==EXTERN||p->v->storage_class==STATIC){
+      if(is_const(p->v->vtyp)){
+	if(!pcrel&&CPU==6812) emit(f,",pc");
+      }else{
+	if(!drel&&CPU==6812) emit(f,",pc");
+      }
+    }
+    emit(f,"]");
+  }
+}
+
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+  /*FIXME: needs a location list and correct register translation */
+  struct obj o;
+  o.flags=REG;
+  o.reg=sp;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+  /*FIXME: always returns D as accumulator, even if byte size */
+  static int dwarf_regs[MAXR+1]={-1,3,7,8,15};
+  return dwarf_regs[r];
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+  /*FIXME*/
+  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+  if(!zmleq(l2zm(0L),v->offset))
+    return l2zm((long)(loff-zm2l(v->offset)));
+  else
+    return v->offset;
+} 
+
+/* test operand for mov instruction */
+static int mov_op(struct obj *o)
+{
+  long off;
+  if(CPU!=6812) return 0;
+  if(o->am){
+    int f=o->am->flags;
+    if(f==POST_INC||f==PRE_INC||f==POST_DEC||f==PRE_DEC||f==ACC_IND)
+      return 1;
+    if(f==IMM_IND){
+      if(o->am->v) return 0;
+      off=o->am->offset;
+      if(off>=-16&&off<=15)
+	return 1;
+      else
+	return 0;
+    }
+    ierror(0);
+  }
+  if(o->flags&(KONST|VARADR)) return 1;
+  if((o->flags&(REG|DREFOBJ))==(REG|DREFOBJ)) return 1;
+  if((o->flags&(VAR|REG|DREFOBJ))==VAR){
+    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN)
+      return 1;
+    off=voff(o);
+    if(off>=-16&&off<=15)
+      return 1;
+    else
+      return 0;
+  }
+  return 0;
+}
+
+/* add an offset to an object describing a memory address */
+static void inc_addr(struct obj *o,long val,int t)
+{
+  if(o->am){
+    int f=o->am->flags;
+    if(f==IMM_IND||f==KONSTINC)
+      o->am->offset+=val;
+    else if(f==POST_INC||f==POST_DEC||f==PRE_INC||f==PRE_DEC){
+      struct AddressingMode *old=o->am;
+      o->am=mymalloc(sizeof(*o->am));
+      o->am->flags=IMM_IND;
+      o->am->base=old->base;
+      o->am->v=0;
+      if(f==POST_DEC) o->am->offset=old->offset-val;
+      else if(f==POST_INC) o->am->offset=-old->offset+val;
+      else if(f==PRE_DEC) o->am->offset=val;
+      else o->am->offset=-val;
+    }else
+      ierror(0);
+  }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    struct AddressingMode *am;
+    o->am=am=mymalloc(sizeof(*am));
+    am->flags=IMM_IND;
+    if(!o->reg) ierror(0);
+    am->base=o->reg;
+    am->offset=zm2l(val);
+    am->v=0;
+  }else if((o->flags&(DREFOBJ|KONST))==KONST){
+    struct AddressingMode *am;
+    if(o->am) ierror(0);
+    o->am=am=mymalloc(sizeof(*am));
+    am->flags=KONSTINC;
+    am->offset=zm2l(val);
+    am->base=t;
+  }else{
+    o->val.vmax=zmadd(o->val.vmax,val);
+  }
+}
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+  if(l-stackoffset>stack)
+    stack=l-stackoffset;
+}
+static void push(long l)
+{
+  stackoffset-=l;
+  if(stackoffset<maxpushed) maxpushed=stackoffset;
+  if(-maxpushed>stack) stack=-maxpushed;
+}
+static void pop(long l)
+{
+  stackoffset+=l;
+}
+static void gen_pop(FILE *f,long l)
+{
+  if(l==0) return;
+  if(l==1&&CPU==6812){
+    emit(f,"\tins\n");
+#if 0 /* might clobber return register */
+  }else if(l==2&&!regs[acc]){
+    emit(f,SPULLD);
+    BSET(regs_modified,acc);
+  }else if(l==2&&!regs[ix]){
+    emit(f,SPULL("x"));
+    BSET(regs_modified,ix);
+  }else if(l==2&&!regs[iy]){
+    emit(f,SPULL("y"));
+    BSET(regs_modified,iy);
+#endif
+  }else{
+    emit(f,"\tleas\t%u,%s\n",SGN16(l),regnames[sp]);
+  }
+  pop(l);
+}
+static void pr(FILE *f,struct IC *p)
+{
+  int r;
+  if(pushed_acc){
+    emit(f,SPULLD);
+    pop(2);
+    pushed_acc=0;
+  }
+  for(r=MAXR;r>=1;r--){
+    if(regs[r]&8){
+      emit(f,"\t%s%s\n",CPU==6812?"pul":"puls\t",regnames[r]);
+      pop(2);
+    }
+    regs[r]&=~12;
+  }
+}
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionskopf                       */
+{
+  int i;
+  emit(f,"# offset=%ld\n",offset);
+  have_frame=0;stack_valid=1;stack=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else{
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  }
+  roff=0;
+  for(i=MAXR;i>0;i--){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      have_frame=1;
+      loff+=2;
+      roff+=2;
+      if(i==iy) emit(f,SPUSH("y"));
+      else if(i==iu){
+	if(CPU!=6812&&regused[iy]){
+	  emit(f,"\tpshs\tu,y\n");
+	  loff+=2;roff+=2;i=iy;
+	}else
+	  emit(f,SPUSH("u"));
+      }else
+	ierror(0);
+    }
+  }
+  if(stack_check){
+    stackchecklabel=++label;
+    emit(f,"\tldy\t#%s%d\n",labprefix,stackchecklabel);
+    /* FIXME: banked */
+    emit(f,"\t%s\t%s__stack_check\n",jsrinst,idprefix);
+  }
+  if(offset){
+    if(CPU==6812&&offset==1)
+      emit(f,SPUSH("b"));
+    else if(CPU==6812&&offset==2)
+      emit(f,SPUSHD);
+    else
+      emit(f,"\tleas\t%ld,%s\n",SGN16(-offset),regnames[sp]);
+    have_frame=1;
+  }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionsende                       */
+{
+  int i;
+  offset-=roff;
+  if(offset){
+    if(offset==1&&CPU==6812)
+      emit(f,"\tins\n");
+    else if(offset==2&&CPU==6812&&!zmeqto(szof(v->vtyp->next),l2zm(4L)))
+      emit(f,SPULL("x"));
+    else if(offset==2&&CPU==6812&&regused[iy])
+      emit(f,SPULL("y"));
+    else
+      emit(f,"\tleas\t%ld,%s\n",SGN16(offset),regnames[sp]);
+  }
+  for(i=1;i<=MAXR;i++){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      have_frame=1;
+      if(i==iy){
+	if(CPU!=6812&&regused[iu]&&!regscratch[iu]&&!regsa[iu]){
+	  emit(f,"\tpuls\tu,y\n");
+	  i=iu;
+	}else
+	  emit(f,SPULL("y"));
+      }else if(i==iu) emit(f,SPULL("u"));
+      else
+	ierror(0);
+    }
+  }
+  if(ret) emit(f,"\t%s\n",ret);
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+    emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+  }else{
+    emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+  }
+  if(stack_check)
+    emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stackchecklabel,offset-maxpushed);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=l2zm(stack+offset);
+    emit(f,"# stacksize=%ld\n",stack+offset);
+    emit(f,"\t.equ\t%s__stack_%s,%ld\n",idprefix,v->identifier,stack+offset);
+  }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/*FIXME*/
+static void clear_ext_ic(struct ext_ic *p)
+{
+  p->flags=0;
+  p->r=0;
+  p->offset=0;
+}
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+static void peephole(struct IC *p)
+{
+  int c,c2,r,t;struct IC *p2;
+  struct AddressingMode *am;
+  zmax incmin,incmax;
+  if(CPU==6812){
+    incmin=l2zm(-8L);
+    incmax=l2zm(8L);
+  }else{
+    incmin=l2zm(-2L);
+    incmax=l2zm(2L);
+  }
+  frame_used=0;
+  for(;p;p=p->next){
+    c=p->code;
+    if(!frame_used){
+      if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+      if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+      if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+    }
+    /* letztes Label merken */
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+#if 0
+    /* and x,#const;bne/beq, FIXME */
+    if(c==AND&&isconst(q2)&&isreg(z)){
+      long bit;
+      eval_const(&p->q2.val,p->typf);
+      if(bit=pof2(vumax)){
+	struct IC *cmp=0;int fr=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==TEST){
+	    if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+	      cmp=p2;continue;
+	    }
+	  }
+	  if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf);
+	    if(ISNULL()){
+	      cmp=p2;continue;
+	    }
+	    break;
+	  }
+	  if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
+	  if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
+	    p->ext.flags=EXT_IC_BTST;
+	    p2->ext.flags=EXT_IC_BTST;
+	    p2->ext.offset=bit-1;
+	    cmp->code=NOP;
+	    cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
+	    break;
+	  }
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==p->z.reg)||((p2->q2.flags&REG)&&p2->q2.reg==p->z.reg)||((p2->z.flags&REG)&&p2->z.reg==p->z.reg)) break;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	}
+      }
+    }
+#endif
+    /* Try d,idx */
+    if(c==ADDI2P&&ISRACC(q2)&&ISRIDX(z)&&(ISRIDX(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||!ISCHWORD(q1typ(p2))) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	    break; /*TODO: check what is possible */
+            if(o||!ISCHWORD(q2typ(p2))) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	    break; /*TODO: check what is possible */
+            if(o||!ISCHWORD(ztyp(p2))) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=ACC_IND;
+              am->base=base;
+	      if(idx!=acc) ierror(0);
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+	  continue;
+	}
+	/* better no instructions between, accu used too much */
+	if(c2!=FREEREG&&c2!=ALLOCREG&&!o) break;
+      }
+    }
+    /* POST_INC/DEC in q1 */
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q1.reg; t=q1typ(p);
+      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q1.am=mymalloc(sizeof(*am));
+	      p->q1.am->base=r;
+	      p->q1.am->v=0;
+	      if(zmleq(vmax,l2zm(0L))){
+		p->q1.am->flags=POST_DEC;
+		p->q1.am->offset=-zm2l(vmax);
+	      }else{
+		p->q1.am->flags=POST_INC;
+		p->q1.am->offset=zm2l(vmax);
+	      }
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* POST_INC/DEC in q2 */
+    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q2.reg; t=q2typ(p);
+      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q2.am=mymalloc(sizeof(*am));
+	      p->q2.am->base=r;
+	      p->q2.am->v=0;
+	      if(zmleq(vmax,l2zm(0L))){
+		p->q2.am->flags=POST_DEC;
+		p->q2.am->offset=-zm2l(vmax);
+	      }else{
+		p->q2.am->flags=POST_INC;
+		p->q2.am->offset=zm2l(vmax);
+	      }
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* POST_INC/DEC in z */
+    if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->z.reg; t=ztyp(p);
+      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->z.am=mymalloc(sizeof(*am));
+	      p->z.am->base=r;
+	      p->z.am->v=0;
+	      if(zmleq(vmax,l2zm(0L))){
+		p->z.am->flags=POST_DEC;
+		p->z.am->offset=-zm2l(vmax);
+	      }else{
+		p->z.am->flags=POST_INC;
+		p->z.am->offset=zm2l(vmax);
+	      }
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+
+    /* R,#c */
+    if((c==ADDI2P||c==SUBIFP)&&ISHWORD(p->typf)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(!drel&&(p->q1.flags&VARADR)))){
+      int base;zmax of;struct obj *o;struct Var *v;
+      if(p->q1.flags&VARADR){
+	v=p->q1.v;
+	of=p->q1.val.vmax;
+	r=p->z.reg;
+	if(isreg(q2)&&ISIDX(p->q2.reg))
+	  base=p->q2.reg;
+	else
+	  base=r;
+      }else{
+	eval_const(&p->q2.val,p->typf);
+	if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+	v=0;
+	r=p->z.reg;
+	if(isreg(q1)&&ISIDX(p->q1.reg)) base=p->q1.reg; else base=r;
+      }
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+	c2=p2->code;
+	if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	    if(o||!ISHWORD(q1typ(p2))) break;
+	    o=&p2->q1;
+	  }
+	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	    if(o||!ISHWORD(q2typ(p2))) break;
+	    o=&p2->q2;
+	  }
+	  if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	    if(o||!ISHWORD(ztyp(p2))) break;
+	    o=&p2->z;
+	  }
+	}
+	if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	  int m;
+	  if(c2==FREEREG) 
+	    m=p2->q1.reg;
+	  else
+	    m=p2->z.reg;
+	  if(m==r){
+	    if(o){
+	      o->am=am=mymalloc(sizeof(*am));
+	      am->flags=IMM_IND;
+	      am->base=base;
+	      am->offset=zm2l(of);
+	      am->v=v;
+	      if(!v){
+		if(isreg(q1)&&ISIDX(p->q1.reg)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }else{
+		if(isreg(q2)&&ISIDX(p->q2.reg)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
+		  p->q2.val.vmax=sizetab[p->typf&NQ];
+		}
+	      }
+	    }
+	    break;
+	  }
+	  if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
+	  continue;
+	}
+      }
+    }      
+  }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/*  Initializes an addressing-mode structure and returns a pointer to   */
+/*  that object. Will not survive a second call!                        */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  am.v=v;
+  return &obj;
+}
+
+static void get_acc(FILE *f,struct IC *p)
+{
+  if(regs[acc]){
+    if(p->q2.am)
+      if(p->q2.am->flags==ACC_IND) ierror(0);
+    else
+      if((p->q2.flags&REG)&&ISACC(p->q2.reg)) ierror(0);
+    if(p->z.am)
+      if(p->z.am->flags==ACC_IND) ierror(0);
+    else
+      if((p->z.flags&REG)&&ISACC(p->z.reg)) ierror(0);
+    if(regs[acc]){
+      emit(f,SPUSHD);
+      push(2);
+      pushed_acc=1;
+    }
+  }
+}
+static int get_idx(FILE *f,IC *p)
+{
+  int r;
+  for(r=1;r<=MAXR;r++){
+    if(ISIDX(r)){
+      if(!regs[r]){
+	regs[r]|=4;
+	return r;
+      }
+    }
+  }
+  for(r=1;r<=MAXR;r++){
+    if(ISIDX(r)){
+      if((!(p->q1.flags&REG)||p->q1.reg!=r)&&
+	 (!(p->q2.flags&REG)||p->q2.reg!=r)&&
+	 (!(p->z.flags&REG)||p->z.reg!=r)){
+	emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[r]);
+	regs[r]|=8;
+	push(2);
+	return r;
+      }
+    }
+  }
+  ierror(0);
+}
+static int get_reg(FILE *f,struct IC *p,int t)
+{
+  int reg;
+  if(!regs[acc])
+    reg=acc;
+  else if(ISHWORD(t)&&!regs[ix])
+    reg=ix;
+#if 0
+  else if(ISHWORD(t)&&!regs[iy])
+    reg=iy;
+#endif
+  else{
+    get_acc(f,p);
+    reg=acc;
+  }
+  BSET(regs_modified,reg);
+  return reg;
+}
+static void load_reg(FILE *f,int r,struct obj *o,int t)
+{
+  if(!o->am){
+    if((o->flags&(REG|DREFOBJ))==REG){
+      if(o->reg==r) return;
+      emit(f,"\ttfr\t%s,%s\n",regnames[o->reg],regnames[r]);
+      return;
+    }
+    if(r==acc&&(o->flags&(KONST|DREFOBJ))==KONST){
+      eval_const(&o->val,t);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+	if(CPU!=6812&&!optsize)
+	  emit(f,"\tldd\t#0\n");
+	else
+	  emit(f,"\tclra\n\tclrb\n"); 
+	cc=o;cc_t=t;
+	return;
+      }
+    }
+  }
+  if(o->flags&VARADR){
+    char *base=0;
+    if(pcrel&&ISFUNC(o->v->vtyp->flags))
+      base="pc";
+    if(drel&&!ISFUNC(o->v->vtyp->flags))
+      base=regnames[iu];
+    if(base&&!skip_rel){
+      if(ISACC(r))
+	emit(f,"\ttfr\t%s,d\n",base);
+      if(ISIDX(r))
+	emit(f,"\tlea%s\t",regnames[r]);
+      else{
+	if(*base=='p') emit(f,"%s%d:\n",labprefix,++label);
+	emit(f,"\taddd\t#");
+      }
+      emitzm(f,o->val.vmax);
+      emit(f,"+");
+      if(o->v->storage_class==EXTERN)
+	emit(f,"%s%s",idprefix,o->v->identifier);
+      else
+	emit(f,"%s%ld",labprefix,zm2l(o->v->offset));
+      if(ISIDX(r))
+	emit(f,",%s",base);
+      else if(*base=='p')
+	emit(f,"-%s%d",labprefix,label);
+      emit(f,"\n");
+      cc=o;cc_t=t;
+      return;
+    }
+    skip_rel=0;
+  }
+  emit(f,"\tld%s\t",(r==acc&&(t&NQ)==CHAR)?(CPU==6812?"ab":"b"):regnames[r]);
+  emit_obj(f,o,t);emit(f,"\n");
+  cc=o;cc_t=t;
+}
+static void store_reg(FILE *f,int r,struct obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==r) return;
+    emit(f,"\ttfr\t%s,%s\n",regnames[r],regnames[o->reg]);
+  }else{
+    if(r==acc&&(t&NQ)==CHAR)
+      emit(f,"\tst%s\t",(CPU==6812)?"ab":"b");
+    else
+      emit(f,"\tst%s\t",regnames[r]);
+    emit_obj(f,o,t);emit(f,"\n");
+    cc=o;cc_t=t;
+  }
+}
+static void load_addr(FILE *f,int r,struct obj *o)
+{
+  if(o->am){
+    if(o->am->flags==IMM_IND){
+      if(o->am->base==r&&o->am->offset==0&&!o->am->v) return;
+      if(ISIDX(r)){
+	emit(f,"\tlea%s\t",regnames[r]);
+	emit_obj(f,o,0);
+	emit(f,"\n");
+      }else{
+	if(r!=acc) ierror(0);
+	emit(f,"\ttfr\t%s,%s\n",regnames[o->am->base],regnames[r]);
+	emit(f,"\taddd\t#%ld\n",o->am->offset);
+	if(o->am->v){
+	  if(o->am->v->storage_class==STATIC)
+	    emit(f,"+%s%ld",labprefix,zm2l(o->am->v->offset));
+	  else
+	    emit(f,"+%s%s",idprefix,o->am->v->identifier);
+	}
+	emit(f,"\n");
+	cc=0;
+      }
+      return;
+    }
+    ierror(0);
+  }
+  if(o->flags&DREFOBJ){
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,o->dtyp);
+    o->flags|=DREFOBJ;
+    return;
+  }
+  if((o->flags&(VAR|VARADR))==VAR){
+    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
+      o->flags|=VARADR;
+      load_reg(f,r,o,POINTER_TYPE(o->v->vtyp));
+      o->flags&=~VARADR;
+      return;
+    }
+    if(voff(o)==0){
+      emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+      return;
+    }
+    if(ISIDX(r)){
+      emit(f,"\tlea%s\t",regnames[r]);
+      emit_obj(f,o,0);
+      emit(f,"\n");
+    }else{
+      if(r!=acc) ierror(0);
+      emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+      emit(f,"\taddd\t#%ld\n",voff(o));
+      cc=0;
+    }
+    return;
+  }
+  ierror(0);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+  int c;
+  while(1){
+    p=p->next;
+    if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+    if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+    if((p->q1.flags&REG)&&p->q1.reg==r) return 0;
+    if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
+    if((p->z.flags&REG)&&p->z.reg==r) return 0;
+  }
+}
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+
+  CPU=CPUOPT;
+
+  if(g_flags[13]&USEDFLAG){
+    msizetab[DOUBLE]=msizetab[LDOUBLE]=8;
+    dct[DOUBLE]=dct[LDOUBLE]=".8byte";
+  }
+  
+
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(1L);
+  char_bit=l2zm(8L);
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i=1;i<=iu;i++){
+    regsize[i]=l2zm(2L);regtype[i]=&ityp;
+  }	
+  regsize[dx]=l2zm(4L);regtype[i]=&ltyp;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=t_min[SHORT];
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=t_max[SHORT];
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=tu_max[SHORT];
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+  if(g_flags[9]&USEDFLAG) drel=1;
+  if(g_flags[10]&USEDFLAG) MINADDI2P=SHORT;
+  if(g_flags[11]&USEDFLAG) nodx=1;
+  if(g_flags[12]&USEDFLAG) nou=1;
+
+
+  if(CPU==6812) switchsubs=1;
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  regsa[sp]=REGSA_NEVER;
+  regscratch[sp]=0;
+
+  if(CPU==6812||drel||nou){
+    regsa[iu]=REGSA_NEVER;
+    regscratch[iu]=0;
+  }
+
+  if(CPU!=6812){
+    regnames[sp]="s";
+    logicals[0]="or";
+  }
+
+  if(!(g_flags[6]&USEDFLAG)){
+    extern int static_cse,dref_cse;
+    static_cse=0;
+    dref_cse=0;
+  }
+
+  if(!(g_flags[7]&USEDFLAG)){
+    regsa[acc]=REGSA_TEMPS;
+    regsa[dx]=REGSA_TEMPS;
+  }
+
+  if(g_flags[8]&USEDFLAG){
+    pcrel=1;
+    jsrinst="lbsr";
+    jmpinst="lbra";
+    rodataname="\t.data\n";
+  }
+
+  if(CPU==6809)
+    marray[1]="__6809__";
+  if(CPU==6309)
+    marray[1]="__6309__";
+  if(CPU==9)
+    marray[1]="__TURBO9__";
+  target_macros=marray;
+
+
+  if(CPU==9||CPU==6812){
+    declare_builtin("__mulint16",INT,INT,acc,INT,iy,1,mystrdup("\temul"));
+    declare_builtin("__divint16",INT,INT,acc,INT,ix,1,mystrdup("\tidivs\n\ttfr\tx,d"));
+    declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,acc,UNSIGNED|INT,ix,1,mystrdup("\tidiv\n\ttfr\tx,d"));
+    declare_builtin("__modint16",INT,INT,acc,INT,ix,1,mystrdup("\tidivs"));
+    declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,acc,UNSIGNED|INT,ix,1,mystrdup("\tidiv"));
+  }else{
+    declare_builtin("__mulint16",INT,INT,acc,INT,0,1,0);
+    declare_builtin("__divint16",INT,INT,ix,INT,acc,1,0);
+    declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+    declare_builtin("__modint16",INT,INT,ix,INT,acc,1,0);
+    declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+  }
+
+  /* TODO: set argument registers */
+  declare_builtin("__mulint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__addint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__subint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__andint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__orint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__eorint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__negint32",LONG,LONG,0,0,0,1,0);
+  declare_builtin("__lslint32",LONG,LONG,0,INT,0,1,0);
+
+  declare_builtin("__divint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+  declare_builtin("__modint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+  declare_builtin("__lsrsint32",LONG,LONG,0,INT,0,1,0);
+  declare_builtin("__lsruint32",UNSIGNED|LONG,UNSIGNED|LONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint32",INT,LONG,0,LONG,0,1,0);
+  declare_builtin("__cmpuint32",INT,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+  declare_builtin("__sint32toflt32",FLOAT,LONG,0,0,0,1,0);
+  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
+  declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
+  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint32",LONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__sint16toflt32",FLOAT,INT,0,0,0,1,0);
+  declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,0,0,0,1,0);
+  declare_builtin("__sint16toflt64",DOUBLE,INT,0,0,0,1,0);
+  declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,0,0,0,1,0);
+  declare_builtin("__flt32tosint16",INT,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint16",INT,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__sint8toflt32",FLOAT,CHAR,0,0,0,1,0);
+  declare_builtin("__uint8toflt32",FLOAT,UNSIGNED|CHAR,0,0,0,1,0);
+  declare_builtin("__sint8toflt64",DOUBLE,CHAR,0,0,0,1,0);
+  declare_builtin("__uint8toflt64",DOUBLE,UNSIGNED|CHAR,0,0,0,1,0);
+  declare_builtin("__flt32tosint8",CHAR,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint8",UNSIGNED|CHAR,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint8",CHAR,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint8",UNSIGNED|CHAR,DOUBLE,0,0,0,1,0);
+
+
+
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64" ,LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,0,0,0,1,0);
+  declare_builtin("__cmpflt32",CHAR,FLOAT,0,FLOAT,0,1,0);
+
+  declare_builtin("__addflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__subflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__mulflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__divflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__negflt32 ",DOUBLE,DOUBLE,0,0,0,1,0);
+  declare_builtin("__cmpflt32 ",CHAR,DOUBLE,0,DOUBLE,0,1,0);
+
+  declare_builtin("__addflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__subflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__mulflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__divflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__negflt64 ",DOUBLE,DOUBLE,0,0,0,1,0);
+  declare_builtin("__cmpflt64 ",CHAR,DOUBLE,0,DOUBLE,0,1,0);
+
+
+  return 1;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+  int f=t->flags&NQ;
+  if(ISSCALAR(f)){
+    if(ISHWORD(f)||f==CHAR)
+      return acc;
+    else if(ISLWORD(f))
+      return dx;
+  }
+  return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(!ISSCALAR(t)) return 0;
+  if(r==dx){
+    if(ISLWORD(t)&&(optflags&2)&&!nodx) return 1;
+    return 0;
+  }
+  if(mode==-1){
+    if(ISHWORD(t)) return 1;
+    if((t&NQ)==CHAR&&ISACC(r)) return 1;
+  }else{
+    if(ISIDX(r)){
+      if(ISPOINTER(t)&&ISHWORD(t))
+	return 1;
+    }
+    if(ISACC(r)){
+      if((t&NQ)==CHAR)
+	return 1;
+      if(ISINT(t)&&ISHWORD(t))
+	return 1;
+    }
+  }
+  return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r==dx){
+    p->r1=acc;
+    p->r2=ix;
+    return 1;
+  }
+  return 0;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  /*FIXME*/
+  int c=p->code;
+  if(r==dx){
+    if(c==GETRETURN||c==SETRETURN||c==PUSH||c==ASSIGN) return 8;
+    return INT_MIN;
+  }
+  if(o->flags&VKONST){
+    struct obj *co=&o->v->cobj;
+    if(o->flags&DREFOBJ)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
+      return 2;
+    }
+    return 0;
+  }
+  if((o->flags&DREFOBJ)){
+    if(!ISIDX(r)) return INT_MIN;
+    if(p->q2.flags&&o!=&p->z)
+      return 6;
+    else
+      return 6;
+  }else if(c==GETRETURN&&p->q1.reg==r){
+    return 4;
+  }else if(c==SETRETURN&&p->z.reg==r){
+    return 4;
+  }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&&regok(r,CHAR,0)){
+    return 3;
+  }
+  if(o==&p->z&&r==acc){
+    if(c==SUB||c==SUBIFP||c==SUBPFP||c==AND||c==OR||c==XOR)
+      return 6;
+    if((c==ADD||c==ADDI2P)&&!(p->q1.flags&(KONST|VKONST))&&!(p->q2.flags&(KONST|VKONST)))
+      return 4;
+    if(c==MULT) return 5;
+    if(c==ASSIGN&&(p->q1.flags&KONST)){
+      eval_const(&p->q1.val,p->typf);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL)))
+	return 3;
+    }
+  }
+#if 1
+  if((o==&p->q2/*||o==&p->z*/)&&!(o->flags&DREFOBJ)&&!ISACC(o->reg)&&(c==MULT||c==DIV||c==MOD))
+    return INT_MIN;
+#endif
+  if(c==COMPARE||c==TEST){
+    if(r==ix) return 3;
+    if(r==iy) return 2;
+    if(r==iu) return 1;
+  }
+  return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG){
+      sprintf(fname,"__cmp%sint32",(t&UNSIGNED)?"u":"s");
+      ret=fname;
+    }
+    if(ISFLOAT(t)){
+      return (t==FLOAT)?"__cmpflt32":"__cmpflt32 ";
+      ret=fname;
+    }
+
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(ISFLOAT(t)&&ISFLOAT(t2)) return 0;
+#if 0
+      /* currently support only 32bit flt */
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+#endif
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%ld",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)){
+        sprintf(fname,"__flt%ldto%cint%ld",zm2l(sizetab[t2&NQ])*8,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+	if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%suint64",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+	}else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%suint32",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LONG){
+          sprintf(fname,"__%sint32",ename[c]);
+          ret=fname;
+        }else{
+	  sprintf(fname,"__%s%s%s%ld%s",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8,(t&NQ)>=DOUBLE?" ":"");
+          ret=fname;
+	}
+      }
+    }
+    if((c==MULT/*&&(CPU!=6812||(t&NQ)==LONG)*/)||c==DIV||c==MOD){
+      sprintf(fname,"__%s%s%s%ld%s",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8,(t&NQ)>=DOUBLE?" ":"");
+      ret=fname;
+    }
+  }
+
+  return ret;
+}
+
+
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+{
+  int op=o&NQ,tp=t&NQ;
+  if(op==tp) return 0;
+  if(ISFLOAT(op)){
+    if(ISFLOAT(tp)) return 0;
+    return 1;
+  }
+  if(ISFLOAT(tp)) return 1;
+  if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+  if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+  if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;  
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  /* nothing to do */
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(v->tattr&DPAGE)
+      emit(f,"\t.direct\t%s%ld\n",labprefix,zm2l(v->offset));
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){
+	emit(f,dataname);if(f) section=DATA;
+      }
+      if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=RODATA){
+	emit(f,rodataname);if(f) section=RODATA;
+      }
+      if(!v->clist&&section!=BSS){
+	emit(f,bssname);if(f) section=BSS;
+      }
+    }
+    emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+    if(v->clist||section==SPECIAL)
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1; 
+  }
+  if(v->storage_class==EXTERN){
+    if(v->flags&(DEFINED|TENTATIVE)){
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+      if(v->tattr&DPAGE)
+	emit(f,"\t.direct\t%s%s\n",idprefix,v->identifier);
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){
+	  emit(f,dataname);if(f) section=DATA;
+	}
+	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=RODATA){
+	  emit(f,rodataname);if(f) section=RODATA;
+	}
+	if(!v->clist&&section!=BSS){
+	  emit(f,bssname);if(f) section=BSS;
+	}
+      }
+      emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+      if(v->clist||section==SPECIAL)
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      else
+        emit(f,"\t.global\t%s%s\n\t.lcomm\t%s%s,",idprefix,v->identifier,idprefix,v->identifier);
+      newobj=1;   
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\t%s\t",dct[t&NQ]);
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      if(zm2l(sizetab[t&NQ])==8){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+    }else{
+      emitval(f,&p->val,(t&NU)|UNSIGNED);
+    }
+  }else{
+    int m=p->tree->o.flags,md=drel,mp=pcrel;
+    p->tree->o.flags&=~VARADR;
+    drel=0;pcrel=0;
+    emit_obj(f,&p->tree->o,t&NU);
+    p->tree->o.flags=m;
+    drel=md;pcrel=mp;
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+static void preload(FILE *f,IC *p)
+{
+  int t,r;
+
+  if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+     ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+    emit(f,"; volatile barrier\n");
+
+  t=q1typ(p);
+  if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+    r=get_idx(f,p);
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,r,&p->q1,INT);
+    p->q1.flags|=(REG|DREFOBJ);
+    p->q1.reg=r;
+  }
+  t=q2typ(p);
+  if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+    r=get_idx(f,p);
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,r,&p->q2,INT);
+    p->q2.flags|=(REG|DREFOBJ);
+    p->q2.reg=r;
+  }else if(isreg(z)&&(((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg)||(p->q2.am&&p->q2.am->base==p->z.reg))){
+    r=get_idx(f,p);
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,r,&p->q2,INT);
+    p->q2.flags|=(REG|DREFOBJ);
+    p->q2.reg=r;
+  }
+  t=ztyp(p);
+  if(!p->z.am&&(p->z.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+    r=get_idx(f,p);
+    p->z .flags&=~DREFOBJ;
+    load_reg(f,r,&p->z ,INT);
+    p->z .flags|=(REG|DREFOBJ);
+    p->z .reg=r;
+  }
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+void gen_code(FILE *f,struct IC *fp,struct Var *v,zmax offset)
+{
+  int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
+  struct obj *bit_obj;char *bit_reg;
+  static int idone;
+  struct obj o;
+  IC *p,*p2;
+  if(v->tattr&INTERRUPT)
+    ret="rti";
+  else
+    ret="rts"; /*FIXME: banked */
+  if(DEBUG&1) printf("gen_code()\n");
+  for(p=fp;p;p=p->next) clear_ext_ic(&p->ext);
+  emit(f,"#off1=%ld\n",zm2l(offset));
+  if(!(g_flags[5]&USEDFLAG)){
+    peephole(fp);
+    if(!frame_used) offset=l2zm(0L);
+  }
+  for(c=1;c<=MAXR;c++) regs[c]=(regsa[c]==REGSA_NEVER)?1:0;
+  for(c=1;c<=MAXR;c++){
+    if((regsa[c]==REGSA_NEVER||regused[c])){
+      BSET(regs_modified,c);
+    }
+  }
+  t=0;
+  for(p=fp;p;p=p->next){
+    c=p->code;
+    if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1;}
+    if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0;}
+    if((c==LSHIFT||c==RSHIFT)&&(p->typf&NQ)>=LONG) regused[iy]=1;
+    if(c==PUSH&&(p->q1.flags&(REG|DREFOBJ))!=REG){
+      if(zmeqto(p->q2.val.vmax,Z1)){
+	if(regs[acc]) t=(t>2)?t:2;
+      }else if(zmeqto(p->q2.val.vmax,l2zm(2L))){
+	if(regs[acc]&&regs[ix]&&regs[iy]&&(CPU==6812||regs[iu])) t=(t>2)?t:2;
+      }else if(zmeqto(p->q2.val.vmax,l2zm(4L))){
+	if(regs[acc]) t=(t>2)?t:2;
+      }else{
+	/* TODO: finer check */
+	if(drel||!regsa[iu])
+	  t=(t>8)?t:8;
+	else
+	  t=(t>6)?t:6;
+      }
+    }
+  }
+  emit(f,"#toff=%d\n",t);
+  loff=zm2l(offset)+t;
+  function_top(f,v,loff);
+  stackoffset=notpopped=dontpop=maxpushed=0;
+  if(!v->fi) v->fi=new_fi();
+  v->fi->flags|=ALL_REGS;
+  for(p=fp;p;pr(f,p),p=p->next){
+    c=p->code;t=p->typf;
+    if(debug_info)
+      dwarf2_line_info(f,p); 
+    short_add=0;
+    if(c==NOP) continue;
+    if(c==ALLOCREG){
+      regs[p->q1.reg]=1;
+      if(p->q1.reg==dx) regs[acc]=regs[ix]=1;
+      continue;
+    }
+    if(c==FREEREG){
+      regs[p->q1.reg]=0;
+      if(p->q1.reg==dx) regs[acc]=regs[ix]=0;
+      continue;
+    }
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||(c>=BEQ&&c<=BRA)){
+	gen_pop(f,notpopped);
+	notpopped=0;
+      }
+    }
+    if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
+    if(c==BRA){
+      if(p->typf==exit_label&&!have_frame){
+	emit(f,"\t%s\n",ret);
+      }else{
+	if(t==exit_label) need_return=1;
+	emit(f,"\tbra\t%s%d\n",labprefix,t);
+      }
+      cc=0;continue;
+    }
+    if(c>=BEQ&&c<BRA){      
+      if((lastcomp&UNSIGNED)||ISPOINTER(lastcomp))
+        emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,t);
+      else
+        emit(f,"\tb%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,SHORT);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->q1.reg,&p->z,SHORT);
+      continue;
+    }
+    
+    /*if(ISFLOAT(t)) {pric2(stdout,p);ierror(0);}*/
+
+    if((t&NQ)==BIT){
+      ierror(0);
+    }
+
+    if(c==CONVERT&&ISLWORD(t)&&ISINT(t)&&ISLWORD(p->typf2)&&ISINT(p->typf2)){
+      p->code=c=ASSIGN;
+      p->q2.val.vmax=l2zm(4L);
+    }
+
+    if((p->q2.flags&REG)&&ISACC(p->q2.reg)&&(c==ADD||c==MULT||c==AND||c==OR||c==XOR)){
+      obj o=p->q1;
+      p->q1=p->q2;
+      p->q2=o;
+    }
+
+    if(c==TEST){
+      lastcomp=t;
+      p->code=c=COMPARE;
+      gval.vmax=l2zm(0L);
+      p->q2.flags=KONST;
+      eval_const(&gval,MAXINT);
+      insert_const(&p->q2.val,t);
+    }
+
+    if(c==SUBPFP){
+      p->code=c=SUB;
+      p->typf=t=(UNSIGNED|INT);
+    }
+
+
+
+    if((c==ASSIGN||c==PUSH)&&zmeqto(p->q2.val.vmax,l2zm(4L))&&ISINT(t))
+      p->typf=t=LONG;
+
+    preload(f,p);
+
+    if(c==ADDI2P||c==SUBIFP){
+      if((p->typf2&NQ)!=HPOINTER){
+	if(p->q2.flags&KONST){
+	  eval_const(&p->q2.val,p->typf);
+	  insert_const(&p->q2.val,p->typf2);
+	  p->typf=t=(UNSIGNED|SHORT);
+	}else{
+	  if(ISLWORD(t)) inc_addr(&p->q2,2,t);
+	  if((t&NQ)==CHAR) short_add=t;
+	  p->typf=t=(UNSIGNED|SHORT);
+	}
+      }else if(ISHWORD(t)){
+	if((t&NQ)==LLONG) 
+	  inc_addr(&p->q2,4,t);
+	else if((t&NQ)!=LONG) 
+	  short_add=t;
+	p->typf=t=(UNSIGNED|LONG);
+      }
+      p->code=c=(c==ADDI2P)?ADD:SUB;
+    }
+
+    if(c==COMPARE&&ISLWORD(t)){
+      IC *branch=p->next;
+      int r;
+      while(branch&&branch->code==FREEREG) branch=branch->next;
+      if(!branch) ierror(0);
+      c=branch->code;
+      if(c<BEQ||c>BGT) ierror(0);
+      if(!regs[ix])
+	r=ix;
+      else
+	r=get_reg(f,p,INT);
+      
+      if(c==BEQ||c==BNE){
+	inc_addr(&p->q1,0,t);
+	inc_addr(&p->q2,0,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	if(pushed_acc) emit(f,SPULLD);
+	emit(f,"\tbne\t%s%d\n",labprefix,c==BEQ?++label:branch->typf);
+	if(pushed_acc) emit(f,SPUSHD);
+	inc_addr(&p->q1,2,t);
+	inc_addr(&p->q2,2,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	pr(f,p);
+	if(c==BEQ){
+	  emit(f,"\tbeq\t%s%d\n",labprefix,branch->typf);
+	  emit(f,"%s%d:\n",labprefix,label);
+	}else
+	  emit(f,"\tbne\t%s%d\n",labprefix,branch->typf);
+      }else{
+	inc_addr(&p->q1,0,t);
+	inc_addr(&p->q2,0,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	label++;
+	if(pushed_acc) emit(f,SPULLD);
+	if(t&UNSIGNED){
+	  if(c==BLT||c==BGT)
+	    emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lo":"hi",labprefix,branch->typf);
+	  else
+	    emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lo":"hi",labprefix,label);
+	}else{
+	  if(c==BLT||c==BGT)
+	    emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lt":"gt",labprefix,branch->typf);
+	  else
+	    emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lt":"gt",labprefix,label);
+	}
+	emit(f,"\tbne\t%s%d\n",labprefix,(c==BLT||c==BGT)?label:branch->typf);
+	if(pushed_acc) emit(f,SPUSHD);
+	inc_addr(&p->q1,2,t);
+	inc_addr(&p->q2,2,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	pr(f,p);
+	emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,branch->typf);
+	emit(f,"%s%d:\n",labprefix,label);
+      }
+      branch->code=NOP;
+      continue;
+    }
+
+    if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
+      int cnt=-1000,i,r=0;
+      int px=0,py=0,pa=0;
+      if(isconst(q2)){
+	eval_const(&p->q2.val,p->typf2);
+	cnt=(int)zm2l(vmax);
+	if(cnt==1&&compare_objects(&p->q1,&p->z)){
+	  if(c==LSHIFT)
+	    emit(f,"\tlsl\t");
+	  else
+	    emit(f,"\t%s\t",(t&UNSIGNED)?"lsr":"asr");
+	  inc_addr(&p->z,c==LSHIFT?3:0,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  continue;
+	}
+      }
+      inc_addr(&p->q1,2,t);
+      inc_addr(&p->z,2,t);
+
+      if(ISRACC(q2)||(regs[acc]&&!scratchreg(acc,p))){
+	emit(f,SPUSHD);
+	push(2);
+	pa=1;
+      }
+
+      if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+	if(regs[ix]&&!scratchreg(ix,p)) {px=1;emit(f,SPUSH("x"));push(2);}
+	if(regs[iy]&&!scratchreg(iy,p)) {py=1;emit(f,SPUSH("y"));push(2);}
+      }
+
+      if(!compare_objects(&p->q1,&p->z)){
+	load_reg(f,acc,&p->q1,INT);
+	store_reg(f,acc,&p->z,INT);
+      }
+      inc_addr(&p->q1,-2,t);
+      inc_addr(&p->z,-2,t);
+      load_reg(f,acc,&p->q1,INT);
+      if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+	if((p->q2.flags&REG)&&p->q2.reg==ix){
+	  if((p->z.flags&REG)&&p->z.reg==iy) ierror(0);
+	}else
+	  load_addr(f,ix,&p->z);
+	if(ISRACC(q2)){
+	  if(scratchreg(acc,p)&&(px+py==0)){
+	    emit(f,SPULL("y"));
+	    pop(2);pa=0;
+	  }else
+	    emit(f,"\tldy\t%d,%s\n",(px+py)*2,regnames[sp]);
+	}else
+	  load_reg(f,iy,&p->q2,p->typf2); /*TODO: types!=INT?? */
+	if((p->q2.flags&REG)&&p->q2.reg==ix)
+	  load_addr(f,ix,&p->z);
+	if(c==LSHIFT)
+	  emit(f,"\t%s\t%s__lsll\n",jsrinst,idprefix);
+	else
+	  emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,(t&UNSIGNED)?"lsrl":"asrl");
+	if(py) {emit(f,SPULL("y"));pop(2);}
+	if(px) {emit(f,SPULL("x"));pop(2);}
+      }else{
+	inc_addr(&p->z,c==LSHIFT?3:2,t);
+	for(i=0;i<cnt;i++){
+	  if(c==LSHIFT){
+	    emit(f,"\tlsl\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,-1,t);
+	    emit(f,"\trol\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,1,t);
+	    emit(f,"\trolb\n");
+	    emit(f,"\trola\n");
+	  }else{
+	    emit(f,"\t%s\n",(t&UNSIGNED)?"lsra":"asra");
+	    emit(f,"\trorb\n");
+	    emit(f,"\tror\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,1,t);
+	    emit(f,"\tror\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,-1,t);
+	  }
+	}
+	inc_addr(&p->z,c==LSHIFT?-3:-2,t);
+	store_reg(f,acc,&p->z,INT);
+      }
+      if(pa) {emit(f,SPULLD);pop(2);}
+      continue;
+    }
+
+    if(ISLWORD(t)&&c!=GETRETURN&&c!=SETRETURN&&c!=COMPARE&&c!=CONVERT&&c!=ADDRESS){
+      if(c==PUSH&&isreg(q1)&&p->q1.reg==dx){
+	if(CPU==6812){
+	  emit(f,"\tpshd\n");
+	  emit(f,"\tpshx\n");
+	}else{
+	  /*emit(f,"\tpshs\ta,b,x\n");*/
+	  emit(f,"\tpshs\tb,a\n");
+	  emit(f,"\tpshs\tx\n");
+	}
+	dontpop += 4;
+	push(4);
+	continue;
+      }
+      if(c==ASSIGN&&isreg(q1)&&p->q1.reg==dx){
+	inc_addr(&p->z,2,t);
+	store_reg(f,ix,&p->z,INT);
+	inc_addr(&p->z,-2,t);
+	store_reg(f,acc,&p->z,INT);
+	continue;
+      }
+      if(c==ASSIGN&&isreg(z)&&p->z.reg==dx){
+	inc_addr(&p->q1,2,t);
+	load_reg(f,ix,&p->q1,INT);
+	inc_addr(&p->q1,-2,t);
+	load_reg(f,acc,&p->q1,INT);
+	continue;
+      }
+      if(c==PUSH){
+	if(regs[acc]) emit(f,"\tstd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+      }else
+	get_acc(f,p);
+      /*TODO: acc in IC, constants */
+      inc_addr(&p->q1,2,t);
+      if(c==MINUS){
+	if(CPU!=6812&&!optsize)
+	  emit(f,"\tldd\t#0\n");
+	else
+	  emit(f,"\tclra\n\tclrb\n");
+      }else
+	load_reg(f,acc,&p->q1,INT);
+      if(c==ADD||c==SUB){
+	inc_addr(&p->q2,2,t);
+	emit(f,"\t%s\t",c==ADD?"addd":"subd");
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+      }else if(c==ASSIGN||c==PUSH){
+      }else if(c==MINUS){
+	emit(f,"\tsubd\t");
+	emit_obj(f,&p->q1,INT);
+	emit(f,"\n");
+      }else if(c==KOMPLEMENT){
+	emit(f,"\tcoma\n");
+	emit(f,"\tcomb\n");
+      }else{
+	if(c==AND)
+	  emit(f,"\tandb\t");
+	else if(c==OR)
+	  emit(f,"\tor%sb\t",CPU==6812?"a":"");
+	else if(c==XOR)
+	  emit(f,"\teorb\t");
+	inc_addr(&p->q2,3,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+	if(c==AND)
+	  emit(f,"\tanda\t");
+	else if(c==OR)
+	  emit(f,"\tor%sa\t",CPU==6812?"a":"");
+	else if(c==XOR)
+	  emit(f,"\teora\t");
+	inc_addr(&p->q2,-1,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+      }
+      if(c==PUSH){
+	if(CPU==6812)
+	  emit(f,"\tpshd\n");
+	else
+	  emit(f,"\tpshs\tb,a\n");
+	push(2);dontpop+=2;
+      }else{
+	inc_addr(&p->z,2,t);
+	store_reg(f,acc,&p->z,INT);
+      }
+      inc_addr(&p->q1,-2,t);
+      if(c==MINUS)
+	emit(f,"\tldd\t#0\n");
+      else
+	load_reg(f,acc,&p->q1,INT);
+      if(c==ADD)
+	emit(f,"\tadcb\t");
+      else if(c==SUB)
+	emit(f,"\tsbcb\t");
+      else if(c==AND)
+	emit(f,"\tandb\t");
+      else if(c==OR)
+	emit(f,"\tor%sb\t",CPU==6812?"a":"");
+      else if(c==XOR)
+	emit(f,"\teorb\t");
+      else if(c==KOMPLEMENT)
+	emit(f,"\tcomb\n");
+      else if(c==MINUS){
+	inc_addr(&p->q1,1,t);
+	emit(f,"\tsbcb\t");
+	emit_obj(f,&p->q1,CHAR);
+	emit(f,"\n");
+      }
+      if(p->q2.flags){
+	inc_addr(&p->q2,-1,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+      }
+      if(c==ADD)
+	emit(f,"\tadca\t");
+      else if(c==SUB)
+	emit(f,"\tsbca\t");
+      else if(c==AND)
+	emit(f,"\tanda\t");
+      else if(c==OR)
+	emit(f,"\tor%sa\t",CPU==6812?"a":"");
+      else if(c==XOR)
+	emit(f,"\teora\t");
+      else if(c==KOMPLEMENT)
+	emit(f,"\tcoma\n");
+      else if(c==MINUS){
+	inc_addr(&p->q1,-1,t);
+	emit(f,"\tsbca\t");
+	emit_obj(f,&p->q1,CHAR);
+	emit(f,"\n");
+      }
+      if(p->q2.flags){
+	inc_addr(&p->q2,-1,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+      }
+      if(c==PUSH){
+	if(CPU==6812)
+	  emit(f,"\tpshd\n");
+	else
+	  emit(f,"\tpshs\tb,a\n");
+	push(2);dontpop+=2;
+	if(regs[acc]) emit(f,"\tldd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+      }else{
+	inc_addr(&p->z,-2,t);
+	store_reg(f,acc,&p->z,INT);
+      }
+      continue;
+    }
+
+ 
+    if(c==COMPARE){
+      int vadr;
+      if(drel&&(p->q1.flags&VARADR)&&!ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+      else if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+      else if(pcrel&&(p->q1.flags&VARADR)&&ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+      else if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+      else vadr=0;
+      if(vadr!=1&&(vadr==2||isconst(q1)||ISRACC(q2))){
+	struct IC *p2;
+	o=p->q1;p->q1=p->q2;p->q2=o;
+	p2=p->next;
+	while(p2&&p2->code==FREEREG) p2=p2->next;
+	if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+	if(p2->code==BLT) p2->code=BGT;
+	else if(p2->code==BGT) p2->code=BLT;
+	else if(p2->code==BLE) p2->code=BGE;
+	else if(p2->code==BGE) p2->code=BLE;
+      }
+      /* case with two relative addresses */
+      if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+      if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+    }
+#if 0
+    /* TODO: fix cc */
+    if(c==COMPARE&&isconst(q2)){
+      eval_const(&p->q2.val,t);
+      if(ISNULL()){
+	if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+	  lastcomp=t;continue;
+	}
+      }
+    }
+#endif
+
+    if(!short_add)
+      switch_IC(p);
+
+    if(c==CONVERT){
+      int to=p->typf2&NU;
+      if(to==INT) to=SHORT;
+      if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
+      if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+      if((t&NU)==INT) t=SHORT;
+      if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+      if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+      /*if((t&NQ)>=LONG||(to&NQ)>=LONG) ierror(0);*/
+      if((to&NQ)<=LONG&&(t&NQ)<=LONG){
+	if((to&NQ)<(t&NQ)){
+	  if(ISLWORD(t)){
+	    get_acc(f,p);
+	    load_reg(f,acc,&p->q1,to);
+	    if((to&NU)==CHAR)
+	      emit(f,SEX);
+	    else if((to&NU)==(UNSIGNED|CHAR))
+	      emit(f,"\tclra\n");
+	    inc_addr(&p->z,2,t);
+	    store_reg(f,acc,&p->z,INT);
+	    inc_addr(&p->z,-2,t);
+	    if(to&UNSIGNED){
+	      emit(f,"\tclra\n\tclrb\n");
+	    }else{
+	      if(CPU==6812)
+		emit(f,"\texg\ta,b\n");
+	      else
+		emit(f,"\ttfr\ta,b\n");
+	      emit(f,SEX);
+	      emit(f,"\ttfr\ta,b\n");
+	    }
+	    store_reg(f,acc,&p->z,INT);
+	    continue;
+	  }
+	  /*emit(f,"#conv RACC=%d, regs=%d scratch=%d\n",(int)ISRACC(z),regs[acc],scratchreg(acc,p));*/
+	  if(!ISRACC(z))
+	    get_acc(f,p);
+	  load_reg(f,acc,&p->q1,to);
+	  if(to&UNSIGNED)
+	    emit(f,"\tclra\n");
+	  else
+	    emit(f,SEX);
+	  store_reg(f,acc,&p->z,t);
+	  cc=&p->z;cc_t=t;
+	  continue;
+	}else if((to&NQ)>(t&NQ)){
+	  if(!ISRACC(z)&&!ISRACC(q1))
+	    get_acc(f,p);
+	  if(ISLWORD(to))
+	    inc_addr(&p->q1,2,to);
+	  load_reg(f,acc,&p->q1,to);
+	  store_reg(f,acc,&p->z,t);
+	  continue;
+	}else{
+	  c=ASSIGN;
+	  p->q2.val.vmax=sizetab[t&NQ];
+	}
+      }
+    }
+    if(c==KOMPLEMENT){
+      cc=0;
+      if(compare_objects(&p->q1,&p->z)&&!isreg(q1)&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&(!p->q1.am||p->q1.am->flags!=ACC_IND)){
+	emit(f,"\tcom\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	if(ISHWORD(t)){
+	  mobj=p->z;
+	  inc_addr(&mobj,1,t);
+	  emit(f,"\tcom\t");
+	  emit_obj(f,&mobj,INT);
+	  emit(f,"\n");
+	}
+	continue;
+      }
+      if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	get_acc(f,p);
+      load_reg(f,acc,&p->q1,t);
+      emit(f,"\tcoma\n\tcomb\n");
+      store_reg(f,acc,&p->z,t);
+      continue;
+    }
+    if(c==MINUS){
+      if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	get_acc(f,p);
+      if(isreg(q1)){
+	load_reg(f,acc,&p->q1,t);
+	emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+      }else{
+	if(CPU!=6812&&!optsize)
+	  emit(f,"\tldd\t#0\n");
+	else
+	  emit(f,"\tclra\n\tclrb\n");
+	emit(f,"\tsubd\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      cc=&p->z;cc_t=t;
+      store_reg(f,acc,&p->z,t);
+      continue;
+    }
+    if(c==SETRETURN){
+      if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+      if(p->z.reg){
+	if(ISLWORD(t)){
+	  inc_addr(&p->q1,0,t);
+	  load_reg(f,ix,&p->q1,INT);
+	  BSET(regs_modified,ix);
+	  inc_addr(&p->q1,2,t);
+	}
+	load_reg(f,acc,&p->q1,t);
+	BSET(regs_modified,acc);
+
+      }
+      continue;
+    }
+    if(c==GETRETURN){
+      if(isreg(z)&&p->z.reg==p->q1.reg) continue;
+      if(p->q1.reg){
+	if(ISLWORD(t)){
+	  store_reg(f,ix,&p->z,INT);
+	  BSET(regs_modified,ix);
+	  inc_addr(&p->z,2,t);
+	}
+	store_reg(f,acc,&p->z,(t&NQ)==CHAR?t:INT);
+      }
+      continue;
+    }
+    if(c==CALL){
+      int reg,jmp=0;
+      cc=0;
+      if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	long of=va_offset(v)+loff+2;
+	emit(f,"\ttfr\t%s,d\n",regnames[sp]);
+	if(of) emit(f,"\taddd\t#%ld\n",of);
+	continue;
+      }
+      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	jmp=1;
+      }else{
+	if(stackoffset==0&&!have_frame&&!strcmp(ret,"rts")){
+	  struct IC *p2;
+	  jmp=1;
+	  for(p2=p->next;p2;p2=p2->next){
+	    if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL){
+	      jmp=0;break;
+	    }
+	  }
+	}
+	if(p->q1.flags&DREFOBJ){
+	  /*FIXME: test this*/
+	  if(jmp)
+	    emit(f,"\tjmp\t");
+	  else
+	    emit(f,"\tjsr\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}else{
+	  if(jmp){
+	    emit(f,"\t%s\t",jmpinst); /*emit(f,"\tbra\t");*/
+	    /*if(!need_return) ret=0;*/ /*TODO: works with optimizer? */
+	  }else{
+	    emit(f,"\t%s\t",jsrinst); /*emit(f,"\tbsr\t");*/
+	  }
+	  if(pcrel){
+	    pcrel=0;
+	    emit_obj(f,&p->q1,t);
+	    pcrel=1;
+	  }else
+	    emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+      }
+      if(stack_valid){
+        int i;
+        if(p->call_cnt<=0){
+          err_ic=p;if(f) error(320);
+          stack_valid=0;
+        }
+        for(i=0;stack_valid&&i<p->call_cnt;i++){
+          if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+	    /*FIXME: size of return addr depends on mode */
+	    if(!jmp) push(2);
+	    callee_push(zm2l(p->call_list[i].v->fi->stack1));
+	    if(!jmp) pop(2);
+          }else{
+            err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+            stack_valid=0;
+          }
+        }
+      }
+      if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+	notpopped+=zm2l(p->q2.val.vmax);
+	dontpop-=zm2l(p->q2.val.vmax);
+	if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+	  /*  Entfernen der Parameter verzoegern  */
+	}else{
+	  gen_pop(f,zm2l(p->q2.val.vmax));
+	  notpopped-=zm2l(p->q2.val.vmax);
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+      if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	unsigned long size;int qr=0,zr=0,cr=0,px=0,py=0,pu=0,pd=0,lq=0,lz=0;
+	size=zm2l(p->q2.val.vmax);
+	if(c==ASSIGN){
+	  if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->z.reg)){
+	    zr=p->z.reg;lz=1;
+	  }
+	}
+	if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->q1.reg)&&p->q1.reg!=zr){
+	  qr=p->q1.reg;lq=1;
+	}
+	if(!qr){
+	  if(zr==ix) qr=iy;
+	  else if(zr==iy||zr==iu) qr=ix;
+	  else{qr=ix;zr=iy;}
+	}else if(!zr){
+	  if(qr==ix) zr=iy; else zr=ix;
+	}
+	if(CPU!=6812){
+	  if(qr!=iu&&zr!=iu) cr=iu;
+	  if(qr!=ix&&zr!=ix) cr=ix;
+	  if(qr!=iy&&zr!=iy) cr=iy;
+	  if(!cr) ierror(0);
+	}
+	if(c==PUSH){
+	  emit(f,"\tleas\t%ld,%s\n",SGN16(-size),regnames[sp]);
+	  push(size);
+	}
+	if(CPU!=6812&&(drel||!regused[iu]||(regs[iu]&&!scratchreg(iu,p)))){
+	  if(c==PUSH)
+	    emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPUSH("u"));
+	    push(2);
+	  }
+	  pu=1;
+	}
+	if(!regused[iy]||(regs[iy]&&!scratchreg(iy,p))){
+	  if(c==PUSH)
+	    emit(f,"\tsty\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPUSH("y"));
+	    push(2);
+	  }
+	  py=1;
+	}
+	if(regs[ix]&&!scratchreg(ix,p)){
+	  if(c==PUSH)
+	    emit(f,"\tstx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPUSH("x"));
+	    push(2);
+	  }
+	  px=1;
+	}
+	if(!lq) load_addr(f,qr,&p->q1);
+	if(c==PUSH)
+	  emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[zr]);
+	else
+	  if(!lz) load_addr(f,zr,&p->z);
+	if(size<=6||(size<=16&&!optsize)){
+	  if(CPU!=6812){
+	    if(!scratchreg(acc,p)){
+	      if(c==PUSH)
+		emit(f,"\tstd\t%ld,%s\n",loff-roff-6-stackoffset,regnames[sp]);
+	      else{
+		emit(f,SPUSHD);
+		push(2);
+	      }
+	      pd=2;
+	    }
+	  }
+	  while(size>2){
+	    if(CPU==6812)
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	    else
+	      emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+	    size-=2;
+	  }
+	  if(CPU==6812)
+	    emit(f,"\tmov%c\t0,%s,0,%s\n",size==2?'w':'b',regnames[qr],regnames[zr]);
+	  else
+	    emit(f,"\tld%c\t,%s\n\tst%c\t,%s\n",size==2?'d':'b',regnames[qr],size==2?'d':'b',regnames[zr]);
+	}else{
+	  int l=++label,cnt=(int)(optsize?(CPU==6812?size:(size/2)):size/8);
+	  if(regs[acc]&&!scratchreg(acc,p)){
+	    if(c==PUSH)
+	      emit(f,"\tst%c\t%ld,%s\n",(CPU!=6812&&cnt<=255)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+	    else{
+	      if(CPU!=6812&&cnt<=255){
+		emit(f,SPUSH("b"));
+		push(1);
+	      }else{
+		emit(f,SPUSHD);
+		push(2);
+	      }
+	    }
+	    pd=(CPU!=6812&&cnt<=255)?1:2;
+	  }
+	  if(CPU!=6812&&cnt<=255)
+	    emit(f,"\tldb\t#%lu\n",cnt);
+	  else
+	    emit(f,"\tldd\t#%lu\n",cnt);
+	  cc=0;
+#if 0
+	  if(CPU!=6812&&((!regsa[iu]&&regs[iu])||drel)){
+	    if(c==PUSH){
+	      emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); 
+	    }else{
+	      emit(f,SPUSH("u"));push(2);
+	    }
+	  }
+#endif
+	  emit(f,"%s%d:\n",labprefix,l);
+	  if(CPU==6812){
+	    if(optsize){
+	      emit(f,"\tmovb\t1,%s+,1,%s+\n",regnames[qr],regnames[zr]);
+	      size=0;
+	    }else{
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      size=size&7;
+	    }
+	    emit(f,"\tdbne\td,%s%d\n",labprefix,l);
+	  }else{
+	    if(optsize){
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      size&=1;
+	    }else{
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      size&=7;
+	    }
+	    if(cnt<=255)
+	      emit(f,"\tdecb\n");
+	    else
+	      emit(f,"\tsubd\t#1\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,l);
+	  }
+#if 0
+	  if(CPU!=6812&&((!regsa[iu]&&regs[iu])||drel)){
+	    if(c==PUSH){
+	      emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+	    }else{
+	      emit(f,SPULL("u"));pop(2);
+	    }
+	  }
+#endif
+	  while(size>=2){
+	    if(CPU==6812)
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	    else
+	      emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+	    size-=2;
+	  }
+	  if(size){
+	    if(CPU==6812)
+	      emit(f,"\tmovb\t0,%s,0,%s\n",regnames[qr],regnames[zr]);
+	    else
+	      emit(f,"\tldb\t,%s\n\tstb\t,%s\n",regnames[qr],regnames[zr]);
+	  }
+	}
+	if(pd){
+	  if(c==PUSH) 
+	    emit(f,"\tld%c\t%ld,%s\n",(pd==1)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+	  else{
+	    if(pd==1){
+	      emit(f,SPULL("b"));
+	      pop(1);
+	    }else{
+	      emit(f,SPULLD);
+	      pop(2);
+	    }
+	  }
+	}
+	if(px){
+	  if(c==PUSH) 
+	    emit(f,"\tldx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPULL("x"));
+	    pop(2);
+	  }
+	}
+	if(py){
+	  if(c==PUSH) 
+	    emit(f,"\tldy\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPULL("y"));
+	    pop(2);
+	  }
+	}
+	if(pu){
+	  if(c==PUSH) 
+	    emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPULL("u"));
+	    pop(2);
+	  }
+	}
+	continue;
+      }
+      if(!ISSCALAR(t)) t=zmeqto(p->q2.val.vmax,l2zm(1L))?CHAR:INT;
+      if((t&NQ)==CHAR&&!zmeqto(p->q2.val.vmax,l2zm(1L))) t=INT;	
+      if(mov_op(&p->q1)&&(c==PUSH||mov_op(&p->z))){
+	emit(f,"\tmov%c\t",ISHWORD(t)?'w':'b');
+	emit_obj(f,&p->q1,t);
+	if(c==ASSIGN){
+	  emit(f,",");
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	}else{
+	  emit(f,",%d,-%s\n",ISHWORD(t)?2:1,regnames[sp]);
+	  push(ISHWORD(t)?2:1);
+	}
+	continue;
+      }
+      if(((regs[acc]&&regs[ix])||(t&NQ)==CHAR)&&(p->q1.flags&KONST)&&!isreg(z)){
+	eval_const(&p->q1.val,t);
+	if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&((p->z.flags&(REG|DREFOBJ))!=DREFOBJ||(t&NQ)==CHAR)&&(!p->z.am||p->z.am->flags!=ACC_IND||(t&NQ)==CHAR)){
+	  emit(f,"\tclr\t");
+	  if(c==ASSIGN){
+	    emit_obj(f,&p->z,t);emit(f,"\n");
+	  }else{
+	    emit(f,CPU==6812?"1,-sp\n":",-s\n");
+	    push(1);
+	  }
+	  if(!ISHWORD(t)) continue;
+	  emit(f,"\tclr\t");
+	  if(c==ASSIGN){
+	    mobj=p->z;
+	    inc_addr(&mobj,1,t);
+	    emit_obj(f,&mobj,t);emit(f,"\n");
+	  }else{
+	    emit(f,CPU==6812?"1,-sp\n":",-s\n");
+	    push(1);
+	  }
+	  continue;
+	}
+
+      }
+      if(c==PUSH){
+	int st=0;
+	if(isreg(q1)){
+	  reg=p->q1.reg;
+	}else{
+	  if((t&NQ)==CHAR||!regs[acc]||scratchreg(acc,p)) reg=acc;
+	  else if(!regs[ix]||scratchreg(ix,p)) reg=ix;
+	  else if(regused[iy]&&(!regs[iy]||scratchreg(iy,p))) reg=iy;
+	  else if(regused[iu]&&!drel&&CPU!=6812&&(!regs[iu]||scratchreg(iu,p))) reg=iu;
+	  else reg=acc;
+	  if(regs[reg]&&!scratchreg(reg,p)){
+	    st=1;
+	    emit(f,"\tst%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+	  }
+	  load_reg(f,reg,&p->q1,t);
+	}
+	if((t&NQ)==CHAR)
+	  emit(f,SPUSH("b"));
+	else if(reg==ix)
+	  emit(f,SPUSH("x"));
+	else if(reg==iy)
+	  emit(f,SPUSH("y"));
+	else if(reg==iu)
+	  emit(f,SPUSH("u"));
+	else
+	  emit(f,SPUSHD);
+	push(zm2l(p->q2.val.vmax));
+	if(st)
+	  emit(f,"\tld%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+	continue;
+      }
+      if(c==ASSIGN){
+	if(isreg(q1)&&isreg(z)){
+	  if(p->q1.reg!=p->z.reg)
+	    emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]);
+	}else if(isreg(q1)){
+	  store_reg(f,p->q1.reg,&p->z,t);
+	}else if(isreg(z)){
+	  load_reg(f,p->z.reg,&p->q1,t);
+	}else{
+	  reg=get_reg(f,p,t);
+	  load_reg(f,reg,&p->q1,t);
+	  store_reg(f,reg,&p->z,t);
+	}
+	continue;
+      }
+      ierror(0);
+    }
+    if(c==ADDRESS){
+      int px=0;
+      if(isreg(z)){
+	reg=p->z.reg;
+      }else if(!regs[ix]){
+	reg=ix;
+      }else if(!regs[iy]){
+	reg=iy;
+      }else{
+	/*FIXME: test if x used in q1 */
+	px=1;
+	emit(f,SPUSH("x"));
+	reg=ix;
+	push(2);
+      }
+      load_addr(f,reg,&p->q1);
+      if(!(p->z.flags&REG)||p->z.reg!=reg)
+	store_reg(f,reg,&p->z,p->typf2);
+      if(px){
+	emit(f,SPULL("x"));
+	pop(2);
+      }
+      continue;
+    }
+
+    if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
+      long ln;
+      eval_const(&p->q2.val,t);
+      if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	if((ln=pof2(vumax))&&ln<5){
+	  if(c==MOD){
+	    vmax=zmsub(vmax,l2zm(1L));
+	    c=p->code=c=AND;
+	  }else{
+	    vmax=l2zm(ln-1);
+	    if(c==DIV) p->code=c=RSHIFT; else p->code=c=LSHIFT;
+	  }
+	  c=p->code;
+	  gval.vmax=vmax;
+	  eval_const(&gval,MAXINT);
+	  if(c==AND){
+	    insert_const(&p->q2.val,t);
+	  }else{
+	    insert_const(&p->q2.val,t);
+	    p->typf2=INT;
+	  }
+	}
+      }
+    }
+    if(c==MOD||c==DIV){
+      ierror(0);
+      continue;
+    }
+
+
+    if((c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(p->q1.flags&(REG|DREFOBJ))!=REG&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&!p->q1.am&&!p->z.am&&compare_objects(&p->q1,&p->z)){
+      eval_const(&p->q2.val,t);
+      if(c==SUB) vmax=zmsub(Z0,vmax);
+      if((t&NQ)==CHAR&&zmeqto(vmax,Z1)){
+	emit(f,"\tinc\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	continue;
+      }else if((t&NQ)==CHAR&&zmeqto(vmax,l2zm(-1L))){
+	emit(f,"\tdec\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	continue;
+      }else if(((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(1L))){
+	inc_addr(&p->z,1,t);
+	emit(f,"\tinc\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	inc_addr(&p->z,-1,t);
+	emit(f,"\tinc\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	continue;
+      }else if(regs[acc]&&((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(-1L))){
+	inc_addr(&p->z,1,t);
+	emit(f,"\ttst\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	inc_addr(&p->z,-1,t);
+	emit(f,"\tdec\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	inc_addr(&p->z,1,t);
+	emit(f,"\tdec\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	continue;
+      }
+    }
+
+    if((c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP||c==SUBPFP||(c>=OR&&c<=AND)||c==COMPARE){
+      char *s;
+      /*FIXME: nicht immer besser*/
+      if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
+	eval_const(&p->q2.val,t);
+	if(zm2l(vmax)==1){
+	  p->code=c=ADD;
+	  p->q2=p->q1;
+	}
+      }
+      if((c==ADD||c==ADDI2P||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&!isreg(q1)&&!short_add){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+      }
+      if((c==ADD||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&p->q2.reg==acc&&!short_add){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+      }
+      if(c==MULT||c==MOD){
+	if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	  get_acc(f,p);
+	reg=acc;
+	/*FIXME: y bzw. x-Register*/
+      }else if(c==LSHIFT||c==RSHIFT||c==AND||c==OR||c==XOR){
+	if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	  get_acc(f,p);
+	reg=acc;
+      }else if(c==DIV){
+	reg=ix;
+	ierror(0);
+      }else if(isreg(z)){
+	reg=p->z.reg;
+      }else if(isreg(q1)&&(c==COMPARE||scratchreg(p->q1.reg,p))){
+	reg=p->q1.reg;
+      }else{
+	if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==COMPARE){
+	  if(ISRACC(q2))
+	    reg=acc;
+	  else
+	    reg=get_reg(f,p,t);
+	}else{
+	  get_acc(f,p);
+	  reg=acc;
+	}
+      }
+      if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
+	int opdone=0;
+	if(isreg(q1)){
+	  if(ISIDX(reg)&&ISIDX(p->q1.reg)&&isconst(q2)){
+	    eval_const(&p->q2.val,short_add?short_add:q2typ(p));
+	    if(CPU==6812&&p->q1.reg==reg&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
+	      emit(f,"\t%s%s\n",c==SUB?"de":"in",regnames[reg]);
+	      /*FIXME: condition-codes for bne/beq could be used */
+	    }else{
+	      emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],c==SUB?SGN16(-zm2l(vmax)):SGN16(zm2l(vmax)),regnames[p->q1.reg]);
+	    }
+	    opdone=1;
+	  }else	if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISIDX(p->q1.reg)&&ISRACC(q2)){
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NQ)==CHAR||(short_add&NQ)==CHAR)?"b":"d",regnames[p->q1.reg]);
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISACC(p->q1.reg)&&ISRIDX(q2)){
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[p->q2.reg]);
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&!short_add){
+	    load_reg(f,reg,&p->q2,t);
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&(short_add&NU)==(UNSIGNED|CHAR)&&scratchreg(acc,p)){
+	    emit(f,"\taddb\t");
+	    emit_obj(f,&p->q2,short_add);
+	    emit(f,"\n");
+	    emit(f,"\tadca\t#0\n");
+	    emit(f,"\ttfr\td,y\n");
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&ISACC(p->q1.reg)&&ISRACC(z)&&isreg(q2)&&ISIDX(p->q2.reg)){
+	    if(!scratchreg(p->q2.reg,p)) emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[p->q2.reg],regnames[acc],regnames[p->q2.reg]);
+	    emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+	    opdone=1;
+	  }else	if(p->q1.reg!=reg){
+	    if(c==ADD||c==ADDI2P||!ISRACC(q2))
+	      emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[reg]);
+	  }
+	}else if(short_add&&c==SUB&&reg==acc&&!(short_add&UNSIGNED)){
+	  load_reg(f,reg,&p->q2,short_add);
+	  emit(f,"\tclra\n");
+	  emit(f,"\tnegb\n");
+	  emit(f,"\tsbca\t#0\n");
+	  emit(f,"\taddd\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	  store_reg(f,reg,&p->z,ztyp(p));
+	  continue;
+	}else if(short_add&&c==ADD&&reg==acc){
+	  load_reg(f,reg,&p->q2,short_add);
+	  if(short_add&UNSIGNED)
+	    emit(f,"\tclra\n");
+	  else
+	    emit(f,SEX);
+	  emit(f,"\taddd\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	  store_reg(f,reg,&p->z,ztyp(p));
+	  continue;
+	}else{
+	  if(!ISRACC(q2))
+	    load_reg(f,reg,&p->q1,q1typ(p));
+	}
+	if(!opdone){
+	  if(reg==acc){
+	    if(ISRACC(q2)){
+	      if(!ISRACC(z)) get_acc(f,p);
+	      if(c==ADD||c==ADDI2P){
+		if(short_add){
+		  if(short_add&UNSIGNED)
+		    emit(f,"\tclra\n");
+		  else
+		    emit(f,SEX);
+		  emit(f,"\taddd\t");
+		  emit_obj(f,&p->q1,t);
+		  emit(f,"\n");
+		}else{
+		  if(CPU==6812)
+		    emit(f,"\tasld\n"); /* only cases with q1=q2=acc should remain */
+		  else{
+		    emit(f,"\taslb\n");
+		    if((t&NQ)!=CHAR)
+		      emit(f,"\trola\n");
+		  }
+		}
+	      }else{
+		if(short_add){
+		  if(short_add&UNSIGNED)
+		    emit(f,"\tld%sa\t#255\n",(CPU==6812)?"a":"");
+		  else{
+		    emit(f,SEX);
+		    emit(f,"\tnega\n");
+		  }
+		  emit(f,"\tnegb\n\tsbca\t#0\n");
+		}else if((t&NQ)!=CHAR){
+		  emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+		}else{
+		  emit(f,"\tnegb\n");
+		}
+		
+		if(ISRIDX(q1)){
+		  emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[p->q1.reg]);
+		  emit(f,"\taddd\t%s\n",CPU==6812?"1,s+":",s++");
+		}else{
+		  emit(f,"\taddd\t");
+		  emit_obj(f,&p->q1,t);
+		  emit(f,"\n");
+		}
+	      }
+	    }else{
+	      if(ISRIDX(q2)){
+		if(CPU==6812)
+		  emit(f,"\tpsh%s\n",regnames[p->q2.reg]);
+		else
+		  emit(f,"\tpshs\t%s\n",regnames[p->q2.reg]);
+		push(2);pop(2);
+		if(CPU==6812)
+		  emit(f,"\t%sd\t2,%s+\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+		else
+		  emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+	      }else{
+		emit(f,"\t%s%s\t",(c==ADD||c==ADDI2P)?"add":"sub",(short_add||(t&NQ)==CHAR)?"b":"d");
+		emit_obj(f,&p->q2,short_add?short_add:t);emit(f,"\n");
+		if(short_add){
+		  if(short_add&UNSIGNED)
+		    emit(f,"\t%s\t#0\n",c==ADD?"adca":"sbca");
+		  else
+		    ierror(0);
+		}
+		if(drel&&(p->q2.flags&VARADR)){
+		  if(CPU==6812) ierror(0);
+		  emit(f,"\tpshs\t%s\n",regnames[iu]);push(2);
+		  emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+		  pop(2);
+		}
+	      }
+	    }
+	    cc=&p->z;cc_t=t;
+	  }else{
+	    if(isconst(q2)){
+	      long l;
+	      eval_const(&p->q2.val,short_add?short_add:t);
+	      l=zm2l(vmax);
+	      if(c==SUB) l=-l;
+	      /*FIXME: condition-codes for bne/beq could be used */
+	      if(l==1&&reg==ix&&CPU==6812){
+		emit(f,"\tinx\n");
+	      }else if(l==1&&reg==iy&&CPU==6812){
+		emit(f,"\tiny\n");
+	      }else if(l==-1&&reg==ix&&CPU==6812){
+		emit(f,"\tdex\n");
+	      }else if(l==-1&&reg==iy&&CPU==6812){
+		emit(f,"\tdey\n");
+	      }else{
+		emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],SGN16(l),regnames[reg]);
+	      }
+	    }else{
+	      if(c!=ADD&&c!=ADDI2P){
+		if(!ISRACC(q2)){
+		  if(!scratchreg(acc,p))
+		    get_acc(f,p);
+		  load_reg(f,acc,&p->q2,t);
+		  if((t&NQ)!=CHAR){
+		    emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+		  }else{
+		    emit(f,"\tnegb\n");
+		  }
+		  /*load_reg(f,reg,&p->q1,t);*/
+		}else{
+		  get_acc(f,p);
+		  load_reg(f,reg,&p->q1,t);
+		  if((t&NQ)==CHAR)
+		    emit(f,"\tnegb\n");
+		  else
+		    emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+		}  
+	      }else if(!ISRACC(q2)){
+		get_acc(f,p);
+		if(short_add){
+		  load_reg(f,acc,&p->q2,short_add);
+		  if(short_add&UNSIGNED){
+		    if(reg==ix){
+		      emit(f,"\tabx\n");
+		      store_reg(f,reg,&p->z,ztyp(p));
+		      continue;
+		    }else{
+		      emit(f,"\tclra\n");
+		    }
+		  }else
+		    t=CHAR;
+		}else
+		  load_reg(f,acc,&p->q2,t);
+	      }else{
+		load_reg(f,reg,&p->q1,t);
+		if(short_add&UNSIGNED)
+		  emit(f,"\tclra\n");
+		emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NU)==CHAR||(short_add&NU)==CHAR)?"b":"d",regnames[reg]);
+		store_reg(f,reg,&p->z,ztyp(p));
+		continue;
+	      }
+	      emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+	    }
+	  }
+	}
+	store_reg(f,reg,&p->z,ztyp(p));
+	continue;
+      }
+      if(c!=LSHIFT&&c!=RSHIFT)
+	load_reg(f,reg,&p->q1,t);
+      if(c==MULT){
+	if(CPU==6812){
+	  int py=0;
+	  if(reg!=acc) ierror(reg);
+	  if(!ISRY(q2)&&regs[iy]){
+	    emit(f,"\tpshy\n");
+	    push(2);
+	    py=1;
+	  }
+	  load_reg(f,iy,&p->q2,t);
+	  emit(f,"\temul\n");
+	  if(py){
+	    emit(f,SPULL("y"));
+	    pop(2);
+	  }
+	  store_reg(f,acc,&p->z,t);
+	  continue;
+	}else
+	  ierror(0);
+      }
+      if(c==LSHIFT||c==RSHIFT){
+	if(isconst(q2)){
+	  int l,oldl;
+	  load_reg(f,acc,&p->q1,t);
+	  eval_const(&p->q2.val,t);
+	  oldl=l=zm2l(vmax);
+	  if(l>=16){
+	    if(CPU!=6812&&!optsize)
+	      emit(f,"\tldd\t#0\n");
+	    else
+	      emit(f,"\tclra\n\tclrb\n");
+	    l=0;
+	  }
+	  if(l>=8){
+	    if(c==LSHIFT)
+	      emit(f,"\t%s\n\tclrb\n",(CPU==6812)?"tba":"tfr\tb,a");
+	    else{
+	      if(t&UNSIGNED)
+		emit(f,"\ttfr\ta,b\n\tclra\n");
+	      else{
+		emit(f,"\ttfr\ta,b\n");
+		emit(f,SEX);
+	      }
+	    }
+	    l-=8;
+	  }
+	  while(l--){
+	    if(c==RSHIFT){
+	      if(t&UNSIGNED){
+		if((t&NQ)==CHAR)
+		  emit(f,"\tlsrb\n");
+		else
+		  emit(f,CPU!=6812?"\tlsra\n\trorb\n":"\tlsrd\n");
+	      }else{
+		if(oldl>8||(t&NQ)==CHAR)
+		  emit(f,"\tasrb\n");
+		else
+		  emit(f,"\tasra\n\trorb\n");
+	      }
+	    }else{
+	      if((t&NQ)==CHAR)
+		emit(f,"\taslb\n");
+	      else
+		emit(f,CPU!=6812?"\taslb\n\trola\n":"\tasld\n");
+	    }
+	  }
+	}else{
+	  int px;char *s;
+	  if(regs[ix]&&!scratchreg(ix,p)&&(!isreg(z)||p->z.reg!=ix)){
+	    emit(f,SPUSH("x"));
+	    push(2);px=1;
+	  }else
+	    px=0;
+
+	  /* tell if X or D are ready for shifting */
+	  int xdone = 0; 
+	  int ddone = 0;
+
+	  /* free X if q1 is in X */
+	  if (ISRX(q1)) {
+	    ddone = 1;
+	    if (ISRACC(q2)) {
+	      xdone = 1;
+	      if (ISCHAR(p->typf2)) emit(f, EXTEND(p->typf2));
+	      emit(f, "\texg\tx,d\n");
+	    }
+	    else {
+	      emit(f, "\ttfr\tx,d\n");
+	    }
+	  }
+	  /* load q2 in X if not done yet */
+	  if (!xdone) {
+	    if (ISLWORD(p->typf2)) {
+	      /* q2 is 32bit, it is in memory, we take the lower 16bit */
+	      inc_addr(&p->q2, 2, p->typf2);
+	      load_reg(f, ix, &p->q2, INT);
+	    }
+	    else if (ISHWORD(p->typf2)) {
+	      /* q2 is 16bit, load it directly in X */
+	      load_reg(f, ix, &p->q2, INT);
+	    }
+	    else {
+	      /* q2 is 8bit, we must extend it in D */
+	      /* if D is busy with q1, save q1 in X */
+	      if (ddone || ISRACC(q1)) {
+		if (ISCHAR(t)) emit(f, EXTEND(t));
+		emit(f, "\ttfr\td,x\n");
+		load_reg(f, acc, &p->q2, CHAR);
+		emit(f, EXTEND(p->typf2));
+		emit(f, "\texg\tx,d\n");
+		ddone = 1;
+	      }
+	      else {
+		load_reg(f, acc, &p->q2, CHAR);
+		emit(f, EXTEND(p->typf2));
+		emit(f, "\ttfr\td,x\n");
+	      }
+	    }
+	  }
+	  /* load q1 in D if not done yet */
+	  if (!ddone) {
+	    load_reg(f, acc, &p->q1, t);
+	    if (ISCHAR(t)) emit(f, EXTEND(t));
+	  }
+
+
+	  if(c==LSHIFT) s="lsl";
+	  else if(t&UNSIGNED) s="lsr";
+	  else s="asr";
+	  emit(f,"\t.global\t%s__%s\n",idprefix,s);
+	  emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,s);
+	  if(px){
+	    emit(f,SPULL("x"));
+	    /*emit(f,"\tpul%s\n",regnames[ix]);*/
+	    pop(2);
+	  }
+	}
+	cc=0;
+	store_reg(f,acc,&p->z,t);
+	continue;
+      }
+      if(c>=OR&&c<=AND){
+	s=logicals[c-OR];
+	if(p->q2.am&&p->q2.am->flags==ACC_IND){
+	  mobj=p->q1;p->q1=p->q2;p->q2=mobj;
+	}
+	if(p->q2.flags&KONST){
+	  unsigned long l,h;
+	  eval_const(&p->q2.val,t);
+	  l=zum2ul(vumax);
+	  if((t&NQ)!=CHAR){
+	    h=(l>>8)&255;
+	    if(c==AND&&h==0)
+	      emit(f,"\tclra\n");
+	    else if(c==XOR&&h==255)
+	      emit(f,"\tcoma\n");
+	    else if((c==AND&&h!=255)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+	      emit(f,"\t%sa\t#%lu\n",s,h);
+	  }
+	  h=l&255;
+	  if(c==AND&&h==0)
+	    emit(f,"\tclrb\n");
+	  else if(c==XOR&&h==255)
+	    emit(f,"\tcomb\n");
+	  else if((c==AND&&h!=255)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+	    emit(f,"\t%sb\t#%lu\n",s,h);
+	}else{
+	  if(isreg(q2)){
+	    if(p->q2.reg==acc){
+	      if(c==XOR){
+		emit(f,"\tclrb\n");
+		if((t&NQ)!=CHAR) emit(f,"\tclra\n");
+	      }
+	    }else{
+	      if((t&NQ)==CHAR){
+		emit(f,SPUSH("a"));
+		push(1);
+		emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+		pop(1);
+	      }else{
+		emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+		push(2);
+		emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+		emit(f,"\t%sb\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+		pop(2);
+	      }
+	    }
+	  }else if((p->q2.flags&(REG|DREFOBJ))==DREFOBJ&&(t&NQ)!=CHAR){
+	    int xr=0;
+	    if(!regs[ix]) xr=ix;
+	    else if(!regs[iy]) xr=iy;
+	    else{
+	      xr=ix;
+	      emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[xr]);
+	      push(2);
+
+	    }
+	    BSET(regs_modified,xr);
+	    load_addr(f,xr,&p->q2);
+	    if((t&NQ)==CHAR)
+	      emit(f,"\t%sb\t0,%s\n",s,regnames[xr]);
+	    else{
+	      emit(f,"\t%sa\t0,%s\n",s,regnames[xr]);
+	      emit(f,"\t%sb\t1,%s\n",s,regnames[xr]);
+	    }
+	    if(regs[ix]&&xr==ix){
+	      emit(f,SPULL("x"));
+	      pop(2);
+	    }
+	  }else{
+	    emit(f,"\t%sb\t",s);
+	    if((t&NQ)!=CHAR) inc_addr(&p->q2,1,t);
+	    emit_obj(f,&p->q2,t);
+	    emit(f,"\n");
+	    if((t&NQ)!=CHAR){
+	      inc_addr(&p->q2,-1,t);
+	      emit(f,"\t%sa\t",s);
+	      emit_obj(f,&p->q2,t);
+	      emit(f,"\n");
+	    }
+	  }
+	}
+	cc=0;
+	store_reg(f,reg,&p->z,t);
+	continue;
+      }else if(c==COMPARE){
+	lastcomp=t;
+	if(isreg(q2)){
+	  emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+	  push(2);
+	}
+	if(reg==acc){
+	  if((t&NQ)==CHAR)
+	    emit(f,"\tcmpb\t");
+	  else
+	    emit(f,SCMP("d"));
+	}else if(reg==ix){
+	  emit(f,SCMP("x"));
+	}else if(reg==iy){
+	  emit(f,SCMP("y"));
+	}else if(reg==iu){
+	  emit(f,SCMP("u"));
+	}else
+	  ierror(0);
+	if(isreg(q2)){
+	  if(CPU==6812)
+	    emit(f,"2,%s+\n",regnames[sp]);
+	  else
+	    emit(f,",%s++\n",regnames[sp]);
+	  pop(2);
+	}else{
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+	continue;
+      }
+      ierror(0);
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  if(notpopped){
+    gen_pop(f,notpopped);
+    notpopped=0;
+  }
+  function_bottom(f,v,loff);
+  if(debug_info){
+    emit(f,"%s%d:\n",labprefix,++label);
+    dwarf2_function(f,v,label);
+    if(f) section=-1;
+  }     
+}
+
+int shortcut(int c,int t)
+{
+  if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
+  if((c==LSHIFT||c==RSHIFT)&&ISCHWORD(t&NQ)) return 1;
+  return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+  if(f&&stack_check)
+    emit(f,"\t.global\t%s__stack_check\n",idprefix);
+  while(p=firstfpc){
+    if(f){
+      if(section!=RODATA){
+	emit(f,rodataname);if(f) section=RODATA;
+      }
+      emit(f,"%s%d\n\t%s\t",labprefix,p->label,dct[LONG]);
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+  if(p->gpr) return 0;
+  if(ISSCALAR(t->flags)&&!ISFLOAT(t->flags)&&!ISLWORD(t->flags)){
+    p->gpr=1;
+    return acc;
+  }
+  return 0;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+  t&=NU;
+  if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}  
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==NPOINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==BIT){
+	if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
+      }else if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==BIT){
+	if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
+      }else if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==NPOINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==BIT){vmax=zc2zm(p->vchar);fprintf(f,"B%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);fprintf(f,"UB%d",!zumeqto(vmax,ul2zum(0UL)));}
+  if(t==CHAR){vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+} 
+void emitval(FILE *f,union atyps *p,int t)
+{
+  t&=NU;
+  if((t&NQ)==NPOINTER) t=(UNSIGNED|INT);
+  if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+	if(strstr(attr,STR_NEAR))
+	  p->flags=((p->flags&~NU)|NPOINTER);
+	if(strstr(attr,STR_FAR))
+	  p->flags=((p->flags&~NU)|FPOINTER);
+	if(strstr(attr,STR_HUGE))
+	  p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+      p->flags=((p->flags&~NU)|BIT);
+    p=p->next;
+  }
+}
+
+void init_db(FILE *f)
+{
+  dwarf2_setup(sizetab[HPOINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+  dwarf2_print_comp_unit_header(f);
+}
+void cleanup_db(FILE *f)
+{
+  dwarf2_cleanup(f);
+  if(f) section=-1;
+} 
diff --git a/machines/hc12/machine.dt b/machines/hc12/machine.dt
new file mode 100755
index 0000000..7c090f1
--- /dev/null
+++ b/machines/hc12/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S32BIEEEBE
+S32BIEEEBE
+S16BUbE S16BULE
+
+
diff --git a/machines/hc12/machine.h b/machines/hc12/machine.h
new file mode 100755
index 0000000..096e608
--- /dev/null
+++ b/machines/hc12/machine.h
@@ -0,0 +1,191 @@
+/*  Example of a code-generator for Motorola 68hc12 16bit microcontrollers.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them:      */
+/* - #define HAVE_EXT_TYPES
+   - #undef all standard types
+   - #define all standard types plus new types
+   - write eval_const and insert_const
+   - write typedefs for zmax and zumax
+   - write typname[]
+   - write conv_typ()
+   - optionally #define ISPOINTER, ISARITH, ISINT etc.
+   - optionally #define HAVE_TGT_PRINTVAL and write printval
+   - optionally #define POINTER_TYPE
+   - optionally #define HAVE_TGT_FALIGN and write falign
+   - optionally #define HAVE_TGT_SZOF and write szof
+   - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+    struct Var *v;
+};
+
+/* This type will be added to every IC. Can be used by the cg.      */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+  int flags;
+  int r;
+  long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 6
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+extern int MINADDI2P;
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+extern int switchsubs;
+#define SWITCHSUBS switchsubs
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+  int gpr;
+};
+
+/*  We use unsigned int as size_t rather than unsigned long which   */
+/*  is the default setting.                                         */
+#define HAVE_INT_SIZET 1
+
+/*  We have register pairs.                                         */
+#define HAVE_REGPAIRS 1
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define HAVE_POF2OPT 1
+
+/* Use char for return of comparison libcalls */
+#define LIBCALL_CMPTYPE CHAR
diff --git a/machines/i386/machine.c b/machines/i386/machine.c
new file mode 100755
index 0000000..68c553c
--- /dev/null
+++ b/machines/i386/machine.c
@@ -0,0 +1,2048 @@
+
+/*  Code generator for Intel 80386 or higher.                   */
+
+#include "supp.h"
+#include "vbc.h" /* nicht schoen, aber ... */
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for i386 V0.7a (c) in 1996-2006 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+                    0,0,0,0,
+		    0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+                           "merge-constants","elf","longalign","safe-fp",
+			   "use-framepointer"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","bshort","int","bint",
+		 "long","blong","long long","blong long",
+		 "float","bfloat","double","bdouble",
+		 "long double","blong double","void",
+                 "pointer","bpointer",
+		 "array","struct","union","enum","function"};
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[MAXR+1]={"noreg","%eax","%ecx","%edx","%ebx",
+                                "%esi","%edi","%ebp","%esp",
+                                "%st(0)","%st(1)","%st(2)","%st(3)",
+                                "%st(4)","%st(5)","%st(6)","%st(7)",
+                                "%eax/%edx","%esi/%edi"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0};
+
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+
+#define USEFP (g_flags[8]&USEDFLAG)
+
+static long malign[MAX_TYPE+1]=  {1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,1,1,2,2};
+static long msizetab[MAX_TYPE+1]={0,1,2,2,4,4,4,4,8,8,4,4,8,8,8,8,0,4,4,0,0,0,4,0};
+
+#define ISBE(x) (((x)&NQ)==BPOINTER||(((x)&NQ)>=BSHORT&&((x)&NQ)<=BLDOUBLE&&((x)&1)))
+#define LETYPE(x) ((x)-1)
+
+struct Typ ltyp={LONG},ldbl={DOUBLE};
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+
+static char *marray[]={"__I386__","__X86__",
+		       "__bigendian=__attr(\"bigendian\")",
+		       "__littleendian=__attr(\"littleendian\")",
+		       0};
+
+static int section=-1,newobj;
+static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="";
+static const int ax=1,cx=2,dx=3,bx=4,si=5,di=6,bp=7,sp=8,axdx=17,sidi=18;
+static char x_t[]={'?','b','w','w','l','l','l','l','?','?','s','s','l','l','l','l','v','l','l','a','s','u','e','f'};
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+#define isvaddr(x) ((p->x.flags&(VARADR|DREFOBJ))==VARADR)
+#define isvconst(x) (isconst(x)||isvaddr(x))
+
+static long loff,stackoffset,notpopped,dontpop,maxpushed,stack;
+
+static char *ccs[]={"z","nz","l","ge","le","g","mp"};
+static char *ccu[]={"z","nz","b","ae","be","a","mp"};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"sal","sar","add","sub","imul","div","mod"};
+static char *farithmetics[]={"f?","f?","fadd","fsub","fmul","fdiv","fsubr","fdivr"};
+static char *dct[]={"","byte","short","short","long","long",
+		    "long","long","long","long","long","long","long","long",
+		    "long","long","long","long","long","long"};
+
+static int pushedsize,pushorder=2;
+static int fst[8];
+static int cxl,dil,sil;
+static char *idprefix="",*labprefix="l";
+
+static struct fpconstlist {
+    struct fpconstlist *next;
+    int label,typ;
+    union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+	eval_const(&p->val,t);
+	if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return(p->label);
+	if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return(p->label);
+	if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return(p->label);
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+}
+static void push(long l)
+{
+  stackoffset-=l;
+  if(stackoffset<maxpushed) maxpushed=stackoffset;
+}
+static void pop(long l)
+{
+  stackoffset+=l;
+}
+
+void title(FILE *f)
+{
+  static int done;
+  extern char *inname; /*grmpf*/
+  if(!done&&f){
+    done=1;
+    emit(f,"\t.file\t\"%s\"\n",inname);
+  }
+} 
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/*  Gibt Objekt auf Bildschirm aus                      */
+{
+  if((p->flags&(DREFOBJ|KONST))==(DREFOBJ|KONST)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"(");
+  if(p->flags&VARADR) emit(f,"$");
+  if((p->flags&VAR)&&!(p->flags&REG)) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      if(USEFP||vlas){
+	if(!zmleq(l2zm(0L),p->v->offset))
+	  emit(f,"%ld(%s)",(long)(-zm2l(p->v->offset)+zm2l(p->val.vmax))+4,regnames[bp]);
+	else
+	  emit(f,"%ld(%s)",(long)(zm2l(p->v->offset)+zm2l(p->val.vmax))-loff-pushedsize,regnames[bp]);
+      }else{
+	if(!zmleq(l2zm(0L),p->v->offset))
+	  emit(f,"%ld(%s)",(long)(loff-zm2l(p->v->offset)+zm2l(p->val.vmax))-stackoffset+pushedsize,regnames[sp]);
+	else
+	  emit(f,"%ld(%s)",(long)(zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset),regnames[sp]);
+      }
+    }else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&REG){
+    if(p->reg>8){
+      int i;
+      for(i=0;i<8;i++){
+        if(fst[i]==p->reg)
+          emit(f,"%s",regnames[i+9]);
+      }
+    }else{
+      t&=NQ;
+      if(t==CHAR&&!(p->flags&DREFOBJ)) emit(f,"%%%cl",regnames[p->reg][2]);
+      else if(t==SHORT&&!(p->flags&DREFOBJ)) emit(f,"%%%s",regnames[p->reg]+2);
+      else emit(f,"%s",regnames[p->reg]);
+    }
+  }
+  if(p->flags&KONST){
+    if(ISFLOAT(t)){
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    }else{
+      emit(f,"$");emitval(f,&p->val,t&NU);
+    }
+  }
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,")");
+}
+
+static char *mregname(int r,int t)
+{
+  static char s[8];
+  t&=NQ;
+  if(t==CHAR) sprintf(s,"%%%cl",regnames[r][2]);
+  else if(t==SHORT) sprintf(s,"%%%s",regnames[r]+2);
+  else sprintf(s,"%s",regnames[r]);
+  return s;
+}
+
+
+static void emit_lword(FILE *f,struct obj *o)
+{
+  if(o->flags&KONST){
+    static struct obj cobj;
+    cobj.flags=KONST;
+    eval_const(&o->val,UNSIGNED|LLONG);
+    vumax=zumand(vumax,ul2zum(0xffffffff));
+    cobj.val.vulong=zum2zul(vumax);
+    emit_obj(f,&cobj,UNSIGNED|LONG);
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp)) ierror(0);
+    emit(f,"%s",regnames[rp.r1]);
+  }else
+    emit_obj(f,o,UNSIGNED|LONG);
+}
+
+static void emit_hword(FILE *f,struct obj *o)
+{
+  if(o->flags&KONST){
+    static struct obj cobj;
+    cobj.flags=KONST;
+    eval_const(&o->val,UNSIGNED|LLONG);
+    vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+    cobj.val.vulong=zum2zul(vumax);
+    emit_obj(f,&cobj,UNSIGNED|LONG);
+  }else if(o->flags&DREFOBJ){
+    if(!(o->flags&REG)) ierror(0);
+    emit(f,"4(%s)",regnames[o->reg]);
+  }else if(o->flags&REG){
+    if(!reg_pair(o->reg,&rp)) ierror(0);
+    emit(f,"%s",regnames[rp.r2]);
+  }else{
+    o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+    emit_obj(f,o,UNSIGNED|LONG);
+    o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+  }
+}
+
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+  /*FIXME: needs a location list and correct register trabslation */
+  struct obj o;
+  o.flags=REG;
+  if(USEFP||vlas)
+    o.reg=bp;
+  else
+    o.reg=sp;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+  static int dwarf_regs[17]={-1,0,1,2,3,6,7,5,4,16,17,18,19,20,21,22,23};
+  return dwarf_regs[r];
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+  if(USEFP||vlas){
+    if(!zmleq(l2zm(0L),v->offset))
+      return l2zm((long)(-zm2l(v->offset))+4);
+    else
+      return l2zm((long)(zm2l(v->offset))-loff-pushedsize);
+  }else{
+    if(!zmleq(l2zm(0L),v->offset))
+      return l2zm((long)(loff-zm2l(v->offset))+pushedsize);
+    else
+      return v->offset;
+  }
+}
+static void fxch(FILE *f,int i)
+{
+    int m;
+    emit(f,"\tfxch\t%s\n",regnames[i+9]);
+    m=fst[0];fst[0]=fst[i];fst[i]=m;
+}
+static int freest(void)
+{
+    int i;
+    for(i=0;i<8;i++){
+        if(fst[i]<0) return i;
+    }
+    for(i=0;i<8;i++){
+        if(fst[i]==0) return i;
+    }
+    ierror(0);
+}
+static void fpush(FILE *f)
+{
+    int i;
+    if(fst[7]>0){
+        i=freest();
+        if(fst[i]==0) emit(f,"\tffree\t%s\n",regnames[i+9]);
+        fxch(f,i);fxch(f,7);
+    }
+    for(i=7;i>0;i--)
+        fst[i]=fst[i-1];
+    fst[0]=-1;
+}
+static void fpop(void)
+{
+    int i;
+/*    if(fst[0]>0&&regs[fst[0]]) ierror(0);*/
+    for(i=0;i<7;i++)
+        fst[i]=fst[i+1];
+    fst[7]=-1;
+}
+static void fload(FILE *f,struct obj *o,int t)
+{
+    emit(f,"\tfld");
+    if((o->flags&(REG|DREFOBJ))==REG) emit(f,"\t");
+        else emit(f,"%c\t",x_t[t&NQ]);
+    emit_obj(f,o,t);emit(f,"\n");
+    fpush(f);
+}
+static void fstore(FILE *f,struct obj *o,int t)
+{
+    int i;
+    if((o->flags&(REG|DREFOBJ))==REG){
+        for(i=0;i<8;i++)
+            if(fst[i]==o->reg) fst[i]=0;
+        fst[0]=o->reg;
+    }else{
+        emit(f,"\tfstp%c\t",x_t[t&NQ]);emit_obj(f,o,t);
+        fpop();emit(f,"\n");
+    }
+}
+static void prfst(FILE *f,char *s)
+{
+    int i;
+    if(DEBUG==0) return;
+    emit(f,"#\t%s\t",s);
+    for(i=0;i<8;i++){
+        if(fst[i]>=0){
+            if(fst[i]==0) emit(f,"+++ ");
+              else        emit(f,"%s ",regnames[fst[i]]+3);
+        }else{
+            emit(f,"--- ");
+        }
+    }
+    emit(f,"\n");
+}
+static void finit(void)
+{
+    int i;
+    for(i=0;i<8;i++){
+        if(regs[i+9])
+            fst[i]=i+9;
+        else
+            fst[i]=-1;
+    }
+}
+static void forder(FILE *f)
+{
+    int i,m,unordered;
+    prfst(f,"forder");
+    for(i=0;i<8;i++){
+        if(fst[i]==0){emit(f,"\tffree\t%s\n",regnames[i+9]);fst[i]=-1;}
+    }
+oloop:
+    unordered=0;
+    for(i=0;i<8;i++){
+        if(fst[i]>0&&fst[i]!=i+9&&regs[fst[i]]){unordered=1;break;}
+    }
+    if(!unordered) return;
+    if(fst[0]>=0&&regs[fst[0]]){
+        if(fst[0]!=9){
+            fxch(f,fst[0]-9);
+            goto oloop;
+        }else{
+            fxch(f,freest());
+        }
+    }
+    for(i=1;i<8;i++){
+        if(fst[i]>=0&&fst[i]!=i+9&&regs[fst[i]]&&fst[i]!=9){
+            fxch(f,i);
+            goto oloop;
+        }
+    }
+    if(regs[9]){
+        for(i=1;i<8;i++){
+            if(fst[i]==9){ fxch(f,i);return;}
+        }
+    }
+}
+static void pr(FILE *f,struct IC *p)
+{
+    int i;
+    for(;pushorder>2;pushorder>>=1){
+        for(i=1;i<=8;i++){
+            if(regs[i]&pushorder){
+	      if(p->code==PUSH||p->code==CALL){
+		emit(f,"\tmovl\t%ld(%s),%s\n",loff-4-stackoffset,regnames[sp],regnames[i]);
+	      }else{
+                emit(f,"\tpopl\t%s\n",regnames[i]);
+                pop(4);
+	      }
+	      regs[i]&=~pushorder;
+            }
+        }
+    }
+    for(i=1;i<=8;i++)
+        if(regs[i]&2) regs[i]&=~2;
+}
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionskopf                       */
+{
+    int i;
+    if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+    if(v->storage_class==EXTERN){
+      if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+	emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+      emit(f,"%s%s:\n",idprefix,v->identifier);
+    }else
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    if(USEFP||vlas)
+      emit(f,"\tpushl\t%s\n\tmovl\t%s,%s\n",regnames[bp],regnames[sp],regnames[bp]);
+    for(pushedsize=0,i=1;i<sp;i++){
+        if(regused[i]&&!regscratch[i]){
+            emit(f,"\tpushl\t%s\n",regnames[i]);
+            pushedsize+=4;
+        }
+    }
+    if(offset) emit(f,"\tsubl\t$%ld,%%esp\n",offset);
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionsende                       */
+{
+    int i;
+    forder(f);
+    if(offset) emit(f,"\taddl\t$%ld,%%esp\n",offset);
+    for(i=sp-1;i>0;i--){
+        if(regused[i]&&!regscratch[i]){
+            emit(f,"\tpopl\t%s\n",regnames[i]);
+        }
+    }
+    if(USEFP||vlas) emit(f,"\tpopl\t%s\n",regnames[bp]);
+    emit(f,"\tret\n");
+    if(v->storage_class==EXTERN){
+      emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,.-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+    }else{
+      emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+      emit(f,"\t.size\t%s%ld,.-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+    }    
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+static int get_reg(FILE *f,struct IC *p,int type)
+{
+  int i;
+  /*  If we can use a register which was already used by the compiler */
+  /*  or it is a sratch register then we can use it without problems. */
+  for(i=1;i<=8;i++){
+    if(!regs[i]&&(regused[i]||regscratch[i])&&regok(i,type,0)){
+      regs[i]=2;
+      BSET(regs_modified,i);
+      return(i);
+    }
+  }
+  /*  Otherwise we have to save this register.                        */
+  /*  We may not use a register which is used in this IC.             */
+  for(i=1;i<=8;i++){
+    if(regs[i]<2&&regok(i,type,0)
+       &&(!(p->q1.flags&REG)||p->q1.reg!=i)
+       &&(!(p->q2.flags&REG)||p->q2.reg!=i)
+       &&(!(p->z.flags&REG)||p->z.reg!=i)
+       &&(p->code!=SETRETURN||p->z.reg!=i)
+       &&(p->code!=GETRETURN||p->q1.reg!=i) ){
+      
+      if(p->code==PUSH||p->code==CALL){
+	emit(f,"\tmovl\t%s,%ld(%s)\n",regnames[i],loff-4-stackoffset,regnames[sp]);
+      }else{
+	emit(f,"\tpushl\t%s\n",regnames[i]);
+	push(4);
+      }
+      /*  Mark register as pushed (taking care of the order). */
+      pushorder<<=1; regs[i]|=pushorder;
+      BSET(regs_modified,i);
+      return i;
+    }
+  }
+  ierror(0);
+}
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/*  Generates code to move object q (or register qr) into object z (or  */
+/*  register zr).                                                       */
+{
+  t&=NQ;
+  if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+  if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+  if((t&NQ)==LLONG){
+    if(qr&&zr&&qr==zr) return;
+    emit(f,"\tmovl\t");
+    if(qr){
+      if(!reg_pair(qr,&rp)) ierror(0);
+      emit(f,"%s",regnames[rp.r1]);
+    }else
+      emit_lword(f,q);
+    emit(f,",");
+    if(zr){
+      if(!reg_pair(zr,&rp)) ierror(0);
+      emit(f,"%s",regnames[rp.r1]);
+    }else
+      emit_lword(f,z);
+    emit(f,"\n");
+    emit(f,"\tmovl\t");
+    if(qr){
+      if(!reg_pair(qr,&rp)) ierror(0);
+      emit(f,"%s",regnames[rp.r2]);
+    }else
+      emit_hword(f,q);
+    emit(f,",");
+    if(zr){
+      if(!reg_pair(zr,&rp)) ierror(0);
+      emit(f,"%s",regnames[rp.r2]);
+    }else
+      emit_hword(f,z);
+    emit(f,"\n");
+    return;
+  }
+  if(qr&&zr){
+    if(qr!=zr)
+      emit(f,"\tmovl\t%s,%s\n",regnames[qr],regnames[zr]);
+    return;
+  }
+  if(zr&&(q->flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&q->val,t);
+    if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+      emit(f,"\txorl\t%s,%s\n",regnames[zr],regnames[zr]);
+      return;
+    }
+  }
+  emit(f,"\tmov%c\t",x_t[t&NQ]);
+  if(qr){
+    emit(f,"%s",mregname(qr,t));
+  }else
+    emit_obj(f,q,t);
+  emit(f,",");
+  if(zr){
+    emit(f,"%s",mregname(zr,t));
+  }else
+    emit_obj(f,z,t);
+  emit(f,"\n");
+}
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+    zumax p;int ln=1;
+    p=ul2zum(1UL);
+    while(ln<=32&&zumleq(p,x)){
+        if(zumeqto(x,p)) return ln;
+        ln++;p=zumadd(p,p);
+    }
+    return 0;
+}
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(4L);
+  char_bit=l2zm(8L);
+  if(g_flags[6]&USEDFLAG){
+    for(i=SHORT;i<=MAX_TYPE;i++) malign[i]=4;
+  }
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i=1;i<= 8;i++) {regsize[i]=l2zm(4L);regtype[i]=&ltyp;}
+  for(i=9;i<=16;i++) {regsize[i]=l2zm(8L);regtype[i]=&ldbl;}
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  t_min[BSHORT]=l2zm(-32768L);
+  t_min[BINT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[BLONG]=t_min(INT);
+  t_min[BLLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_max[BSHORT]=ul2zum(32767UL);
+  t_max[BINT]=ul2zum(2147483647UL);
+  t_max[BLONG]=t_max(INT);
+  t_max[BLLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[BSHORT]=ul2zum(65535UL);
+  tu_max[BINT]=ul2zum(4294967295UL);
+  tu_max[BLONG]=t_max(UNSIGNED|INT);
+  tu_max[BLLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  We only reserve the stack-pointer here.                     */
+  regsa[sp]=1;
+  if(USEFP) regsa[bp]=regscratch[bp]=1;
+  /*  We need at least one free slot in the flaoting point stack  */
+  regsa[16]=1;regscratch[16]=0;
+  /*  Use l%d as labels and _%s as identifiers by default. If     */
+  /*  -elf is specified we use .l%d and %s instead.               */
+  if(g_flags[5]&USEDFLAG) labprefix=".l"; else idprefix="_";
+  target_macros=marray;
+
+  declare_builtin("__mulll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negll",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__notll",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslll",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modll",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__modull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrll",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsrull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpll",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpull",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+  return 1;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+    if(ISFLOAT(t->flags)) return 9;
+    if((t->flags&NQ)==LLONG) return axdx;
+    if(ISSCALAR(t->flags)) return ax;
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r==axdx){
+    p->r1=ax;
+    p->r2=dx;
+    return 1;
+  }else if(r==sidi){
+    p->r1=si;
+    p->r2=di;
+    return 1;
+  }
+  return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+    if(r==0) return(0);
+    t&=NQ;
+    if(r>8&&r<axdx){
+      if(g_flags[7]&USEDFLAG) return 0;
+      if(ISFLOAT(t)) return 1;
+        else                  return 0;
+    }
+    if(r==axdx||r==sidi) 
+      return t==LLONG;
+    if(t==CHAR&&(r==si||r==di||r==bp)) return 0;
+    if(t<=BLONG) return 1;
+    if(ISPOINTER(t)) return 1;
+    return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  In this generic 32bit RISC cpu pointers and 32bit   */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ,of,tf;
+  of=ISBE(op);
+  tf=ISBE(tp);
+  if(of!=tf) return 1;
+  if(of) op=LETYPE(op);
+  if(tf) tp=LETYPE(tp);
+    
+  if(tp==POINTER&&op==POINTER) return 0;
+  if((t&UNSIGNED)&&(o&UNSIGNED)&&zmeqto(sizetab[tp],sizetab[op])) return 0;
+  if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return 0;
+  if(op==tp) return 0;
+  return 1;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG){
+      sprintf(fname,"__cmp%sll",(t&UNSIGNED)?"u":"");
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    if(c==CONVERT){
+      if(ISFLOAT(t)&&(t2&NU)==LLONG){
+	sprintf(fname,"__%cint64toflt%d",(t2&UNSIGNED)?'u':'s',(t==FLOAT)?32:64);
+	ret=fname;
+      }
+      if(ISFLOAT(t2)&&(t&NU)==LLONG){
+	sprintf(fname,"__flt%dto%cint64",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s');
+	ret=fname;
+      }
+    }
+    if((t&NQ)==LLONG){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==PMULT||(c>=EQUAL&&c<=GREATEREQ)||c==KOMPLEMENT||c==MINUS){
+	if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%sull",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LLONG){
+	  sprintf(fname,"__%sll",ename[c]);
+	  ret=fname;
+	}else printf("un %d\n",c);
+      }
+    }
+  }
+  return ret;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  title(f);
+  if(newobj) emit(f,"%ld\n",zm2l(size));
+  else   emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  title(f);
+  if(zm2l(align)>1) emit(f,"\t.align\t4\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  title(f);
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if((v->vtyp->flags&NQ)==FUNKT) return;
+    emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+    if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+    if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+    if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    if(section!=BSS)
+      emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
+    else{
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+      newobj=1;
+    }
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+      if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      if(section!=BSS)
+        emit(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier);
+      else{
+        emit(f,"\t.comm\t%s%s,",idprefix,v->identifier);
+	newobj=1;
+      }
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+    title(f);
+    emit(f,"\t.%s\t",dct[t&NQ]);
+    if(!p->tree){
+        if(ISFLOAT(t)){
+        /*  auch wieder nicht sehr schoen und IEEE noetig   */
+            unsigned char *ip;
+            ip=(unsigned char *)&p->val.vdouble;
+            emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+            if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+                emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+            }
+	}else if((t&NQ)==LLONG){
+	  zumax tmp;
+	  eval_const(&p->val,t);
+	  tmp=vumax;
+	  vumax=zumand(vumax,ul2zum(0xffffffff));
+	  gval.vulong=zum2zul(vumax);
+	  emitval(f,&gval,UNSIGNED|LONG);
+	  emit(f,",");
+	  vumax=zumand(zumrshift(tmp,ul2zum(32UL)),ul2zum(0xffffffff));
+	  gval.vulong=zum2zul(vumax);
+	  emitval(f,&gval,UNSIGNED|LONG);
+        }else{
+            emitval(f,&p->val,t&NU);
+        }
+    }else{
+        int m=p->tree->o.flags;
+        p->tree->o.flags&=~VARADR;
+        emit_obj(f,&p->tree->o,t&NU);
+        p->tree->o.flags=m;
+    }
+    emit(f,"\n");newobj=0;
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+    int c,t,lastcomp=0,reg;
+    struct IC *m;
+    if(DEBUG&1) printf("gen_code()\n");
+    for(c=1;c<=15;c++) regs[c]=regsa[c];
+    regs[16]=0;
+    for(c=1;c<=MAXR;c++){
+      if(regsa[c]||regused[c]){
+	BSET(regs_modified,c);
+      }
+    }
+    title(f);
+    loff=((zm2l(offset)+3)/4)*4;
+    for(m=p;m;m=m->next){
+      /* do we need another stack-slot? */
+      /* could do a more precise check */
+      if((m->code==PUSH&&(m->q1.flags&(REG|DREFOBJ))==DREFOBJ)||
+	 (m->code==CALL&&(m->q1.flags&DREFOBJ))||
+	 (m->code==CONVERT&&!ISFLOAT(m->typf)&&ISFLOAT(m->typf2)) ){
+	loff+=4;
+	break;
+      }
+    }
+    function_top(f,v,loff);
+    stackoffset=notpopped=dontpop=0;
+    finit();
+    for(;p;pr(f,p),p=p->next){
+        c=p->code;t=p->typf;
+	if(debug_info)
+	  dwarf2_line_info(f,p);
+        if(c==NOP) continue;
+        if(c==SUBPFP) c=SUB;
+        if(c==SUBIFP) c=SUB;
+        if(c==ADDI2P) c=ADD;
+        if(c==ALLOCREG){
+            regs[p->q1.reg]=1;
+            continue;
+        }
+        if(c==FREEREG){
+            if(p->q1.reg>=9){
+                for(c=0;c<8;c++)
+                    if(fst[c]==p->q1.reg) fst[c]=0;
+            }
+            regs[p->q1.reg]=0;
+            continue;
+        }
+        if(notpopped&&!dontpop){
+	  if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+	    emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+	    pop(notpopped);
+	    notpopped=0;
+	  }
+        }
+
+	if(c==COMPARE&&isconst(q2)&&(t&NQ)!=LLONG){
+	  struct case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
+	  if(ct&&ct->num>=JUMP_TABLE_LENGTH){
+	    int r,defl,tabl=++label;
+	    long l;unsigned long ul;
+	    /*FIXME: we do not generate a jump-table if we do not have a
+	      free register */
+	    for(r=1;r<=8;r++){
+	      if(!regs[r]&&regscratch[r])
+		break;
+	    }
+	    if(r<=8){
+	      BSET(regs_modified,r);
+	      if(ct->next_ic->code==BRA)
+		defl=ct->next_ic->typf;
+	      else
+		defl=++label;
+	      if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+		p->q1.flags&=~DREFOBJ;
+		emit(f,"\tmovl\t");
+		emit_obj(f,&p->q1,POINTER);
+		emit(f,",%s\n",regnames[r]);
+		p->q1.flags|=(REG|DREFOBJ);
+		p->q1.reg=r;
+	      }
+	      emit(f,"\tmovl\t");
+	      emit_obj(f,&p->q1,t);
+	      emit(f,",%s\n",regnames[r]);
+	      emit(f,"\tsubl\t$");
+	      if(t&UNSIGNED)
+		emitzum(f,ct->min.vumax);
+	      else
+		emitzm(f,ct->min.vmax);
+	      emit(f,",%s\n",regnames[r]);
+	      emit(f,"\tcmpl\t$");
+	      emitzum(f,ct->diff);
+	      emit(f,",%s\n",regnames[r]);
+	      emit(f,"\tja\t%s%d\n",labprefix,defl);
+	      emit(f,"\tjmp\t*%s%d(,%s,4)\n",labprefix,tabl,regnames[r]);
+	      emit(f,"\t.align\t2\n");
+	      emit(f,"%s%d:\n",labprefix,tabl);
+	      emit_jump_table(f,ct,"\t.long\t",labprefix,defl);
+	      if(ct->next_ic->code!=BRA){
+		emit(f,"%s%d:\n",labprefix,defl);
+		p=ct->next_ic->prev;
+	      }else
+		p=ct->next_ic;
+	      continue;
+	    }
+	  }
+	}
+        if(c==LABEL){
+	  if(t>label) ierror(0);
+	  forder(f);
+	  emit(f,"%s%d:\n",labprefix,t);
+	  continue;
+	}
+        if(c>=BEQ&&c<=BRA){
+            forder(f);
+            if(lastcomp&UNSIGNED) emit(f,"\tj%s\t%s%d\n",ccu[c-BEQ],labprefix,t);
+                else              emit(f,"\tj%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+            continue;
+        }
+        if(c==MOVETOREG){
+            if(p->z.reg>8){
+                for(c=0;c<8;c++){
+                    if(fst[c]==p->z.reg) fst[c]=0;
+                }
+                fload(f,&p->q1,DOUBLE);
+                fst[0]=p->z.reg;
+                continue;
+            }
+            move(f,&p->q1,0,0,p->z.reg,LONG);
+            continue;
+        }
+        if(c==MOVEFROMREG){
+            if(p->q1.reg>8){
+                if(fst[0]!=p->q1.reg){
+                    for(c=0,reg=-1;c<8;c++){
+                        if(fst[c]==p->q1.reg) reg=c;
+                    }
+                    if(reg<0) ierror(0);
+                    fxch(f,reg);
+                }
+                emit(f,"\tfstpl\t");emit_obj(f,&p->z,DOUBLE);
+                emit(f,"\n");fpop();
+                continue;
+            }
+            move(f,0,p->q1.reg,&p->z,0,LONG);
+            continue;
+        }
+        if((p->q1.flags&(DREFOBJ|REG|KONST))==DREFOBJ||((p->q1.flags&DREFOBJ)&&ISBE(p->q1.dtyp))){
+	  reg=get_reg(f,p,LONG);
+	  move(f,&p->q1,0,0,reg,LONG);
+	  p->q1.flags|=REG;p->q1.reg=reg;
+	  p->q1.flags&=~KONST;
+	  if(ISBE(p->q1.dtyp))
+	    emit(f,"\tbswap\t%s\n",regnames[reg]);
+        }
+        if((p->q2.flags&(DREFOBJ|REG|KONST))==DREFOBJ||((p->q2.flags&DREFOBJ)&&ISBE(p->q2.dtyp))){
+	  reg=get_reg(f,p,LONG);
+	  move(f,&p->q2,0,0,reg,LONG);
+	  p->q2.flags|=REG;p->q2.reg=reg;
+	  p->q2.flags&=~KONST;
+	  if(ISBE(p->q2.dtyp))
+	    emit(f,"\tbswap\t%s\n",regnames[reg]);
+        }
+        if((p->z.flags&(DREFOBJ|REG|KONST))==DREFOBJ||((p->z.flags&DREFOBJ)&&ISBE(p->z.dtyp))){
+	  reg=get_reg(f,p,LONG);
+	  /* sehr unschoen */
+	  if(c==GETRETURN&&reg==p->q1.reg) reg=get_reg(f,p,LONG);
+	  move(f,&p->z,0,0,reg,LONG);
+	  p->z.flags|=REG;p->z.reg=reg;
+	  p->z.flags&=~KONST;
+	  if(ISBE(p->z.dtyp))
+	    emit(f,"\tbswap\t%s\n",regnames[reg]);
+        }
+	if((t&NQ)==LDOUBLE) p->typf=t=DOUBLE;
+	if(c==CONVERT&&(t&NQ)==LLONG&&(p->typf2&NQ)==LLONG) c=ASSIGN;
+        if(c==CONVERT){
+            int to=p->typf2&NU;
+	    if(to==LDOUBLE) to=DOUBLE;
+            if((t&NU)==LONG) t=INT;
+            if((t&NU)==(UNSIGNED|LONG)||(t&NU)==POINTER) t=(UNSIGNED|INT);
+            if((to&NU)==LONG) to=INT;
+            if((to&NU)==(UNSIGNED|LONG)||(to&NU)==POINTER) to=(UNSIGNED|INT);
+	    if((to&NQ)==LLONG){
+	      int useqreg=0;
+	      if(isreg(z)) 
+		reg=p->z.reg;
+	      else if(isreg(q1)&&reg_pair(p->q1.reg,&rp)&&regok(rp.r1,t,0))
+		reg=useqreg=rp.r1;
+	      else
+		reg=get_reg(f,p,INT);
+	      if(!useqreg){
+		emit(f,"\tmovl\t");
+		if(isreg(q1)){
+		  if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+		  emit(f,"%s",regnames[rp.r1]);
+		}else{
+		  emit_obj(f,&p->q1,INT);
+		}
+		emit(f,",%s\n",regnames[reg]);
+	      }
+	      if(!isreg(z)||p->z.reg!=reg)
+		move(f,0,reg,&p->z,0,t);
+	      continue;
+	    }
+            if((to&NQ)<=INT&&(t&NQ)<=LLONG){
+	      if(isreg(z)){
+		reg=p->z.reg;
+		if(reg_pair(reg,&rp)) reg=rp.r1;
+	      }else if(isreg(q1)&&regok(p->q1.reg,t,0))
+		reg=p->q1.reg;
+	      else
+		reg=get_reg(f,p,((to&NQ)==CHAR||(t&NQ)==CHAR)?CHAR:LONG);
+	      if((to&NQ)<=SHORT){
+		emit(f,"\tmov%c%cl\t",(to&UNSIGNED)?'z':'s',x_t[to&NQ]);
+		emit_obj(f,&p->q1,to);
+		emit(f,",%s\n",regnames[reg]);
+	      }else{
+		move(f,&p->q1,0,0,reg,to);
+	      }
+	      if((t&NQ)==LLONG){
+		if(isreg(z)){
+		  if(to&UNSIGNED)
+		    emit(f,"\txorl\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+		  else{
+		    move(f,0,reg,0,rp.r2,INT);
+		    emit(f,"\tsarl\t$31,%s\n",regnames[rp.r2]);
+		  }
+		}else{
+		  move(f,0,reg,&p->z,0,INT);
+		  if(to&UNSIGNED){
+		    emit(f,"\tmovl\t$0,");
+		    emit_hword(f,&p->z);
+		    emit(f,"\n");
+		  }else{
+		    emit(f,"\tsarl\t$31,%s\n",regnames[reg]);
+		    emit(f,"\tmovl\t%s,",regnames[reg]);
+		    emit_hword(f,&p->z);
+		    emit(f,"\n");
+		  }
+		}
+	      }else
+		move(f,0,reg,&p->z,0,t);
+	      continue;
+            }
+            if(ISFLOAT(t)){
+                if(ISFLOAT(to)){
+                    if(isreg(q1)&&fst[0]==p->q1.reg){
+                        if(isreg(z)){
+                            if(p->z.reg==fst[0]) continue;
+                            for(reg=0,c=7;c>=0;c--){
+                                if(fst[c]==p->z.reg){reg=c;break;}
+                                if(fst[c]<0) reg=c;
+                            }
+                            fst[reg]=p->z.reg;
+                        }
+                        emit(f,"\tfst%c\t",x_t[t&NQ]);
+                        emit_obj(f,&p->z,t);emit(f,"\n");
+                        continue;
+                    }
+                    fload(f,&p->q1,to);
+                    fstore(f,&p->z,t);
+                    continue;
+                }
+                if((to&NQ)<=SHORT){
+                    if(isreg(q1)){
+                        reg=p->q1.reg;
+                        if(to&UNSIGNED){
+                            emit(f,"\tandl\t$%ld,%s\n",(to&NQ)==CHAR?255L:65535L,regnames[reg]);
+                        }else{
+/*                            emit(f,"\tc%ctl\t%s\n",x_t[to&NQ],regnames[reg]);*/
+                            if((to&NQ)==SHORT){
+                                emit(f,"\tmovswl\t%%%s,%s\n",regnames[reg]+2,regnames[reg]);
+                            }else{
+                                emit(f,"\tmovsbl\t%%%cl,%s\n",regnames[reg][2],regnames[reg]);
+                            }
+                        }
+                    }else{
+                        reg=get_reg(f,p,LONG);
+                        if(to&UNSIGNED){
+                            emit(f,"\tmovz%cl\t",x_t[to&NQ]);
+                        }else{
+                            emit(f,"\tmovs%cl\t",x_t[to&NQ]);
+                        }
+                        emit_obj(f,&p->q1,to);emit(f,",%s\n",regnames[reg]);
+                    }
+                    emit(f,"\tpushl\t%s\n",regnames[reg]);
+                    emit(f,"\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[sp],regnames[sp]);
+                }else{
+                    if(to&UNSIGNED){
+                        emit(f,"\tpushl\t$0\n\tpushl\t");
+			push(4);
+                        emit_obj(f,&p->q1,to);
+                        emit(f,"\n\tfildq\t(%s)\n\taddl\t$8,%s\n",regnames[sp],regnames[sp]);
+			pop(4);
+                    }else{
+                        if(isreg(q1)){
+                            emit(f,"\tpushl\t%s\n\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[p->q1.reg],regnames[sp],regnames[sp]);
+                        }else{
+                            emit(f,"\tfildl\t");emit_obj(f,&p->q1,t);
+                            emit(f,"\n");
+                        }
+                    }
+                }
+                fpush(f);
+                fstore(f,&p->z,t);
+                continue;
+            }
+            if(ISFLOAT(to)){
+	      int cwr;
+	      if(isreg(z)&&regok(p->z.reg,CHAR,0))
+		cwr=p->z.reg;
+	      else
+		cwr=get_reg(f,p,CHAR);
+	      emit(f,"\tfnstcw\t%d(%s)\n",loff-4-stackoffset,regnames[sp]);
+	      emit(f,"\tmovw\t%d(%s),%%%s\n",loff-4-stackoffset,regnames[sp],regnames[cwr]+2);
+	      emit(f,"\tmovb\t$12,%%%ch\n",regnames[cwr][2]);
+	      emit(f,"\tmovw\t%%%s,%d(%s)\n",regnames[cwr]+2,loff-2-stackoffset,regnames[sp]);
+	      emit(f,"\tfldcw\t%d(%s)\n",loff-2-stackoffset,regnames[sp]);
+	      if(isreg(q1)&&fst[0]==p->q1.reg){
+		if((t&NQ)==CHAR){
+		  if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,CHAR);
+		  emit(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+		  move(f,0,reg,&p->z,0,t);
+		}else{
+		  if(isreg(z)){
+		    emit(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+		    push(4);
+		    emit_obj(f,&p->z,t);emit(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+		    pop(4);
+		  }else{
+		    emit(f,"\tfist%c\t",x_t[t&NQ]);
+		    emit_obj(f,&p->z,t);emit(f,"\n");
+		  }
+		}
+	      }else{
+		fload(f,&p->q1,to);
+		if((t&NQ)==CHAR){
+		  if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,CHAR);
+		  emit(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+		  fpop(); move(f,0,reg,&p->z,0,t);
+		}else{
+		  if(isreg(z)){
+		    emit(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+		    push(4);
+		    emit_obj(f,&p->z,t);
+		    emit(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+		    pop(4);
+		    fpop();
+		  }else{
+		    emit(f,"\tfistp%s\t",(t&NQ)==SHORT?"":"l");
+		    emit_obj(f,&p->z,t);emit(f,"\n");fpop();
+		  }
+		}
+	      }
+	      emit(f,"\tfldcw\t%d(%s)\n",loff-4-stackoffset,regnames[sp]);
+	      continue;
+            }
+pric2(stdout,p);
+            ierror(0);
+        }
+        if(c==MINUS||c==KOMPLEMENT){
+            char *s;
+            if(ISFLOAT(t)){
+                if(isreg(z)&&p->z.reg==9&&isreg(q1)&&p->q1.reg==9){
+                    emit(f,"\tfchs\n");
+                    continue;
+                }
+                fload(f,&p->q1,t);
+                emit(f,"\tfchs\n");
+                emit(f,"\tfstp%c\t",x_t[t&NQ]);
+                emit_obj(f,&p->z,t);emit(f,"\n");
+                fpop();
+                continue;
+            }
+            if(c==MINUS) s="neg"; else s="not";
+            if(compare_objects(&p->q1,&p->q2)){
+                emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+                emit_obj(f,&p->z,t);emit(f,"\n");
+                continue;
+            }
+            if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,t);
+            move(f,&p->q1,0,0,reg,t);
+            emit(f,"\t%s%c\t%s\n",s,x_t[t&NQ],regnames[reg]);
+            move(f,0,reg,&p->z,0,t);
+            continue;
+        }
+        if(c==SETRETURN){
+            if(p->z.reg){
+                if(p->z.reg==9){
+                    if(!isreg(q1)||fst[0]!=p->q1.reg)
+                        fload(f,&p->q1,t);
+                }else{
+                    move(f,&p->q1,0,0,p->z.reg,t);
+                }
+		BSET(regs_modified,p->z.reg);
+            }
+            continue;
+        }
+        if(c==GETRETURN){
+            if(p->q1.reg){
+                if(p->q1.reg==9){
+                    if(!isreg(z)||fst[0]!=p->z.reg)
+                        fstore(f,&p->z,t);
+                }else{
+                    move(f,0,p->q1.reg,&p->z,0,t);
+                }
+            }
+            continue;
+        }
+        if(c==CALL){
+            int reg;
+            if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+              emit_inline_asm(f,p->q1.v->fi->inline_asm);
+            }else{
+              if(p->q1.flags&DREFOBJ){
+                if(!(p->q1.flags&REG)) ierror(0);
+                emit(f,"\tcall\t*%s\n",regnames[p->q1.reg]);
+              }else{
+                emit(f,"\tcall\t");emit_obj(f,&p->q1,t);
+                emit(f,"\n");
+              }
+            }
+            if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+              notpopped+=zm2l(p->q2.val.vmax);
+              dontpop-=zm2l(p->q2.val.vmax);
+              if(!(g_flags[2]&USEDFLAG)&&!vlas&&stackoffset==-notpopped){
+                /*  Entfernen der Parameter verzoegern  */
+              }else{
+                emit(f,"\taddl\t$%ld,%%esp\n",zm2l(p->q2.val.vmax));
+                pop(zm2l(p->q2.val.vmax));
+                notpopped-=zm2l(p->q2.val.vmax);
+              }
+            }
+	    if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	      bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+	    }else{
+	      int i;
+	      for(i=1;i<=MAXR;i++){
+		if(regscratch[i]) BSET(regs_modified,i);
+	      }
+	    }
+            continue;
+        }
+        if(c==ASSIGN||c==PUSH){
+            if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+            if(ISFLOAT(t)){
+                if(c==ASSIGN){
+                    prfst(f,"fassign");
+                    fload(f,&p->q1,t);
+                    fstore(f,&p->z,t);
+                    continue;
+                }else if(isreg(q1)){
+                    prfst(f,"fpush");
+                    emit(f,"\tsubl\t$%ld,%s\n",zm2l(sizetab[t&NQ]),regnames[sp]);
+                    push(zm2l(sizetab[t&NQ]));
+                    if(fst[0]==p->q1.reg){
+                        emit(f,"\tfst%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+                    }else{
+                        fload(f,&p->q1,t);
+                        emit(f,"\tfstp%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+                        fpop();
+                    }
+                    continue;
+                }
+            }
+	    if((t&NQ)==LLONG){
+	      if(c==ASSIGN){
+		if(isconst(q1)||isreg(q1)||isreg(z)){
+		  move(f,&p->q1,0,&p->z,0,t);
+		}else{
+		  int r=get_reg(f,p,INT);
+		  emit(f,"\tmovl\t");
+		  emit_lword(f,&p->q1);
+		  emit(f,",%s\n",regnames[r]);
+		  emit(f,"\tmovl\t%s,",regnames[r]);
+		  emit_lword(f,&p->z);
+		  emit(f,"\n");
+		  emit(f,"\tmovl\t");
+		  emit_hword(f,&p->q1);
+		  emit(f,",%s\n",regnames[r]);
+		  emit(f,"\tmovl\t%s,",regnames[r]);
+		  emit_hword(f,&p->z);
+		  emit(f,"\n");
+		}
+	      }else{
+		emit(f,"\tpushl\t");
+		emit_hword(f,&p->q1);
+		emit(f,"\n");
+		push(4);
+		emit(f,"\tpushl\t");
+		emit_lword(f,&p->q1);
+		emit(f,"\n");
+		push(4);
+	      }
+	      continue;
+	    }
+            if(!ISSCALAR(t)||!zmeqto(p->q2.val.vmax,sizetab[t&NQ])||!zmleq(p->q2.val.vmax,l2zm(4L))){
+                int mdi=di,msi=si,m=0;long l;
+                l=zm2l(p->q2.val.vmax);
+                if(regs[cx]){m|=1;if(!cxl)cxl=++label;emit(f,"\tmovl\t%s,%s%d\n",regnames[cx],labprefix,cxl);}
+                if(regs[msi]||!regused[msi]){m|=2;if(!sil)sil=++label;emit(f,"\tmovl\t%s,%s%d\n",regnames[msi],labprefix,sil);}
+                if(regs[mdi]||!regused[mdi]){m|=4;if(!dil)dil=++label;emit(f,"\tmovl\t%s,%s%d\n",regnames[mdi],labprefix,dil);}
+                if((p->z.flags&REG)&&p->z.reg==msi&&(p->q1.flags&REG)&&p->q1.reg==mdi){
+                    msi=di;mdi=si;
+                    m|=8;
+                }
+                if(!(p->z.flags&REG)||p->z.reg!=msi){
+                    emit(f,"\tleal\t");emit_obj(f,&p->q1,t);
+                    emit(f,",%s\n",regnames[msi]);
+                }
+                if(c==PUSH){
+                    emit(f,"\tsubl\t$%ld,%s\n\tmovl\t%s,%s\n",l,regnames[sp],regnames[sp],regnames[mdi]);
+                    push(l);
+		    l=zm2l(p->z.val.vmax);
+                }else{
+                    emit(f,"\tleal\t");emit_obj(f,&p->z,t);
+                    emit(f,",%s\n",regnames[mdi]);
+                }
+                if((p->z.flags&REG)&&p->z.reg==msi){
+                    emit(f,"\tleal\t");emit_obj(f,&p->q1,t);
+                    emit(f,",%s\n",regnames[msi]);
+                }
+                if(m&8){
+                    msi=si;mdi=di;
+                    emit(f,"\txchg\t%s,%s\n",regnames[msi],regnames[mdi]);
+                }
+                if((t&NQ)==ARRAY||(t&NQ)==CHAR||l<4){
+                    emit(f,"\tmovl\t$%ld,%s\n\trep\n\tmovsb\n",l,regnames[cx]);
+                }else{
+                    if(l>=8)
+                        emit(f,"\tmovl\t$%ld,%s\n\trep\n",l/4,regnames[cx]);
+                    emit(f,"\tmovsl\n");
+                    if(l&2) emit(f,"\tmovsw\n");
+                    if(l&1) emit(f,"\tmovsb\n");
+                }
+                if(m&4) emit(f,"\tmovl\t%s%d,%s\n",labprefix,dil,regnames[mdi]);
+                if(m&2) emit(f,"\tmovl\t%s%d,%s\n",labprefix,sil,regnames[msi]);
+                if(m&1) emit(f,"\tmovl\t%s%d,%s\n",labprefix,cxl,regnames[cx]);
+                continue;
+            }
+            if(c==PUSH){
+                emit(f,"\tpush%c\t",(t&NQ)==FLOAT?x_t[LONG]:x_t[t&NQ]);
+                emit_obj(f,&p->q1,t);emit(f,"\n");
+                push(zm2l(p->q2.val.vmax));
+                continue;
+            }
+            if(c==ASSIGN){
+                if(isconst(q1)){
+                    move(f,&p->q1,0,&p->z,0,t);
+                    continue;
+                }
+                if(isreg(z)) reg=p->z.reg;
+                else if(isreg(q1)) reg=p->q1.reg;
+                else reg=get_reg(f,p,t);
+                move(f,&p->q1,0,0,reg,t);
+                move(f,0,reg,&p->z,0,t);
+                continue;
+            }
+            ierror(0);
+        }
+        if(c==ADDRESS){
+            if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,LONG);
+            emit(f,"\tleal\t");emit_obj(f,&p->q1,t);
+            emit(f,",%s\n",regnames[reg]);
+            move(f,0,reg,&p->z,0,POINTER);
+            continue;
+        }
+        if(c==TEST){
+            lastcomp=t;
+            if(ISFLOAT(t)){
+                if(isreg(q1)&&fst[0]==p->q1.reg){
+                    emit(f,"\tftst\n");lastcomp|=UNSIGNED;
+                    continue;
+                }else{
+                    p->code=c=COMPARE;
+                    p->q2.flags=KONST;
+                    p->q2.val.vldouble=d2zld(0.0);
+                    if((t&NQ)==FLOAT) p->q2.val.vfloat=zld2zf(p->q2.val.vldouble);
+                    if((t&NQ)==DOUBLE) p->q2.val.vdouble=zld2zd(p->q2.val.vldouble);
+
+                    /*  fall through to COMPARE */
+                }
+            }else{
+              if(isvconst(q1)){
+                reg=get_reg(f,p,t);
+                move(f,&p->q1,0,0,reg,t);
+                p->q1.flags=REG;
+                p->q1.reg=reg;
+              }
+	      if((t&NQ)==LLONG){
+		reg=get_reg(f,p,INT);
+		if(isreg(q1)){
+		  if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+		  move(f,0,rp.r1,0,reg,INT);
+		  emit(f,"\torl\t%s,%s\n",regnames[rp.r2],regnames[reg]);
+		}else{
+		  move(f,&p->q1,0,0,reg,INT);
+		  emit(f,"\torl\t");
+		  emit_hword(f,&p->q1);
+		  emit(f,",%s\n",regnames[reg]);
+		}
+		continue;
+	      }
+	      if(isreg(q1)){
+		emit(f,"\ttest%c\t",x_t[t&NQ]);
+                emit_obj(f,&p->q1,t);emit(f,",");
+                emit_obj(f,&p->q1,t);emit(f,"\n");
+	      }else{
+		emit(f,"\tcmp%c\t$0,",x_t[t&NQ]);
+		emit_obj(f,&p->q1,t);emit(f,"\n");
+	      }
+	      continue;
+            }
+        }
+        if(c==COMPARE){
+            lastcomp=t;
+            if(isreg(q2)||isvconst(q1)){
+                struct IC *b=p->next;
+                struct obj o;
+                o=p->q1;p->q1=p->q2;p->q2=o;
+                while(b&&b->code==FREEREG) b=b->next;
+                if(!b) ierror(0);
+                if(b->code==BLT) b->code=BGT;
+                else if(b->code==BLE) b->code=BGE;
+                else if(b->code==BGT) b->code=BLT;
+                else if(b->code==BGE) b->code=BLE;
+            }
+            if(ISFLOAT(t)){
+                prfst(f,"fcomp");
+                if(isreg(q1)&&p->q1.reg==fst[0]){
+                    emit(f,"\tfcom%c\t",x_t[t&NQ]);
+                    emit_obj(f,&p->q2,t);emit(f,"\n");
+                }else{
+                    fload(f,&p->q1,t);
+                    emit(f,"\tfcomp%c\t",x_t[t&NQ]);
+                    emit_obj(f,&p->q2,t);emit(f,"\n");
+                    fpop();
+                }
+		if(regs[ax]) emit(f,"\tpushl\t%s\n",regnames[ax]);
+                emit(f,"\tfstsw\n\tsahf\n");
+		if(regs[ax]) emit(f,"\tpopl\t%s\n",regnames[ax]);
+                lastcomp|=UNSIGNED;
+                continue;
+            }
+            if(!isreg(q1)){
+                if(!isreg(q2)&&(!isvconst(q2)||isvconst(q1))){
+                    reg=get_reg(f,p,t);
+                    move(f,&p->q1,0,0,reg,t);
+                    p->q1.flags=REG;
+                    p->q1.reg=reg;
+                }
+            }
+	    if(isreg(q1)&&isconst(q2)){
+	      eval_const(&p->q2.val,t);
+	      if(zmeqto(vmax,l2zm(0L))){
+		emit(f,"\ttest%c\t",x_t[t&NQ]);
+                emit_obj(f,&p->q1,t);emit(f,",");
+                emit_obj(f,&p->q1,t);emit(f,"\n");
+		continue;
+	      }
+	    }
+	    if(isreg(q2)&&isconst(q1)){
+	      eval_const(&p->q1.val,t);
+	      if(zmeqto(vmax,l2zm(0L))){
+		emit(f,"\ttest%c\t",x_t[t&NQ]);
+                emit_obj(f,&p->q2,t);emit(f,",");
+                emit_obj(f,&p->q2,t);emit(f,"\n");
+		continue;
+	      }
+	    }
+            emit(f,"\tcmp%c\t",x_t[t&NQ]);
+            emit_obj(f,&p->q2,t);emit(f,",");
+            emit_obj(f,&p->q1,t);emit(f,"\n");
+            continue;
+        }
+        if(ISFLOAT(t)){
+            char s[2];
+            prfst(f,"fmath");
+            if(isreg(q2)) s[0]=0; else {s[0]=x_t[t&NQ];s[1]=0;}
+            if(isreg(z)&&isreg(q1)&&p->q1.reg==fst[0]&&p->z.reg==fst[0]){
+                emit(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+                emit_obj(f,&p->q2,t); emit(f,"\n");continue;
+            }
+            fload(f,&p->q1,t);
+            emit(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+            emit_obj(f,&p->q2,t); emit(f,"\n");
+            fstore(f,&p->z,t); continue;
+        }
+        if((c==MULT||((c==DIV||c==MOD)&&(p->typf&UNSIGNED)))&&isconst(q2)){
+            long ln;
+            eval_const(&p->q2.val,t);
+            if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+                if(ln=pof2(vumax)){
+                    if(c==MOD){
+                        vmax=zmsub(vmax,l2zm(1L));
+                        p->code=AND;
+                    }else{
+                        vmax=l2zm(ln-1);
+                        if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+                    }
+                    c=p->code;
+		    gval.vmax=vmax;
+		    eval_const(&gval,MAXINT);
+		    if(c==AND){
+		      insert_const(&p->q2.val,t);
+		    }else{
+		      insert_const(&p->q2.val,INT);
+		      p->typf2=INT;
+		    }
+                }
+            }
+        }
+        if(c==MOD||c==DIV){
+            int m=0;
+	    BSET(regs_modified,dx);
+	    BSET(regs_modified,ax);
+            if(regs[ax]&&(!isreg(z)||p->z.reg!=ax)){
+                emit(f,"\tpushl\t%s\n",regnames[ax]);
+		push(4);
+		m|=1;
+            }
+            if(isreg(q2)&&p->q2.reg==ax){
+                emit(f,"\tpushl\t%s\n",regnames[ax]);
+		push(4);
+		m|=16;
+            }
+            if(regs[dx]&&(!isreg(z)||p->z.reg!=dx)){
+                emit(f,"\tpushl\t%s\n",regnames[dx]);
+		push(4);
+		m|=2;
+            }
+            if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(p->q2.reg==ax||p->q2.reg==dx)){
+                move(f,&p->q2,0,0,dx,t);
+                emit(f,"\tpushl\t%s\n",regnames[dx]);
+		push(4);
+                m|=8;
+            }
+	    if(isreg(q1)&&p->q1.reg==dx&&(m&10)==10)
+	      emit(f,"\tmovl\t4(%s),%s\n",regnames[sp],regnames[ax]);
+	    else
+	      move(f,&p->q1,0,0,ax,t);
+            if(isconst(q2)){
+                emit(f,"\tpush%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+                emit(f,"\n");
+		push(4);
+		m|=4;
+            }
+	    if(isreg(q2)&&p->q2.reg==dx){
+	      emit(f,"\tpushl\t%s\n",regnames[dx]);
+	      push(4);
+	      m|=4;
+	    }
+            if(t&UNSIGNED) emit(f,"\txorl\t%s,%s\n\tdivl\t",regnames[dx],regnames[dx]);
+                else       emit(f,"\tcltd\n\tidivl\t");
+            if((m&12)||(isreg(q2)&&p->q2.reg==dx)){
+                emit(f,"(%s)",regnames[sp]);
+            }else if(isreg(q2)&&p->q2.reg==ax){
+                emit(f,"%s(%s)",(m&10)?"4":"",regnames[sp]);
+            }else{
+                emit_obj(f,&p->q2,t);
+            }
+            emit(f,"\n");
+            if(c==DIV) move(f,0,ax,&p->z,0,t);
+                else   move(f,0,dx,&p->z,0,t);
+            if(m&4){ emit(f,"\taddl\t$%ld,%s\n",zm2l(sizetab[t&NQ]),regnames[sp]);pop(4);}
+            if(m&8){ emit(f,"\tpopl\t%s\n",regnames[dx]);pop(4);}
+            if(m&2){ emit(f,"\tpopl\t%s\n",regnames[dx]);pop(4);}
+            if(m&1){ emit(f,"\tpopl\t%s\n",regnames[ax]);pop(4);}
+            if(m&16){ emit(f,"\taddl\t$%ld,%s\n",zm2l(sizetab[t&NQ]),regnames[sp]);pop(4);}
+            continue;
+        }
+        if(!isconst(q2)&&(c==LSHIFT||c==RSHIFT)){
+            char *s=arithmetics[c-LSHIFT];
+            int fl=0;
+            if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+            if(((p->q1.flags&REG)&&p->q1.reg==cx)||((p->z.flags&REG)&&p->z.reg==cx)
+               ||(!compare_objects(&p->q1,&p->z)&&!isreg(q1))){
+                fl=regs[cx];regs[cx]=2; /* don't want cx */
+                reg=get_reg(f,p,t);
+                regs[cx]=fl;
+                if(isreg(z)&&p->z.reg==cx) fl=0;
+                if(fl){emit(f,"\tpushl\t%s\n",regnames[cx]);push(4);}
+                move(f,&p->q1,0,0,reg,t);
+                move(f,&p->q2,0,0,cx,t);
+                emit(f,"\t%s%c\t%%cl,%s\n",s,x_t[t&NQ],mregname(reg,t));
+                move(f,0,reg,&p->z,0,t);
+                if(fl){emit(f,"\tpopl\t%s\n",regnames[cx]);pop(4);}
+                continue;
+            }else{
+                if(!isreg(q2)||p->q2.reg!=cx){
+                    if(regs[cx]){emit(f,"\tpushl\t%s\n",regnames[cx]);push(4);fl=1;}
+                    move(f,&p->q2,0,0,cx,t);
+                }
+                if(compare_objects(&p->q1,&p->z)){
+                    emit(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+                    emit_obj(f,&p->z,t);emit(f,"\n");
+                }else{
+                    move(f,0,p->q1.reg,&p->z,0,t);
+                    emit(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+                    emit_obj(f,&p->z,t);emit(f,"\n");
+                }
+                if(fl) {emit(f,"\tpopl\t%s\n",regnames[cx]);pop(4);}
+                continue;
+            }
+        }
+        if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)){
+            char *s;
+            if(c>=OR&&c<=AND) s=logicals[c-OR];
+                else s=arithmetics[c-LSHIFT];
+            if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+            if(c!=MULT&&compare_objects(&p->q1,&p->z)){
+                if(isreg(z)||isreg(q1)||isconst(q2)){
+                    if(isconst(q2)&&(c==ADD||c==SUB)){
+                        eval_const(&p->q2.val,t);
+                        if(zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))&&zldeqto(vldouble,d2zld(1.0))){
+                            if(c==ADD) s="inc"; else s="dec";
+                            emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+                            emit_obj(f,&p->z,t);emit(f,"\n");
+                            continue;
+                        }
+                    }
+                    emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+                    emit_obj(f,&p->q2,t);emit(f,",");
+                    emit_obj(f,&p->z,t);emit(f,"\n");
+                    continue;
+                }else{
+                    if(isreg(q2)) reg=p->q2.reg; else reg=get_reg(f,p,t);
+                    move(f,&p->q2,0,0,reg,t);
+                    emit(f,"\t%s%c\t%s",s,x_t[t&NQ],mregname(reg,t));
+                    emit(f,","); emit_obj(f,&p->z,t);emit(f,"\n");
+                    continue;
+                }
+            }
+	    if(c==AND&&isreg(z)){
+	      /* can we use test instruction? */
+	      struct IC *p2=p->next;
+	      while(p2->code==ALLOCREG||p2->code==FREEREG)
+		p2=p2->next;
+	      if(p2->code==TEST&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+		struct IC *p3=p2->next;
+		while(p3->code==ALLOCREG||p3->code==FREEREG){
+		  if(p3->code==FREEREG&&p3->q1.reg==p->z.reg)
+		    break;
+		  p3=p3->next;
+		}
+		if(p3->code==FREEREG&&p3->q1.reg==p->z.reg){
+		  /* we can use test */
+		  p2->code=NOP;
+		  if(notpopped&&!dontpop){
+		    emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+		    pop(notpopped);
+		    notpopped=0;
+		  }
+		  if(isconst(q1)){
+		    struct obj tmp=p->q1;
+		    p->q1=p->q2;
+		    p->q2=tmp;
+		  }
+		  if(!isreg(q1)&&!isreg(q2)&&!isconst(q2)){
+		    int r=get_reg(f,p,t);
+		    move(f,&p->q1,0,0,r,t);
+		    p->q1.flags=REG;
+		    p->q1.reg=r;
+		  }
+		  emit(f,"\ttest%c\t",x_t[t&NQ]);
+		  emit_obj(f,&p->q2,t);
+		  emit(f,",");
+		  emit_obj(f,&p->q1,t);
+		  emit(f,"\n");
+		  continue;
+		}
+	      }
+	    }
+	      
+	    if(isreg(z)&&(p->q2.flags&REG)&&p->q2.reg==p->z.reg){
+	      if(c==ADD||c==AND||c==OR||c==XOR){
+		struct obj tmp;
+		tmp=p->q1;
+		p->q1=p->q2;
+		p->q2=tmp;
+	      }
+	    }
+            if(isreg(z)&&(!(p->q2.flags&REG)||p->q2.reg!=p->z.reg)) reg=p->z.reg; else reg=get_reg(f,p,t);
+            move(f,&p->q1,0,0,reg,t);
+            if(isconst(q2)&&(c==ADD||c==SUB)){
+                eval_const(&p->q2.val,t);
+                if(zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))&&zldeqto(vldouble,d2zld(1.0))){
+                    if(c==ADD) s="inc"; else s="dec";
+                    emit(f,"\t%s%c\t%s\n",s,x_t[t&NQ],mregname(reg,t));
+                }else{
+                    emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+                    emit_obj(f,&p->q2,t);emit(f,",%s\n",mregname(reg,t));
+                }
+            }else{
+                emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+                emit_obj(f,&p->q2,t);emit(f,",%s\n",mregname(reg,t));
+            }
+            move(f,0,reg,&p->z,0,t);
+            continue;
+        }
+        ierror(0);
+    }
+    if(notpopped){
+        emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+        pop(notpopped);notpopped=0;
+    }
+    function_bottom(f,v,loff);
+    if(debug_info){
+      emit(f,"%s%d:\n",labprefix,++label);
+      dwarf2_function(f,v,label);
+      if(f) section=-1;
+    }          
+}
+
+int shortcut(int code,int typ)
+{
+  return(0);
+}
+
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+
+  title(f);
+  while(p=firstfpc){
+    if(f){
+      if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+      emit(f,"\t.align\t4\n");
+      emit(f,"%s%d:\n\t.long\t",labprefix,p->label);
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+      if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+  if(f){
+    if(section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    if(cxl) emit(f,"\t.lcomm\t%s%d,4\n",labprefix,cxl);
+    if(sil) emit(f,"\t.lcomm\t%s%d,4\n",labprefix,sil);
+    if(dil) emit(f,"\t.lcomm\t%s%d,4\n",labprefix,dil);
+  }
+}
+void init_db(FILE *f)
+{
+  dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+  dwarf2_print_comp_unit_header(f);
+}
+void cleanup_db(FILE *f)
+{
+  dwarf2_cleanup(f);
+  if(f) section=-1;
+}
+
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+  t&=NU;
+  if(ISBE(t))
+    t=LETYPE(t);
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==POINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(ISBE(f))
+    f=LETYPE(f);
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax); 
+}
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(ISBE(t)){
+    fprintf(f,"B");
+    t=LETYPE(t);
+  }
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);}
+  if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);}
+  /*FIXME*/
+  if(t==POINTER){fprintf(f,"P");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+}
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  /*FIXME?*/
+  if(ISBE(t))
+    t=LETYPE(t);
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT){emitzm(f,p->vmax);}
+  if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);}
+  /*FIXME*/
+  if(t==POINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+} 
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISSCALAR(p->flags)&&(p->flags&NQ)!=CHAR&&(attr=p->attr)&&strstr(attr,"bigendian")){
+      if(!ISBE(p->flags))
+	p->flags++;
+    }
+    if(ISSCALAR(p->flags)&&(p->flags&NQ)!=CHAR&&(attr=p->attr)&&strstr(attr,"littleendian")){
+      if(ISBE(p->flags))
+	p->flags--;
+    }
+    p=p->next;
+  }
+}
diff --git a/machines/i386/machine.dt b/machines/i386/machine.dt
new file mode 100755
index 0000000..47b1bfa
--- /dev/null
+++ b/machines/i386/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S32BULE S32BUBE
+
+
diff --git a/machines/i386/machine.h b/machines/i386/machine.h
new file mode 100755
index 0000000..6c1aed5
--- /dev/null
+++ b/machines/i386/machine.h
@@ -0,0 +1,176 @@
+/*  Example of a code-generator for an Intel 386 or higher.         */
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them:      */
+/* - #define HAVE_EXT_TYPES
+   - #undef all standard types
+   - #define all standard types plus new types
+   - write eval_const and insert_const
+   - write typedefs for zmax and zumax
+   - write typname[]
+   - write conv_typ()
+   - optionally #define ISPOINTER, ISARITH, ISINT etc.
+   - optionally #define HAVE_TGT_PRINTVAL and write printval
+   - optionally #define POINTER_TYPE
+   - optionally #define HAVE_TGT_FALIGN and write falign
+   - optionally #define HAVE_TGT_SZOF and write szof
+   - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define BSHORT 3
+#define INT 4
+#define BINT 5
+#define LONG 6
+#define BLONG 7
+#define LLONG 8
+#define BLLONG 9
+#define FLOAT 10
+#define BFLOAT 11
+#define DOUBLE 12
+#define BDOUBLE 13
+#define LDOUBLE 14
+#define BLDOUBLE 15
+#define VOID 16
+#define POINTER 17
+#define BPOINTER 18
+#define ARRAY 19
+#define STRUCT 20
+#define UNION 21
+#define ENUM 22
+#define FUNKT 23
+ 
+#define MAXINT 24 /* should not be accesible to application */
+ 
+#define MAX_TYPE MAXINT
+
+#define ISPOINTER(x) ((x&NQ)==POINTER||(x&NQ)==BPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=BPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=BLLONG)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+  int mode;
+  int base;
+  int idx;
+  int scal;
+  zmax offset;
+  struct Var *v;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 18
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 10
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+#define MAXADDI2P LONG
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 4
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* support for variable-length arrays */
+#define ALLOCVLA_REG 1
+#define ALLOCVLA_INLINEASM "\tsubl\t%eax,%esp\n\tandl\t$-5,%esp\n\tmovl\t%esp,%eax"
+/* TODO: find a better solution some time */
+#define FREEVLA_REG 0
+#define FREEVLA_INLINEASM "\tmovl\t(%esp),%esp\n\tsubl\t$4,%esp"
+#define OLDSPVLA_INLINEASM "\tmovl\t%esp,%eax"
+#define FPVLA_REG 7
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
+
diff --git a/machines/m65/compress.c b/machines/m65/compress.c
new file mode 100644
index 0000000..19f033d
--- /dev/null
+++ b/machines/m65/compress.c
@@ -0,0 +1,123 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "vcpr.h"
+
+
+const char tg_copyright[]="6502 code compressor V0.1 (c) 2020 by Volker Barthelmann";
+
+char *inst[]={
+  "lda","ldx","sta","stx","ldy","sty",
+  "adc","sbc","and","ora","eor",
+  "bne","beq","bcc","bcs","bvs","bvc","bpl","bmi",
+  "clc","sec",
+  /*"pla","pha",*/
+  "txa","tax","tya","tay",
+  "inc","dec","dex","inx","iny","dey",
+  /*"rts","rti",*/"jsr","jmp",
+  "cmp","cpx","cpy",
+  "asl","lsr","ror","rol"
+};
+
+int minsave=5;
+
+void parse_line(char *s,line *p)
+{
+  int l,i;
+  static int secok=0;
+  char buf[16],buf2[16],*e;
+
+  if(sscanf(s," %8s %8s",buf,buf2)==2&&!strcmp(buf,"section")){
+    if(!strcmp(buf2,"text"))
+      secok=1;
+    else
+      secok=0;
+    p->flags=BARRIER;
+    return;
+  }
+
+  if(sscanf(s,"l%d:",&l)==1){
+    p->flags|=LABDEF;
+    p->l1=l;
+    p->size=0;
+    if(!secok) p->flags|=BARRIER;
+    return;
+  }
+
+  if(!secok){
+    p->flags|=BARRIER;
+    return;
+  }
+
+  if(!isspace(*s)){
+    p->flags=BARRIER;
+    return;
+  }
+  while(isspace(*s))
+    s++;
+  for(e=s;isalpha(*e);e++);
+
+  for(i=0;i<sizeof(inst)/sizeof(inst[0]);i++){
+    if(!strncmp(s,inst[i],e-s)){
+      while(isspace(*e)) e++;
+      if(*e==0){
+	p->size=1;
+	return;
+      }
+      p->size=2;
+      if(sscanf(e,"l%d",&l)==1){
+	p->flags|=LABUSE;
+	p->l1=l;
+      }
+      if(*s=='b'||!strncmp(s,"jmp",3)){
+	p->flags|=BRANCH;
+      }
+      return;
+    }
+  }
+  p->flags=BARRIER;
+}
+
+static int nlab;
+
+#define SECTION "\tsection\ttext\n"
+
+void add_header(line *after)
+{
+  nlab=new_label();
+  line *new;
+  new=new_line();
+  new->flags=LABDEF;
+  new->l1=nlab;
+  new->code=mymalloc(16); /* TODO */
+  sprintf(new->code,"x%d:\n",nlab);
+  insert_line(after,new);
+  new=new_line();
+  new->flags=BARRIER;
+  new->code=mymalloc(strlen(SECTION)+1);
+  strcpy(new->code,SECTION);
+  insert_line(after,new);
+}
+
+void add_ret(line *after)
+{
+  line *new=new_line();
+  new->size=1;
+  new->flags=BARRIER;
+  new->code=mymalloc(8); /*TODO*/
+  strcpy(new->code,"\trts\n");
+  insert_line(after,new);
+}
+
+void add_jsr(line *after)
+{
+  line *new=new_line();
+  new->flags=LABUSE;
+  new->size=3;
+  new->l1=nlab;
+  new->code=mymalloc(24); /* TODO */
+  sprintf(new->code,"\tjsr\tx%d\n",nlab);
+  insert_line(after,new);
+}
diff --git a/machines/m65/machine.c b/machines/m65/machine.c
new file mode 100644
index 0000000..45819f1
--- /dev/null
+++ b/machines/m65/machine.c
@@ -0,0 +1,5163 @@
+/*  MEGA65 45GS02 backend for vbcc
+    (c) Volker Barthelmann 2020
+    (c) Paul Gardner-Stephen 2020
+
+*/                                                                             
+
+#include "supp.h"
+#include "vbc.h"
+
+#include <math.h>
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc 45GS02 (MEGA65) code-generator V0.1 (c) in 2020 by Volker Barthelmann, Paul Gardner-Stephen";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+		    VALFLAG,0,0,
+		    0,0,
+		    VALFLAG,VALFLAG,0,0,
+		    VALFLAG,0,0,0,
+		    0,0,0,
+		    0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"std-syntax","no-rax",
+			   "volatile-regs","ieee","no-peephole",
+			   "cbmascii","softstack",
+			   "reg-args","int-args","mainargs","no-bank-vars",
+			   "common-banknr","btmp-zpage","oldfp","large",
+			   "glob-acc","avoid-bank-switch","manual-banking",
+			   "atascii","65c02"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__zpage","__nocpr",0};
+
+#define INTERRUPT 1
+#define ZPAGE 2
+#define NOCOMPRESS 4
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define STDSYNTAX  (g_flags[0]&USEDFLAG)
+#define NORAX      (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define IEEE       (g_flags[3]&USEDFLAG)
+#define NOPEEP     (g_flags[4]&USEDFLAG)
+#define CBMASCII   (g_flags[5]&USEDFLAG)
+#define SOFTSTACK  (g_flags[6]&USEDFLAG)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:8)
+#define MAINARGS   (g_flags[9]&USEDFLAG)
+#define NOBANKVARS (g_flags[10]&USEDFLAG)
+#define COMMONBANK ((g_flags[11]&USEDFLAG)?g_flags_val[11].l:0)
+#define BIGZPAGE   (g_flags[12]&USEDFLAG)
+#define OLDFP      (g_flags[13]&USEDFLAG)
+#define LARGE      (g_flags[14]&USEDFLAG)
+#define GLOBACC    (g_flags[15]&USEDFLAG)
+#define NOSWITCH   (g_flags[16]&USEDFLAG)
+#define NOBANKING  (g_flags[17]&USEDFLAG)
+#define ATASCII    (g_flags[18]&USEDFLAG)
+#define C02        (g_flags[19]&USEDFLAG)
+
+
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define PLA (-1)
+#define JMPIND (-2)
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isacc(x) (isreg(x)&&(p->x.reg==ra||p->x.reg==rax))
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define isptr(r) ((r)>=FIRST_PAIR&&(r)<=LAST_PAIR)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"ora","eor","and"};
+static char *arithmetics[]={"slw","srw","adc","sbc","mullw","divw","mod"};
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,2,4,8,4,4,4,0,2,3,3,0,0,0,1,0};
+static char *mregnames[MAXR+1];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","int","long","long long",
+                 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+                 "array","struct","union","enum","function"};
+
+
+/* used to initialize regtyp[] */
+static struct Typ ityp={INT},ctyp={CHAR},ftyp={FLOAT},lltyp={LLONG};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__m65__", 
+		       "__SIZE_T_INT",
+		       "__bank(x)=__vattr(\"bank(\"#x\")\")",
+                       "__far=__attr(\"far\")",
+                       "__near=__attr(\"near\")",
+                       "__huge=__attr(\"huge\")",
+		       0};
+
+/* special registers */
+static int ra=1, rx=2, ry=3, rz=4, sp1=5,sp2=6,sp=7,fp,fp1,fp2;
+static int t4=LAST_GPR,t3=LAST_GPR-1,t2=LAST_GPR-2,t1=LAST_GPR-3;
+static int rax=8;
+static int raxyz=9;
+static int yval;
+#define NOVAL 1000
+
+static int t1,t2,f1,f2; /*tODO: remove*/
+
+static int pushedacc,pushedx,nopeep,cbmascii,atascii,ieee;
+static int c02,noy;
+static int has_inc_a=1;                // MEGA65 has INC A / INA instruction
+static int has_zero_reg=0;
+static char *jmpinst;
+static int pass;
+static int libsave;
+static struct rpair rp2;
+static int cbank;
+static Var bankv;
+static int bankvoffset;
+static int bankcnum;
+static obj zstore;
+static int zstoreflag;
+
+#define SECLEN 128
+char *use_sec;
+int use_bank=-1;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* perhaps provide version with 8bit int? */
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSHORT(t) ((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==POINTER)
+#define ISFPOINTER(t) ((t&NQ)==FPOINTER)
+#define ISLONG(t) ((t&NQ)==LONG)
+#define ISLLONG(t) ((t&NQ)==LLONG)
+
+#define ISIDX(r) (r==rx||r==rz)
+
+/* am */
+#define IMM_IND 1
+#define GPR_IND 2
+#define ABS_IND 3
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\tsection\ttext",
+  *dataname="\tsection\tdata",
+  *bssname="\tsection\tbss",
+  *rodataname="\tsection\trodata";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+
+static long localsize,rsavesize,rscnt,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static int bank(Var *v)
+{
+  char *s=v->vattr;
+  int n,r;
+  if(!NOBANKING&&s&&(s=strstr(s,"bank("))){
+    if(sscanf(s+5,"%i",&n)==1)
+      return n;
+  }
+  return -1;
+}
+
+static void ebank(FILE *f,int b)
+{
+  if(b>=0) emit(f,"%d",b);
+  emit(f,"\n");
+}
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize-off-zm2l(maxalign);
+  }
+
+  off+=argsize;
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(v->tattr&ZPAGE){
+    emit(f,"\tsection\tzpage\n");
+  }else{
+    if(!v->vattr) return 0;
+    sec=strstr(v->vattr,"section(");
+    if(!sec) return 0;
+    sec+=strlen("section(");
+    emit(f,"\tsection\t");
+    while(*sec&&*sec!=')') emit_char(f,*sec++);
+    emit(f,"\n");
+  }
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+
+
+#define chk_coll(x) do{if((x)==r||(x)==r1||(x)==r2) return 0;	\
+    if(reg_pair((x),&rp)&&(rp.r1==r||rp.r2==r)) return 0;}while(0)
+
+static int scratch(IC *p,int r)
+{
+  int r1,r2;
+  if(!p) return 1;
+  if(reg_pair(r,&rp)){
+    r1=rp.r1;
+    r2=rp.r2;
+  }else{
+    r1=0;
+    r2=0;
+  }
+  if(isreg(z)&&p->z.reg==r){
+    if(!(p->q2.flags&REG))
+      return 1;
+    if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)
+      return 0;
+    if(reg_pair(p->q2.reg,&rp))
+      if(rp.r1==r||rp.r2==r)
+	return 0;
+    return 1;
+  }
+  while(p){
+    if(p->code==LABEL||p->code==CALL)
+      return 0;
+    if(p->code>=BEQ&&p->code<=BRA)
+      return 0;
+    if(p->code==FREEREG||p->code==ALLOCREG){
+      if(p->q1.reg==r)
+	return 1;
+      if(reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))
+	return 1;
+    }
+    if(p->q1.am) chk_coll(p->q1.am->base);
+    if(p->q2.am) chk_coll(p->q2.am->base);
+    if(p->z.am) chk_coll(p->z.am->base);
+    if(p->q1.flags&REG) chk_coll(p->q1.reg);
+    if(p->q2.flags&REG) chk_coll(p->q2.reg);
+    if(p->z.flags&REG){
+      if(p->z.flags&DREFOBJ)
+	chk_coll(p->z.reg);
+      else{
+	if(p->z.reg==r)
+	  return 1;
+	if(reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r))
+	  return 1;
+      }
+    }
+
+    p=p->next;
+  }
+  return 1;
+}
+
+static int rsavecur;
+static int in_isr;
+
+static int get_reg(FILE *f,IC *p,int t)
+{
+  int r,r1,r2,pass,flag;
+
+  for(pass=0;pass<5;pass++){
+    for(r=MAXR;r>sp;r--){
+      if(reg_pair(r,&rp)){
+	r1=rp.r1;
+	r2=rp.r2;
+      }else{
+	r1=0;
+	r2=0;
+      }
+      if((pass==0||pass==3)&&(!regscratch[r]||in_isr))
+	continue;
+      if(pass<3){
+	if(regs[r]) continue;
+	if(r1&&(regs[r1]||regs[r2])) continue;
+      }
+      if(pass==2&&!(regs[r]&4))
+	continue;
+      if((p->q1.flags&REG)&&(p->q1.reg==r||p->q1.reg==r1||p->q1.reg==r2)) continue;
+      if((p->q2.flags&REG)&&(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)) continue;
+      if((p->z.flags&REG)&&(p->z.reg==r||p->z.reg==r1||p->z.reg==r2)) continue;
+      if(regok(r,t,1)){
+	flag=8;
+	if(regs[r]){
+	  flag|=2;
+	  if(p->code==COMPARE||p->code==TEST)
+	    ierror(0);
+	  if(regs[ra]){
+	    emit(f,"\ttay\n");
+	    yval=NOVAL;
+	  }
+	  if(r1){
+	    emit(f,"\tlda\t%s\n",mregnames[r1]);
+	    emit(f,"\tpha\n");
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    emit(f,"\tpha\n");
+	  }else{
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    emit(f,"\tpha\n");
+	  }
+	  if(regs[ra])
+	    emit(f,"\ttya\n");
+	}
+	if(r1){
+	  regs[r1]|=flag;
+	  regs[r2]|=flag;
+	}
+	regs[r]|=flag;
+	regused[r]=1;
+	regused[r1]=1;
+	regused[r2]=1;
+	return r;
+      }
+    }
+  }
+  pric2(stdout,p);
+  ierror(0);
+}
+
+static void get_acc(FILE *f, IC *p,int t)
+{
+  int r;
+  if(isacc(z)) return;
+  t&=NQ;
+  if(ISCHAR(t)){
+    if(1/*!isreg(q1)||(p->q1.reg!=ra&&p->q1.reg!=rax)*/){
+      if((regs[ra]||regs[rax])&&!scratch(p,ra)&&!pushedacc){
+	if(optsize||(regs[t1]&&regs[t2]&&regs[t3]&&regs[t4])){
+	  emit(f,"\tpha\n");
+	  pushedacc=-1;
+	}else{
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	  pushedacc=r;
+	}
+      }
+    }
+  }else{
+    if(1/*!isreg(q1)||p->q1.reg!=rax*/){
+      if((regs[ra]||regs[rax])&&(!scratch(p,ra)||!scratch(p,rax))&&!pushedacc){
+	r=get_reg(f,p,CHAR);
+	emit(f,"\tsta\t%s\n",mregnames[r]);
+	pushedacc=r;
+      }
+      if((regs[rx]||regs[rax])&&!scratch(p,rax)&&!pushedx){
+	r=get_reg(f,p,CHAR);
+	emit(f,"\tstx\t%s\n",mregnames[r]);
+	pushedx=r;
+      }
+    }
+  }
+}
+
+static int cmp_get_acc(FILE *f,IC *p,IC *branch)
+{
+  if(!regs[ra]&&!regs[rax])
+    return 0;
+  if(branch==0&&pushedacc)
+    return 0;
+  if(branch&&isreg(q1)&&(p->q1.reg==ra||p->q1.reg==rax))
+    if(branch->code==BEQ||branch->code==BNE||(p->typf&UNSIGNED))
+      return 0;
+  if(scratch(p,ra))
+    return 0;
+  if(!regs[rx]&&!regs[rax]){
+    emit(f,"\ttax\n");
+    pushedacc=rx;
+  }
+  emit(f,"\tpha\n");
+  pushedacc=-1;
+  return pushedacc;
+}
+
+static void reload_acc_opt(FILE *f,IC *p)
+{
+  if(pushedacc==0) return;
+  if(pushedacc>0){
+    while(p){
+      if(p->code!=FREEREG) break;
+      if(p->q1.reg==ra||p->q1.reg==rax){
+	pushedacc=0;
+	return;
+      }
+      p=p->next;
+    }
+  }
+  if(pushedacc==-1)
+    emit(f,"\tpla\n");
+  else if(pushedacc==rx)
+    emit(f,"\ttxa\n");
+  else if(pushedacc==ry)
+    emit(f,"\ttya\n");
+  else if(pushedacc){
+    emit(f,"\tlda\t%s\n",mregnames[pushedacc]);
+    regs[pushedacc]&=~8;
+  }
+  pushedacc=0;
+}
+
+static void reload_acc(FILE *f)
+{
+  reload_acc_opt(f,0);
+}
+
+static void push(int i)
+{
+  pushed-=i;
+  if(pushed<maxpushed)
+    maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+  pushed+=i;
+  if(pushed>0) ierror(0);
+}
+
+static int indirect(obj *o)
+{
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ)
+    return 1;
+  if((o->flags&(REG|VAR))!=VAR){
+    if(o->reg==ra||ISIDX(o->reg)||o->reg==rax)
+      return 1;
+    return 0;
+  }
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+    return 1;
+  return 0;
+}
+
+void convfloat(void)
+{
+}  
+
+void sety(FILE *f,int val)
+{
+  if(yval==val)
+    return;
+  if(val-yval==1)
+    emit(f,"\tiny\n");
+  else if(yval-val==1)
+    emit(f,"\tdey\n");
+  else{
+    emit(f,"\tldy\t#%d\n",val);
+    if(val<0||val>255)
+      ierror(0);
+  }
+  yval=val;
+}
+
+static void cnv_fp(void)
+{
+  double d,mant;
+  int exp;
+  unsigned long t;
+
+  if(ieee){
+    vfloat=zld2zf(vldouble);
+    memcpy((void*)&vmax,(void*)&vfloat,4);
+  }else{
+    d=zld2d(vldouble);
+    mant=frexp(d,&exp);
+    exp=(exp+127)&255;
+    t=((unsigned long)(mant*8388608))&0xffffff;
+    t|=((long)exp)<<24;
+    
+    t=((t&0xff)<<24)|((t&0xff00)<<8)|((t&0xff0000)>>8)|((t&0xff000000)>>24);
+    vmax=l2zm((long)t);
+    if(mant==0&&d==0) vmax=Z0;
+  }
+}
+
+static void emit_ieee(FILE *f,union atyps *p,int t)
+{
+  unsigned char *ip=(unsigned char *)&p->vdouble;
+  emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+  if(t==DOUBLE||t==LDOUBLE)
+    emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+  emit(f,"\n");
+}
+
+static void emit_lobyte(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+       emit(f,"%d",zm2l(vmax));
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",zm2l(vmax)&255);
+    }
+  }else if(o->flags&VARADR){
+    emit(f,"#<(");
+    emit_obj(f,o,t);
+    emit(f,")");
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp))
+      emit(f,"%s",mregnames[o->reg]);
+    else
+      emit(f,"%s",mregnames[rp.r1]);
+  }else{
+    if(c02&&(o->flags&(DREFOBJ|KONST))==DREFOBJ) noy=1;
+    emit_obj(f,o,t);
+    noy=0;
+  }
+}
+
+static void emit_hibyte(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+1);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>8)&255);
+    }
+  }else if(o->flags&VARADR){
+    emit(f,"#>(");
+    emit_obj(f,o,t);
+    emit(f,")");
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg>=FIRST_BIG&&o->reg<=LAST_BIGP){
+      emit(f,"%s+1",mregnames[o->reg]);
+    }else{
+      if(!reg_pair(o->reg,&rp))
+	ierror(0);
+      emit(f,"%s",mregnames[rp.r2]);
+    }
+  }else{
+    if(o->flags&VARADR)
+      emit(f,"#");
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,Z1);
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,Z1);
+  }
+}
+
+static void emit_byte3(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+2);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>16)&255);
+    }
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    emit(f,"%s+2",mregnames[o->reg]);
+  }else if(o->flags&VARADR){
+    emit(f,"#%d",bank(o->v));
+  }else{
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,l2zm(2L));
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,l2zm(2L));
+  }
+}
+
+static void emit_byte4(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+3);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>24)&255);
+    }
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    emit(f,"%s+3",mregnames[o->reg]);
+  }else{
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,l2zm(3L));
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,l2zm(3L));
+  }
+}
+
+static void do_lobyte(FILE *f,char *s,obj *o,int type)
+{
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset);
+    else if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+      if(o->am->idx==ra)
+	emit(f,"\ttay\n");
+      else{
+	if(ISIDX(o->am->idx)){
+	  if(o->am->flags==GPR_IND){
+	    emit(f,"\tpha\n");
+	    emit(f,"\tt%sa\n",mregnames[o->am->idx]);
+	    emit(f,"\ttay\n");
+	    emit(f,"\tpla\n");
+	  }
+	}else
+	  emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      }
+      yval=NOVAL;
+    }else
+      ierror(0);
+  }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    if(!c02) sety(f,0);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o));
+  }
+  emit(f,"\t%s\t",s);
+  emit_lobyte(f,o,type);
+  emit(f,"\n");
+}
+
+static void do_hibyte(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+1);
+    else if(o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      o->am->offset++;ami=1;
+      yval=NOVAL;
+    }else
+      ierror(0);
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,1);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+1);
+  }
+  emit(f,"\t%s\t",s);
+  emit_hibyte(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset--;
+}
+
+static void do_byte3(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+2);
+    else if(o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      yval=NOVAL;
+      o->am->offset+=2;ami=1;
+    }else
+      ierror(0);
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,2);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+2);
+  }
+  emit(f,"\t%s\t",s);
+  emit_byte3(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset-=2;
+}
+
+static void do_byte4(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+3);
+    else if(o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      yval=NOVAL;
+      o->am->offset+=3;ami=1;
+    }else
+      ierror(0);
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,3);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+3);
+  }
+  emit(f,"\t%s\t",s);
+  emit_byte4(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset-=3;
+}
+
+static void load_lobyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==ra||o->reg==rax)
+      return;
+    if(o->reg==rx){
+      emit(f,"\ttxa\n");
+      return;
+    }
+  }
+  do_lobyte(f,"lda",o,t);
+}
+
+static void load_hibyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&REG)&&(o->reg==rx||o->reg==rax))
+    emit(f,"\ttxa\n");
+  else
+    do_hibyte(f,"lda",o,t);
+}
+
+static void store_lobyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==ra||o->reg==rax)
+      return;
+    if(o->reg==rx){
+      emit(f,"\ttax\n");
+      return;
+    }
+  }
+  do_lobyte(f,"sta",o,t);
+}
+
+static void store_hibyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&REG)&&(o->reg==rx||o->reg==rax))
+    emit(f,"\ttax\n");
+  else
+    do_hibyte(f,"sta",o,t);
+}
+
+static void load_acc(FILE *f,obj *o,int type)
+{
+  if((o->flags&REG)&&(o->reg==ra||o->reg==rax))
+    return;
+  if(!ISCHAR(type)){
+    if(indirect(o)){
+      do_hibyte(f,"lda",o,type);
+      emit(f,"\ttax\n");
+    }else
+      do_hibyte(f,"ldx",o,type);
+  }
+  if((o->flags&(REG|DREFOBJ))==REG&&o->reg==rx)
+    emit(f,"\ttxa\n");
+  else
+    do_lobyte(f,"lda",o,type);
+}
+
+static void store_acc(FILE *f,obj *o,int type)
+{
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&((!(o->flags&REG))||!isptr(o->reg))){
+    ierror(0);
+  }
+  if((o->flags&REG)&&(o->reg==ra||o->reg==rax))
+    return;
+  if((o->flags&REG)&&o->reg==rx){
+    emit(f,"\ttax\n");
+    return;
+  }
+  store_lobyte(f,o,type);
+  if(!ISCHAR(type)){
+    if(indirect(o)){
+      /*TODO: save accu */
+      emit(f,"\ttxa\n");
+      store_hibyte(f,o,type);
+    }else
+      do_hibyte(f,"stx",o,type);
+  }
+}
+
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  static obj ro;
+  if(ISIDX(r)&&!indirect(o)){
+    static char ldr[4]="ldr";
+    ldr[2]=mregnames[r][0];
+    do_lobyte(f,ldr,o,type);
+    return;
+  }
+  ro.flags=REG;
+  ro.reg=r;
+  load_lobyte(f,o,type);
+  store_lobyte(f,&ro,type);
+  if(!ISCHAR(type)){
+    load_hibyte(f,o,type);
+    store_hibyte(f,&ro,type);
+  }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  static obj ro;
+  if(ISIDX(r)){
+    if((o->flags&(REG|DREFOBJ))==REG){
+      if(o->reg==r)
+	return;
+      if(o->reg==ra){
+	emit(f,"\tt%sa\n",mregnames[r]);
+	return;
+      }
+    }
+    if(!indirect(o)){
+      static char str[4]="str";
+      str[2]=mregnames[r][0];
+      do_lobyte(f,str,o,type);
+      return;
+    }
+  }
+  ro.flags=REG;
+  ro.reg=r;
+  if(r!=ra&&r!=rax)
+    load_acc(f,&ro,type);
+  store_acc(f,o,type);
+}
+
+static struct fpconstlist {
+  struct fpconstlist *next;
+  int label;
+  int t;
+  union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(t==LDOUBLE) t=DOUBLE;
+  for(p=firstfpc;p;p=p->next){
+    if(t==p->t){
+      eval_const(&p->val,t);
+      if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+      if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+      if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+      if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->t=t;
+  p->label=++label;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+/* generate code to load the address of a local variable into register r */
+static void load_laddr(FILE *f,int r,struct obj *o)
+{
+  long l=real_offset(o);
+  /* assumes acc is available */
+  if(!reg_pair(r,&rp)) ierror(0);
+  emit(f,"\tlda\t%s\n",mregnames[fp]);
+  if(l!=0)
+    emit(f,"\tclc\n");
+  if(l&255)
+    emit(f,"\tadc\t#%ld\n",l&255);
+  emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+  emit(f,"\tlda\t%s\n",mregnames[fp2]);
+  if(l!=0)
+    emit(f,"\tadc\t#%ld\n",(l>>8)&255);
+  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int t)
+{
+  if(o->flags&DREFOBJ){
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER);
+    o->flags|=DREFOBJ;
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t#>%s\n",mregnames[o->reg]);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    emit(f,"\tlda\t#<%s\n",mregnames[o->reg]);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);    
+  }else if(o->flags&VAR){
+    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+      load_laddr(f,r,o);
+    }else{
+      o->flags|=VARADR;
+      load_reg(f,r,o,POINTER);
+      o->flags&=~VARADR;
+    }
+  }else if((o->flags&(KONST|DREFOBJ))==KONST){
+    int l=addfpconst(o,t);
+    if(!ieee) ierror(0);
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t#>%s%d\n",labprefix,l);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    emit(f,"\tlda\t#<%s%d\n",labprefix,l);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);    
+  }else
+    ierror(0);
+}
+
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static void incmem(FILE *f,obj *o,int t,int op,int x)
+{
+  int i,idx=0;
+  char *s;
+  if((o->flags&(REG|DREFOBJ))==REG&&ISIDX(o->reg)){
+    static char buf[4]="   ";
+    idx=1;s=buf;
+    if(op==ADD){s[0]='i';s[1]='n';}else{s[0]='d';s[1]='e';}
+    s[2]=mregnames[o->reg][0];
+  }else if(op==ADD)
+    s="inc";
+  else if(op==SUB)
+    s="dec";
+  else if(op==LSHIFT)
+    s="asl";
+  else if(op==RSHIFT&&(t&UNSIGNED))
+    s="clc\n\tror";
+  else if(op==RSHIFT){
+    s="cmp\t#128\n\tror";
+  }else
+    ierror(0);
+  if(ISCHAR(t)){
+    for(i=0;i<x;i++){
+      if(idx){
+	emit(f,"\t%s\n",s);
+      }else{
+	emit(f,"\t%s\t",s);
+	emit_obj(f,o,t);
+	emit(f,"\n");
+      }
+    }
+  }else{
+    for(i=0;i<x;i++){
+      if(op==SUB){
+	/* caller mus make sure accu is available */
+	load_lobyte(f,o,t);
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	emit(f,"\tdec\t");
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	emit(f,"\tdec\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");	
+      }else if(op==ADD){
+	emit(f,"\t%s\t",s);
+	emit_lobyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	emit(f,"\t%s\t",s);
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+      }else if(op==LSHIFT){
+	// 4510 / 45GS02 have ASW/ROW operations
+	// for left-shifting 16-bit values
+	
+	emit(f,"\tasw\t");
+	emit_obj(f,o,t);
+	emit(f,"\n");
+
+      }else if(op==RSHIFT&&(t&UNSIGNED)){
+	emit(f,"\tclc\n");
+	emit(f,"\tror\t");
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"\tror\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");
+      }else if(op==RSHIFT){
+	load_hibyte(f,o,t);
+	emit(f,"\tcmp\t#128\n");
+	emit(f,"\tror\t");
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"\tror\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");	
+      }else{
+	printf("op=%d\n",op);
+	ierror(0);
+      }
+    }
+  }
+}
+
+static void preload_obj(FILE *f,IC *p,obj *o)
+{
+  int r;long of;
+
+  if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+     ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+    emit(f,"; volatile barrier\n");
+
+
+  if((o->flags&(VAR|REG))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&(of=real_offset(o))+zm2l(szof(o->v->vtyp))>255){
+    r=get_reg(f,p,POINTER);
+    if(o->flags&DREFOBJ)
+      get_acc(f,p,INT);
+    else
+      cmp_get_acc(f,p,0);
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t%s\n",mregnames[fp1]);
+    emit(f,"\tclc\n");
+    if(of&0xff)
+      emit(f,"\tadc\t#%ld\n",of&0xff);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    emit(f,"\tlda\t%s\n",mregnames[fp2]);
+    if(1/*of&0xff00*/)
+      emit(f,"\tadc\t#%ld\n",(of>>8)&0xff);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    o->flags|=REG;
+    o->reg=r;
+    if(o->flags&DREFOBJ){
+      if(!c02) sety(f,0);
+      emit(f,"\tlda\t(%s)%s\n",mregnames[r],c02?"":",y");
+      emit(f,"\ttxa\n");
+      sety(f,1);
+      emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+      emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+      emit(f,"\tstx\t%s\n",mregnames[rp.r1]);
+    }else{
+      o->flags|=DREFOBJ;
+      o->dtyp=POINTER;
+    }
+  }
+
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&(!(o->flags&REG)||!isptr(o->reg))&&(!(o->flags&VAR)||!(o->v->tattr&ZPAGE))&&!ISFPOINTER(o->dtyp)){
+    cmp_get_acc(f,p,0);
+    r=get_reg(f,p,POINTER);
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER);
+    o->flags|=REG|DREFOBJ;
+    o->reg=r;
+  }
+}
+
+static void far_copy(FILE *f,IC *p)
+{
+  int b;long l;
+  get_acc(f,p,INT);
+  if(p->code==PUSH){
+    if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+    emit(f,"\tlda\t%s\n",mregnames[sp]);
+    if(pushed) emit(f,"\tclc\n");
+    if(pushed&0xff) emit(f,"\tadc\t#%d\n",(pushed&0xff));
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+    if(pushed) emit(f,"\tadc\t#%d\n",((pushed>>8)&0xff));
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    pushed+=zm2l(p->q2.val.vmax);
+    emit(f,"\tldx\t#%d\n",bankcnum);
+  }else if(p->z.flags&DREFOBJ){
+    if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+    p->z.flags&=~DREFOBJ;
+    load_lobyte(f,&p->z,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    load_hibyte(f,&p->z,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    if(indirect(&p->z)){
+      do_byte3(f,"lda",&p->z,FPOINTER);
+      emit(f,"\ttax\n");
+    }else
+      do_byte3(f,"ldx",&p->z,FPOINTER);
+  }else{
+    load_address(f,LAST_PAIR,&p->z,POINTER);
+    b=bank(p->z.v);
+    emit(f,"\tldx\t#%d\n",b>=0?b:bankcnum);
+  }
+  if(p->q1.flags&DREFOBJ){
+    if(!reg_pair(LAST_PAIR-1,&rp)) ierror(0);
+    p->q1.flags&=~DREFOBJ;
+    load_lobyte(f,&p->q1,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    load_hibyte(f,&p->q1,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    if(indirect(&p->q1)){
+      do_byte3(f,"lda",&p->q1,FPOINTER);
+      emit(f,"\ttay\n");
+    }else
+      do_byte3(f,"ldy",&p->q1,FPOINTER);
+  }else{
+    load_address(f,LAST_PAIR-1,&p->q1,POINTER);
+    b=bank(p->q1.v);
+    sety(f,b>=0?b:bankcnum);
+  }
+  l=zm2l(p->q2.val.vmax);
+  emit(f,"\tlda\t#%d\n",(l>>8)&0xff);
+  emit(f,"\tsta\t%s__bankcopy_len+1\n",idprefix);
+  emit(f,"\tlda\t#%d\n",(l)&0xff);
+  emit(f,"\tsta\t%s__bankcopy_len\n",idprefix);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  emit(f,"\tjsr\t%s__bankcopy\n",idprefix);
+  yval=NOVAL;
+}
+
+static void load_far(FILE *f,IC *p,obj *o,int t)
+{
+  int pushed=0;
+  if(!(o->flags&DREFOBJ)) ierror(0);
+  o->flags&=~DREFOBJ;
+  t&=NQ;
+  if(zmeqto(sizetab[t],Z0)) return;
+  /*get_acc(f,p,INT);*/
+  if(pushedacc==t3||pushedacc==t4) ierror(0);
+  if(pushedx==t3||pushedx==t4) ierror(0);
+  if(regs[ra]||regs[rax]){
+    if(isacc(q1)||isacc(q2)||!isacc(z)){
+      pushed=1;
+      emit(f,"\tpha\n");
+      if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+    }
+  }
+  load_reg(f,LAST_PAIR,o,POINTER);
+  if(!indirect(o))
+    do_byte3(f,"ldy",o,CHAR);
+  else{
+    do_byte3(f,"lda",o,CHAR);
+    emit(f,"\ttay\n");
+  }
+  emit(f,"\tldx\t#%d\n",bankvoffset);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+  yval=NOVAL;
+  o->flags=VAR;
+  o->v=&bankv;
+  o->val.vmax=l2zm((long)bankvoffset);
+  bankvoffset+=zm2l(sizetab[t]);
+  if(pushed){
+    if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+    emit(f,"\tpla\n");
+  }
+}
+
+static void load_banked(FILE *f,IC *p,obj *o,int t)
+{
+  int pushed=0,m;
+  if(o->flags&DREFOBJ) t=o->dtyp;
+  t&=NQ;
+  if(zmeqto(sizetab[t],Z0)) return;
+  /*get_acc(f,p,INT);*/
+  if(pushedacc==t3||pushedacc==t4) ierror(0);
+  if(pushedx==t3||pushedx==t4) ierror(0);
+  if(regs[ra]||regs[rax]){
+    if(isacc(q1)||isacc(q2)||!isacc(z)){
+      pushed=1;
+      emit(f,"\tpha\n");
+      if(regs[rax]||regs[rx]) emit(f,"\ttxa\n\tpha\n");
+    }
+  }
+  m=o->flags;
+  o->flags&=~DREFOBJ;
+  load_address(f,LAST_PAIR,o,POINTER);
+  o->flags=m;
+  emit(f,"\tldx\t#%d\n",bankvoffset);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  sety(f,bank(o->v));
+  emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+  yval=NOVAL;
+  o->v=&bankv;
+  o->val.vmax=l2zm((long)bankvoffset);
+  bankvoffset+=zm2l(sizetab[t]);
+  if(pushed){
+    if(regs[rax]||regs[rx]) emit(f,"\tpla\n\ttax\n");
+    emit(f,"\tpla\n");
+  }
+}
+
+static void preload(FILE *f,IC *p)
+{
+  int r,mra=regs[ra],mrax=regs[rax];
+  int bq1=-1,bq2=-1,bz=-1,sb=-1,zbuf=0;
+
+  if(p->code==GETRETURN&&p->q1.reg==ra&&!regs[ra])
+    regs[ra]=1;
+
+  if(p->code==GETRETURN&&p->q1.reg==rax&&!regs[rax])
+    regs[rax]=1;
+
+  bankvoffset=0;
+
+  if(!NOBANKVARS){
+    if((p->q1.flags&(VAR|VARADR))==VAR) bq1=bank(p->q1.v);
+    if((p->q2.flags&(VAR|VARADR))==VAR) bq2=bank(p->q2.v);
+    if((p->z.flags&(VAR|VARADR))==VAR) bz=bank(p->z.v);
+
+    if((p->q1.flags&(VAR|VARADR))==(VAR|VARADR)){
+      r=bank(p->q1.v);
+      /*if(r>=0&&r!=cbank) ierror(0);*/
+    }
+    
+    if((p->code==ASSIGN||p->code==PUSH)&&!zmleq(p->q2.val.vmax,l2zm(4L))){
+      if(p->q1.flags&DREFOBJ) preload_obj(f,p,&p->q1);
+      if(p->z.flags&DREFOBJ) preload_obj(f,p,&p->z);
+      return;
+    }
+
+    if(p->code!=CALL){
+      /* TODO: some optimizations possible */
+      if(bq1>=0&&bq1!=cbank){
+	if(cbank<0&&!NOSWITCH)
+	  sb=bq1;
+	else
+	  load_banked(f,p,&p->q1,q1typ(p));
+      }
+      if(bq2>=0&&bq2!=cbank){
+	if((bq2==sb||(cbank<0&&sb<0))&&!NOSWITCH)
+	  sb=bq2;
+	else
+	  load_banked(f,p,&p->q2,q2typ(p));
+      }
+      if(bz>=0&&bz!=cbank&&(p->z.flags&DREFOBJ)){
+	if((bz==sb||(cbank<0&&sb<0))||!NOSWITCH)
+	  sb=bz;
+	else
+	  load_banked(f,p,&p->z,ztyp(p));
+      }
+      
+      if(sb>=0){
+	if(NOSWITCH) ierror(0);
+	sety(f,sb);
+	emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+	yval=NOVAL;
+      }
+    }
+  }
+
+  if((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp)&&p->code!=CALL) load_far(f,p,&p->q1,q1typ(p));
+  if((p->q2.flags&DREFOBJ)&&ISFPOINTER(p->q2.dtyp)) load_far(f,p,&p->q2,q2typ(p));
+
+  if(isacc(q2)){
+    static obj o;
+    int t=q2typ(p);
+    r=get_reg(f,p,t);
+    o.flags=REG;
+    o.reg=r;
+    store_acc(f,&o,t);
+    p->q2.reg=r;
+  }
+
+  if(p->code!=ADDRESS){
+    preload_obj(f,p,&p->q1);
+    if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+       (p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+       p->q1.v==p->q2.v){
+      p->q2.flags|=REG;
+      p->q2.reg=p->q1.reg;
+    }
+    if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+       (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+       p->q1.v==p->z.v){
+      p->z.flags|=REG;
+      p->z.reg=p->q1.reg;
+    }
+  }
+
+  preload_obj(f,p,&p->q2);
+  if((p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+     (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+     p->q2.v==p->z.v){
+    p->z.flags|=REG;
+    p->z.reg=p->q1.reg;
+  }
+
+
+  if((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp)) zbuf=1;
+  if((p->z.flags&(VAR|DREFOBJ))==VAR){
+    bz=bank(p->z.v);
+    if(bz>=0&&bz!=cbank) zbuf=1;
+  }
+  
+  if(zbuf&&!NOBANKVARS){
+    zstore=p->z;
+    p->z.flags=VAR;
+    p->z.v=&bankv;
+    p->z.val.vmax=l2zm((long)bankvoffset);
+    zstoreflag=1;
+    /*bankvoffset+=zm2l(sizetab[p->typf&NQ]);*/
+  }else{
+    preload_obj(f,p,&p->z);
+
+    if(isreg(z)){
+      r=0;
+      if(p->q1.am&&p->q1.am->base==p->z.reg){
+	r=get_reg(f,p,POINTER);
+	cmp_get_acc(f,p,0);
+	if(!reg_pair(p->q1.am->base,&rp)) ierror(0);
+	if(!reg_pair(r,&rp2)) ierror(0);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	p->q1.am->base=p->q1.reg=r;
+      }else if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg==p->z.reg){
+	r=get_reg(f,p,POINTER);
+	cmp_get_acc(f,p,0);
+	if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	if(!reg_pair(r,&rp2)) ierror(0);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	p->q1.reg=r;
+      }
+      if(p->q2.am&&p->q2.am->base==p->z.reg){
+	if(r==0){
+	  r=get_reg(f,p,POINTER);
+	  cmp_get_acc(f,p,0);
+	  if(!reg_pair(p->q2.am->base,&rp)) ierror(0);
+	  if(!reg_pair(r,&rp2)) ierror(0);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	}
+	p->q2.am->base=p->q2.reg=r;
+      }else if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg){
+	if(r==0){
+	  r=get_reg(f,p,POINTER);
+	  cmp_get_acc(f,p,0);
+	  if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	  if(!reg_pair(r,&rp2)) ierror(0);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	}
+	p->q2.reg=r;
+      }
+    }
+    if(isacc(z)){
+      if(isacc(q2)){
+	if(p->q2.reg==rax){
+	  r=get_reg(f,p,INT);
+	  if(!reg_pair(r,&rp)) ierror(0);
+	  emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tstx\t%s\n",mregnames[rp.r2]);
+	}else{
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	}
+	p->q2.reg=r;
+	if(isacc(q1))
+	  p->q1.reg=r;
+      }
+    }
+  }     
+ 
+  reload_acc(f);
+
+  regs[ra]=mra;
+  regs[rax]=mrax;
+}
+
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  ierror(0);
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags==IMM_IND)
+      emit(f,"(%s),y ;am(%ld)",mregnames[p->am->base],p->am->offset);
+    else if(p->am->flags==GPR_IND)
+      emit(f,"(%s),y ;am(%s)",mregnames[p->am->base],mregnames[p->am->idx]);
+    else if(p->am->flags==ABS_IND){
+      emit(f,"%ld",p->am->offset);
+      if(p->am->v){
+	Var *v=p->am->v;
+	if(v->storage_class==EXTERN)
+	  emit(f,"+%s%s",idprefix,v->identifier);
+	else
+	  emit(f,"+%s%ld",labprefix,zm2l(v->offset));
+      }
+      if(ISIDX(p->am->idx))
+	emit(f,",%s ;am(%s)",mregnames[p->am->idx],mregnames[p->am->idx]);
+      else
+	emit(f,",y ;am(%s)",mregnames[p->am->idx]);
+    }else
+      ierror(0);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",mregnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"(%s),y",mregnames[fp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    if(/*ieee&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)*/ISFLOAT(t))
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    else
+      emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")%s",noy?"":",y");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+char amode_buff[8192];
+char *render_amode(struct AddressingMode *am)
+{
+  return "(amode: not implemented)";
+}
+
+char val_buff[8192];
+char *render_val(union atyps val)
+{
+  snprintf(val_buff,8192,"(val: %02x...)",
+	   val.vuchar);
+  return val_buff;
+}
+
+char var_buff[8192];
+char *render_var(struct Var *v)
+{
+  if (!v) return "<null>";
+  snprintf(var_buff,8192,"(var id=%s)",v->identifier);
+  return var_buff;
+}
+
+char obj_buff[8192];
+char *render_obj(struct obj o)
+{
+  // XXX Calling render_var() can result in segfaults
+  snprintf(obj_buff,8192,"(flags=%d, reg=%d, dtype=%d, var=%s, amode=%s, val=%s)",
+	   o.flags,o.reg,o.dtyp,"render_var(o.v)",render_amode(o.am),render_val(o.val));
+  return obj_buff;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  fprintf(stderr,"peephole() called.\n");
+
+  /*
+    XXX PGS Things to consider adding here:
+    1. Removal of dead loads when we know a register already has loaded the target we want.
+    2. Removal of dead stores to local stack variables that never get read before returning from a function?
+    3. Removal of SP decrement and increment, when no use of local stack is made.
+    4. Promoting stack variables to global variables where it saves time and/or space?
+    5. Using Z as a temporary scratch register for local variables, where it doesn't upset
+       other things?
+  */
+    
+  
+  for(;p;p=p->next){
+    fprintf(stderr,"  Instruction @ %p : ",p);
+    fprintf(stderr,"code=%d, ",p->code);
+    fprintf(stderr,"\n    q1=%s, ",render_obj(p->q1));
+    fprintf(stderr,"\n    q2=%s, ",render_obj(p->q2));
+    fprintf(stderr,"\n    z=%s, ",render_obj(p->z));
+    fprintf(stderr,"\n");
+    
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&!ISFPOINTER(p->typf2)){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(zmleq(Z0,of)&&zmleq(of,l2zm(255L))){
+	r=p->z.reg;
+	if(isreg(q1)&&isptr(p->q1.reg)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    int t,mc;
+	    if((c2==ASSIGN|c2==PUSH)&&(p2->typf&NQ)==CHAR&&!zmeqto(p2->q2.val.vmax,Z1))
+	      mc=1;
+	    else
+	      mc=0;
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o||mc) break;
+	      t=q1typ(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o||mc) break;
+	      t=q2typ(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o||mc) break;
+	      t=ztyp(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else{
+	      m=p2->z.reg;
+	      if(o==&p->q1||o==&p->q2) break;
+	    }
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=(int)zm2l(of);
+		if(isreg(q1)&&isptr(p->q1.reg)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(c==ADDI2P&&(p->typf&NU)==(UNSIGNED|CHAR)&&!ISFPOINTER(p->typf2)&&isreg(q2)&&p->q2.reg!=ra&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx,ind;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST)
+	ind=0;
+      else
+	ind=1;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(ind&&(q1typ(p2)&NQ)!=CHAR)) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(ind&&(q2typ(p2)&NQ)!=CHAR)) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ind&&(ztyp(p2)&NQ)!=CHAR)) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+	      am->idx=idx;
+	      if(ind){
+		am->flags=GPR_IND;
+		am->base=base;
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }else{
+		am->flags=ABS_IND;
+		am->base=0;
+		eval_const(&p->q1.val,MAXINT);
+		am->offset=zm2l(vmax);
+		if(p->q1.flags&VARADR)
+		  am->v=p->q1.v;
+		else
+		  am->v=0;
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(zstoreflag){
+    int off;
+    if(p->z.flags!=VAR||p->z.v!=&bankv) ierror(0);
+    off=(int)zm2l(p->z.val.vmax);
+    p->z=zstore;
+    get_acc(f,p,INT);
+    if(zstore.flags&DREFOBJ){
+      if(!ISFPOINTER(zstore.dtyp)) ierror(0);
+      zstore.flags&=~DREFOBJ;
+      load_reg(f,LAST_PAIR,&zstore,POINTER);
+      if(indirect(&zstore)){
+	do_byte3(f,"lda",&zstore,FPOINTER);
+	emit(f,"\ttay\n");
+      }else
+	do_byte3(f,"ldy",&zstore,FPOINTER);
+      yval=NOVAL;
+    }else{
+      load_address(f,LAST_PAIR,&zstore,p->typf);
+      r=bank(zstore.v);
+      sety(f,r>=0?r:bankcnum);
+    }
+    emit(f,"\tldx\t#%d\n",off);
+    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+    emit(f,"\tjsr\t%s__bankstore%d\n",idprefix,(int)zm2l(sizetab[p->typf&NQ]));
+    yval=NOVAL;
+    zstoreflag=0;
+  }
+
+  for(r=1;r<=MAXR;r++){
+    if(regs[r]&8)
+      regs[r]&=~8;
+  }
+  for(r=FIRST_GPR;r<=LAST_GPR;r++){
+    int ta=0;
+    if(regs[r]&2){
+      if(regs[ra]&&!pushedacc){
+	emit(f,"\ttay\n");
+	yval=NOVAL;
+	ta=1;
+      }
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s\n",mregnames[r]);
+      regs[r]&=~2;
+    }
+    if(ta)
+      emit(f,"\ttya\n");
+  }
+  if(pushedx){
+    emit(f,"\tldx\t%s\n",mregnames[pushedx]);
+    pushedx=0;
+  }
+
+  reload_acc_opt(f,p->next);
+}
+
+struct cmplist {struct cmplist *next;int from,to,mode;} *first_cmplist;
+
+static void add_cmplist(int from, int to, int mode)
+{
+  struct cmplist *new;
+  new=mymalloc(sizeof(*new));
+  new->next=first_cmplist;
+  new->from=from;
+  new->to=to;
+  new->mode=mode;
+  first_cmplist=new;
+}
+
+static void incsp(FILE *f,long of)
+{
+  if(of==0) return;
+  if(of==1||of==-1){
+    static obj o;
+    o.flags=REG;
+    o.reg=sp;
+    if(of==1)
+      incmem(f,&o,INT,ADD,1);
+    else
+      incmem(f,&o,INT,SUB,1);
+  }else if(of==256){
+    emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+  }else if(of==-256){
+    emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+  }else{
+    long abs;
+    if(of>0){
+      abs=of;
+      emit(f,"\tclc\n");
+    }else{
+      abs=-of;
+      emit(f,"\tsec\n");
+    }
+    if(abs&255){
+      emit(f,"\tlda\t%s\n",mregnames[sp]);
+      if(of>0){
+	emit(f,"\tadc\t#%ld\n",abs&255);
+      }else{
+	emit(f,"\tsbc\t#%ld\n",abs&255);
+      }
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+    }
+    if((abs&0xff00)==0){
+      if(of>0){
+	emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+	emit(f,"%s%d:\n",labprefix,label);
+      }else{
+	emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+	emit(f,"%s%d:\n",labprefix,label);
+      }	
+    }else{
+      emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+      if(of>0)
+	emit(f,"\tadc\t#%ld\n",(abs>>8)&255);
+      else
+	emit(f,"\tsbc\t#%ld\n",(abs>>8)&255);
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  int i,r,of;
+  rsavesize=0;
+  libsave=1;
+  
+  if(!optsize||(v->tattr&NOCOMPRESS)) emit(f,";vcprmin=10000\n");
+  if(vlas) emit(f,"___fo\tset\t%ld\n",(long)argsize);
+  r=0;
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+      if(i!=LAST_GPR-VOL_GPRS+1&&r==0) libsave=0;
+      rsavesize++;
+      r=1;
+    }else{
+      if(i==LAST_GPR-VOL_GPRS+1) libsave=0;
+      r=0;
+    }
+  }
+  rscnt=rsavesize;
+  if(rscnt&&!SOFTSTACK){
+    if(optspeed||rscnt<2)
+      rsavesize=0;
+    else if(!optsize&&rscnt<=5)
+      rsavesize=0;
+  }
+  
+  if(!special_section(f,v)){emit(f,codename);ebank(f,bank(v));if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  
+  offset=localsize+argsize+rsavesize;
+  
+  if(in_isr){
+    emit(f,"\tpha\n");
+    emit(f,"\tphx\n");
+    emit(f,"\tphy\n");
+    emit(f,"\tphz\n");
+    if(offset||function_calls){
+      emit(f,"\tlda\t%s\n",mregnames[sp]);
+      emit(f,"\tpha\n");
+      emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+      emit(f,"\tpha\n");
+      emit(f,"\tlda\t#<(___isrstack-%ld)\n",offset);
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+      emit(f,"\tlda\t#>(___isrstack-%ld)\n",offset);
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+    }
+  }
+
+  if(MAINARGS&&v->storage_class==EXTERN&&!strcmp(v->identifier,"main")&&v->vtyp->exact->count>1)
+    emit(f,"\tjsr\tinitmainargs\n");
+
+  yval=NOVAL;
+  of=argsize+localsize;
+
+  if(rsavesize>0&&of+rsavesize>255){
+    offset-=rsavesize;
+    incsp(f,-rsavesize);
+    of=0;
+  }else{
+    incsp(f,-offset);
+    offset=0;
+  }
+
+
+  if(!libsave||rscnt!=rsavesize||optspeed||rscnt<=1||(rscnt<=3&&(!optsize)))
+    libsave=0;
+  
+  if(libsave){
+    sety(f,of+rsavesize-1);
+    emit(f,"\tjsr\t%s__rsave%ld\n",idprefix,rscnt);
+    yval=of;
+  }else{
+    for(i=FIRST_GPR;i<=LAST_GPR;i++){
+      if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	if(rscnt!=rsavesize){
+	  emit(f,"\tlda\t%s\n",mregnames[i]);
+	  emit(f,"\tpha\n");
+	}else{
+	  sety(f,of++);
+	  emit(f,"\tlda\t%s\n",mregnames[i]);
+	  emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	}
+      }
+    }
+  }
+
+
+
+  incsp(f,-offset);
+
+  if(vlas){
+    emit(f,"\tlda\t%s\n",mregnames[sp]);
+    emit(f,"\tsta\t%s\n",mregnames[fp]);
+    emit(f,"\tlda\t%s\n",mregnames[sp2]);
+    emit(f,"\tsta\t%s\n",mregnames[fp2]);
+  }
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  int i,of,ar;
+  struct cmplist *p;
+  offset=localsize+argsize+rsavesize;
+  of=argsize+localsize;
+
+  i=freturn(v->vtyp->next);
+  if(i==ra||i==rax) ar=1; else ar=0;
+
+  if(rscnt!=rsavesize){
+    if(ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    for(i=LAST_GPR;i>=FIRST_GPR;i--){
+      if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	emit(f,"\tpla\n");
+	emit(f,"\tsta\t%s\n",mregnames[i]);
+      }
+    }
+  }
+  if(rsavesize>0&&of+rsavesize>255){
+    if(of!=1&&ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    incsp(f,of);
+    offset-=of;
+    of=0;
+  }
+  if(rsavesize>0){
+    if(ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+  }
+  if(rsavesize){
+    if(libsave){
+      sety(f,of+rsavesize-1);
+      emit(f,"\tjsr\t%s__rload%ld\n",idprefix,rscnt);
+      yval=of;
+    }else{
+      for(i=FIRST_GPR;i<=LAST_GPR;i++){
+	if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	  sety(f,of++);
+	  emit(f,"\tlda\t(%s),y\n",mregnames[sp]);
+	  emit(f,"\tsta\t%s\n",mregnames[i]);
+	}
+      }
+    }
+  }
+  if(in_isr){
+    if(offset||function_calls){
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+    }
+  }else if(offset==2&&!pushedacc){
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+    reload_acc(f);
+    emit(f,ret);
+    emit(f,"%s%d:\n",labprefix,label-1);
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"%s%d:\n",labprefix,label);
+    emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+  }else{
+    if(offset!=0&&ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    incsp(f,offset);
+  }
+
+  reload_acc(f);
+
+  if(in_isr){
+    emit(f,"\tplz\n");
+    emit(f,"\tply\n");
+    emit(f,"\tplx\n");
+    emit(f,"\tpla\n");
+  }
+  emit(f,ret);
+
+  for(p=first_cmplist;p;){
+    struct cmplist *m;
+    emit(f,"%s%d:\n",labprefix,p->from);
+    if(p->mode==JMPIND){
+      /* indirect call */
+      emit(f,"\tjmp\t(%s)\n",mregnames[p->to]);
+    }else{
+      pushedacc=p->mode;
+      reload_acc(f);
+      emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,p->to);
+    }
+    m=p;
+    p=p->next;
+    free(m);
+  }
+  first_cmplist=0;
+  pushedacc=0;
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(1L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(1);
+
+  if(IEEE){
+    ieee=1;
+    msizetab[DOUBLE]=msizetab[LDOUBLE]=l2zm(8L);
+  }
+
+
+  mregnames[0]=regnames[0]="noreg";
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"r%d",i-FIRST_GPR);
+    mregnames[i]=regnames[i];
+    regsize[i]=l2zm(1L);
+    regtype[i]=&ctyp;
+  }
+  for(i=FIRST_PAIR;i<=LAST_PAIR;i++){
+    int sr=(i-FIRST_PAIR)*2+FIRST_GPR;
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+    mregnames[i]=regnames[sr];
+    regsize[i]=l2zm(2L);
+    regtype[i]=&ityp;
+  }
+  for(i=FIRST_BIG;i<=LAST_BIG;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"btmp%d",i-FIRST_BIG);
+    mregnames[i]=regnames[i];
+    regsize[i]=msizetab[FLOAT];
+    regtype[i]=&ftyp;
+    regsa[i]=0;
+    regscratch[i]=1;
+  }
+  for(i=FIRST_BIGP;i<=LAST_BIGP;i++){
+    int sr=(i-FIRST_BIGP)*2+FIRST_BIG;
+    regnames[i]=mymalloc(20);
+    sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+    mregnames[i]=regnames[sr];
+    regsize[i]=msizetab[LLONG];
+    regtype[i]=&lltyp;
+    regsa[i]=0;
+    regscratch[i]=1;
+  }
+
+  mregnames[ra] = regnames[ra] = "a";
+  mregnames[rx] = regnames[rx] = "x";
+  mregnames[ry] = regnames[ry] = "y";
+  mregnames[rz] = regnames[rz] = "z";
+  regsize[ra]=regsize[rx]=regsize[ry]=regsize[rz]=l2zm(1L);
+  regtype[ra]=regtype[rx]=regtype[ry]=regtype[rz]=&ctyp;
+  mregnames[sp]=regnames[sp] = "sp";
+  mregnames[sp1]=regnames[sp1] = "sp";
+  mregnames[sp2]=regnames[sp2] = "sp+1";
+
+  mregnames[rax]=regnames[rax] = "ax";
+  regsize[rax]=regsize[sp]=l2zm(2L);
+  regtype[rax]=regtype[sp]=&ityp;
+
+  reg_prio[ra]=reg_prio[rax]=100;
+  reg_prio[rx]=50;
+  reg_prio[rz]=50;
+
+  mregnames[raxyz]=regnames[raxyz] = "axyz";
+  regsize[raxyz]=l2zm(4L);
+  regtype[raxyz]=&ftyp;
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  short_push=1;
+
+  static_cse=0;
+
+  dref_cse=1;
+
+  /*prefer_statics=1; TODO */
+
+
+  if(optsize){
+    clist_copy_stack=2;
+    clist_copy_pointer=2;
+    clist_copy_static=2;
+  }else if(optspeed){
+    clist_copy_stack=64;
+    clist_copy_pointer=64;
+    clist_copy_static=64;
+  }else{
+    clist_copy_stack=8;
+    clist_copy_pointer=8;
+    clist_copy_static=8;
+  }
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[INT]=t_min(SHORT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[INT]=t_max(SHORT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[INT]=t_max(UNSIGNED|SHORT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  regsa[raxyz]=regsa[ry]=regsa[sp]=regsa[sp1]=regsa[sp2]=REGSA_NEVER;
+  regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=REGSA_NEVER;
+  regscratch[ra]=regscratch[rx]=regscratch[rax]=1;
+  if(!GLOBACC)
+    regsa[ra]=/*regsa[rx]=*/regsa[rax]=REGSA_TEMPS;
+  regscratch[sp]=regscratch[sp1]=regscratch[sp2]=regscratch[ry]=regscratch[rz]=0;
+  regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=1;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++){
+    regscratch[i]=1;
+    if(i&1)
+      regscratch[FIRST_PAIR+(i-FIRST_GPR)/2]=1;
+  }
+
+  target_macros=marray;
+
+  declare_builtin("__mulint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__muluint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__modint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+
+  declare_builtin("__mulint32",LONG,LONG,FIRST_BIG+1,LONG,FIRST_BIG+2,1,0);
+  declare_builtin("__muluint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG+1,UNSIGNED|LONG,FIRST_BIG+2,1,0);
+  declare_builtin("__divint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__modint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+  declare_builtin("__sint32toflt32",FLOAT,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32tosint32",LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__sint16toflt32",FLOAT,INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__flt32tosint16",INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+  declare_builtin("__sint32toflt64",DOUBLE,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt64tosint32",LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__sint16toflt64",DOUBLE,INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__flt64tosint16",INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__cmpsflt32",CHAR,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+
+#if 0
+  for(i=1;i<MAXR;i++){
+    printf("%02d %s scratch=%d ",i,regnames[i],regscratch[i]);
+    if(reg_pair(i,&rp))
+      printf("pair(%s,%s)",regnames[rp.r1],regnames[rp.r2]);
+    printf("\n");
+  }
+#endif
+
+  if(NOPEEP) nopeep=1;
+  if(CBMASCII) cbmascii=1;
+  if(ATASCII) atascii=1;
+  if(C02){
+    c02=1;
+    has_zero_reg=1;
+    has_inc_a=1;
+    jmpinst="bra";
+  }else
+    jmpinst="jmp";
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  bankv.storage_class=EXTERN;
+  bankv.identifier="__bankv";
+  bankv.vtyp=new_typ();
+  bankv.vtyp->flags=CHAR;
+
+  bankcnum=COMMONBANK;
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  int typ=t->flags&NQ;
+  if(ISSTRUCT(typ)||ISUNION(typ)||typ==VOID) 
+    return 0;
+  if(OLDFP&&ISFLOAT(typ)) return FIRST_GPR;
+  if(typ==LONG||typ==FLOAT||ISFPOINTER(typ)||(!ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+    return FIRST_BIG;
+  if(typ==LLONG||(ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+    return FIRST_BIGP;
+  if(zmleq(szof(t),l2zm(1L)))
+    return ra;
+  if(zmleq(szof(t),l2zm(2L))) 
+    return rax;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r>=FIRST_PAIR&&r<=LAST_PAIR){
+    p->r1=(r-FIRST_PAIR)*2+FIRST_GPR;
+    p->r2=p->r1+1;
+    return 1;
+  }else if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+    p->r1=(r-FIRST_BIGP)*2+FIRST_BIG;
+    p->r2=p->r1+1;
+    return 1;
+  }else if(r==rax){
+    p->r1=ra;
+    p->r2=rx;
+    return 1;
+  }else if(r==raxyz) {
+    // TODO: PGS: How do we declare a reg pair that is made of 4 regs, not 2?
+    return 0;
+  }else if(r==sp){
+    p->r1=sp1;
+    p->r2=sp2;
+    return 1;
+  }
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(ISIDX(r)){
+    if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP){
+      if(o==&p->q2&&c!=ADDI2P) return -2;
+    }else if(c==ASSIGN){
+      if(o==&p->q1&&indirect(&p->z)) return 1;
+      if(o==&p->z&&indirect(&p->q1)) return 1;
+    }else if(c==COMPARE){
+      //if(o==&p->q1&&indirect(&p->q2)) return INT_MIN;
+      //if(o==&p->q2&&indirect(&p->q1)) return INT_MIN;
+    }else if(c==TEST){
+    }else if(c==SETRETURN||c==GETRETURN){
+    }else
+      return INT_MIN;
+  }
+  /*TODO: adapt this */
+  if(o->flags&VKONST){
+    return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ){
+    if(isptr(r))
+      return 4;
+    if(r==rax)
+      return INT_MIN;
+  }
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 6;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 6;
+  if(r==ra)
+    return 5;
+  if(ISIDX(r))
+    return 4;
+  if(r==rax)
+    return 2;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  if(r==rax&&NORAX)
+    return 0;
+  t&=NQ;
+  if(ISCHAR(t))
+    if(r==ra||(ISIDX(r)&&(optflags&2))||(r>=FIRST_GPR&&r<=LAST_GPR))
+      return 1;
+  if(ISSHORT(t)){
+    if(r==rax){
+      if(t==POINTER&&mode<0)
+	return 1;
+      if(t!=POINTER)
+	return 1;
+    }
+    if(r>=FIRST_PAIR&&r<=LAST_PAIR)
+      return 1;
+  }
+  if(r>=FIRST_BIG&&r<=LAST_BIG){
+    if(t==LONG||t==FLOAT||((t==DOUBLE||t==LDOUBLE)&&!ieee))
+      return 1;
+    if(t==FPOINTER)
+      return 1;
+  }
+  if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+    if(t==LLONG||((t==DOUBLE||t==LDOUBLE)&&ieee))
+      return 1;
+  }
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+
+  if(op==tp) return 0;
+  if(ISCHAR(op)&&ISCHAR(tp)) return 0;
+  if(ISSHORT(op)&&ISSHORT(tp)) return 0;
+  if(!ieee&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(STDSYNTAX)
+    emit(f,"\tspace\t%ld\n",zm2l(size));
+  else
+    emit(f,"\treserve\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\talign 1\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag,b=bank(v);char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(v->tattr&ZPAGE)
+      emit(f,"\tzpage\t%s%ld\n",labprefix,zm2l(v->offset));
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+      if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+    }
+    gen_align(f,falign(v->vtyp));
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+    if(v->tattr&ZPAGE)
+      emit(f,"\tzpage\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+	if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+      }
+
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%s:\n",idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if(ISCHAR(t))
+    emit(f,"\tbyte\t");
+  else
+    emit(f,"\tword\t");
+  if(!p->tree){
+    if(ISLONG(t)||ISFLOAT(t)){
+      if(ieee&&ISFLOAT(t)){
+	emit_ieee(f,&p->val,t&NQ);
+      }else{
+	eval_const(&p->val,t&NU);
+	if(ISFLOAT(t)) cnv_fp();
+	gval.vmax=zmand(vmax,l2zm(0xffffL));
+	emitval(f,&gval,MAXINT);
+	emit(f,",");
+	gval.vmax=zmand(zmrshift(vmax,l2zm(16L)),l2zm(0xffffL));
+	emitval(f,&gval,MAXINT);
+      }
+    }else{
+      if(ISFPOINTER(t)){
+	eval_const(&p->val,t&NU);
+	emit(f,"%ld\n",(long)zm2l(vmax)&0xffff);
+	emit(f,"\tbyte\t%d\n",(int)((zm2l(vmax)>>16)&0xff));
+      }else
+	emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+    if(ISFPOINTER(t)){
+      int b;
+      if((p->tree->o.flags&(VAR|VARADR))!=(VAR|VARADR)) ierror(0);
+      b=bank(p->tree->o.v);
+      emit(f,"\n\tbyte\t%d",b>=0?b:bankcnum);
+    }
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *mi;
+  FILE *rf=f;
+  static char *dbgfile;
+  static int dbgline;
+
+  if(vlas){
+    fp=FPVLA_REG;
+    if(!reg_pair(fp,&rp)) ierror(0);
+    fp1=rp.r1;
+    fp2=rp.r2;
+    regused[fp]=regused[fp1]=regused[fp2]=1;
+   }else{
+    fp=sp;
+    fp1=sp1;
+    fp2=sp2;
+  }
+  argsize=0;
+  localsize=offset;
+  if(DEBUG&1) printf("gen_code()\n");
+
+  cbank=bank(v);
+
+  if(!v->fi) v->fi=new_fi();
+  v->fi->flags|=ALL_REGS;
+
+  for(pass=0;pass<2;pass++){
+
+    if(DEBUG&1) printf("pass %d\n",pass);
+
+    if(pass==0){
+      f=0;
+      mi=clone_ic(p);
+    }else
+      f=rf;
+
+    for(c=1;c<=MAXR;c++) regs[c]=0; /*regsa[c];*/
+    maxpushed=0;
+
+    /*FIXME*/
+    if(v->tattr&INTERRUPT){
+      ret="\trti\n";
+      in_isr=1;
+    }else{
+      ret="\trts\n";
+      in_isr=0;
+    }
+
+    if(!nopeep) peephole(pass==0?p:mi);
+
+    function_top(f,v,localsize);
+
+    pushed=0;
+
+    yval=NOVAL;
+
+    dbgfile=0;
+    dbgline=0;
+
+    for(p=pass==0?p:mi;p;pr(f,p),p=p->next){
+
+
+
+      if(DEBUG&1) pric2(stdout,p);
+
+      if(debug_info){
+	if(p->file&&p->line){
+	  if(p->file!=dbgfile||p->line!=dbgline){
+	    dbgfile=p->file;
+	    dbgline=p->line;
+	    emit(f,"; %d \"%s\"\n",dbgline,dbgfile);
+	  }
+	}
+      }
+
+      c=p->code;t=p->typf;
+
+      if(c==NOP) {p->z.flags=0;continue;}
+      if(c==ALLOCREG){
+	regs[p->q1.reg]=1;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regs[rp.r1]=1;
+	  regs[rp.r2]=1;
+	}
+	continue;
+      }
+      if(c==FREEREG){
+	regs[p->q1.reg]=0;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regs[rp.r1]=0;
+	  regs[rp.r2]=0;
+	}
+	continue;
+      }
+      if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);yval=NOVAL;continue;}
+      if(c==BRA){
+	yval=NOVAL;
+	if(t==exit_label&&localsize+argsize+rsavesize+rscnt==0)
+	  emit(f,ret);
+	else
+	  emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,t);
+	continue;
+      }
+      if(c>=BEQ&&c<BRA){
+	yval=NOVAL;
+	continue;
+      }
+
+      if(c==MOVETOREG){
+	p->code=c=ASSIGN;
+	p->typf=t=regtype[p->z.reg]->flags;
+	p->q2.val.vmax=sizetab[regtype[p->z.reg]->flags];
+      }
+      if(c==MOVEFROMREG){
+	p->code=c=ASSIGN;
+	p->typf=t=regtype[p->q1.reg]->flags;
+	p->q2.val.vmax=sizetab[regtype[p->q1.reg]->flags];
+      }
+      if(c==CONVERT&&ISCHAR(t)&&ISCHAR(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[CHAR];
+      }
+      if(c==CONVERT&&msizetab[t&NQ]==3&&msizetab[p->typf2&NQ]==3){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[SHORT];
+      }
+      if(c==CONVERT&&ISSHORT(t)&&ISSHORT(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[SHORT];
+      }
+      if(c==CONVERT&&ISLONG(t)&&ISLONG(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[LONG];
+      }
+      if(c==CONVERT&&ISLLONG(t)&&ISLLONG(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[LLONG];
+      }
+      if(c==CONVERT&&ISFLOAT(t)&&ISFLOAT(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[t&NQ];
+      }
+
+
+      /* switch commutative operands if suitable */
+      if(c==ADD||c==MULT||c==AND||c==XOR||c==OR||(c==ADDI2P&&ISSHORT(t)&&!ISFPOINTER(p->typf2))){
+	if(compare_objects(&p->q2,&p->z)||isacc(q2)){
+	  struct obj tmp;
+	  tmp=p->q1;
+	  p->q1=p->q2;
+	  p->q2=tmp;
+	}
+      }
+
+      if(c==COMPARE&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+	obj tmp;
+	tmp=p->q1;
+	p->q1=p->q2;
+	p->q2=tmp;
+      }
+
+      c=p->code;
+      if(c==SUBPFP) c=SUB;
+      /*if(c==ADDI2P) c=ADD;*/
+      /*if(c==SUBIFP) c=SUB;*/
+
+
+      if(c==MINUS){
+	if(isacc(q1)&&isacc(z)){
+          if(ISCHAR(t)){
+            emit(f,"\tneg\n");
+          }else{
+	    emit(f,"\teor\t#255\n");
+            emit(f,"\tclc\n");
+            emit(f,"\tadc\t#1\n");
+          }
+          if(!ISCHAR(t)){
+            emit(f,"\tpha\n");
+            emit(f,"\ttxa\n");
+            emit(f,"\teor\t#255\n");
+            emit(f,"\tadc\t#0\n");
+            emit(f,"\ttax\n");
+            emit(f,"\tpla\n");
+          }
+          continue;
+        }
+	p->code=c=SUB;
+	p->q2=p->q1;
+	p->q1.flags=KONST;
+	p->q1.am=0;
+	gval.vmax=Z0;
+	eval_const(&gval,MAXINT);
+	insert_const(&p->q1.val,t);
+      }
+
+      preload(f,p);
+
+      if(c==CONVERT){
+	int to=q1typ(p)&NU;
+	t&=NU;
+	if(ISCHAR(t)){
+	  get_acc(f,p,CHAR);
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  continue;
+	}
+	if(ISLONG(to)){
+	  if(!isacc(z))
+	    get_acc(f,p,CHAR);
+	  if(zm2l(sizetab[t&NQ])==3){
+	    do_byte3(f,"lda",&p->q1,to);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  if(zm2l(sizetab[t&NQ])>=2){
+	    load_hibyte(f,&p->q1,to);
+	    store_hibyte(f,&p->z,t);
+	  }
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  continue;
+	}
+	if(ISSHORT(to)){
+	  if((t&UNSIGNED)||ISFPOINTER(t))
+	    get_acc(f,p,CHAR);
+	  else
+	    get_acc(f,p,SHORT);
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  load_hibyte(f,&p->q1,to);
+	  store_hibyte(f,&p->z,t);
+	  if(ISFPOINTER(t)){
+	    int b=-1;
+	    if((p->q1.flags&(VARADR|DREFOBJ))==VARADR) b=bank(p->q1.v);
+	    emit(f,"\tlda\t#%d\n",b>=0?b:bankcnum);
+	    do_byte3(f,"sta",&p->z,t);
+	    continue;
+	  }
+	  if(to&UNSIGNED){
+	    if(has_zero_reg&&!indirect(&p->z)){
+	      // 65C02 Z is Zero, not a changeable register, so we can
+	      // use it to clear upper bytes.
+	      // This is NOT the case on 4510/M65, where Z is an index register
+	      do_byte3(f,"stz",&p->z,t);
+	      do_byte4(f,"stz",&p->z,t);
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      do_byte3(f,"sta",&p->z,t);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	  }else{
+	    emit(f,"\tldx\t#0\n");
+	    emit(f,"\tcmp\t#0\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(indirect(&p->z)){
+	      emit(f,"\ttxa\n");
+	      do_byte3(f,"sta",&p->z,t);
+	      do_byte4(f,"sta",&p->z,t);
+	    }else{
+	      do_byte3(f,"stx",&p->z,t);
+	      do_byte4(f,"stx",&p->z,t);
+	    }
+	  }
+	  continue;
+	}
+	if(ISCHAR(to)){
+	  if(to&UNSIGNED){
+	    get_acc(f,p,CHAR);
+	    if(ISLONG(t)){
+	      load_lobyte(f,&p->q1,to);
+	      store_lobyte(f,&p->z,t);
+	      if(has_zero_reg&&!indirect(&p->z)){
+		// 65C02 Z is Zero, not a changeable register, so we can
+		// use it to clear upper bytes.
+		// This is NOT the case on 4510/M65, where Z is an index register
+		do_hibyte(f,"stz",&p->z,t);
+		do_byte3(f,"stz",&p->z,t);
+		if(ISLONG(t))
+		  do_byte4(f,"stz",&p->z,t);
+	      }else{
+		emit(f,"\tlda\t#0\n");
+		store_hibyte(f,&p->z,t);
+		do_byte3(f,"sta",&p->z,t);
+		if(ISLONG(t))
+		  do_byte4(f,"sta",&p->z,t);
+	      }
+	      continue;
+	    }
+	    if(isacc(z))
+	      emit(f,"\tldx\t#0\n");
+	    else if(isacc(q1)){
+	      emit(f,"\tldx\t#0\n");
+	      store_acc(f,&p->z,t);
+	      continue;
+	    }else{
+	      if(has_zero_reg&&!indirect(&p->z)){
+		// 65C02 Z is Zero, not a changeable register, so we can
+		// use it to clear upper bytes.
+		// This is NOT the case on 4510/M65, where Z is an index register
+		do_hibyte(f,"stz",&p->z,t);
+	      }else{
+		emit(f,"\tlda\t#0\n");
+		store_hibyte(f,&p->z,t);
+	      }
+	    }
+	    load_lobyte(f,&p->q1,to);
+	    store_lobyte(f,&p->z,t);
+	  }else{
+	    int l=++label;
+	    get_acc(f,p,SHORT);
+	    emit(f,"\tldx\t#0\n");
+	    if(isreg(q1)&&p->q1.reg==ra)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      load_lobyte(f,&p->q1,to);
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    store_lobyte(f,&p->z,t);
+	    if(indirect(&p->z)&&(!isreg(z)||p->z.reg!=rax)){
+	      emit(f,"\ttxa\n");
+	      store_hibyte(f,&p->z,t);
+	      if(ISLONG(t)){
+		do_byte3(f,"sta",&p->z,t);
+		do_byte4(f,"sta",&p->z,t);
+	      }
+	    }else{
+	      if(!isreg(z)||p->z.reg!=rax){
+		emit(f,"\tstx\t");
+		emit_hibyte(f,&p->z,t);
+		emit(f,"\n");
+	      }
+	      if(ISLONG(t)){
+		do_byte3(f,"stx",&p->z,t);
+		do_byte4(f,"stx",&p->z,t);
+	      }
+	    }
+	  }
+	  if(ISFPOINTER(t)){
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  continue;
+	}
+	if(ISFPOINTER(to)){
+	  get_acc(f,p,CHAR);
+	  if(zm2l(sizetab[t&NQ])>=3){
+	    do_byte3(f,"lda",&p->q1,to);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  if(zm2l(sizetab[t&NQ])>=2){
+	    load_hibyte(f,&p->q1,to);
+	    store_hibyte(f,&p->z,t);
+	  }
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+
+	  continue;
+	}
+	ierror(0);
+      }
+
+      if(c==KOMPLEMENT){
+	get_acc(f,p,CHAR);
+	if(ISCHAR(t)){
+	  load_acc(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_acc(f,&p->z,t);
+	}else{
+	  if(isacc(q1))
+	    emit(f,"\tpha\n");
+	  if(ISLONG(t)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\teor\t#-1\n");
+	    do_byte4(f,"sta",&p->z,t);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\teor\t#-1\n");
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  load_hibyte(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_hibyte(f,&p->z,t);
+	  if(isacc(q1))
+	    emit(f,"\tpla\n");
+	  load_lobyte(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_lobyte(f,&p->z,t);
+	}
+	continue;
+      }
+      if(c==SETRETURN){
+	t&=NQ;
+	if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+	if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+	  long l=zm2l(p->q2.val.vmax);
+	  int zr=p->z.reg;
+	  //get_acc(f,p,t);
+	  if((optsize||l>4)&&!ISFPOINTER(t)){
+	    int ind=indirect(&p->q1);
+	    if(ind) load_address(f,LAST_PAIR,&p->q1,t);
+	    BSET(regused,t3);
+	    BSET(regused,t4);
+	    sety(f,l-1);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    if(ind)
+	      emit(f,"\tlda\t(%s),y\n",mregnames[LAST_PAIR]);
+	    else{
+	      emit(f,"\tlda\t");
+	      if(!ISFLOAT(t)&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+		emit(f,"%s%d",labprefix,addfpconst(&p->q1,t));
+	      }else
+		emit_obj(f,&p->q1,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tsta\t%s,y\n",mregnames[zr]);
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    yval=255;
+	  }else{
+	    if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	      if(p->q1.reg==zr){
+		int r=get_reg(f,p,POINTER);
+		if(r==FIRST_PAIR||r==FIRST_PAIR+1)
+		  ierror(0);
+		if(!reg_pair(r,&rp2)) ierror(0);
+		emit(f,"\tlda\t%s\n",mregnames[zr]);
+		emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+		emit(f,"\tlda\t%s+1\n",mregnames[zr]);
+		emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+		p->q1.reg=r;
+	      }
+	    }
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[zr]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s+1\n",mregnames[zr]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s+2\n",mregnames[zr]);
+	    if(!ISFPOINTER(t)){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s+3\n",mregnames[zr]);
+	    }
+	    /*TODO:regused OLDFP */
+	    regused[zr]=1;
+	  }
+	  continue;
+	}
+	//get_acc(f,p,t);
+	load_acc(f,&p->q1,t);
+	regused[ra]=1;
+	regused[rx]=1;
+	continue;
+      }
+      if(c==GETRETURN){
+	t&=NQ;
+	if(isreg(z)&&p->q1.reg==p->z.reg) continue;
+	if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+	  long l=zm2l(p->q2.val.vmax);
+	  int qr=p->q1.reg;
+	  if((optsize||l>4)&&!ISFPOINTER(t)){
+	    int ind=indirect(&p->z);
+	    if(ind) load_address(f,LAST_PAIR,&p->z,t);
+	    BSET(regused,t3);
+	    BSET(regused,t4);
+	    sety(f,l-1);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    emit(f,"\tlda\t%s,y\n",mregnames[qr]);
+	    if(ind)
+	      emit(f,"\tsta\t(%s),y\n",mregnames[LAST_PAIR]);
+	    else{
+	      emit(f,"\tsta\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    yval=255;
+	  }else{
+	    if((p->z.reg&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	      if(p->z.reg==qr) ierror(0);
+	    }
+	    emit(f,"\tlda\t%s\n",mregnames[qr]);
+	    store_lobyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s+1\n",mregnames[qr]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s+2\n",mregnames[qr]);
+	    do_byte3(f,"sta",&p->z,t);
+	    if(!ISFPOINTER(t)){
+	      emit(f,"\tlda\t%s+3\n",mregnames[qr]);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	  }
+	  continue;
+	}
+	if(p->q1.reg)
+	  store_acc(f,&p->z,t);
+	continue;
+      }
+      if(c==CALL){
+	int reg;
+
+	if(argsize<zm2l(p->q2.val.vmax)) argsize=zm2l(p->q2.val.vmax);
+
+	/*FIXME*/
+#if 0      
+	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	  if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	    stack=framesize+zum2ul(p->q1.v->fi->stack1);
+	}else
+	  stack_valid=0;
+#endif
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	  long of=va_offset(v)+localsize+rsavesize+argsize;
+	  emit(f,"\tlda\t%s\n",mregnames[fp]);
+	  if(of){
+	    emit(f,"\tclc\n");
+	    if(of&255)
+	      emit(f,"\tadc\t#%d\n",(of&255));
+	  }
+	  emit(f,"\tldx\t%s+1\n",mregnames[fp]);
+	  if(of&0xff00){
+	    emit(f,"\tpha\n");
+	    emit(f,"\ttxa\n");
+	    emit(f,"\tadc\t#%d\n",(of>>8)&255);
+	    emit(f,"\ttax\n");
+	    emit(f,"\tpla\n");
+	  }else if(of){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	    emit(f,"\tinx\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }
+	  continue;
+	}
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	  emit(f,";startinline\n");
+	  emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	  emit(f,";endinline\n");
+	}else if(p->q1.flags&DREFOBJ){
+	  if(ISFPOINTER(p->q1.dtyp)){
+	    p->q1.flags&=~DREFOBJ;
+	    load_reg(f,LAST_PAIR,&p->q1,POINTER);
+	    if(indirect(&p->q1)){
+	      do_byte3(f,"lda",&p->q1,FPOINTER);
+	      emit(f,"\ttay\n");
+	    }else
+	      do_byte3(f,"ldy",&p->q1,FPOINTER);
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	    emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+	    yval=NOVAL;
+	  }else{
+	    if(!(p->q1.flags&REG)) ierror(0);
+	    emit(f,"\tjsr\t%s%d\n",labprefix,++label);
+	    yval=NOVAL;
+	    add_cmplist(label,p->q1.reg,JMPIND);
+	  }
+	}else{
+	  int tbank=-1;
+	  if(p->q1.flags&VAR) tbank=bank(p->q1.v);
+	  if(tbank!=cbank&&tbank>=0){
+	    if(cbank>=0){
+	      load_address(f,LAST_PAIR,&p->q1,t);
+	      sety(f,tbank);
+	      emit(f,"\tlda\t#%d\n",cbank);
+	      emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+	      yval=NOVAL;
+	      continue;
+	    }
+	    sety(f,tbank);
+	    emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+	    yval=NOVAL;
+	  }
+	  if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"_fmemcpy"))
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	  emit(f,"\tjsr\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+	pushed-=zm2l(p->q2.val.vmax);
+	if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+	yval=NOVAL;
+	continue;
+      }
+      if(c==ASSIGN||c==PUSH){
+	if(t==0) ierror(0);
+	if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)==LLONG){
+	  int i;
+	  eval_const(&p->q1.val,t);
+	  for(i=0;i<8;i++){
+	    emit(f,"\tlda\t#%d\n",zm2l(vmax)&255);
+	    vmax=zmrshift(vmax,l2zm(8L));
+	    if(c==PUSH||(p->z.flags&DREFOBJ)){
+	      sety(f,i+((c==PUSH)?pushed:0));
+	      emit(f,"\tsta\t(%s),y\n",(c==PUSH)?mregnames[sp]:mregnames[p->z.reg]);
+	    }else{
+	      p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((long)i));
+	      emit(f,"\tsta\t");
+	      emit_lobyte(f,&p->z,t);
+	      emit(f,"\n");
+	      p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)i));
+	    }
+	  }
+	  if(c==PUSH) pushed+=8;
+	  continue;
+	}  
+
+	if(!zmleq(p->q2.val.vmax,l2zm(4L))){
+	  long len=zm2l(p->q2.val.vmax);
+	  int r1,r2,loops,looplab;
+	  if(len>32767) ierror(0);
+	  if(!NOBANKVARS){
+	    int bq=-1,bz=-1,s=-1;
+	    if((p->q1.flags&(VAR|DREFOBJ))==VAR) bq=bank(p->q1.v);
+	    if((p->z.flags&(VAR|DREFOBJ))==VAR) bz=bank(p->z.v);
+	    if(((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp))||
+	       ((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp))){
+	      far_copy(f,p);
+	      continue;
+	    }
+	    if(cbank<0){
+	      if(bq>=0&&bz>=0){
+		if(bq!=bz){
+		  far_copy(f,p);
+		  continue;
+		}
+		s=bq;
+	      }else{
+		if(bq>=0) s=bq;
+		if(bz>=0) s=bz;
+	      }
+	      if(s>=0){
+		sety(f,s);
+		emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+		yval=NOVAL;
+	      }
+	    }else{
+	      if((bq>=0&&bq!=cbank)||(bz>=0&&bz!=cbank)){
+		far_copy(f,p);
+		continue;
+	      }
+	    }
+	  }
+	  get_acc(f,p,CHAR);
+	  if((p->q1.flags&(DREFOBJ|KONST))==DREFOBJ){
+	    if(p->q1.flags&REG){
+	      r1=p->q1.reg;
+	      if(!reg_pair(r1,&rp)) ierror(0);
+	      if(len>128){
+		emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+		emit(f,"\tclc\n");
+		if(len&128)
+		  emit(f,"\tadc\t#128\n");
+		emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+		if(len>255){
+		  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+		  emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+		  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);	
+		}else{
+		  emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+		  emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+		  emit(f,"%s%d:\n",labprefix,label);
+		}
+	      }
+	    }else
+	      ierror(0);
+	  }else if(!indirect(&p->q1)&&len<=128&&(p->q1.flags&(DREFOBJ|KONST))!=KONST){
+	    r1=0;
+	  }else{
+	    Var *v=p->q1.v;
+	    /*if((p->q1.flags&(VARADR|VAR))!=VAR) ierror(0);*/
+	    r1=get_reg(f,p,POINTER);
+	    if(len>128) p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm(len&0xff80));
+	    load_address(f,r1,&p->q1,t);
+	    if(len>128) p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm(len&0xff80));
+	  }
+	  if((p->z.flags&(DREFOBJ|KONST))==DREFOBJ){
+	    if(p->z.flags&REG){
+	      r2=p->z.reg;
+	      if(!reg_pair(r2,&rp)) ierror(0);
+	      if(len>128){
+		emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+		emit(f,"\tclc\n");
+		if(len&128)
+		  emit(f,"\tadc\t#128\n");
+		emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+		if(len>255){
+		  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+		  emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+		  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);	
+		}else{
+		  emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+		  emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+		  emit(f,"%s%d:\n",labprefix,label);
+		}
+	      }
+	    }else
+	      ierror(0);
+	  }else if(c==PUSH){
+	    if(len<=128&&pushed==0){
+	      r2=sp;
+	    }else{
+	      r2=get_reg(f,p,POINTER);
+	      if(!reg_pair(r2,&rp)) ierror(0);
+	      emit(f,"\tlda\t%s\n",mregnames[sp]);
+	      emit(f,"\tclc\n");
+	      if(((pushed+(len&128))&255)!=0)
+		emit(f,"\tadc\t#%ld\n",(pushed+(len&128))&255);
+	      emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	      emit(f,"\tlda\t%s\n",mregnames[sp2]);
+	      emit(f,"\tadc\t#%ld\n",((pushed+len)>>8)&255);
+	      emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+	    }
+	  }else if(!indirect(&p->z)&&len<=128){
+	    r2=0;
+	  }else{
+	    Var *v=p->z.v;
+	    r2=get_reg(f,p,POINTER);
+	    if(len>128) p->z.val.vmax=zmadd(p->z.val.vmax,l2zm(len&0xff80));
+	    load_address(f,r2,&p->z,t);
+	    if(len>128) p->z.val.vmax=zmsub(p->z.val.vmax,l2zm(len&0xff80));
+	  }
+	  if(len>128){
+	    get_acc(f,p,POINTER); /* get x */
+	    emit(f,"\tldx\t#%ld\n",((len>>7)+1)&255);
+	  }
+	  sety(f,(len-1)&127);
+	  if((optsize&&len>4)||len>8){
+	    emit(f,"%s%d:\n",labprefix,looplab=++label);
+	    if(optsize)
+	      loops=1;
+	    else{
+	      if((len&3)==0)
+		loops=4;
+	      else if((len&1)==0)
+		loops=2;
+	      else
+		loops=1;
+	    }
+	  }else
+	    loops=len;
+	  if(r1&&!reg_pair(r1,&rp)) ierror(0);
+	  if(r2&&!reg_pair(r2,&rp2)) ierror(0);
+	  for(i=0;i<loops;i++){
+	    if(r1)
+	      emit(f,"\tlda\t(%s),y\n",mregnames[rp.r1]);
+	    else{
+	      emit(f,"\tlda\t");
+	      emit_obj(f,&p->q1,t);
+	      emit(f,",y\n");
+	    }
+	    if(r2)
+	      emit(f,"\tsta\t(%s),y\n",mregnames[rp2.r1]);
+	    else{
+	      emit(f,"\tsta\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tdey\n");
+	  }
+	  if(loops!=len){
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	  }	  
+	  if(len>128){
+	    emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	    emit(f,"\tsec\n");
+	    emit(f,"\tsbc\t#128\n");
+	    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	    emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	    emit(f,"\tlda\t%s\n",mregnames[rp2.r1]);
+	    emit(f,"\tsec\n");
+	    emit(f,"\tsbc\t#128\n");
+	    emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	    emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdec\t%s\n",mregnames[rp2.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	    emit(f,"\tldy\t#127\n");
+	    emit(f,"\tdex\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,looplab);
+	  }
+	  yval=NOVAL;
+	  if(c==PUSH)
+	    pushed+=zm2l(p->q2.val.vmax);
+	  continue;
+	}
+	if(c==PUSH){
+	  get_acc(f,p,CHAR);
+	  load_lobyte(f,&p->q1,t);
+	  if(c02&&pushed==0){
+	    emit(f,"\tsta\t(%s)\n",mregnames[sp]);
+	  }else{
+	    sety(f,pushed);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,Z1)){
+	    load_hibyte(f,&p->q1,t);
+	    sety(f,pushed+1);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	    do_byte3(f,"lda",&p->q1,t);
+	    sety(f,pushed+2);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+	    do_byte4(f,"lda",&p->q1,t);
+	    sety(f,pushed+3);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+
+	  pushed+=zm2l(p->q2.val.vmax);
+	  continue;
+	}
+	if(c==ASSIGN){
+	  int c2m;unsigned long v;
+	  if(isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) continue;
+	  if(isacc(q1)){
+	    if(p->q1.reg==rax) get_acc(f,p,CHAR);
+	    store_acc(f,&p->z,t);
+	    continue;
+	  }
+	  if(c02&&!indirect(&p->z)&&(p->q1.flags&(DREFOBJ|KONST))==KONST){
+	    eval_const(&p->q1.val,t);
+	    if(ISFLOAT(t)){
+	      cnv_fp();
+	      v=zum2ul(zm2zum(vmax));
+	    }else
+	      v=zum2ul(vumax);
+	    c2m=1;
+	  }else
+	    c2m=0;
+	  if(!c2m||v!=0)
+	    get_acc(f,p,CHAR);
+	  if(0/*ISCHAR(t)*/){
+	    load_acc(f,&p->q1,t);
+	    store_acc(f,&p->z,t);
+	  }else{
+            // TODO: PGS: Use AXYZ for 32-bit copy if appropriate
+	    // TOGO: PGS: Consider using AXYZ for load, even for 16 or 24-bit values
+	    if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+	      if(c2m&&(v&0xFF000000)==0){
+		// 65C02 Z is Zero, not a changeable register, so we can
+		// use it to clear upper bytes.
+		// This is NOT the case on 4510/M65, where Z is an index register
+		do_byte4(f,"stz",&p->z,t);
+	      }else{
+		do_byte4(f,"lda",&p->q1,t);
+		do_byte4(f,"sta",&p->z,t);
+	      }
+	    }
+	    if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	      if(c2m&&(v&0xFF0000)==0){
+		// 65C02 Z is Zero, not a changeable register, so we can
+		// use it to clear upper bytes.
+		// This is NOT the case on 4510/M65, where Z is an index register
+		do_byte3(f,"stz",&p->z,t);
+	      }else{
+		do_byte3(f,"lda",&p->q1,t);
+		do_byte3(f,"sta",&p->z,t);
+	      }
+	    }
+	    if(!zmleq(p->q2.val.vmax,l2zm(1L))){
+	      if(c2m&&(v&0xFF00)==0){
+		// 65C02 Z is Zero, not a changeable register, so we can
+		// use it to clear upper bytes.
+		// This is NOT the case on 4510/M65, where Z is an index register
+		do_hibyte(f,"stz",&p->z,t);
+	      }else{
+		load_hibyte(f,&p->q1,t);
+		store_hibyte(f,&p->z,t);
+	      }
+	    }
+	    if(c2m&&(v&0xFF)==0){
+	      // 65C02 Z is Zero, not a changeable register, so we can
+	      // use it to clear upper bytes.
+	      // This is NOT the case on 4510/M65, where Z is an index register
+	      do_lobyte(f,"stz",&p->z,t);
+	    }else{
+	      if(isreg(q1)&&ISIDX(p->q1.reg)){
+		store_reg(f,p->q1.reg,&p->z,CHAR);
+	      }else if(isreg(z)&&ISIDX(p->z.reg)){
+		load_reg(f,p->z.reg,&p->q1,t);
+	      }else{
+		load_lobyte(f,&p->q1,t);
+		store_lobyte(f,&p->z,t);
+	      }
+	    }
+	  }
+	}
+	continue;
+      }
+      if(c==ADDRESS){
+	long o=real_offset(&p->q1);
+	get_acc(f,p,CHAR);
+	emit(f,"\tlda\t%s\n",mregnames[fp1]);
+	if(o){
+	  emit(f,"\tclc\n");
+	  if((o&255)!=0)
+	    emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)&255);
+	}
+	store_lobyte(f,&p->z,t);
+	if(isacc(z)) emit(f,"\tpha\n");
+	emit(f,"\tlda\t%s\n",mregnames[fp2]);
+	if(o!=0)
+	  emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)>>8&255);
+	store_hibyte(f,&p->z,t);
+	if(isacc(z)) emit(f,"\tpla\n");
+	continue;
+      }
+
+      if(c==COMPARE||c==TEST){
+	IC *branch=p->next;
+	int pacc=0,bc,bout;
+	while(branch){
+	  if(branch->code>=BEQ&&branch->code<BRA)
+	    break;
+	  if(branch->code!=FREEREG&&branch->code!=ALLOCREG&&branch->code!=NOP)
+	    ierror(0);
+	  branch=branch->next;
+	}
+	bc=branch->code;
+	bout=branch->typf;
+	if(c==TEST){
+	  p->q2.flags=KONST;
+	  gval.vmax=Z0;
+	  eval_const(&gval,MAXINT);
+	  insert_const(&p->q2.val,t);
+	}
+	if((bc==BLE||bc==BGT)&&(p->q2.flags&(DREFOBJ|KONST))==KONST){
+	  eval_const(&p->q2.val,t);
+	  if(!zmeqto(vmax,l2zm(255L))){
+	    vmax=zmadd(vmax,Z1);
+	    gval.vmax=vmax;
+	    eval_const(&gval,t);
+	    insert_const(&p->q2.val,t);
+	    if(bc==BLE) bc=BLT; else bc=BGE;
+	    branch->code=bc;
+	  }
+	}
+	if(ieee&&ISFLOAT(t)){
+	  if(!ieee) ierror(0);
+	  t&=NQ;
+	  if(regs[LAST_PAIR]) ierror(0);
+	  regs[LAST_PAIR]=1;
+	  if(regs[ra]||regs[rax])
+	    ierror(0);
+	  load_address(f,LAST_PAIR,&p->q2,t);
+	  BSET(regused,t3);
+	  BSET(regused,t4);
+	  emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->q1,t);
+	  emit(f,"\tjsr\t%s__fcmp%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  regs[LAST_PAIR]=0;
+	  if(bc==BLT||bc==BLE)
+	    emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	  else if(bc==BGT|bc==BGE)
+	    emit(f,"\tbvs\t%s%d\n",labprefix,bout);
+	  if(bc==BEQ||bc==BLE||bc==BGE)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  continue;
+	}
+	if(ISCHAR(t)){
+	  char *s=0;
+	  if(isreg(q1)&&ISIDX(p->q1.reg)&&!indirect(&p->q2)&&(bc==BEQ||bc==BNE||(t&UNSIGNED))){
+	    static char buf[4]="cpr";
+	    s=buf;s[2]=mregnames[p->q1.reg][0];
+	  }else{
+	    if(pacc=cmp_get_acc(f,p,branch))
+	      bout=++label;
+	    load_acc(f,&p->q1,t);
+	    if(bc==BEQ||bc==BNE||(t&UNSIGNED)){
+	      s="cmp";
+	    }else{
+	      if(bc==BLT||bc==BGE)
+		emit(f,"\tsec\n");
+	      else
+		emit(f,"\tclc\n");
+	      s="sbc";
+	    }
+	  }
+	  if(c==TEST)
+	    emit(f,"\t%s\t#0\n",s);
+	  else
+	    do_lobyte(f,s,&p->q2,t);
+	  if(bc==BEQ)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(t&UNSIGNED){
+	    if(bc==BLT)
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    else if(bc==BGE)
+	      emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+	    else if(bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	    }else if(bc==BGT){
+	      emit(f,";\n\tbeq\t%s%d\n",labprefix,++label);
+	      emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+	      emit(f,"%s%d:\n",labprefix,label);
+	    }else
+	      ierror(0);
+	  }else{
+	    emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	    emit(f,"\teor\t#128\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(bc==BLT||bc==BLE)
+	      emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	    else
+	      emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	  }
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue;
+	}else if(bc==BEQ||bc==BNE||(t&UNSIGNED)||ISFPOINTER(t)){
+	  int in=0;
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+
+	  // PGS Check for special cases of comparing to constants
+	  if(!(ISLONG(t)||ISFPOINTER(t)||isacc(q1))) {
+	    // Is a 16-bit value
+	    if (p->q2.flags&KONST) {
+	      if (!(p->q2.flags&DREFOBJ)) {
+		eval_const(&p->q2.val,t);
+		if(ISFLOAT(t)) cnv_fp();
+		if (zm2l(vmax)==0x100) {
+		  if (bc==BGE) {
+		    // >= $100 we can check by just reading the 2nd byte
+		    // If non-zero, then we take the branch
+		    do_hibyte(f,"lda",&p->q1,t);
+		    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+		    continue;
+		  } else if (bc==BLT) {
+		    // <$100 we can check by just reading the 2nd byte
+		    // And if zero, then we take the branch
+		    do_hibyte(f,"lda",&p->q1,t);
+		    emit(f,"\tbeq\t%s%d\n",labprefix,bout);		  
+		    continue;
+		  }
+		} else if (zm2l(vmax)<0x100) {
+		  // Values <$100 we can do almost as simply, but we have to
+		  // also check the low byte for exceptions.
+		  // XXX PGS TODO
+		  
+		}
+	      }
+	    }
+	  }
+	  
+	  // Far-Pointers are 32-bit on M65
+	  if(ISLONG(t)||ISFPOINTER(t)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_byte4(f,"cmp",&p->q2,t);
+	    if(bc==BEQ)
+	      emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+	    else if(bc==BNE)
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    else if(bc==BLT||bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+	    }else if(bc==BGE||bc==BGT){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,in=++label);	
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    }else
+	      ierror(0);
+	  }
+	  if(ISLONG(t)||ISFPOINTER(t)){
+	    do_byte3(f,"lda",&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_byte3(f,"cmp",&p->q2,t);
+	    if(bc==BEQ)
+	      emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	    else if(bc==BNE)
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    else if(bc==BLT||bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	    }else if(bc==BGE||bc==BGT){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));	
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    }else
+	      ierror(0);	  
+	  }
+	  if(isacc(q1)){
+	    if(!indirect(&p->q2)){
+	      do_hibyte(f,"cpx",&p->q2,t);
+	    }else{
+	      int r=get_reg(f,p,CHAR);
+	      emit(f,"\tpha\n");
+	      load_hibyte(f,&p->q2,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tpla\n");
+	      emit(f,"\tcpx\t%s\n",mregnames[r]);
+	    }
+	  }else{
+	    load_hibyte(f,&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_hibyte(f,"cmp",&p->q2,t);
+	  }
+	  if(bc==BEQ)
+	    emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(bc==BLT||bc==BLE){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	  }else if(bc==BGE||bc==BGT){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  }else
+	    ierror(0);
+	  load_lobyte(f,&p->q1,t);
+	  if(c==TEST)
+	    emit(f,"\tcmp\t#0\n");
+	  else
+	    do_lobyte(f,"cmp",&p->q2,t);
+	  if(bc==BEQ)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(bc==BLT)
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	  else if(bc==BGE)
+	    emit(f,"\tbcs\t%s%d\n",labprefix,bout);	
+	  else if(bc==BLE){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  }else if(bc==BGT){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,in);
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  }else
+	    ierror(0);
+	  if(in)
+	    emit(f,"%s%d:\n",labprefix,in);
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue;
+	}else{
+	  if(bc==BGT||bc==BLE){
+	    obj o;
+	    if(isacc(q1)){
+	      int r;
+	      if(pacc=cmp_get_acc(f,p,branch))
+		bout=++label;
+	      r=get_reg(f,p,CHAR);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_lobyte(f,&p->q2,t);
+	      emit(f,"\tcmp\t%s\n",mregnames[r]);
+	      emit(f,"\tstx\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q2,t);
+	      emit(f,"\tsbc\t%s\n",mregnames[r]);
+	      emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	      emit(f,"\teor\t#128\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      if(bc==BGT)
+		emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	      else
+		emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	      if(pacc){
+		reload_acc(f);
+		add_cmplist(bout,branch->typf,pacc);
+	      }
+	      continue;
+	    }else{
+	      o=p->q1;p->q1=p->q2;p->q2=o;
+	      if(bc==BGT) bc=BLT; else bc=BGE;
+	    }
+	  }
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+	  if(ISLONG(t)){
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,"cmp",&p->q2,t);
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,"sbc",&p->q2,t);
+	    do_byte3(f,"lda",&p->q1,t);
+	    do_byte3(f,"sbc",&p->q2,t);
+	    do_byte4(f,"lda",&p->q1,t);
+	    do_byte4(f,"sbc",&p->q2,t);
+	  }else{
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,"cmp",&p->q2,t);
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,"sbc",&p->q2,t);
+	  }
+	  emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	  emit(f,"\teor\t#128\n");
+	  emit(f,"%s%d:\n",labprefix,label);
+	  if(bc==BLT)
+	    emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	  else if(bc==BGE)
+	    emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	  else
+	    ierror(0);
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue; 
+	}
+	ierror(0);
+      }
+      if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&compare_objects(&p->q1,&p->z)&&(!indirect(&p->q1)||(isreg(q1)&&ISIDX(p->q1.reg)))&&isconst(q2)&&!isacc(z)){
+	long l;
+	eval_const(&p->q2.val,q2typ(p));
+	l=zm2l(vmax);
+	if(c==ADDI2P/*&&(t2&NQ)==POINTER*/) {c=ADD;t=UNSIGNED|INT;}
+	if(c==SUBIFP/*&&(t2&NQ)==POINTER*/) {c=SUB;t=UNSIGNED|INT;}
+	if(c==SUB||c==SUBIFP) l=-l;
+	/*TODO: allow larger types */
+	if(l<3&&l>-3&&(t&NQ)<=INT){
+	  if(l<0){
+	    get_acc(f,p,CHAR);
+	    incmem(f,&p->z,t,SUB,-l);
+	  }else
+	    incmem(f,&p->z,t,ADD,l);
+	  continue;
+	}
+      }
+
+      if((c==LSHIFT||c==RSHIFT)&&isreg(q1)&&isreg(z)&&isconst(q2)&&p->q1.reg==p->z.reg&&p->z.reg!=ra&&p->z.reg!=rax){
+	long l;
+	eval_const(&p->q2.val,q2typ(p));
+	l=zm2l(vmax);
+	/*TODO: allow larger types */
+	if(l<5&&(t&NQ)<=INT){
+	  if(c==RSHIFT&&!(t&UNSIGNED))
+	    get_acc(f,p,CHAR);
+	  incmem(f,&p->z,t,c,l);
+	  continue;
+	}
+      }
+
+      if(c==LSHIFT||c==RSHIFT){
+	long l=-1;int loop=0,r,r2,r3,outl=0;
+	if(isconst(q2)){
+	  eval_const(&p->q2.val,q2typ(p));
+	  l=zm2l(vmax);
+	  loop=0;
+	}else
+	  loop=1;
+	if(l>=0&&optsize){
+	  if(c==LSHIFT&&(l&7)>6) 
+	    loop=1;
+	  else if(c==RSHIFT&&(t&UNSIGNED)&&(l&7)>3)
+	    loop=1;
+	  else if(c==RSHIFT&&!(t&UNSIGNED)&&(l&7)>2)
+	    loop=1;
+	}
+
+	if(!ISCHAR(t))
+	  r=get_reg(f,p,CHAR);
+	if(ISLONG(t)){
+	  r2=get_reg(f,p,CHAR);
+	  r3=get_reg(f,p,CHAR);
+	}
+	if(ISLONG(t)){
+	  get_acc(f,p,CHAR);
+	  if(l>=24){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	      emit(f,"\tsty\t%s\n",mregnames[r2]);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      do_byte4(f,"lda",&p->q1,t);
+
+	    }
+	  }else if(l>=16){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      do_byte3(f,"lda",&p->q1,t);
+
+	    }
+	  }else if(l>=8){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q1,t);
+
+	    }
+	  }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r3]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r]);
+	    do_byte4(f,"lda",&p->q1,t);
+	  }else{
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r3]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r]);
+	    load_lobyte(f,&p->q1,t);
+	  }
+	}else
+	  get_acc(f,p,t);
+	if(!ISLONG(t)){
+	  if(l>=8){
+	    if(!ISSHORT(t)) ierror(0);
+	    if(c==LSHIFT){
+	      if(indirect(&p->q1)){
+		load_lobyte(f,&p->q1,t);
+		emit(f,"\ttax\n");
+		emit(f,"\tlda\t#0\n");
+	      }else{
+		if(isacc(q1))
+		  emit(f,"\ttax\n");
+		else
+		  do_lobyte(f,"ldx",&p->q1,t);
+		emit(f,"\tlda\t#0\n");
+	      }
+	    }else{
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tldx\t#0\n");
+	      if(!(t&UNSIGNED)){
+		emit(f,"\tcmp\t#0\n");
+		emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+		emit(f,"\tdex\n");
+		emit(f,"%s%d:\n",labprefix,label);
+	      }
+	    }
+	  }else
+	    load_acc(f,&p->q1,t);
+	}
+	if(ISSHORT(t))
+	  emit(f,"\tstx\t%s\n",mregnames[r]);
+	if(l>=0) l&=7;
+	if(loop){
+	  if(l>=0)
+	    sety(f,l);
+	  else{
+	    if(indirect(&p->q2)){
+	      emit(f,"\tpha\n");
+	      load_lobyte(f,&p->q2,q2typ(p));
+	      emit(f,"\ttay\n");
+	      emit(f,"\tpla\n");
+	      emit(f,"\tcpy\t#0\n");
+	    }else{
+	      emit(f,"\tldy\t");
+	      emit_lobyte(f,&p->q2,q2typ(p));
+	      emit(f,"\n");
+	    }
+	    outl=++label;
+	    emit(f,"\tbeq\t%s%d\n",labprefix,outl);
+	  }
+	  emit(f,"%s%d:\n",labprefix,++label);
+	}else{
+	  if(ISCHAR(t))
+	    l&=7;
+	  else if(ISSHORT(t))
+	    l&=15;
+	  else
+	    l&=31;
+	}
+	while(l>0||loop){
+	  if(c==LSHIFT){
+	    emit(f,"\tasl\n");
+	    if(!ISCHAR(t))
+	      emit(f,"\trol\t%s\n",mregnames[r]);
+	    if(ISLONG(t)){
+	      emit(f,"\trol\t%s\n",mregnames[r2]);
+	      emit(f,"\trol\t%s\n",mregnames[r3]);
+	    }
+	  }else if(t&UNSIGNED){
+	    emit(f,"\tclc\n");
+	    if(ISLONG(t)){
+	      emit(f,"\tror\t%s\n",mregnames[r3]);
+	      emit(f,"\tror\t%s\n",mregnames[r2]);
+	    }
+	    if(!ISCHAR(t))
+	      emit(f,"\tror\t%s\n",mregnames[r]);
+	    emit(f,"\tror\n");
+	  }else{
+	    if(ISLONG(t)){
+	      emit(f,"\tcmp\t#128\n");
+	      emit(f,"\tror\n");
+	      emit(f,"\tror\t%s\n",mregnames[r]);
+	      emit(f,"\tror\t%s\n",mregnames[r2]);
+	      emit(f,"\tror\t%s\n",mregnames[r3]);
+	    }else{
+	      if(!ISCHAR(t)){
+		emit(f,"\tcpx\t#128\n");
+		emit(f,"\tror\t%s\n",mregnames[r]);
+	      }else
+		emit(f,"\tcmp\t#128\n");
+	      emit(f,"\tror\n");
+	    }
+	  }
+	  if(loop){
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,label);
+	    if(outl) emit(f,"%s%d:\n",labprefix,outl);
+	    yval=0;
+	    break;
+	  }
+	  l--;
+	}
+	if(ISLONG(t)){
+	  if(c==RSHIFT&&!(t&UNSIGNED)){
+	    do_byte4(f,"sta",&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    do_byte3(f,"sta",&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r3]);
+	    store_lobyte(f,&p->z,t);
+	  }else{
+	    store_lobyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    do_byte3(f,"sta",&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r3]);
+	    do_byte4(f,"sta",&p->z,t);
+	  }
+	}else{
+	  if(!ISCHAR(t))
+	    emit(f,"\tldx\t%s\n",mregnames[r]);
+	  if(ISCHAR(t)||indirect(&p->z))
+	    store_acc(f,&p->z,t);
+	  else{
+	    store_lobyte(f,&p->z,t);
+	    if(!isreg(z)||p->z.reg!=rax){
+	      emit(f,"\tstx\t");
+	      emit_hibyte(f,&p->z,t);
+	      emit(f,"\n");
+	    }
+	  }
+	}
+	continue;
+      }
+
+      if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP){
+	char *s;int t2=t,pt=p->typf2;
+	if(!isacc(z))
+	  get_acc(f,p,CHAR);
+	if(c==ADDI2P||c==SUBIFP){
+	  if(c==ADDI2P) c=ADD; else c=SUB;
+	  t=UNSIGNED|INT;
+	  if((pt&NQ)==POINTER&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q1.val,POINTER);
+	    insert_const(&p->q1.val,UNSIGNED|INT);
+	  }
+	}
+	if(c>=OR&&c<=AND)
+	  s=logicals[c-OR];
+	else
+	  s=arithmetics[c-LSHIFT];
+      
+	if(ISFLOAT(t)){
+	  if(!ieee) ierror(0);
+	  t&=NQ;
+	  if(regs[LAST_PAIR]) ierror(0);
+	  get_acc(f,p,INT);
+	  regs[LAST_PAIR]=1;
+	  load_address(f,LAST_PAIR,&p->q1,t);
+	  BSET(regused,t3);
+	  BSET(regused,t4);
+	  emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->q2,t);
+	  emit(f,"\tjsr\t%s__f%s%c\n",idprefix,ename[c],(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->z,t);
+	  emit(f,"\tjsr\t%s__fstore%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  regs[LAST_PAIR]=0;
+	  continue;
+	}else if(ISLONG(t)){
+	  if(c==ADD) emit(f,"\tclc\n");
+	  if(c==SUB) emit(f,"\tsec\n");
+	  load_lobyte(f,&p->q1,t);
+	  do_lobyte(f,s,&p->q2,t);
+	  store_lobyte(f,&p->z,t);
+	  load_hibyte(f,&p->q1,t);
+	  do_hibyte(f,s,&p->q2,t);
+	  store_hibyte(f,&p->z,t);
+	  do_byte3(f,"lda",&p->q1,t);
+	  do_byte3(f,s,&p->q2,t);
+	  do_byte3(f,"sta",&p->z,t);
+	  do_byte4(f,"lda",&p->q1,t);
+	  do_byte4(f,s,&p->q2,t);
+	  do_byte4(f,"sta",&p->z,t);
+	  continue;
+	}else if(ISCHAR(t)){
+	  load_acc(f,&p->q1,t);
+	  if(has_inc_a&&(c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q2.val,t);
+	    if(zmeqto(vmax,Z1)||zmeqto(vmax,l2zm(2L))){
+	      if(zmeqto(vmax,l2zm(2L)))
+		emit(f,"\t%s\n",c==ADD?"ina":"dea");
+	      emit(f,"\t%s\n",c==ADD?"ina":"dea");
+	      store_acc(f,&p->z,t);
+	      continue;
+	    }
+	  }
+	  if(c==ADD) emit(f,"\tclc\n");
+	  if(c==SUB) emit(f,"\tsec\n");
+	  if(isreg(q2)&&ISIDX(p->q2.reg)){
+	    int r=get_reg(f,p,CHAR);
+	    emit(f,"\tst%s\t%s\n",mregnames[p->q2.reg],mregnames[r]);
+	    p->q2.flags=REG;
+	    p->q2.reg=r;
+	  }
+	  do_lobyte(f,s,&p->q2,t);
+	  store_acc(f,&p->z,t);
+	}else if(c==ADD||c==SUB){
+	  int a,r;long l=1;
+	  if(isconst(q2)){
+	    eval_const(&p->q2.val,t2);
+	    l=zm2l(vmax);
+	    l&=0xff00;
+	  }
+	  if(isreg(z)&&p->z.reg==rax) a=1; else a=0;
+	  if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+	    emit(f,"\tldx\t#0\n");
+	  }
+	  if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+	    load_lobyte(f,&p->q2,t);
+	    emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(c==ADD){
+	      if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+	      do_lobyte(f,s,&p->q1,t);
+	      if(isacc(z))
+		emit(f,"\tpha\n");
+	      else
+		store_lobyte(f,&p->z,t);
+	      emit(f,"\ttxa\n");
+	      do_hibyte(f,s,&p->q1,t);
+	      store_hibyte(f,&p->z,t);
+	      if(ISFPOINTER(pt)&&!compare_objects(&p->q1,&p->z)){
+		do_byte3(f,"lda",&p->q1,pt);
+		do_byte3(f,"sta",&p->z,pt);
+	      }
+	      if(isacc(z))
+		emit(f,"\tpla\n");
+	      continue;
+	    }
+	    r=get_reg(f,p,CHAR);
+	    emit(f,"\tstx\t%s\n",mregnames[r]);
+	  }
+	  load_lobyte(f,&p->q1,t);
+	  if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+	  do_lobyte(f,s,&p->q2,t2);
+	  store_lobyte(f,&p->z,t);
+	  if(l==0&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+	    if(c==ADD){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	      if(a)
+		emit(f,"\tinx\n");
+	      else{
+		/*if(!reg_pair(p->z.reg,&rp)) ierror(0);*/
+		emit(f,"\tinc\t%s+1\n",mregnames[p->z.reg]);
+	      }
+	    }else{
+	      emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	      if(a)
+		emit(f,"\tdex\n");
+	      else{
+		if(!reg_pair(p->z.reg,&rp)) ierror(0);
+		emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+	      }
+	    }
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }else{
+	    if(a==1) emit(f,"\tpha\n");
+	    if((t2&NQ)==CHAR){
+	      if(t2&UNSIGNED){
+		load_hibyte(f,&p->q1,t);
+		emit(f,"\t%s\t#0\n",s);
+	      }else{
+		load_hibyte(f,&p->q1,t);
+		if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+		  eval_const(&p->q2.val,t2);
+		  if(zmleq(Z0,vmax))
+		    emit(f,"\t%s\t#0\n",s);
+		  else
+		    emit(f,"\t%s\t#255\n",s);
+		}else{
+		  emit(f,"\t%s\t%s\n",s,mregnames[r]);
+		}
+	      }
+	    }else{
+	      load_hibyte(f,&p->q1,t);
+	      do_hibyte(f,s,&p->q2,t2);
+	    }
+	    store_hibyte(f,&p->z,t);
+	    if(a==1) emit(f,"\tpla\n");
+	    if(ISFPOINTER(pt)&&p->code!=SUBPFP){
+	      if(!compare_objects(&p->q1,&p->z)){
+		do_byte3(f,"lda",&p->q1,FPOINTER);
+		do_byte3(f,"sta",&p->z,FPOINTER);
+	      }
+	    }
+	  }
+	}else{
+	  if(isacc(q1))
+	    emit(f,"\tpha\n");
+	  load_hibyte(f,&p->q1,t);
+	  do_hibyte(f,s,&p->q2,t);
+	  store_hibyte(f,&p->z,t);
+	  if(isacc(q1))
+	    emit(f,"\tpla\n");
+	  load_lobyte(f,&p->q1,t);
+	  do_lobyte(f,s,&p->q2,t);
+	  store_lobyte(f,&p->z,t);
+	}
+	continue;
+      }
+      pric2(stdout,p);
+      ierror(0);
+    }
+
+    function_bottom(f,v,localsize);
+    
+    for(c=1;c<=MAXR;c++){
+      if(regsa[c]||regused[c]){
+	BSET(regs_modified,c);
+      }
+    }
+
+    if(stack_valid){
+      if(!v->fi) v->fi=new_fi();
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=stack;
+    }
+  }
+
+  free_IC(mi);
+
+  emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  if(code==COMPARE/*||code==MULT*/||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT||code==MINUS||code==KOMPLEMENT||code==NEGATION)
+    return 1;
+
+  return 0;
+}
+
+static int fattr(type *p,char *s)
+{
+  if(p->attr&&strstr(p->attr,s))
+    return 1;
+  if(p->next)
+    return fattr(p->next,s);
+  else
+    return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+
+  if(vararg)
+    return 0;
+  f=t->flags&NQ;
+  if(OLDFP&&ISFLOAT(f)) return 0;
+  if(d&&fattr(d,"__stackparms__"))
+    return 0;
+  if(d&&fattr(d,"__cc65__")){
+    m->regs++;
+    printf("arg=%d cnt=%d\n",m->regs,d->exact->count);
+    if(m->regs==d->exact->count-1){
+      if(ISCHAR(t->flags))
+	return ra;
+      if(ISSHORT(t->flags))
+	return rax;
+    }
+    return 0;
+  }
+  if(ISCHAR(f)){
+    if(!t->exact){
+      if(m->regs>=GPR_ARGS-1)
+	return 0;
+      f=FIRST_GPR+m->regs;
+      m->regs+=2;
+      return f;
+    }else{
+      if(m->regs>=GPR_ARGS)
+	return 0;
+      else
+	return FIRST_GPR+m->regs++;
+    }
+  }
+  if(ISSHORT(f)||f==POINTER){
+    if(m->regs>=GPR_ARGS-1)
+      return 0;
+    else{
+      if(m->regs&1) m->regs+=1;
+      m->regs+=2;
+      return FIRST_PAIR+m->regs/2-1;
+    }
+  }
+  if(f==FPOINTER||f==LONG||f==FLOAT||(!ieee&&(f==DOUBLE||f==LDOUBLE))){
+    if(m->bregs>=4)
+      return 0;
+    else
+      return FIRST_BIG+m->bregs++;
+  }
+  if(f==LLONG||(ieee&&(f==DOUBLE||f==LDOUBLE))){
+    if(m->bregs>=3)
+      return 0;
+    else{
+      if(m->bregs&1)  m->bregs++;
+      m->bregs+=2;
+      return FIRST_BIGP+m->bregs/2-1;
+    }
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+  static char sec[SECLEN];
+  int i;
+  if(sscanf(s,"section %127s",sec)==1){
+    if(!strcmp(sec,"default"))
+      use_sec=0;
+    else
+      use_sec=sec;
+    return 1;
+  }
+  if(sscanf(s,"bank %d",&i)==1){
+    use_bank=i;
+    return 1;
+  }
+}
+void cleanup_cg(FILE *f)
+{
+  int i;
+  struct fpconstlist *p=firstfpc;
+
+  if(f&&p){
+    emit(f,rodataname);emit(f,"\n");
+    section=RODATA;
+  }
+  while(p=firstfpc){
+    emit(f,"%s%d:\n\tword\t",labprefix,p->label);
+    if(ieee)
+      emit_ieee(f,&p->val,p->t);
+    else{
+      int words=zm2l(sizetab[p->t&NQ])/2;
+      eval_const(&p->val,p->t);
+      if(ISFLOAT(p->t)) cnv_fp();
+      for(i=0;i<words;i++){
+	emit(f,"%ld",zm2l(vmax)&0xffff);
+	if(i<words-1){emit(f,",");vmax=zmrshift(vmax,l2zm(16L));}
+      }
+      emit(f,"\n");
+      /*emit(f,"%ld,%ld\n",zm2l(vmax)&0xffff,zm2l(zmrshift(vmax,l2zm(16L)))&0xffff);*/
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+
+  emit(f,"\tzpage\t%s\n",mregnames[sp]);
+  for(i=FIRST_GPR;i<=LAST_GPR;i++)
+    emit(f,"\tzpage\t%s\n",mregnames[i]);
+  for(i=FIRST_BIG;i<=LAST_BIG;i++)
+    emit(f,"\tzpage\t%s\n",mregnames[i]);
+
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
+static char *zops[]={
+  "adc","and","asl","bit","eor","lda","ora",
+  "tax","txa","tay","tya","sbc"};
+
+static int setszflag(char *op)
+{
+  int i;
+  for(i=0;i<sizeof(zops)/sizeof(zops[0]);i++)
+    if(!strcmp(op,zops[i]))
+      return 1;
+  return 0;
+}
+
+static char *zxops[]={
+  "tax","txa","ldx","inx","dex"};
+
+static int setszxflag(char *op)
+{
+  int i;
+  for(i=0;i<sizeof(zxops)/sizeof(zxops[0]);i++)
+    if(!strcmp(op,zxops[i]))
+      return 1;
+  return 0;
+}
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+
+
+int emit_peephole(void)
+{
+  int entries,i,j;
+  char *asmline[EMIT_BUF_DEPTH];
+  char buf1[1024],buf2[1024];
+  char op1[8],op2[8];
+  static char ca[1024],cx[1024],cy[1024],cz[1024];
+  static int rm,disabled;
+
+  fprintf(stderr,"Called emit_peephole()\n");
+  
+  static struct peeps elim[]={
+    "lda","sta",0,NEEDSAME,
+    "ldx","stx",0,NEEDSAME,
+    "sta","sta",0,NEEDSAME,
+    "stx","stx",0,NEEDSAME,
+    "sta","lda",0,NEEDSAME,
+    "stx","ldx",0,NEEDSAME,
+    "txa","tax",0,0,
+    "tax","txa",0,0,
+    "lda","lda",0,REMOVE1ST,
+    "ldx","ldx",0,REMOVE1ST,
+    "ldy","ldy",0,REMOVE1ST,
+    "ldz","ldz",0,REMOVE1ST,
+    "lda","pla",0,REMOVE1ST,
+    "lda","txa",0,REMOVE1ST,
+    "lda","tya",0,REMOVE1ST,
+    "ldx","tax",0,REMOVE1ST,
+    "ldy","tay",0,REMOVE1ST,
+    "tay","ldy",0,REMOVE1ST,
+    "taz","ldz",0,REMOVE1ST,
+    "tax","ldx",0,REMOVE1ST,
+    "txa","lda",0,REMOVE1ST,
+    "tya","lda",0,REMOVE1ST,
+    "tza","lda",0,REMOVE1ST,
+    "lda","ldx","\ttax\n",NEEDSAME,
+    "lda","ldy","\ttay\n",NEEDSAME,
+    "ldx","lda","\ttxa\n",NEEDSAME,
+    "ldy","lda","\ttya\n",NEEDSAME,
+    "sta","ldx","\ttax\n",NEEDSAME,
+    "sta","ldy","\ttay\n",NEEDSAME,
+    "stx","lda","\ttxa\n",NEEDSAME,
+    "sty","lda","\ttya\n",NEEDSAME,
+
+  };
+
+  if(nopeep) return 0;
+
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+
+  if(!strcmp(asmline[0],";startinline\n")) disabled=1;
+  if(!strcmp(asmline[0],";endinline\n")) disabled=0;
+  if(disabled) return 0;
+
+  buf1[0]=0;op1[0]=0;
+  if((j=sscanf(asmline[0]," %6s %999s",op1,buf1))>=1){
+    printf("a=%s x=%s y=%s, z=%s\n",ca,cx,cy,cz);
+    printf("\t\t%s %s\n",op1,buf1);
+    if(!strcmp(op1,"sta")) {
+      // Work out when we are accessing variables on the stack
+      if (!strcmp(buf1,"(sp),y")) {
+	// We invalidate this when Y changes
+	snprintf(ca,1024,"(sp),y",cy);
+      } 
+    } else if(!strcmp(op1,"sta")){
+      // Remove writes to wherever A was loaded from
+      if (!strcmp(buf1,ca)) {
+	remove_asm();
+	return rm=1;
+      }
+    } else if(!strcmp(op1,"lda")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,ca)){remove_asm();return rm=1;}
+	strcpy(ca,buf1);
+      }else {
+	// Work out when we are accessing variables on the stack
+	if (!strcmp(buf1,"(sp),y")) {	 
+	  if(!strcmp(buf1,ca)){
+	    remove_asm();
+	    return rm=1;
+	  }
+	  snprintf(ca,1024,"(sp),y",cy);
+	}
+	// Similarly look for register loads
+	// We can sometimes remove some of those, too.
+	if ((strlen(buf1)>1)&&(buf1[0]=='r')) {
+	  if (strcmp(ca,buf1)) 
+	    snprintf(ca,1024,"%s",buf1);
+	  else {
+	    // Don't re-load A with the same contents it already has
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+    }else if(!strcmp(op1,"ldx")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cx)){remove_asm();return rm=1;}
+	strcpy(cx,buf1);
+      }else cx[0]=0;
+    }else if(!strcmp(op1,"ldy")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cy)){remove_asm();return rm=1;}
+	strcpy(cy,buf1);
+      }else cy[0]=0;
+    }else if(!strcmp(op1,"ldz")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cz)){remove_asm();return rm=1;}
+	strcpy(cz,buf1);
+      }else cz[0]=0;
+    }else{
+      // TODO: PGS: Add the AXYZ operations to the clobber lists.
+      //            Will we need to handle them specially?
+      static char clobbernone[]="clc cld cli clv cmp cpx cpy dec inc nop pha php plp sec sed sei sta stx sty stz";
+      static char clobbera[]="adc and asl eor lsr ora pla rol ror sbc txa tya tza neg";
+      static char clobberx[]="dex inx tax tsx";
+      static char clobbery[]="dey iny tay";
+      static char clobberz[]="dez inz taz";
+      if(strstr(clobbernone,op1)){
+	// Invalidate A holding a stack variable byte if SP changes
+	if (strstr(buf1,"sp")) {
+	  printf("buf1='%s'\n",buf1);
+	  if (strstr(ca,"(sp),y")) ca[0]=0;
+	}	
+      }else if(strstr(clobbera,op1))
+	ca[0]=0;
+      else if(strstr(clobberx,op1))
+	cx[0]=0;
+      else if(strstr(clobbery,op1)) {
+	cy[0]=0;
+	// Invalidate A holding a stack variable byte if Y changes
+	if (strstr(ca,"(sp),y")) ca[0]=0;
+      }
+      else if(strstr(clobberz,op1))
+	cz[0]=0;
+      else
+	ca[0]=cx[0]=cy[0]=cz[0]=0;
+    }
+  }else{
+    ca[0]=cx[0]=cy[0]=cz[0]=0;
+  }
+
+  rm=0;
+
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"and")&&!strcmp(buf1,"#0")){
+    strcpy(asmline[0],"\tlda\t#0\n");
+    return rm=1;
+  }
+
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+
+
+    if(!strcmp(asmline[0],"; volatile barrier\n")&&!strcmp(asmline[0],asmline[1])){
+      remove_asm();
+      return rm=1;
+    }
+
+    if(sscanf(asmline[0]," %6s",op1)==1&&!strcmp(op1,"rts")&&
+       sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&!strcmp(op2,"jsr")){
+      sprintf(asmline[1],"\tjmp\t%s\n",buf2);
+      remove_asm();
+      return rm=1;
+    }
+
+    for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+      if(elim[j].flags&NEEDSAME){
+	if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+	   sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+	   !strcmp(buf1,buf2)){
+	  if(elim[j].r){
+	    strcpy(asmline[0],elim[j].r);
+	  }else{
+	    if(elim[j].flags&REMOVE1ST)
+	      strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	  }
+	  return rm=1;
+	}
+      }else{
+	if(sscanf(asmline[1]," %6s",op1)==1&&
+	   sscanf(asmline[0]," %6s",op2)==1&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+	  if(elim[j].flags&REMOVE1ST)
+	    strcpy(asmline[1],asmline[0]);
+	  remove_asm();
+	  return rm=1;
+	}
+      }
+    }
+
+
+  }
+
+  if(entries>=3){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[2]=emit_buffer[i];
+    if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+#if 0
+      if(!strcmp(op1,"lda")&&buf1[0]=='#'){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"sta")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)==2&&
+	     !strcmp(op2,"lda")&&!strcmp(buf1,buf2)){
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+#endif
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"cmp")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s",op2)==1&&
+	     setszflag(op2)){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"cpx")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s",op2)==1&&
+	     setszxflag(op2)){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+    }
+  }
+  
+  return 0;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||(ISFLOAT(t)&&!ieee)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(ISSHORT(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+      return 0;
+    if(ISLONG(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+      return 0;
+
+    if(!ieee&&ISFLOAT(t)) t=FLOAT;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(!ieee&&ISFLOAT(t2)) t2=FLOAT;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==INT||(t&NQ)==LONG||(t&NQ)==LLONG||(!ieee&&ISFLOAT(t))){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+        if(t==(UNSIGNED|LLONG)&&(c==MULT||c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint64",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+        }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint32",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LONG){
+          sprintf(fname,"__%sint32",ename[c]);
+          ret=fname;
+        }else if(t==(UNSIGNED|INT)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint16",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==INT){
+          sprintf(fname,"__%sint16",ename[c]);
+          ret=fname;
+        }else{
+          sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+        }
+      }
+    }
+  }
+
+  return ret;
+}
+
+
+int pointer_varadr(Var *v)
+{
+  int b=bank(v);
+  if(b>=0&&b!=bankcnum&&!NOBANKVARS){
+    if(cur_funcv&&bank(cur_funcv)!=b)
+      return FPOINTER;
+  }
+  return pointer_type(v->vtyp);
+}
+
+int pointer_type(struct Typ *p)
+{
+  struct Typ *merk=p;
+  if(!p) ierror(0);
+  if(LARGE) return FPOINTER;
+  while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+  if(p->attr){
+    char *s;
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return POINTER;
+  }
+  return POINTER;
+}
+
+unsigned char cbmconv(unsigned char x)
+{
+  static unsigned char ctab[256]={
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+    0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0xBF,0x5D,0x5E,0xA4,
+    0xAD,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB3,0xDD,0xAB,0xB1,0xDF,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0x5F,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0x7D,0xAC,0x60,0xAE,0xAF,
+    0xB0,0x7E,0xB2,0x7B,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0x5C,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0xDC,0x7C,0xDE,0x7F,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+  };
+
+  static unsigned char atab[]={0xfd,8,0x7f,0x9b,11,0x7d};
+
+  if(cbmascii)
+    return ctab[x&255];
+  else if(atascii&&x>=7&&x<=12)
+    return atab[x-7];
+  else
+    return x;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+/*  *p = (union atyps) 0 ; /* rfi: clear unused bits */
+  t&=NU;
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==POINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==POINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==POINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==POINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+        if(strstr(attr,STR_NEAR))
+          p->flags=((p->flags&~NU)|POINTER);
+        if(strstr(attr,STR_FAR))
+          p->flags=((p->flags&~NU)|FPOINTER);
+        if(strstr(attr,STR_HUGE))
+          p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    p=p->next;
+  }
+}
+
+void add_var_hook_post(Var *v)
+{
+  if(use_sec&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+    char buf[SECLEN+32];
+    sprintf(buf,"section(\"%s\");",use_sec);
+    add_attr(&v->vattr,buf);
+  }
+  if(use_bank>=0&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+    char buf[64];
+    /*sprintf(buf,"section(\"bank%d\");bank(%d)",use_bank,use_bank);*/
+    sprintf(buf,"bank(%d)",use_bank);
+    add_attr(&v->vattr,buf);
+  }
+}
+
+int decide_reverse(zmax v)
+{
+  if(zmeqto(v,Z1)||zmeqto(v,l2zm(2L)))
+    return 1;
+  if(optspeed)
+    if(zmeqto(v,l2zm(4L))||zmeqto(v,l2zm(8L))||zmeqto(v,l2zm(256L))||zmeqto(v,l2zm(512L)))
+      return 1;
+  
+  return 0;
+}
+
+static int is_single_eff_ic(struct IC *p)
+{
+  struct Var *v,*idx;
+  if(p->code!=ADDI2P||(p->typf2&NQ)!=POINTER)
+    return 0;
+  if(!(p->q2.flags&KONST)){
+    if((p->typf&NU)!=(UNSIGNED|CHAR))
+      return 0;
+    if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+      return 0;
+    if(p->q2.v->storage_class!=AUTO&&p->q2.v->storage_class!=REGISTER)
+      return 0;
+    idx=p->q2.v;
+  }else{
+    idx=0;
+    eval_const(&p->q2.val,p->typf);
+    /* TODO: more precise check considering data type useful? */
+    if(!zmleq(vumax,l2zm(255L)))
+      return 0;
+    return 1;
+  }
+  if(p->q1.flags&DREFOBJ)
+    return 0;
+  if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+    return 0;
+  v=p->z.v;
+  for(p=p->next;p;p=p->next){
+    int c=p->code;
+    if(c==LABEL||(c>=BEQ&&c<=BRA))
+      return 1; /* TODO: how elaborate should we test? */
+    if((p->q1.flags&VAR)&&p->q1.v==v){
+      if(p->q1.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==v){
+      if(p->q2.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->z.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==idx)
+      return 0;
+  }
+  return 0;
+}
+
+void mark_eff_ics(void)
+{
+  struct IC *p;
+  for(p=first_ic;p;p=p->next){
+    if(is_single_eff_ic(p))
+      p->flags|=EFF_IC;
+    else
+      p->flags&=~EFF_IC;
+  }
+}
diff --git a/machines/m65/machine.dt b/machines/m65/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/m65/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/m65/machine.h b/machines/m65/machine.h
new file mode 100755
index 0000000..ca54ff9
--- /dev/null
+++ b/machines/m65/machine.h
@@ -0,0 +1,269 @@
+/*  MEGA65 / 45GS02 backend for vbcc
+    (c) Volker Barthelmann 2020
+    (c) Paul Gardner-Stephen 2020
+
+*/
+
+/* built-time configurable options: */
+#define NUM_GPRS 32
+#define NUM_PAIRS (NUM_GPRS/2)
+#define NUM_BIG 4
+#define NUM_BIGP (NUM_BIG/2)
+#define FIXED_SP 1
+
+#include "dt.h"
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define FPOINTER 11
+#define HPOINTER 12
+#define ARRAY 13
+#define STRUCT 14
+#define UNION 15
+#define ENUM 16
+#define FUNKT 17
+#define BOOL 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+
+#define POINTER_TYPE(x) pointer_type(x)
+#define POINTER_VARADR(x) pointer_varadr(x)
+extern int pointer_type();
+extern int pointer_varadr();
+#define ISPOINTER(x) ((x&NQ)>=POINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+
+/* internally used by the backend */
+#define FIRST_GPR 10
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_PAIR (LAST_GPR+1)
+#define LAST_PAIR (FIRST_PAIR+NUM_PAIRS-1)
+#define FIRST_BIG (LAST_PAIR+1)
+#define LAST_BIG (FIRST_BIG+NUM_BIG-1)
+#define FIRST_BIGP (LAST_BIG+1)
+#define LAST_BIGP (FIRST_BIGP+NUM_BIGP-1)
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+  int flags;
+  int base;
+  int idx;
+  long offset;
+  void *v;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR LAST_BIGP
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P CHAR
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+  int regs;
+  int bregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 3
+// MEGA65 CPU has one wait-state on reads when CPU is at full speed
+#define cost_load_reg(x,y) 5
+#define cost_save_reg(x,y) 4
+#define cost_pushpop_reg(x) 6
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 8
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we have additional types */
+#define HAVE_EXT_TYPES
+#define HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#define HAVE_REGPAIRS 1
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 0
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 0
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* Use char for return of comparison libcalls */
+#define LIBCALL_CMPTYPE CHAR
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define BESTCOPYT CHAR
+
+#define HAVE_AOS4 1
+
+#define CHARCONV(x) cbmconv(x)
+unsigned char cbmconv(unsigned char);
+
+#define ALLOCVLA_REG FIRST_PAIR
+#define ALLOCVLA_INLINEASM "\tlda\tsp\n"\
+                           "\tsec\n"\
+                           "\tsbc\tr0\n"\
+                           "\tsta\tsp\n"\
+                           "\tlda\tsp+1\n"\
+                           "\tsbc\tr1\n"\
+                           "\tsta\tsp+1\n"\
+                           "\tlda\tsp\n"\
+                           "\tclc\n"\
+                           "\tldx\tsp+1\n"\
+                           "\tadc\t#___fo\n"\
+                           "\tbcc\t*+3\n"\
+                           "\tinx\n"
+
+#define FREEVLA_REG FIRST_PAIR
+#define FREEVLA_INLINEASM "\tlda\tr0\n"\
+                          "\tsta\tsp\n"\
+                          "\tlda\tr1\n"\
+                          "\tsta\tsp+1\n"
+
+#define OLDSPVLA_INLINEASM "\tlda\tsp+1\n"\
+                           "\ttax\n"\
+                           "\tlda\tsp"
+
+#define FPVLA_REG (LAST_PAIR-2)
+
+#define HAVE_TARGET_VARHOOK_POST 1
+
+#define HAVE_DECIDE_REVERSE 1
+
+#define HAVE_TARGET_EFF_IC 1
diff --git a/machines/m65/merge.c b/machines/m65/merge.c
new file mode 100755
index 0000000..2e43d73
--- /dev/null
+++ b/machines/m65/merge.c
@@ -0,0 +1,4995 @@
+/*  MEGA65 45GS02 backend for vbcc
+    (c) Volker Barthelmann 2020
+    (c) Paul Gardner-Stephen 2020
+
+*/                                                                             
+
+#include "supp.h"
+#include "vbc.h"
+
+#include <math.h>
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc 45GS02 (MEGA65) code-generator V0.1 (c) in 2020 by Volker Barthelmann, Paul Gardner-Stephen";
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+		    VALFLAG,0,0,
+		    0,0,
+		    VALFLAG,VALFLAG,0,0,
+		    VALFLAG,0,0,0,
+		    0,0,0,
+		    0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"std-syntax","no-rax",
+			   "volatile-regs","ieee","no-peephole",
+			   "cbmascii","softstack",
+			   "reg-args","int-args","mainargs","no-bank-vars",
+			   "common-banknr","btmp-zpage","oldfp","large",
+			   "glob-acc","avoid-bank-switch","manual-banking",
+			   "atascii"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__zpage","__nocpr",0};
+
+#define INTERRUPT 1
+#define ZPAGE 2
+#define NOCOMPRESS 4
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define STDSYNTAX  (g_flags[0]&USEDFLAG)
+#define NORAX      (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define IEEE       (g_flags[3]&USEDFLAG)
+#define NOPEEP     (g_flags[4]&USEDFLAG)
+#define CBMASCII   (g_flags[5]&USEDFLAG)
+#define SOFTSTACK  (g_flags[6]&USEDFLAG)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:8)
+#define MAINARGS   (g_flags[9]&USEDFLAG)
+#define NOBANKVARS (g_flags[10]&USEDFLAG)
+#define COMMONBANK ((g_flags[11]&USEDFLAG)?g_flags_val[11].l:0)
+#define BIGZPAGE   (g_flags[12]&USEDFLAG)
+#define OLDFP      (g_flags[13]&USEDFLAG)
+#define LARGE      (g_flags[14]&USEDFLAG)
+#define GLOBACC    (g_flags[15]&USEDFLAG)
+#define NOSWITCH   (g_flags[16]&USEDFLAG)
+#define NOBANKING  (g_flags[17]&USEDFLAG)
+#define ATASCII    (g_flags[18]&USEDFLAG)
+
+
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define PLA (-1)
+#define JMPIND (-2)
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isacc(x) (isreg(x)&&(p->x.reg==ra||p->x.reg==rax))
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define isptr(r) ((r)>=FIRST_PAIR&&(r)<=LAST_PAIR)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"ora","eor","and"};
+static char *arithmetics[]={"slw","srw","adc","sbc","mullw","divw","mod"};
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,2,4,8,4,4,4,0,2,3,3,0,0,0,1,0};
+static char *mregnames[MAXR+1];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","int","long","long long",
+                 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+                 "array","struct","union","enum","function"};
+
+
+/* used to initialize regtyp[] */
+static struct Typ ityp={INT},ctyp={CHAR},ftyp={FLOAT},lltyp={LLONG};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__m65__", 
+		       "__SIZE_T_INT",
+		       "__bank(x)=__vattr(\"bank(\"#x\")\")",
+                       "__far=__attr(\"far\")",
+                       "__near=__attr(\"near\")",
+                       "__huge=__attr(\"huge\")",
+		       0};
+
+/* special registers */
+static int ra=1, rx=2, ry=3, rz=4, sp1=5,sp2=6,sp=7,fp,fp1,fp2;
+static int t4=LAST_GPR,t3=LAST_GPR-1,t2=LAST_GPR-2,t1=LAST_GPR-3;
+static int rax=8;
+static int raxyz=9;
+static int yval;
+#define NOVAL 1000
+
+static int t1,t2,f1,f2; /*tODO: remove*/
+
+static int pushedacc,pushedx,nopeep,cbmascii,atascii,ieee;
+static int pass;
+static int libsave;
+static struct rpair rp2;
+static int cbank;
+static Var bankv;
+static int bankvoffset;
+static int bankcnum;
+static obj zstore;
+static int zstoreflag;
+
+#define SECLEN 128
+char *use_sec;
+int use_bank=-1;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* perhaps provide version with 8bit int? */
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSHORT(t) ((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==POINTER)
+#define ISFPOINTER(t) ((t&NQ)==FPOINTER)
+#define ISLONG(t) ((t&NQ)==LONG)
+#define ISLLONG(t) ((t&NQ)==LLONG)
+
+/* am */
+#define IMM_IND 1
+#define GPR_IND 2
+#define ABS_IND 3
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\tsection\ttext",
+  *dataname="\tsection\tdata",
+  *bssname="\tsection\tbss",
+  *rodataname="\tsection\trodata";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+
+static long localsize,rsavesize,rscnt,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static int bank(Var *v)
+{
+  char *s=v->vattr;
+  int n,r;
+  if(!NOBANKING&&s&&(s=strstr(s,"bank("))){
+    if(sscanf(s+5,"%i",&n)==1)
+      return n;
+  }
+  return -1;
+}
+
+static void ebank(FILE *f,int b)
+{
+  if(b>=0) emit(f,"%d",b);
+  emit(f,"\n");
+}
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize-off-zm2l(maxalign);
+  }
+
+  off+=argsize;
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(v->tattr&ZPAGE){
+    emit(f,"\tsection\tzpage\n");
+  }else{
+    if(!v->vattr) return 0;
+    sec=strstr(v->vattr,"section(");
+    if(!sec) return 0;
+    sec+=strlen("section(");
+    emit(f,"\tsection\t");
+    while(*sec&&*sec!=')') emit_char(f,*sec++);
+    emit(f,"\n");
+  }
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+
+
+#define chk_coll(x) do{if((x)==r||(x)==r1||(x)==r2) return 0;	\
+    if(reg_pair((x),&rp)&&(rp.r1==r||rp.r2==r)) return 0;}while(0)
+
+static int scratch(IC *p,int r)
+{
+  int r1,r2;
+  if(!p) return 1;
+  if(reg_pair(r,&rp)){
+    r1=rp.r1;
+    r2=rp.r2;
+  }else{
+    r1=0;
+    r2=0;
+  }
+  if(isreg(z)&&p->z.reg==r){
+    if(!(p->q2.flags&REG))
+      return 1;
+    if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)
+      return 0;
+    if(reg_pair(p->q2.reg,&rp))
+      if(rp.r1==r||rp.r2==r)
+	return 0;
+    return 1;
+  }
+  while(p){
+    if(p->code==LABEL||p->code==CALL)
+      return 0;
+    if(p->code>=BEQ&&p->code<=BRA)
+      return 0;
+    if(p->code==FREEREG||p->code==ALLOCREG){
+      if(p->q1.reg==r)
+	return 1;
+      if(reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))
+	return 1;
+    }
+    if(p->q1.am) chk_coll(p->q1.am->base);
+    if(p->q2.am) chk_coll(p->q2.am->base);
+    if(p->z.am) chk_coll(p->z.am->base);
+    if(p->q1.flags&REG) chk_coll(p->q1.reg);
+    if(p->q2.flags&REG) chk_coll(p->q2.reg);
+    if(p->z.flags&REG){
+      if(p->z.flags&DREFOBJ)
+	chk_coll(p->z.reg);
+      else{
+	if(p->z.reg==r)
+	  return 1;
+	if(reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r))
+	  return 1;
+      }
+    }
+
+    p=p->next;
+  }
+  return 1;
+}
+
+static int rsavecur;
+static int in_isr;
+
+static int get_reg(FILE *f,IC *p,int t)
+{
+  int r,r1,r2,pass,flag;
+
+  for(pass=0;pass<5;pass++){
+    for(r=MAXR;r>sp;r--){
+      if(reg_pair(r,&rp)){
+	r1=rp.r1;
+	r2=rp.r2;
+      }else{
+	r1=0;
+	r2=0;
+      }
+      if((pass==0||pass==3)&&(!regscratch[r]||in_isr))
+	continue;
+      if(pass<3){
+	if(regs[r]) continue;
+	if(r1&&(regs[r1]||regs[r2])) continue;
+      }
+      if(pass==2&&!(regs[r]&4))
+	continue;
+      if((p->q1.flags&REG)&&(p->q1.reg==r||p->q1.reg==r1||p->q1.reg==r2)) continue;
+      if((p->q2.flags&REG)&&(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)) continue;
+      if((p->z.flags&REG)&&(p->z.reg==r||p->z.reg==r1||p->z.reg==r2)) continue;
+      if(regok(r,t,1)){
+	flag=8;
+	if(regs[r]){
+	  flag|=2;
+	  if(p->code==COMPARE||p->code==TEST)
+	    ierror(0);
+	  if(regs[ra]){
+	    emit(f,"\ttay\n");
+	    yval=NOVAL;
+	  }
+	  if(r1){
+	    emit(f,"\tlda\t%s\n",mregnames[r1]);
+	    emit(f,"\tpha\n");
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    emit(f,"\tpha\n");
+	  }else{
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    emit(f,"\tpha\n");
+	  }
+	  if(regs[ra])
+	    emit(f,"\ttya\n");
+	}
+	if(r1){
+	  regs[r1]|=flag;
+	  regs[r2]|=flag;
+	}
+	regs[r]|=flag;
+	regused[r]=1;
+	regused[r1]=1;
+	regused[r2]=1;
+	return r;
+      }
+    }
+  }
+  pric2(stdout,p);
+  ierror(0);
+}
+
+static void get_acc(FILE *f, IC *p,int t)
+{
+  int r;
+  if(isacc(z)) return;
+  t&=NQ;
+  if(ISCHAR(t)){
+    if(1/*!isreg(q1)||(p->q1.reg!=ra&&p->q1.reg!=rax)*/){
+      if((regs[ra]||regs[rax])&&!scratch(p,ra)&&!pushedacc){
+	if(optsize||(regs[t1]&&regs[t2]&&regs[t3]&&regs[t4])){
+	  emit(f,"\tpha\n");
+	  pushedacc=-1;
+	}else{
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	  pushedacc=r;
+	}
+      }
+    }
+  }else{
+    if(1/*!isreg(q1)||p->q1.reg!=rax*/){
+      if((regs[ra]||regs[rax])&&(!scratch(p,ra)||!scratch(p,rax))&&!pushedacc){
+	r=get_reg(f,p,CHAR);
+	emit(f,"\tsta\t%s\n",mregnames[r]);
+	pushedacc=r;
+      }
+      if((regs[rx]||regs[rax])&&!scratch(p,rax)&&!pushedx){
+	r=get_reg(f,p,CHAR);
+	emit(f,"\tstx\t%s\n",mregnames[r]);
+	pushedx=r;
+      }
+    }
+  }
+}
+
+static int cmp_get_acc(FILE *f,IC *p,IC *branch)
+{
+  if(!regs[ra]&&!regs[rax])
+    return 0;
+  if(branch==0&&pushedacc)
+    return 0;
+  if(branch&&isreg(q1)&&(p->q1.reg==ra||p->q1.reg==rax))
+    if(branch->code==BEQ||branch->code==BNE||(p->typf&UNSIGNED))
+      return 0;
+  if(scratch(p,ra))
+    return 0;
+  if(!regs[rx]&&!regs[rax]){
+    emit(f,"\ttax\n");
+    pushedacc=rx;
+  }
+  emit(f,"\tpha\n");
+  pushedacc=-1;
+  return pushedacc;
+}
+
+static void reload_acc_opt(FILE *f,IC *p)
+{
+  if(pushedacc==0) return;
+  if(pushedacc>0){
+    while(p){
+      if(p->code!=FREEREG) break;
+      if(p->q1.reg==ra||p->q1.reg==rax){
+	pushedacc=0;
+	return;
+      }
+      p=p->next;
+    }
+  }
+  if(pushedacc==-1)
+    emit(f,"\tpla\n");
+  else if(pushedacc==rx)
+    emit(f,"\ttxa\n");
+  else if(pushedacc==ry)
+    emit(f,"\ttya\n");
+  else if(pushedacc){
+    emit(f,"\tlda\t%s\n",mregnames[pushedacc]);
+    regs[pushedacc]&=~8;
+  }
+  pushedacc=0;
+}
+
+static void reload_acc(FILE *f)
+{
+  reload_acc_opt(f,0);
+}
+
+static void push(int i)
+{
+  pushed-=i;
+  if(pushed<maxpushed)
+    maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+  pushed+=i;
+  if(pushed>0) ierror(0);
+}
+
+static int indirect(obj *o)
+{
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ)
+    return 1;
+  if((o->flags&(REG|VAR))!=VAR)
+    return 0;
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+    return 1;
+  return 0;
+}
+
+void convfloat(void)
+{
+}  
+
+void sety(FILE *f,int val)
+{
+  if(yval==val)
+    return;
+  if(val-yval==1)
+    emit(f,"\tiny\n");
+  else if(yval-val==1)
+    emit(f,"\tdey\n");
+  else{
+    emit(f,"\tldy\t#%d\n",val);
+    if(val<0||val>255)
+      ierror(0);
+  }
+  yval=val;
+}
+
+static void cnv_fp(void)
+{
+  double d,mant;
+  int exp;
+  unsigned long t;
+
+  if(ieee){
+    vfloat=zld2zf(vldouble);
+    memcpy((void*)&vmax,(void*)&vfloat,4);
+  }else{
+    d=zld2d(vldouble);
+    mant=frexp(d,&exp);
+    exp=(exp+127)&255;
+    t=((unsigned long)(mant*8388608))&0xffffff;
+    t|=((long)exp)<<24;
+    
+    t=((t&0xff)<<24)|((t&0xff00)<<8)|((t&0xff0000)>>8)|((t&0xff000000)>>24);
+    vmax=l2zm((long)t);
+  }
+}
+
+static void emit_ieee(FILE *f,union atyps *p,int t)
+{
+  unsigned char *ip=(unsigned char *)&p->vdouble;
+  emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+  if(t==DOUBLE||t==LDOUBLE)
+    emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+  emit(f,"\n");
+}
+
+static void emit_lobyte(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+       emit(f,"%d",zm2l(vmax));
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",zm2l(vmax)&255);
+    }
+  }else if(o->flags&VARADR){
+    emit(f,"#<(");
+    emit_obj(f,o,t);
+    emit(f,")");
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp))
+      emit(f,"%s",mregnames[o->reg]);
+    else
+      emit(f,"%s",mregnames[rp.r1]);
+  }else{
+    emit_obj(f,o,t);
+  }
+}
+
+static void emit_hibyte(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+1);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>8)&255);
+    }
+  }else if(o->flags&VARADR){
+    emit(f,"#>(");
+    emit_obj(f,o,t);
+    emit(f,")");
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg>=FIRST_BIG&&o->reg<=LAST_BIGP){
+      emit(f,"%s+1",mregnames[o->reg]);
+    }else{
+      if(!reg_pair(o->reg,&rp))
+	ierror(0);
+      emit(f,"%s",mregnames[rp.r2]);
+    }
+  }else{
+    if(o->flags&VARADR)
+      emit(f,"#");
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,Z1);
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,Z1);
+  }
+}
+
+static void emit_byte3(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+2);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>16)&255);
+    }
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    emit(f,"%s+2",mregnames[o->reg]);
+  }else if(o->flags&VARADR){
+    emit(f,"#%d",bank(o->v));
+  }else{
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,l2zm(2L));
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,l2zm(2L));
+  }
+}
+
+static void emit_byte4(FILE *f,obj *o,int t)
+{
+  if(o->flags&KONST){
+    if(o->flags&DREFOBJ){
+      eval_const(&o->val,o->dtyp);
+      emit(f,"%d",zm2l(vmax)+3);
+    }else{
+      eval_const(&o->val,t);
+      if(ISFLOAT(t)) cnv_fp();
+      emit(f,"#%d",(zm2l(vmax)>>24)&255);
+    }
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    emit(f,"%s+3",mregnames[o->reg]);
+  }else{
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmadd(o->val.vmax,l2zm(3L));
+    emit_obj(f,o,t);
+    if(!(o->flags&DREFOBJ))
+      o->val.vmax=zmsub(o->val.vmax,l2zm(3L));
+  }
+}
+
+static void do_lobyte(FILE *f,char *s,obj *o,int type)
+{
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset);
+    else if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      yval=NOVAL;
+    }else
+      ierror(0);
+  }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,0);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o));
+  }
+  emit(f,"\t%s\t",s);
+  emit_lobyte(f,o,type);
+  emit(f,"\n");
+}
+
+static void do_hibyte(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+1);
+    else if(o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      o->am->offset++;ami=1;
+      yval=NOVAL;
+    }else
+      ierror(0);
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,1);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+1);
+  }
+  emit(f,"\t%s\t",s);
+  emit_hibyte(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset--;
+}
+
+static void do_byte3(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+2);
+    else if(o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      yval=NOVAL;
+      o->am->offset+=2;ami=1;
+    }else
+      ierror(0);
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,2);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+2);
+  }
+  emit(f,"\t%s\t",s);
+  emit_byte3(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset-=2;
+}
+
+static void do_byte4(FILE *f,char *s,obj *o,int type)
+{
+  int ami=0;
+  if(o->am){
+    if(o->am->flags==IMM_IND)
+      sety(f,o->am->offset+3);
+    else if(o->am->flags==ABS_IND){
+      if(o->am->offset==ra)
+	emit(f,"\ttay\n");
+      else
+	emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+      yval=NOVAL;
+      o->am->offset+=3;ami=1;
+    }else
+      ierror(0);
+  }else  if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+    sety(f,3);
+  }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+    sety(f,(int)real_offset(o)+3);
+  }
+  emit(f,"\t%s\t",s);
+  emit_byte4(f,o,type);
+  emit(f,"\n");
+  if(ami) o->am->offset-=3;
+}
+
+static void load_lobyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==ra||o->reg==rax)
+      return;
+    if(o->reg==rx){
+      emit(f,"\ttxa\n");
+      return;
+    }
+  }
+  do_lobyte(f,"lda",o,t);
+}
+
+static void load_hibyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&REG)&&(o->reg==rx||o->reg==rax))
+    emit(f,"\ttxa\n");
+  else
+    do_hibyte(f,"lda",o,t);
+}
+
+static void store_lobyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==ra||o->reg==rax)
+      return;
+    if(o->reg==rx){
+      emit(f,"\ttax\n");
+      return;
+    }
+  }
+  do_lobyte(f,"sta",o,t);
+}
+
+static void store_hibyte(FILE *f,obj *o,int t)
+{
+  if((o->flags&REG)&&(o->reg==rx||o->reg==rax))
+    emit(f,"\ttax\n");
+  else
+    do_hibyte(f,"sta",o,t);
+}
+
+static void load_acc(FILE *f,obj *o,int type)
+{
+  if((o->flags&REG)&&(o->reg==ra||o->reg==rax))
+    return;
+  if(!ISCHAR(type)){
+    if(indirect(o)){
+      do_hibyte(f,"lda",o,type);
+      emit(f,"\ttax\n");
+    }else
+      do_hibyte(f,"ldx",o,type);
+  }
+  if((o->flags&(REG|DREFOBJ))==REG&&o->reg==rx)
+    emit(f,"\ttxa\n");
+  else
+    do_lobyte(f,"lda",o,type);
+}
+
+static void store_acc(FILE *f,obj *o,int type)
+{
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&((!(o->flags&REG))||!isptr(o->reg))){
+    ierror(0);
+  }
+  if((o->flags&REG)&&(o->reg==ra||o->reg==rax))
+    return;
+  if((o->flags&REG)&&o->reg==rx){
+    emit(f,"\ttax\n");
+    return;
+  }
+  store_lobyte(f,o,type);
+  if(!ISCHAR(type)){
+    if(indirect(o)){
+      /*TODO: save accu */
+      emit(f,"\ttxa\n");
+      store_hibyte(f,o,type);
+    }else
+      do_hibyte(f,"stx",o,type);
+  }
+}
+
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  static obj ro;
+  ro.flags=REG;
+  ro.reg=r;
+  load_lobyte(f,o,type);
+  store_lobyte(f,&ro,type);
+  if(!ISCHAR(type)){
+    load_hibyte(f,o,type);
+    store_hibyte(f,&ro,type);
+  }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  static obj ro;
+  if(r==rx){
+    if((o->flags&(REG|DREFOBJ))==REG){
+      if(o->reg==rx)
+	return;
+      if(o->reg==ra){
+	emit(f,"\ttxa\n");
+	return;
+      }
+    }
+  }
+  ro.flags=REG;
+  ro.reg=r;
+  if(r!=ra&&r!=rax)
+    load_acc(f,&ro,type);
+  store_acc(f,o,type);
+}
+
+static struct fpconstlist {
+  struct fpconstlist *next;
+  int label;
+  int t;
+  union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(t==LDOUBLE) t=DOUBLE;
+  for(p=firstfpc;p;p=p->next){
+    if(t==p->t){
+      eval_const(&p->val,t);
+      if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+      if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+      if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+      if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->t=t;
+  p->label=++label;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+/* generate code to load the address of a local variable into register r */
+static void load_laddr(FILE *f,int r,struct obj *o)
+{
+  long l=real_offset(o);
+  /* assumes acc is available */
+  if(!reg_pair(r,&rp)) ierror(0);
+  emit(f,"\tlda\t%s\n",mregnames[fp]);
+  if(l!=0)
+    emit(f,"\tclc\n");
+  if(l&255)
+    emit(f,"\tadc\t#%ld\n",l&255);
+  emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+  emit(f,"\tlda\t%s\n",mregnames[fp2]);
+  if(l!=0)
+    emit(f,"\tadc\t#%ld\n",(l>>8)&255);
+  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int t)
+{
+  if(o->flags&DREFOBJ){
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER);
+    o->flags|=DREFOBJ;
+  }else if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t#>%s\n",mregnames[o->reg]);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    emit(f,"\tlda\t#<%s\n",mregnames[o->reg]);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);    
+  }else if(o->flags&VAR){
+    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+      load_laddr(f,r,o);
+    }else{
+      o->flags|=VARADR;
+      load_reg(f,r,o,POINTER);
+      o->flags&=~VARADR;
+    }
+  }else if((o->flags&(KONST|DREFOBJ))==KONST){
+    int l=addfpconst(o,t);
+    if(!ieee) ierror(0);
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t#>%s%d\n",labprefix,l);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    emit(f,"\tlda\t#<%s%d\n",labprefix,l);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);    
+  }else
+    ierror(0);
+}
+
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static void incmem(FILE *f,obj *o,int t,int op,int x)
+{
+  int i;
+  char *s;
+
+  // PGS: All registers and pseudo registers on the M65 target
+  // live in zero-page, so we can use INW and DEW for fast
+  // increment/decrement.
+  if (o->flags&REG) {
+    switch(op) {
+    case ADD:
+      if(ISCHAR(t)){
+	emit(f,"\tinc\t");
+	emit_obj(f,o,t);
+	emit(f,"\n");	
+      } else {
+	emit(f,"\tinw\t");
+	emit_obj(f,o,t);
+	emit(f,"\n");	
+      }
+      return;
+      break;
+    case SUB:
+      if(ISCHAR(t)){
+	emit(f,"\tdec\t");
+	emit_obj(f,o,t);
+	emit(f,"\n");	
+      } else {
+	emit(f,"\tdew\t");
+	emit_obj(f,o,t);
+	emit(f,"\n");	
+      }
+      return;
+      break;
+    }
+  }
+  
+  if(op==ADD)
+    s="inc";
+  else if(op==SUB)
+    s="dec";
+  else if(op==LSHIFT)
+    s="asl";
+  else if(op==RSHIFT&&(t&UNSIGNED))
+    s="clc\n\tror";
+  else if(op==RSHIFT){
+    s="cmp\t#128\n\tror";
+  }else
+    ierror(0);
+  if(ISCHAR(t)){
+    for(i=0;i<x;i++){
+      emit(f,"\t%s\t",s);
+      emit_obj(f,o,t);
+      emit(f,"\n");
+    }
+  }else{
+    for(i=0;i<x;i++){
+      if(op==SUB){
+	/* caller mus make sure accu is available */
+	load_lobyte(f,o,t);
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	emit(f,"\tdec\t");
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	emit(f,"\tdec\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");	
+      }else if(op==ADD){
+	emit(f,"\t%s\t",s);
+	emit_lobyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	emit(f,"\t%s\t",s);
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+      }else if(op==LSHIFT){
+	// 4510 / 45GS02 have ASW/ROW operations
+	// for left-shifting 16-bit values
+	
+	emit(f,"\tasw\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");
+
+      }else if(op==RSHIFT&&(t&UNSIGNED)){
+	emit(f,"\tclc\n");
+	emit(f,"\tror\t");
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"\tror\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");
+      }else if(op==RSHIFT){
+	load_hibyte(f,o,t);
+	emit(f,"\tcmp\t#128\n");
+	emit(f,"\tror\t");
+	emit_hibyte(f,o,t);
+	emit(f,"\n");
+	emit(f,"\tror\t");
+	emit_lobyte(f,o,t);
+	emit(f,"\n");	
+      }else{
+	printf("op=%d\n",op);
+	ierror(0);
+      }
+    }
+  }
+}
+
+static void preload_obj(FILE *f,IC *p,obj *o)
+{
+  int r;long of;
+
+  if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+     ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+    emit(f,"; volatile barrier\n");
+
+
+  if((o->flags&(VAR|REG))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&(of=real_offset(o))+zm2l(szof(o->v->vtyp))>255){
+    r=get_reg(f,p,POINTER);
+    if(o->flags&DREFOBJ)
+      get_acc(f,p,INT);
+    else
+      cmp_get_acc(f,p,0);
+    if(!reg_pair(r,&rp)) ierror(0);
+    emit(f,"\tlda\t%s\n",mregnames[fp1]);
+    emit(f,"\tclc\n");
+    if(of&0xff)
+      emit(f,"\tadc\t#%ld\n",of&0xff);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    emit(f,"\tlda\t%s\n",mregnames[fp2]);
+    if(1/*of&0xff00*/)
+      emit(f,"\tadc\t#%ld\n",(of>>8)&0xff);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    o->flags|=REG;
+    o->reg=r;
+    if(o->flags&DREFOBJ){
+      sety(f,0);
+      emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+      emit(f,"\ttxa\n");
+      sety(f,1);
+      emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+      emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+      emit(f,"\tstx\t%s\n",mregnames[rp.r1]);
+    }else{
+      o->flags|=DREFOBJ;
+      o->dtyp=POINTER;
+    }
+  }
+
+  if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&(!(o->flags&REG)||!isptr(o->reg))&&(!(o->flags&VAR)||!(o->v->tattr&ZPAGE))&&!ISFPOINTER(o->dtyp)){
+    cmp_get_acc(f,p,0);
+    r=get_reg(f,p,POINTER);
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER);
+    o->flags|=REG|DREFOBJ;
+    o->reg=r;
+  }
+}
+
+static void far_copy(FILE *f,IC *p)
+{
+  int b;long l;
+  get_acc(f,p,INT);
+  if(p->code==PUSH){
+    if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+    emit(f,"\tlda\t%s\n",mregnames[sp]);
+    if(pushed) emit(f,"\tclc\n");
+    if(pushed&0xff) emit(f,"\tadc\t#%d\n",(pushed&0xff));
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+    if(pushed) emit(f,"\tadc\t#%d\n",((pushed>>8)&0xff));
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    pushed+=zm2l(p->q2.val.vmax);
+    emit(f,"\tldx\t#%d\n",bankcnum);
+  }else if(p->z.flags&DREFOBJ){
+    if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+    p->z.flags&=~DREFOBJ;
+    load_lobyte(f,&p->z,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    load_hibyte(f,&p->z,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    if(indirect(&p->z)){
+      do_byte3(f,"lda",&p->z,FPOINTER);
+      emit(f,"\ttax\n");
+    }else
+      do_byte3(f,"ldx",&p->z,FPOINTER);
+  }else{
+    load_address(f,LAST_PAIR,&p->z,POINTER);
+    b=bank(p->z.v);
+    emit(f,"\tldx\t#%d\n",b>=0?b:bankcnum);
+  }
+  if(p->q1.flags&DREFOBJ){
+    if(!reg_pair(LAST_PAIR-1,&rp)) ierror(0);
+    p->q1.flags&=~DREFOBJ;
+    load_lobyte(f,&p->q1,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+    load_hibyte(f,&p->q1,FPOINTER);
+    emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+    if(indirect(&p->q1)){
+      do_byte3(f,"lda",&p->q1,FPOINTER);
+      emit(f,"\ttay\n");
+    }else
+      do_byte3(f,"ldy",&p->q1,FPOINTER);
+  }else{
+    load_address(f,LAST_PAIR-1,&p->q1,POINTER);
+    b=bank(p->q1.v);
+    sety(f,b>=0?b:bankcnum);
+  }
+  l=zm2l(p->q2.val.vmax);
+  emit(f,"\tlda\t#%d\n",(l>>8)&0xff);
+  emit(f,"\tsta\t%s__bankcopy_len+1\n",idprefix);
+  emit(f,"\tlda\t#%d\n",(l)&0xff);
+  emit(f,"\tsta\t%s__bankcopy_len\n",idprefix);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  emit(f,"\tjsr\t%s__bankcopy\n",idprefix);
+  yval=NOVAL;
+}
+
+static void load_far(FILE *f,IC *p,obj *o,int t)
+{
+  int pushed=0;
+  if(!(o->flags&DREFOBJ)) ierror(0);
+  o->flags&=~DREFOBJ;
+  t&=NQ;
+  if(zmeqto(sizetab[t],Z0)) return;
+  /*get_acc(f,p,INT);*/
+  if(pushedacc==t3||pushedacc==t4) ierror(0);
+  if(pushedx==t3||pushedx==t4) ierror(0);
+  if(regs[ra]||regs[rax]){
+    if(isacc(q1)||isacc(q2)||!isacc(z)){
+      pushed=1;
+      emit(f,"\tpha\n");
+      if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+    }
+  }
+  load_reg(f,LAST_PAIR,o,POINTER);
+  if(!indirect(o))
+    do_byte3(f,"ldy",o,CHAR);
+  else{
+    do_byte3(f,"lda",o,CHAR);
+    emit(f,"\ttay\n");
+  }
+  emit(f,"\tldx\t#%d\n",bankvoffset);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+  yval=NOVAL;
+  o->flags=VAR;
+  o->v=&bankv;
+  o->val.vmax=l2zm((long)bankvoffset);
+  bankvoffset+=zm2l(sizetab[t]);
+  if(pushed){
+    if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+    emit(f,"\tpla\n");
+  }
+}
+
+static void load_banked(FILE *f,IC *p,obj *o,int t)
+{
+  int pushed=0,m;
+  if(o->flags&DREFOBJ) t=o->dtyp;
+  t&=NQ;
+  if(zmeqto(sizetab[t],Z0)) return;
+  /*get_acc(f,p,INT);*/
+  if(pushedacc==t3||pushedacc==t4) ierror(0);
+  if(pushedx==t3||pushedx==t4) ierror(0);
+  if(regs[ra]||regs[rax]){
+    if(isacc(q1)||isacc(q2)||!isacc(z)){
+      pushed=1;
+      emit(f,"\tpha\n");
+      if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+    }
+  }
+  m=o->flags;
+  o->flags&=~DREFOBJ;
+  load_address(f,LAST_PAIR,o,POINTER);
+  o->flags=m;
+  emit(f,"\tldx\t#%d\n",bankvoffset);
+  emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+  sety(f,bank(o->v));
+  emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+  yval=NOVAL;
+  o->v=&bankv;
+  o->val.vmax=l2zm((long)bankvoffset);
+  bankvoffset+=zm2l(sizetab[t]);
+  if(pushed){
+    if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+    emit(f,"\tpla\n");
+  }
+}
+
+static void preload(FILE *f,IC *p)
+{
+  int r,mra=regs[ra],mrax=regs[rax];
+  int bq1=-1,bq2=-1,bz=-1,sb=-1,zbuf=0;
+
+  if(p->code==GETRETURN&&p->q1.reg==ra&&!regs[ra])
+    regs[ra]=1;
+
+  if(p->code==GETRETURN&&p->q1.reg==rax&&!regs[rax])
+    regs[rax]=1;
+
+  bankvoffset=0;
+
+  if(!NOBANKVARS){
+    if((p->q1.flags&(VAR|VARADR))==VAR) bq1=bank(p->q1.v);
+    if((p->q2.flags&(VAR|VARADR))==VAR) bq2=bank(p->q2.v);
+    if((p->z.flags&(VAR|VARADR))==VAR) bz=bank(p->z.v);
+
+    if((p->q1.flags&(VAR|VARADR))==(VAR|VARADR)){
+      r=bank(p->q1.v);
+      /*if(r>=0&&r!=cbank) ierror(0);*/
+    }
+    
+    if((p->code==ASSIGN||p->code==PUSH)&&!zmleq(p->q2.val.vmax,l2zm(4L))){
+      if(p->q1.flags&DREFOBJ) preload_obj(f,p,&p->q1);
+      if(p->z.flags&DREFOBJ) preload_obj(f,p,&p->z);
+      return;
+    }
+
+    if(p->code!=CALL){
+      /* TODO: some optimizations possible */
+      if(bq1>=0&&bq1!=cbank){
+	if(cbank<0&&!NOSWITCH)
+	  sb=bq1;
+	else
+	  load_banked(f,p,&p->q1,q1typ(p));
+      }
+      if(bq2>=0&&bq2!=cbank){
+	if((bq2==sb||(cbank<0&&sb<0))&&!NOSWITCH)
+	  sb=bq2;
+	else
+	  load_banked(f,p,&p->q2,q2typ(p));
+      }
+      if(bz>=0&&bz!=cbank&&(p->z.flags&DREFOBJ)){
+	if((bz==sb||(cbank<0&&sb<0))||!NOSWITCH)
+	  sb=bz;
+	else
+	  load_banked(f,p,&p->z,ztyp(p));
+      }
+      
+      if(sb>=0){
+	if(NOSWITCH) ierror(0);
+	sety(f,sb);
+	emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+	yval=NOVAL;
+      }
+    }
+  }
+
+  if((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp)&&p->code!=CALL) load_far(f,p,&p->q1,q1typ(p));
+  if((p->q2.flags&DREFOBJ)&&ISFPOINTER(p->q2.dtyp)) load_far(f,p,&p->q2,q2typ(p));
+
+  if(isacc(q2)){
+    static obj o;
+    int t=q2typ(p);
+    r=get_reg(f,p,t);
+    o.flags=REG;
+    o.reg=r;
+    store_acc(f,&o,t);
+    p->q2.reg=r;
+  }
+
+  if(p->code!=ADDRESS){
+    preload_obj(f,p,&p->q1);
+    if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+       (p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+       p->q1.v==p->q2.v){
+      p->q2.flags|=REG;
+      p->q2.reg=p->q1.reg;
+    }
+    if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+       (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+       p->q1.v==p->z.v){
+      p->z.flags|=REG;
+      p->z.reg=p->q1.reg;
+    }
+  }
+
+  preload_obj(f,p,&p->q2);
+  if((p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+     (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+     p->q2.v==p->z.v){
+    p->z.flags|=REG;
+    p->z.reg=p->q1.reg;
+  }
+
+
+  if((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp)) zbuf=1;
+  if((p->z.flags&(VAR|DREFOBJ))==VAR){
+    bz=bank(p->z.v);
+    if(bz>=0&&bz!=cbank) zbuf=1;
+  }
+  
+  if(zbuf&&!NOBANKVARS){
+    zstore=p->z;
+    p->z.flags=VAR;
+    p->z.v=&bankv;
+    p->z.val.vmax=l2zm((long)bankvoffset);
+    zstoreflag=1;
+    /*bankvoffset+=zm2l(sizetab[p->typf&NQ]);*/
+  }else{
+    preload_obj(f,p,&p->z);
+
+    if(isreg(z)){
+      r=0;
+      if(p->q1.am&&p->q1.am->base==p->z.reg){
+	r=get_reg(f,p,POINTER);
+	cmp_get_acc(f,p,0);
+	if(!reg_pair(p->q1.am->base,&rp)) ierror(0);
+	if(!reg_pair(r,&rp2)) ierror(0);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	p->q1.am->base=p->q1.reg=r;
+      }else if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg==p->z.reg){
+	r=get_reg(f,p,POINTER);
+	cmp_get_acc(f,p,0);
+	if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	if(!reg_pair(r,&rp2)) ierror(0);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	p->q1.reg=r;
+      }
+      if(p->q2.am&&p->q2.am->base==p->z.reg){
+	if(r==0){
+	  r=get_reg(f,p,POINTER);
+	  cmp_get_acc(f,p,0);
+	  if(!reg_pair(p->q2.am->base,&rp)) ierror(0);
+	  if(!reg_pair(r,&rp2)) ierror(0);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	}
+	p->q2.am->base=p->q2.reg=r;
+      }else if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg){
+	if(r==0){
+	  r=get_reg(f,p,POINTER);
+	  cmp_get_acc(f,p,0);
+	  if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	  if(!reg_pair(r,&rp2)) ierror(0);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+	  emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+	}
+	p->q2.reg=r;
+      }
+    }
+    if(isacc(z)){
+      if(isacc(q2)){
+	if(p->q2.reg==rax){
+	  r=get_reg(f,p,INT);
+	  if(!reg_pair(r,&rp)) ierror(0);
+	  emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	  emit(f,"\tstx\t%s\n",mregnames[rp.r2]);
+	}else{
+	  r=get_reg(f,p,CHAR);
+	  emit(f,"\tsta\t%s\n",mregnames[r]);
+	}
+	p->q2.reg=r;
+	if(isacc(q1))
+	  p->q1.reg=r;
+      }
+    }
+  }     
+ 
+  reload_acc(f);
+
+  regs[ra]=mra;
+  regs[rax]=mrax;
+}
+
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  ierror(0);
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags==IMM_IND)
+      emit(f,"(%s),y ;am(%ld)",mregnames[p->am->base],p->am->offset);
+    else if(p->am->flags==GPR_IND)
+      emit(f,"(%s),y ;am(%s)",mregnames[p->am->base],mregnames[p->am->idx]);
+    else if(p->am->flags==ABS_IND){
+      emit(f,"%ld",p->am->offset);
+      if(p->am->v){
+	Var *v=p->am->v;
+	if(v->storage_class==EXTERN)
+	  emit(f,"+%s%s",idprefix,v->identifier);
+	else
+	  emit(f,"+%s%ld",labprefix,zm2l(v->offset));
+      }
+      emit(f,",y ;am(%s)",mregnames[p->am->idx]);
+    }else
+      ierror(0);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",mregnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"(%s),y",mregnames[fp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    if(/*ieee&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)*/ISFLOAT(t))
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    else
+      emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,"),y");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+char amode_buff[8192];
+char *render_amode(struct AddressingMode *am)
+{
+  return "(amode: not implemented)";
+}
+
+char val_buff[8192];
+char *render_val(union atyps val)
+{
+  snprintf(val_buff,8192,"(val: %02x...)",
+	   val.vuchar);
+  return val_buff;
+}
+
+char var_buff[8192];
+char *render_var(struct Var *v)
+{
+  if (!v) return "<null>";
+  snprintf(var_buff,8192,"(var id=%s)",v->identifier);
+  return var_buff;
+}
+
+char obj_buff[8192];
+char *render_obj(struct obj o)
+{
+  // XXX Calling render_var() can result in segfaults
+  snprintf(obj_buff,8192,"(flags=%d, reg=%d, dtype=%d, var=%s, amode=%s, val=%s)",
+	   o.flags,o.reg,o.dtyp,"render_var(o.v)",render_amode(o.am),render_val(o.val));
+  return obj_buff;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  fprintf(stderr,"peephole() called.\n");
+
+  /*
+    XXX PGS Things to consider adding here:
+    1. Removal of dead loads when we know a register already has loaded the target we want.
+    2. Removal of dead stores to local stack variables that never get read before returning from a function?
+    3. Removal of SP decrement and increment, when no use of local stack is made.
+    4. Promoting stack variables to global variables where it saves time and/or space?
+    5. Using Z as a temporary scratch register for local variables, where it doesn't upset
+       other things?
+  */
+    
+  
+  for(;p;p=p->next){
+    fprintf(stderr,"  Instruction @ %p : ",p);
+    fprintf(stderr,"code=%d, ",p->code);
+    fprintf(stderr,"\n    q1=%s, ",render_obj(p->q1));
+    fprintf(stderr,"\n    q2=%s, ",render_obj(p->q2));
+    fprintf(stderr,"\n    z=%s, ",render_obj(p->z));
+    fprintf(stderr,"\n");
+    
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&!ISFPOINTER(p->typf2)){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(zmleq(Z0,of)&&zmleq(of,l2zm(255L))){
+	r=p->z.reg;
+	if(isreg(q1)&&isptr(p->q1.reg)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    int t,mc;
+	    if((c2==ASSIGN|c2==PUSH)&&(p2->typf&NQ)==CHAR&&!zmeqto(p2->q2.val.vmax,Z1))
+	      mc=1;
+	    else
+	      mc=0;
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o||mc) break;
+	      t=q1typ(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o||mc) break;
+	      t=q2typ(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o||mc) break;
+	      t=ztyp(p2)&NQ;
+	      if(t>POINTER||ISFLOAT(t)) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else{
+	      m=p2->z.reg;
+	      if(o==&p->q1||o==&p->q2) break;
+	    }
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=(int)zm2l(of);
+		if(isreg(q1)&&isptr(p->q1.reg)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(c==ADDI2P&&(p->typf&NU)==(UNSIGNED|CHAR)&&!ISFPOINTER(p->typf2)&&isreg(q2)&&p->q2.reg!=ra&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx,ind;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST)
+	ind=0;
+      else
+	ind=1;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(ind&&(q1typ(p2)&NQ)!=CHAR)) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(ind&&(q2typ(p2)&NQ)!=CHAR)) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ind&&(ztyp(p2)&NQ)!=CHAR)) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+	      am->idx=idx;
+	      if(ind){
+		am->flags=GPR_IND;
+		am->base=base;
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }else{
+		am->flags=ABS_IND;
+		am->base=0;
+		eval_const(&p->q1.val,MAXINT);
+		am->offset=zm2l(vmax);
+		if(p->q1.flags&VARADR)
+		  am->v=p->q1.v;
+		else
+		  am->v=0;
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(zstoreflag){
+    int off;
+    if(p->z.flags!=VAR||p->z.v!=&bankv) ierror(0);
+    off=(int)zm2l(p->z.val.vmax);
+    p->z=zstore;
+    get_acc(f,p,INT);
+    if(zstore.flags&DREFOBJ){
+      if(!ISFPOINTER(zstore.dtyp)) ierror(0);
+      zstore.flags&=~DREFOBJ;
+      load_reg(f,LAST_PAIR,&zstore,POINTER);
+      if(indirect(&zstore)){
+	do_byte3(f,"lda",&zstore,FPOINTER);
+	emit(f,"\ttay\n");
+      }else
+	do_byte3(f,"ldy",&zstore,FPOINTER);
+      yval=NOVAL;
+    }else{
+      load_address(f,LAST_PAIR,&zstore,p->typf);
+      r=bank(zstore.v);
+      sety(f,r>=0?r:bankcnum);
+    }
+    emit(f,"\tldx\t#%d\n",off);
+    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+    emit(f,"\tjsr\t%s__bankstore%d\n",idprefix,(int)zm2l(sizetab[p->typf&NQ]));
+    yval=NOVAL;
+    zstoreflag=0;
+  }
+
+  for(r=1;r<=MAXR;r++){
+    if(regs[r]&8)
+      regs[r]&=~8;
+  }
+  for(r=FIRST_GPR;r<=LAST_GPR;r++){
+    int ta=0;
+    if(regs[r]&2){
+      if(regs[ra]&&!pushedacc){
+	emit(f,"\ttay\n");
+	yval=NOVAL;
+	ta=1;
+      }
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s\n",mregnames[r]);
+      regs[r]&=~2;
+    }
+    if(ta)
+      emit(f,"\ttya\n");
+  }
+  if(pushedx){
+    emit(f,"\tldx\t%s\n",mregnames[pushedx]);
+    pushedx=0;
+  }
+
+  reload_acc_opt(f,p->next);
+}
+
+struct cmplist {struct cmplist *next;int from,to,mode;} *first_cmplist;
+
+static void add_cmplist(int from, int to, int mode)
+{
+  struct cmplist *new;
+  new=mymalloc(sizeof(*new));
+  new->next=first_cmplist;
+  new->from=from;
+  new->to=to;
+  new->mode=mode;
+  first_cmplist=new;
+}
+
+static void incsp(FILE *f,long of)
+{
+  if(of==0) return;
+  if(of==1||of==-1){
+    static obj o;
+    o.flags=REG;
+    o.reg=sp;
+    if(of==1)
+      incmem(f,&o,INT,ADD,1);
+    else
+      incmem(f,&o,INT,SUB,1);
+  }else if(of==256){
+    emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+  }else if(of==-256){
+    emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+  }else{
+    long abs;
+    if(of>0){
+      abs=of;
+      emit(f,"\tclc\n");
+    }else{
+      abs=-of;
+      emit(f,"\tsec\n");
+    }
+    if(abs&255){
+      emit(f,"\tlda\t%s\n",mregnames[sp]);
+      if(of>0){
+	emit(f,"\tadc\t#%ld\n",abs&255);
+      }else{
+	emit(f,"\tsbc\t#%ld\n",abs&255);
+      }
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+    }
+    if((abs&0xff00)==0){
+      if(of>0){
+	emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+	emit(f,"%s%d:\n",labprefix,label);
+      }else{
+	emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+	emit(f,"%s%d:\n",labprefix,label);
+      }	
+    }else{
+      emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+      if(of>0)
+	emit(f,"\tadc\t#%ld\n",(abs>>8)&255);
+      else
+	emit(f,"\tsbc\t#%ld\n",(abs>>8)&255);
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  int i,r,of;
+  rsavesize=0;
+  libsave=1;
+
+  if(!optsize||(v->tattr&NOCOMPRESS)) emit(f,";vcprmin=10000\n");
+  if(vlas) emit(f,"___fo\tset\t%ld\n",(long)argsize);
+  r=0;
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+      if(i!=LAST_GPR-VOL_GPRS+1&&r==0) libsave=0;
+      rsavesize++;
+      r=1;
+    }else{
+      if(i==LAST_GPR-VOL_GPRS+1) libsave=0;
+      r=0;
+    }
+  }
+  rscnt=rsavesize;
+  if(rscnt&&!SOFTSTACK){
+    if(optspeed||rscnt<2)
+      rsavesize=0;
+    else if(!optsize&&rscnt<=5)
+      rsavesize=0;
+  }
+
+  if(!special_section(f,v)){emit(f,codename);ebank(f,bank(v));if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+  offset=localsize+argsize+rsavesize;
+
+  if(in_isr){
+    emit(f,"\tpha\n");
+    emit(f,"\tphx\n");
+    emit(f,"\tphy\n");
+    emit(f,"\tphz\n");
+    if(offset||function_calls){
+      emit(f,"\tlda\t%s\n",mregnames[sp]);
+      emit(f,"\tpha\n");
+      emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+      emit(f,"\tpha\n");
+      emit(f,"\tlda\t#<(___isrstack-%ld)\n",offset);
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+      emit(f,"\tlda\t#>(___isrstack-%ld)\n",offset);
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+    }
+  }
+
+  if(MAINARGS&&v->storage_class==EXTERN&&!strcmp(v->identifier,"main")&&v->vtyp->exact->count>1)
+    emit(f,"\tjsr\tinitmainargs\n");
+
+  yval=NOVAL;
+  of=argsize+localsize;
+
+  if(rsavesize>0&&of+rsavesize>255){
+    offset-=rsavesize;
+    incsp(f,-rsavesize);
+    of=0;
+  }else{
+    incsp(f,-offset);
+    offset=0;
+  }
+
+
+  if(!libsave||rscnt!=rsavesize||optspeed||rscnt<=1||(rscnt<=3&&(!optsize)))
+    libsave=0;
+  
+  if(libsave){
+    sety(f,of+rsavesize-1);
+    emit(f,"\tjsr\t%s__rsave%ld\n",idprefix,rscnt);
+    yval=of;
+  }else{
+    for(i=FIRST_GPR;i<=LAST_GPR;i++){
+      if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	if(rscnt!=rsavesize){
+	  emit(f,"\tlda\t%s\n",mregnames[i]);
+	  emit(f,"\tpha\n");
+	}else{
+	  sety(f,of++);
+	  emit(f,"\tlda\t%s\n",mregnames[i]);
+	  emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	}
+      }
+    }
+  }
+
+
+
+  incsp(f,-offset);
+
+  if(vlas){
+    emit(f,"\tlda\t%s\n",mregnames[sp]);
+    emit(f,"\tsta\t%s\n",mregnames[fp]);
+    emit(f,"\tlda\t%s\n",mregnames[sp2]);
+    emit(f,"\tsta\t%s\n",mregnames[fp2]);
+  }
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  int i,of,ar;
+  struct cmplist *p;
+  offset=localsize+argsize+rsavesize;
+  of=argsize+localsize;
+
+  i=freturn(v->vtyp->next);
+  if(i==ra||i==rax) ar=1; else ar=0;
+
+  if(rscnt!=rsavesize){
+    if(ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    for(i=LAST_GPR;i>=FIRST_GPR;i--){
+      if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	emit(f,"\tpla\n");
+	emit(f,"\tsta\t%s\n",mregnames[i]);
+      }
+    }
+  }
+  if(rsavesize>0&&of+rsavesize>255){
+    if(of!=1&&ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    incsp(f,of);
+    offset-=of;
+    of=0;
+  }
+  if(rsavesize>0){
+    if(ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+  }
+  if(rsavesize){
+    if(libsave){
+      sety(f,of+rsavesize-1);
+      emit(f,"\tjsr\t%s__rload%ld\n",idprefix,rscnt);
+      yval=of;
+    }else{
+      for(i=FIRST_GPR;i<=LAST_GPR;i++){
+	if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&&regscratch[i]&&!regsa[i])){
+	  sety(f,of++);
+	  emit(f,"\tlda\t(%s),y\n",mregnames[sp]);
+	  emit(f,"\tsta\t%s\n",mregnames[i]);
+	}
+      }
+    }
+  }
+  if(in_isr){
+    if(offset||function_calls){
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+      emit(f,"\tpla\n");
+      emit(f,"\tsta\t%s\n",mregnames[sp]);
+    }
+  }else if(offset==2&&!pushedacc){
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+    reload_acc(f);
+    emit(f,ret);
+    emit(f,"%s%d:\n",labprefix,label-1);
+    emit(f,"\tinc\t%s\n",mregnames[sp]);
+    emit(f,"%s%d:\n",labprefix,label);
+    emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+  }else{
+    if(offset!=0&&ar&&!pushedacc){
+      pushedacc=t4;
+      emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+    }
+    incsp(f,offset);
+  }
+
+  reload_acc(f);
+
+  if(in_isr){
+    emit(f,"\tplz\n");
+    emit(f,"\tply\n");
+    emit(f,"\tplx\n");
+    emit(f,"\tpla\n");
+  }
+  emit(f,ret);
+
+  for(p=first_cmplist;p;){
+    struct cmplist *m;
+    emit(f,"%s%d:\n",labprefix,p->from);
+    if(p->mode==JMPIND){
+      /* indirect call */
+      emit(f,"\tjmp\t(%s)\n",mregnames[p->to]);
+    }else{
+      pushedacc=p->mode;
+      reload_acc(f);
+      emit(f,"\tjmp\t%s%d\n",labprefix,p->to);
+    }
+    m=p;
+    p=p->next;
+    free(m);
+  }
+  first_cmplist=0;
+  pushedacc=0;
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(1L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(1);
+
+  if(IEEE){
+    ieee=1;
+    msizetab[DOUBLE]=msizetab[LDOUBLE]=l2zm(8L);
+  }
+
+
+  mregnames[0]=regnames[0]="noreg";
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"r%d",i-FIRST_GPR);
+    mregnames[i]=regnames[i];
+    regsize[i]=l2zm(1L);
+    regtype[i]=&ctyp;
+  }
+  for(i=FIRST_PAIR;i<=LAST_PAIR;i++){
+    int sr=(i-FIRST_PAIR)*2+FIRST_GPR;
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+    mregnames[i]=regnames[sr];
+    regsize[i]=l2zm(2L);
+    regtype[i]=&ityp;
+  }
+  for(i=FIRST_BIG;i<=LAST_BIG;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"btmp%d",i-FIRST_BIG);
+    mregnames[i]=regnames[i];
+    regsize[i]=msizetab[FLOAT];
+    regtype[i]=&ftyp;
+    regsa[i]=0;
+    regscratch[i]=1;
+  }
+  for(i=FIRST_BIGP;i<=LAST_BIGP;i++){
+    int sr=(i-FIRST_BIGP)*2+FIRST_BIG;
+    regnames[i]=mymalloc(20);
+    sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+    mregnames[i]=regnames[sr];
+    regsize[i]=msizetab[LLONG];
+    regtype[i]=&lltyp;
+    regsa[i]=0;
+    regscratch[i]=1;
+  }
+
+  mregnames[ra] = regnames[ra] = "a";
+  mregnames[rx] = regnames[rx] = "x";
+  mregnames[ry] = regnames[ry] = "y";
+  mregnames[rz] = regnames[rz] = "z";
+  regsize[ra]=regsize[rx]=regsize[ry]=l2zm(1L);
+  regtype[ra]=regtype[rx]=regtype[ry]=&ctyp;
+  mregnames[sp]=regnames[sp] = "sp";
+  mregnames[sp1]=regnames[sp1] = "sp";
+  mregnames[sp2]=regnames[sp2] = "sp+1";
+
+  mregnames[rax]=regnames[rax] = "ax";
+  regsize[rax]=regsize[sp]=l2zm(2L);
+  regtype[rax]=regtype[sp]=&ityp;
+
+  reg_prio[ra]=reg_prio[rax]=100;
+  reg_prio[rx]=50;
+
+  mregnames[raxyz]=regnames[raxyz] = "axyz";
+  regsize[raxyz]=l2zm(3L);
+  regtype[raxyz]=&lltyp;
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  short_push=1;
+
+  static_cse=0;
+
+  dref_cse=1;
+
+  /*prefer_statics=1; TODO */
+
+
+  if(optsize){
+    clist_copy_stack=2;
+    clist_copy_pointer=2;
+    clist_copy_static=2;
+  }else if(optspeed){
+    clist_copy_stack=64;
+    clist_copy_pointer=64;
+    clist_copy_static=64;
+  }else{
+    clist_copy_stack=8;
+    clist_copy_pointer=8;
+    clist_copy_static=8;
+  }
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[INT]=t_min(SHORT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[INT]=t_max(SHORT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[INT]=t_max(UNSIGNED|SHORT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  regsa[raxyz]=regsa[rz]=regsa[ry]=regsa[sp]=regsa[sp1]=regsa[sp2]=REGSA_NEVER;
+  regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=REGSA_NEVER;
+  regscratch[ra]=regscratch[rx]=regscratch[rax]=1;
+  if(!GLOBACC)
+    regsa[ra]=regsa[rx]=regsa[rax]=REGSA_TEMPS;
+  regscratch[sp]=regscratch[sp1]=regscratch[sp2]=regscratch[ry]=regscratch[rz]=0;
+  regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=1;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++){
+    regscratch[i]=1;
+    if(i&1)
+      regscratch[FIRST_PAIR+(i-FIRST_GPR)/2]=1;
+  }
+
+  target_macros=marray;
+
+  declare_builtin("__mulint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__muluint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__divint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+  declare_builtin("__modint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+
+  declare_builtin("__mulint32",LONG,LONG,FIRST_BIG+1,LONG,FIRST_BIG+2,1,0);
+  declare_builtin("__muluint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG+1,UNSIGNED|LONG,FIRST_BIG+2,1,0);
+  declare_builtin("__divint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__modint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+  declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+  declare_builtin("__sint32toflt32",FLOAT,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32tosint32",LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__sint16toflt32",FLOAT,INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__flt32tosint16",INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+  declare_builtin("__sint32toflt64",DOUBLE,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__flt64tosint32",LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__sint16toflt64",DOUBLE,INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+  declare_builtin("__flt64tosint16",INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+  declare_builtin("__cmpsflt32",CHAR,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+
+#if 0
+  for(i=1;i<MAXR;i++){
+    printf("%02d %s scratch=%d ",i,regnames[i],regscratch[i]);
+    if(reg_pair(i,&rp))
+      printf("pair(%s,%s)",regnames[rp.r1],regnames[rp.r2]);
+    printf("\n");
+  }
+#endif
+
+  if(NOPEEP) nopeep=1;
+  if(CBMASCII) cbmascii=1;
+  if(ATASCII) atascii=1;
+
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  bankv.storage_class=EXTERN;
+  bankv.identifier="__bankv";
+  bankv.vtyp=new_typ();
+  bankv.vtyp->flags=CHAR;
+
+  bankcnum=COMMONBANK;
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  int typ=t->flags&NQ;
+  if(ISSTRUCT(typ)||ISUNION(typ)||typ==VOID) 
+    return 0;
+  if(OLDFP&&ISFLOAT(typ)) return FIRST_GPR;
+  if(typ==LONG||typ==FLOAT||ISFPOINTER(typ)||(!ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+    return FIRST_BIG;
+  if(typ==LLONG||(ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+    return FIRST_BIGP;
+  if(zmleq(szof(t),l2zm(1L)))
+    return ra;
+  if(zmleq(szof(t),l2zm(2L))) 
+    return rax;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r>=FIRST_PAIR&&r<=LAST_PAIR){
+    p->r1=(r-FIRST_PAIR)*2+FIRST_GPR;
+    p->r2=p->r1+1;
+    return 1;
+  }else if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+    p->r1=(r-FIRST_BIGP)*2+FIRST_BIG;
+    p->r2=p->r1+1;
+    return 1;
+  }else if(r==rax){
+    p->r1=ra;
+    p->r2=rx;
+    return 1;
+  }else if(r==raxyz) {
+    // TODO: PGS: How do we declare a reg pair that is made of 4 regs, not 2?
+    p->r1=ra;
+    p->r2=rx;
+    return 1;
+  }else if(r==sp){
+    p->r1=sp1;
+    p->r2=sp2;
+    return 1;
+  }
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  /*TODO: adapt this */
+  if(o->flags&VKONST){
+    return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ){
+    if(isptr(r))
+      return 4;
+    if(r==rax)
+      return INT_MIN;
+  }
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 6;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 6;
+  if(r==ra)
+    return 5;
+  if(r==rx)
+    return 4;
+  if(r==rax)
+    return 2;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  if(r==rax&&NORAX)
+    return 0;
+  t&=NQ;
+  if(ISCHAR(t))
+    if(r==ra/*||r==rx*/||(r>=FIRST_GPR&&r<=LAST_GPR))
+      return 1;
+  if(ISSHORT(t)){
+    if(r==rax){
+      if(t==POINTER&&mode<0)
+	return 1;
+      if(t!=POINTER)
+	return 1;
+    }
+    if(r>=FIRST_PAIR&&r<=LAST_PAIR)
+      return 1;
+  }
+  if(r>=FIRST_BIG&&r<=LAST_BIG){
+    if(t==LONG||t==FLOAT||((t==DOUBLE||t==LDOUBLE)&&!ieee))
+      return 1;
+    if(t==FPOINTER)
+      return 1;
+  }
+  if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+    if(t==LLONG||((t==DOUBLE||t==LDOUBLE)&&ieee))
+      return 1;
+  }
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+
+  if(op==tp) return 0;
+  if(ISCHAR(op)&&ISCHAR(tp)) return 0;
+  if(ISSHORT(op)&&ISSHORT(tp)) return 0;
+  if(!ieee&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(STDSYNTAX)
+    emit(f,"\tspace\t%ld\n",zm2l(size));
+  else
+    emit(f,"\treserve\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\talign 1\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag,b=bank(v);char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(v->tattr&ZPAGE)
+      emit(f,"\tzpage\t%s%ld\n",labprefix,zm2l(v->offset));
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+      if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+    }
+    gen_align(f,falign(v->vtyp));
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+    if(v->tattr&ZPAGE)
+      emit(f,"\tzpage\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+	if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+      }
+
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%s:\n",idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if(ISCHAR(t))
+    emit(f,"\tbyte\t");
+  else
+    emit(f,"\tword\t");
+  if(!p->tree){
+    if(ISLONG(t)||ISFLOAT(t)){
+      if(ieee&&ISFLOAT(t)){
+	emit_ieee(f,&p->val,t&NQ);
+      }else{
+	eval_const(&p->val,t&NU);
+	if(ISFLOAT(t)) cnv_fp();
+	gval.vmax=zmand(vmax,l2zm(0xffffL));
+	emitval(f,&gval,MAXINT);
+	emit(f,",");
+	gval.vmax=zmand(zmrshift(vmax,l2zm(16L)),l2zm(0xffffL));
+	emitval(f,&gval,MAXINT);
+      }
+    }else{
+      if(ISFPOINTER(t)){
+	eval_const(&p->val,t&NU);
+	emit(f,"%ld\n",(long)zm2l(vmax)&0xffff);
+	emit(f,"\tbyte\t%d\n",(int)((zm2l(vmax)>>16)&0xff));
+      }else
+	emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+    if(ISFPOINTER(t)){
+      int b;
+      if((p->tree->o.flags&(VAR|VARADR))!=(VAR|VARADR)) ierror(0);
+      b=bank(p->tree->o.v);
+      emit(f,"\n\tbyte\t%d",b>=0?b:bankcnum);
+    }
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *mi;
+  FILE *rf=f;
+  static char *dbgfile;
+  static int dbgline;
+
+  if(vlas){
+    fp=FPVLA_REG;
+    if(!reg_pair(fp,&rp)) ierror(0);
+    fp1=rp.r1;
+    fp2=rp.r2;
+    regused[fp]=regused[fp1]=regused[fp2]=1;
+   }else{
+    fp=sp;
+    fp1=sp1;
+    fp2=sp2;
+  }
+  argsize=0;
+  localsize=offset;
+  if(DEBUG&1) printf("gen_code()\n");
+
+  cbank=bank(v);
+
+  if(!v->fi) v->fi=new_fi();
+  v->fi->flags|=ALL_REGS;
+
+  for(pass=0;pass<2;pass++){
+
+    if(DEBUG&1) printf("pass %d\n",pass);
+
+    if(pass==0){
+      f=0;
+      mi=clone_ic(p);
+    }else
+      f=rf;
+
+    for(c=1;c<=MAXR;c++) regs[c]=0; /*regsa[c];*/
+    maxpushed=0;
+
+    /*FIXME*/
+    if(v->tattr&INTERRUPT){
+      ret="\trti\n";
+      in_isr=1;
+    }else{
+      ret="\trts\n";
+      in_isr=0;
+    }
+
+    if(!nopeep) peephole(pass==0?p:mi);
+
+    function_top(f,v,localsize);
+
+    pushed=0;
+
+    yval=NOVAL;
+
+    dbgfile=0;
+    dbgline=0;
+
+    for(p=pass==0?p:mi;p;pr(f,p),p=p->next){
+
+
+
+      if(DEBUG&1) pric2(stdout,p);
+
+      if(debug_info){
+	if(p->file&&p->line){
+	  if(p->file!=dbgfile||p->line!=dbgline){
+	    dbgfile=p->file;
+	    dbgline=p->line;
+	    emit(f,"; %d \"%s\"\n",dbgline,dbgfile);
+	  }
+	}
+      }
+
+      c=p->code;t=p->typf;
+
+      if(c==NOP) {p->z.flags=0;continue;}
+      if(c==ALLOCREG){
+	regs[p->q1.reg]=1;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regs[rp.r1]=1;
+	  regs[rp.r2]=1;
+	}
+	continue;
+      }
+      if(c==FREEREG){
+	regs[p->q1.reg]=0;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regs[rp.r1]=0;
+	  regs[rp.r2]=0;
+	}
+	continue;
+      }
+      if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);yval=NOVAL;continue;}
+      if(c==BRA){
+	yval=NOVAL;
+	if(t==exit_label&&localsize+argsize+rsavesize+rscnt==0)
+	  emit(f,ret);
+	else
+	  emit(f,"\tjmp\t%s%d\n",labprefix,t);
+	continue;
+      }
+      if(c>=BEQ&&c<BRA){
+	yval=NOVAL;
+	continue;
+      }
+
+      if(c==MOVETOREG){
+	p->code=c=ASSIGN;
+	p->typf=t=regtype[p->z.reg]->flags;
+	p->q2.val.vmax=sizetab[regtype[p->z.reg]->flags];
+      }
+      if(c==MOVEFROMREG){
+	p->code=c=ASSIGN;
+	p->typf=t=regtype[p->q1.reg]->flags;
+	p->q2.val.vmax=sizetab[regtype[p->q1.reg]->flags];
+      }
+      if(c==CONVERT&&ISCHAR(t)&&ISCHAR(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[CHAR];
+      }
+      if(c==CONVERT&&msizetab[t&NQ]==3&&msizetab[p->typf2&NQ]==3){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[SHORT];
+      }
+      if(c==CONVERT&&ISSHORT(t)&&ISSHORT(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[SHORT];
+      }
+      if(c==CONVERT&&ISLONG(t)&&ISLONG(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[LONG];
+      }
+      if(c==CONVERT&&ISLLONG(t)&&ISLLONG(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[LLONG];
+      }
+      if(c==CONVERT&&ISFLOAT(t)&&ISFLOAT(p->typf2)){
+	p->code=c=ASSIGN;
+	p->q2.val.vmax=sizetab[t&NQ];
+      }
+
+
+      /* switch commutative operands if suitable */
+      if(c==ADD||c==MULT||c==AND||c==XOR||c==OR||(c==ADDI2P&&ISSHORT(t)&&!ISFPOINTER(p->typf2))){
+	if(compare_objects(&p->q2,&p->z)||isacc(q2)){
+	  struct obj tmp;
+	  tmp=p->q1;
+	  p->q1=p->q2;
+	  p->q2=tmp;
+	}
+      }
+
+      if(c==COMPARE&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+	obj tmp;
+	tmp=p->q1;
+	p->q1=p->q2;
+	p->q2=tmp;
+      }
+
+      c=p->code;
+      if(c==SUBPFP) c=SUB;
+      /*if(c==ADDI2P) c=ADD;*/
+      /*if(c==SUBIFP) c=SUB;*/
+
+
+      if(c==MINUS){
+	if(isacc(q1)&&isacc(z)){
+	  emit(f,"\tneg\n");
+	  if(!ISCHAR(t)){
+	    emit(f,"\tpha\n");
+	    emit(f,"\ttxa\n");
+	    emit(f,"\teor\t#255\n");
+	    emit(f,"\tadc\t#0\n");
+	    emit(f,"\ttax\n");
+	    emit(f,"\tpla\n");
+	  }
+	  continue;
+	}
+	p->code=c=SUB;
+	p->q2=p->q1;
+	p->q1.flags=KONST;
+	gval.vmax=Z0;
+	eval_const(&gval,MAXINT);
+	insert_const(&p->q1.val,t);
+      }
+
+      preload(f,p);
+
+      if(c==CONVERT){
+	int to=q1typ(p)&NU;
+	t&=NU;
+	if(ISCHAR(t)){
+	  get_acc(f,p,CHAR);
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  continue;
+	}
+	if(ISLONG(to)){
+	  if(!isacc(z))
+	    get_acc(f,p,CHAR);
+	  if(zm2l(sizetab[t&NQ])==3){
+	    do_byte3(f,"lda",&p->q1,to);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  if(zm2l(sizetab[t&NQ])>=2){
+	    load_hibyte(f,&p->q1,to);
+	    store_hibyte(f,&p->z,t);
+	  }
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  continue;
+	}
+	if(ISSHORT(to)){
+	  if((t&UNSIGNED)||ISFPOINTER(t))
+	    get_acc(f,p,CHAR);
+	  else
+	    get_acc(f,p,SHORT);
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+	  load_hibyte(f,&p->q1,to);
+	  store_hibyte(f,&p->z,t);
+	  if(ISFPOINTER(t)){
+	    int b=-1;
+	    if((p->q1.flags&(VARADR|DREFOBJ))==VARADR) b=bank(p->q1.v);
+	    emit(f,"\tlda\t#%d\n",b>=0?b:bankcnum);
+	    do_byte3(f,"sta",&p->z,t);
+	    continue;
+	  }
+	  if(to&UNSIGNED){
+	    emit(f,"\tlda\t#0\n");
+	    do_byte3(f,"sta",&p->z,t);
+	    do_byte4(f,"sta",&p->z,t);
+	  }else{
+	    emit(f,"\tldx\t#0\n");
+	    emit(f,"\tcmp\t#0\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(indirect(&p->z)){
+	      emit(f,"\ttxa\n");
+	      do_byte3(f,"sta",&p->z,t);
+	      do_byte4(f,"sta",&p->z,t);
+	    }else{
+	      do_byte3(f,"stx",&p->z,t);
+	      do_byte4(f,"stx",&p->z,t);
+	    }
+	  }
+	  continue;
+	}
+	if(ISCHAR(to)){
+	  if(to&UNSIGNED){
+	    get_acc(f,p,CHAR);
+	    if(ISLONG(t)){
+	      load_lobyte(f,&p->q1,to);
+	      store_lobyte(f,&p->z,t);
+	      emit(f,"\tlda\t#0\n");
+	      store_hibyte(f,&p->z,t);
+	      do_byte3(f,"sta",&p->z,t);
+	      if(ISLONG(t))
+		do_byte4(f,"sta",&p->z,t);
+	      continue;
+	    }
+	    if(isacc(z))
+	      emit(f,"\tldx\t#0\n");
+	    else if(isacc(q1)){
+	      emit(f,"\tldx\t#0\n");
+	      store_acc(f,&p->z,t);
+	      continue;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      store_hibyte(f,&p->z,t);
+	    }
+	    load_lobyte(f,&p->q1,to);
+	    store_lobyte(f,&p->z,t);
+	  }else{
+	    int l=++label;
+	    get_acc(f,p,SHORT);
+	    emit(f,"\tldx\t#0\n");
+	    if(isreg(q1)&&p->q1.reg==ra)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      load_lobyte(f,&p->q1,to);
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    store_lobyte(f,&p->z,t);
+	    if(indirect(&p->z)){
+	      emit(f,"\ttxa\n");
+	      store_hibyte(f,&p->z,t);
+	      if(ISLONG(t)){
+		do_byte3(f,"sta",&p->z,t);
+		do_byte4(f,"sta",&p->z,t);
+	      }
+	    }else{
+	      if(!isreg(z)||p->z.reg!=rax){
+		emit(f,"\tstx\t");
+		emit_hibyte(f,&p->z,t);
+		emit(f,"\n");
+	      }
+	      if(ISLONG(t)){
+		do_byte3(f,"stx",&p->z,t);
+		do_byte4(f,"stx",&p->z,t);
+	      }
+	    }
+	  }
+	  if(ISFPOINTER(t)){
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  continue;
+	}
+	if(ISFPOINTER(to)){
+	  get_acc(f,p,CHAR);
+	  if(zm2l(sizetab[t&NQ])>=3){
+	    do_byte3(f,"lda",&p->q1,to);
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  if(zm2l(sizetab[t&NQ])>=2){
+	    load_hibyte(f,&p->q1,to);
+	    store_hibyte(f,&p->z,t);
+	  }
+	  load_lobyte(f,&p->q1,to);
+	  store_lobyte(f,&p->z,t);
+
+	  continue;
+	}
+	ierror(0);
+      }
+
+      if(c==KOMPLEMENT){
+	get_acc(f,p,CHAR);
+	if(ISCHAR(t)){
+	  load_acc(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_acc(f,&p->z,t);
+	}else{
+	  if(isacc(q1))
+	    emit(f,"\tpha\n");
+	  if(ISLONG(t)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\teor\t#-1\n");
+	    do_byte4(f,"sta",&p->z,t);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\teor\t#-1\n");
+	    do_byte3(f,"sta",&p->z,t);
+	  }
+	  load_hibyte(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_hibyte(f,&p->z,t);
+	  if(isacc(q1))
+	    emit(f,"\tpla\n");
+	  load_lobyte(f,&p->q1,t);
+	  emit(f,"\teor\t#-1\n");
+	  store_lobyte(f,&p->z,t);
+	}
+	continue;
+      }
+      if(c==SETRETURN){
+	t&=NQ;
+	if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+	if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+	  long l=zm2l(p->q2.val.vmax);
+	  int zr=p->z.reg;
+	  //get_acc(f,p,t);
+	  if((optsize||l>4)&&!ISFPOINTER(t)){
+	    int ind=indirect(&p->q1);
+	    if(ind) load_address(f,LAST_PAIR,&p->q1,t);
+	    BSET(regused,t3);
+	    BSET(regused,t4);
+	    sety(f,l-1);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    if(ind)
+	      emit(f,"\tlda\t(%s),y\n",mregnames[LAST_PAIR]);
+	    else{
+	      emit(f,"\tlda\t");
+	      if(!ISFLOAT(t)&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+		emit(f,"%s%d",labprefix,addfpconst(&p->q1,t));
+	      }else
+		emit_obj(f,&p->q1,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tsta\t%s,y\n",mregnames[zr]);
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    yval=255;
+	  }else{
+	    if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	      if(p->q1.reg==zr){
+		int r=get_reg(f,p,POINTER);
+		if(r==FIRST_PAIR||r==FIRST_PAIR+1)
+		  ierror(0);
+		if(!reg_pair(r,&rp2)) ierror(0);
+		emit(f,"\tlda\t%s\n",mregnames[zr]);
+		emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+		emit(f,"\tlda\t%s+1\n",mregnames[zr]);
+		emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+		p->q1.reg=r;
+	      }
+	    }
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[zr]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s+1\n",mregnames[zr]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s+2\n",mregnames[zr]);
+	    if(!ISFPOINTER(t)){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s+3\n",mregnames[zr]);
+	    }
+	    /*TODO:regused OLDFP */
+	    regused[zr]=1;
+	  }
+	  continue;
+	}
+	//get_acc(f,p,t);
+	load_acc(f,&p->q1,t);
+	regused[ra]=1;
+	regused[rx]=1;
+	continue;
+      }
+      if(c==GETRETURN){
+	t&=NQ;
+	if(isreg(z)&&p->q1.reg==p->z.reg) continue;
+	if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+	  long l=zm2l(p->q2.val.vmax);
+	  int qr=p->q1.reg;
+	  if((optsize||l>4)&&!ISFPOINTER(t)){
+	    int ind=indirect(&p->z);
+	    if(ind) load_address(f,LAST_PAIR,&p->z,t);
+	    BSET(regused,t3);
+	    BSET(regused,t4);
+	    sety(f,l-1);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    emit(f,"\tlda\t%s,y\n",mregnames[qr]);
+	    if(ind)
+	      emit(f,"\tsta\t(%s),y\n",mregnames[LAST_PAIR]);
+	    else{
+	      emit(f,"\tsta\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	    yval=255;
+	  }else{
+	    if((p->z.reg&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	      if(p->z.reg==qr) ierror(0);
+	    }
+	    emit(f,"\tlda\t%s\n",mregnames[qr]);
+	    store_lobyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s+1\n",mregnames[qr]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s+2\n",mregnames[qr]);
+	    do_byte3(f,"sta",&p->z,t);
+	    if(!ISFPOINTER(t)){
+	      emit(f,"\tlda\t%s+3\n",mregnames[qr]);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	  }
+	  continue;
+	}
+	if(p->q1.reg)
+	  store_acc(f,&p->z,t);
+	continue;
+      }
+      if(c==CALL){
+	int reg;
+
+	if(argsize<zm2l(p->q2.val.vmax)) argsize=zm2l(p->q2.val.vmax);
+
+	/*FIXME*/
+#if 0      
+	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	  if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	    stack=framesize+zum2ul(p->q1.v->fi->stack1);
+	}else
+	  stack_valid=0;
+#endif
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	  long of=va_offset(v)+localsize+rsavesize+argsize;
+	  emit(f,"\tlda\t%s\n",mregnames[fp]);
+	  if(of){
+	    emit(f,"\tclc\n");
+	    if(of&255)
+	      emit(f,"\tadc\t#%d\n",(of&255));
+	  }
+	  emit(f,"\tldx\t%s+1\n",mregnames[fp]);
+	  if(of&0xff00){
+	    emit(f,"\tpha\n");
+	    emit(f,"\ttxa\n");
+	    emit(f,"\tadc\t#%d\n",(of>>8)&255);
+	    emit(f,"\ttax\n");
+	    emit(f,"\tpla\n");
+	  }else if(of){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	    emit(f,"\tinx\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }
+	  continue;
+	}
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	  emit(f,";startinline\n");
+	  emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	  emit(f,";endinline\n");
+	}else if(p->q1.flags&DREFOBJ){
+	  if(ISFPOINTER(p->q1.dtyp)){
+	    p->q1.flags&=~DREFOBJ;
+	    load_reg(f,LAST_PAIR,&p->q1,POINTER);
+	    if(indirect(&p->q1)){
+	      do_byte3(f,"lda",&p->q1,FPOINTER);
+	      emit(f,"\ttay\n");
+	    }else
+	      do_byte3(f,"ldy",&p->q1,FPOINTER);
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	    emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+	    yval=NOVAL;
+	  }else{
+	    if(!(p->q1.flags&REG)) ierror(0);
+	    emit(f,"\tjsr\t%s%d\n",labprefix,++label);
+	    yval=NOVAL;
+	    add_cmplist(label,p->q1.reg,JMPIND);
+	  }
+	}else{
+	  int tbank=-1;
+	  if(p->q1.flags&VAR) tbank=bank(p->q1.v);
+	  if(tbank!=cbank&&tbank>=0){
+	    if(cbank>=0){
+	      load_address(f,LAST_PAIR,&p->q1,t);
+	      sety(f,tbank);
+	      emit(f,"\tlda\t#%d\n",cbank);
+	      emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+	      yval=NOVAL;
+	      continue;
+	    }
+	    sety(f,tbank);
+	    emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+	    yval=NOVAL;
+	  }
+	  if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"_fmemcpy"))
+	    emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+	  emit(f,"\tjsr\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+	pushed-=zm2l(p->q2.val.vmax);
+	if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+	yval=NOVAL;
+	continue;
+      }
+      if(c==ASSIGN||c==PUSH){
+	if(t==0) ierror(0);
+	if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)==LLONG){
+	  int i;
+	  eval_const(&p->q1.val,t);
+	  for(i=0;i<8;i++){
+	    emit(f,"\tlda\t#%d\n",zm2l(vmax)&255);
+	    vmax=zmrshift(vmax,l2zm(8L));
+	    if(c==PUSH||(p->z.flags&DREFOBJ)){
+	      sety(f,i+((c==PUSH)?pushed:0));
+	      emit(f,"\tsta\t(%s),y\n",(c==PUSH)?mregnames[sp]:mregnames[p->z.reg]);
+	    }else{
+	      p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((long)i));
+	      emit(f,"\tsta\t");
+	      emit_lobyte(f,&p->z,t);
+	      emit(f,"\n");
+	      p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)i));
+	    }
+	  }
+	  if(c==PUSH) pushed+=8;
+	  continue;
+	}  
+
+	if(!zmleq(p->q2.val.vmax,l2zm(4L))){
+	  long len=zm2l(p->q2.val.vmax);
+	  int r1,r2,loops,looplab;
+	  if(len>32767) ierror(0);
+	  if(!NOBANKVARS){
+	    int bq=-1,bz=-1,s=-1;
+	    if((p->q1.flags&(VAR|DREFOBJ))==VAR) bq=bank(p->q1.v);
+	    if((p->z.flags&(VAR|DREFOBJ))==VAR) bz=bank(p->z.v);
+	    if(((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp))||
+	       ((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp))){
+	      far_copy(f,p);
+	      continue;
+	    }
+	    if(cbank<0){
+	      if(bq>=0&&bz>=0){
+		if(bq!=bz){
+		  far_copy(f,p);
+		  continue;
+		}
+		s=bq;
+	      }else{
+		if(bq>=0) s=bq;
+		if(bz>=0) s=bz;
+	      }
+	      if(s>=0){
+		sety(f,s);
+		emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+		yval=NOVAL;
+	      }
+	    }else{
+	      if((bq>=0&&bq!=cbank)||(bz>=0&&bz!=cbank)){
+		far_copy(f,p);
+		continue;
+	      }
+	    }
+	  }
+	  get_acc(f,p,CHAR);
+	  if((p->q1.flags&(DREFOBJ|KONST))==DREFOBJ){
+	    if(p->q1.flags&REG){
+	      r1=p->q1.reg;
+	      if(!reg_pair(r1,&rp)) ierror(0);
+	      if(len>128){
+		emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+		emit(f,"\tclc\n");
+		if(len&128)
+		  emit(f,"\tadc\t#128\n");
+		emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+		if(len>255){
+		  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+		  emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+		  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);	
+		}else{
+		  emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+		  emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+		  emit(f,"%s%d:\n",labprefix,label);
+		}
+	      }
+	    }else
+	      ierror(0);
+	  }else if(!indirect(&p->q1)&&len<=128&&(p->q1.flags&(DREFOBJ|KONST))!=KONST){
+	    r1=0;
+	  }else{
+	    Var *v=p->q1.v;
+	    /*if((p->q1.flags&(VARADR|VAR))!=VAR) ierror(0);*/
+	    r1=get_reg(f,p,POINTER);
+	    if(len>128) p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm(len&0xff80));
+	    load_address(f,r1,&p->q1,t);
+	    if(len>128) p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm(len&0xff80));
+	  }
+	  if((p->z.flags&(DREFOBJ|KONST))==DREFOBJ){
+	    if(p->z.flags&REG){
+	      r2=p->z.reg;
+	      if(!reg_pair(r2,&rp)) ierror(0);
+	      if(len>128){
+		emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+		emit(f,"\tclc\n");
+		if(len&128)
+		  emit(f,"\tadc\t#128\n");
+		emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+		if(len>255){
+		  emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+		  emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+		  emit(f,"\tsta\t%s\n",mregnames[rp.r2]);	
+		}else{
+		  emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+		  emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+		  emit(f,"%s%d:\n",labprefix,label);
+		}
+	      }
+	    }else
+	      ierror(0);
+	  }else if(c==PUSH){
+	    if(len<=128&&pushed==0){
+	      r2=sp;
+	    }else{
+	      r2=get_reg(f,p,POINTER);
+	      if(!reg_pair(r2,&rp)) ierror(0);
+	      emit(f,"\tlda\t%s\n",mregnames[sp]);
+	      emit(f,"\tclc\n");
+	      if(((pushed+(len&128))&255)!=0)
+		emit(f,"\tadc\t#%ld\n",(pushed+(len&128))&255);
+	      emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	      emit(f,"\tlda\t%s\n",mregnames[sp2]);
+	      emit(f,"\tadc\t#%ld\n",((pushed+len)>>8)&255);
+	      emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+	    }
+	  }else if(!indirect(&p->z)&&len<=128){
+	    r2=0;
+	  }else{
+	    Var *v=p->z.v;
+	    r2=get_reg(f,p,POINTER);
+	    if(len>128) p->z.val.vmax=zmadd(p->z.val.vmax,l2zm(len&0xff80));
+	    load_address(f,r2,&p->z,t);
+	    if(len>128) p->z.val.vmax=zmsub(p->z.val.vmax,l2zm(len&0xff80));
+	  }
+	  if(len>128){
+	    get_acc(f,p,POINTER); /* get x */
+	    emit(f,"\tldx\t#%ld\n",((len>>7)+1)&255);
+	  }
+	  sety(f,(len-1)&127);
+	  if((optsize&&len>4)||len>8){
+	    emit(f,"%s%d:\n",labprefix,looplab=++label);
+	    if(optsize)
+	      loops=1;
+	    else{
+	      if((len&3)==0)
+		loops=4;
+	      else if((len&1)==0)
+		loops=2;
+	      else
+		loops=1;
+	    }
+	  }else
+	    loops=len;
+	  if(r1&&!reg_pair(r1,&rp)) ierror(0);
+	  if(r2&&!reg_pair(r2,&rp2)) ierror(0);
+	  for(i=0;i<loops;i++){
+	    if(r1)
+	      emit(f,"\tlda\t(%s),y\n",mregnames[rp.r1]);
+	    else{
+	      emit(f,"\tlda\t");
+	      emit_obj(f,&p->q1,t);
+	      emit(f,",y\n");
+	    }
+	    if(r2)
+	      emit(f,"\tsta\t(%s),y\n",mregnames[rp2.r1]);
+	    else{
+	      emit(f,"\tsta\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",y\n");
+	    }
+	    emit(f,"\tdey\n");
+	  }
+	  if(loops!=len){
+	    emit(f,"\tbpl\t%s%d\n",labprefix,label);
+	  }	  
+	  if(len>128){
+	    emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+	    emit(f,"\tsec\n");
+	    emit(f,"\tsbc\t#128\n");
+	    emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+	    emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	    emit(f,"\tlda\t%s\n",mregnames[rp2.r1]);
+	    emit(f,"\tsec\n");
+	    emit(f,"\tsbc\t#128\n");
+	    emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+	    emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdec\t%s\n",mregnames[rp2.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	    emit(f,"\tldy\t#127\n");
+	    emit(f,"\tdex\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,looplab);
+	  }
+	  yval=NOVAL;
+	  if(c==PUSH)
+	    pushed+=zm2l(p->q2.val.vmax);
+	  continue;
+	}
+	if(c==PUSH){
+	  get_acc(f,p,CHAR);
+	  load_lobyte(f,&p->q1,t);
+	  sety(f,pushed);
+	  emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  if(!zmleq(p->q2.val.vmax,Z1)){
+	    load_hibyte(f,&p->q1,t);
+	    sety(f,pushed+1);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	    do_byte3(f,"lda",&p->q1,t);
+	    sety(f,pushed+2);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+	  if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+	    do_byte4(f,"lda",&p->q1,t);
+	    sety(f,pushed+3);
+	    emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+	  }
+
+	  pushed+=zm2l(p->q2.val.vmax);
+	  continue;
+	}
+	if(c==ASSIGN){
+	  if(isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) continue;
+	  if(isacc(q1)){
+	    if(p->q1.reg==rax) get_acc(f,p,CHAR);
+	    store_acc(f,&p->z,t);
+	    continue;
+	  }
+	  get_acc(f,p,CHAR);
+	  if(0/*ISCHAR(t)*/){
+	    load_acc(f,&p->q1,t);
+	    store_acc(f,&p->z,t);
+	  }else{
+            // TODO: PGS: Use AXYZ for 32-bit copy if appropriate
+	    // TOGO: PGS: Consider using AXYZ for load, even for 16 or 24-bit values
+	    if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+	      do_byte4(f,"lda",&p->q1,t);
+	      do_byte4(f,"sta",&p->z,t);
+	    }
+	    if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	      do_byte3(f,"lda",&p->q1,t);
+	      do_byte3(f,"sta",&p->z,t);
+	    }
+	    if(!zmleq(p->q2.val.vmax,l2zm(1L))){
+	      load_hibyte(f,&p->q1,t);
+	      store_hibyte(f,&p->z,t);
+	    }
+	    load_lobyte(f,&p->q1,t);
+	    store_lobyte(f,&p->z,t);
+	  }
+	}
+	continue;
+      }
+      if(c==ADDRESS){
+	long o=real_offset(&p->q1);
+	get_acc(f,p,CHAR);
+	emit(f,"\tlda\t%s\n",mregnames[fp1]);
+	if(o){
+	  emit(f,"\tclc\n");
+	  if((o&255)!=0)
+	    emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)&255);
+	}
+	store_lobyte(f,&p->z,t);
+	if(isacc(z)) emit(f,"\tpha\n");
+	emit(f,"\tlda\t%s\n",mregnames[fp2]);
+	if(o!=0)
+	  emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)>>8&255);
+	store_hibyte(f,&p->z,t);
+	if(isacc(z)) emit(f,"\tpla\n");
+	continue;
+      }
+
+      if(c==COMPARE||c==TEST){
+	IC *branch=p->next;
+	int pacc=0,bc,bout;
+	while(branch){
+	  if(branch->code>=BEQ&&branch->code<BRA)
+	    break;
+	  if(branch->code!=FREEREG&&branch->code!=ALLOCREG&&branch->code!=NOP)
+	    ierror(0);
+	  branch=branch->next;
+	}
+	bc=branch->code;
+	bout=branch->typf;
+	if(c==TEST){
+	  p->q2.flags=KONST;
+	  gval.vmax=Z0;
+	  eval_const(&gval,MAXINT);
+	  insert_const(&p->q2.val,t);
+	}
+	if(ieee&&ISFLOAT(t)){
+	  if(!ieee) ierror(0);
+	  t&=NQ;
+	  if(regs[LAST_PAIR]) ierror(0);
+	  regs[LAST_PAIR]=1;
+	  if(regs[ra]||regs[rax])
+	    ierror(0);
+	  load_address(f,LAST_PAIR,&p->q2,t);
+	  BSET(regused,t3);
+	  BSET(regused,t4);
+	  emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->q1,t);
+	  emit(f,"\tjsr\t%s__fcmp%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  regs[LAST_PAIR]=0;
+	  if(bc==BLT||bc==BLE)
+	    emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	  else if(bc==BGT|bc==BGE)
+	    emit(f,"\tbvs\t%s%d\n",labprefix,bout);
+	  if(bc==BEQ||bc==BLE||bc==BGE)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  continue;
+	}
+	if(ISCHAR(t)){
+	  char *s;
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+	  load_acc(f,&p->q1,t);
+	  if(bc==BEQ||bc==BNE||(t&UNSIGNED)){
+	    s="cmp";
+	  }else{
+	    if(bc==BLT||bc==BGE)
+	      emit(f,"\tsec\n");
+	    else
+	      emit(f,"\tclc\n");
+	    s="sbc";
+	  }
+	  if(c==TEST)
+	    emit(f,"\t%s\t#0\n",s);
+	  else
+	    do_lobyte(f,s,&p->q2,t);
+	  if(bc==BEQ)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(t&UNSIGNED){
+	    if(bc==BLT)
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    else if(bc==BGE)
+	      emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+	    else if(bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	    }else if(bc==BGT){
+	      emit(f,";\n\tbeq\t%s%d\n",labprefix,++label);
+	      emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+	      emit(f,"%s%d:\n",labprefix,label);
+	    }else
+	      ierror(0);
+	  }else{
+	    emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	    emit(f,"\teor\t#128\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(bc==BLT||bc==BLE)
+	      emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	    else
+	      emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	  }
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue;
+	}else if(bc==BEQ||bc==BNE||(t&UNSIGNED)||ISFPOINTER(t)){
+	  int in=0;
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+
+	  // PGS Check for special cases of comparing to constants
+	  if(!(ISLONG(t)||ISFPOINTER(t)||isacc(q1))) {
+	    // Is a 16-bit value
+	    if (p->q2.flags&KONST) {
+	      if (!(p->q2.flags&DREFOBJ)) {
+		eval_const(&p->q2.val,t);
+		if(ISFLOAT(t)) cnv_fp();
+		if (zm2l(vmax)==0x100) {
+		  if (bc==BGE) {
+		    // >= $100 we can check by just reading the 2nd byte
+		    // If non-zero, then we take the branch
+		    do_hibyte(f,"lda",&p->q1,t);
+		    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+		    continue;
+		  } else if (bc==BLT) {
+		    // <$100 we can check by just reading the 2nd byte
+		    // And if zero, then we take the branch
+		    do_hibyte(f,"lda",&p->q1,t);
+		    emit(f,"\tbeq\t%s%d\n",labprefix,bout);		  
+		    continue;
+		  }
+		} else if (zm2l(vmax)<0x100) {
+		  // Values <$100 we can do almost as simply, but we have to
+		  // also check the low byte for exceptions.
+		  // XXX PGS TODO
+		  
+		}
+	      }
+	    }
+	  }
+	  
+	  // Far-Pointers are 32-bit on M65
+	  if(ISLONG(t)||ISFPOINTER(t)){
+	    do_byte4(f,"lda",&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_byte4(f,"cmp",&p->q2,t);
+	    if(bc==BEQ)
+	      emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+	    else if(bc==BNE)
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    else if(bc==BLT||bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+	    }else if(bc==BGE||bc==BGT){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,in=++label);	
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    }else
+	      ierror(0);
+	  }
+	  if(ISLONG(t)||ISFPOINTER(t)){
+	    do_byte3(f,"lda",&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_byte3(f,"cmp",&p->q2,t);
+	    if(bc==BEQ)
+	      emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	    else if(bc==BNE)
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    else if(bc==BLT||bc==BLE){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	      emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	    }else if(bc==BGE||bc==BGT){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));	
+	      emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	    }else
+	      ierror(0);	  
+	  }
+	  if(isacc(q1)){
+	    if(!indirect(&p->q2)){
+	      do_hibyte(f,"cpx",&p->q2,t);
+	    }else{
+	      int r=get_reg(f,p,CHAR);
+	      emit(f,"\tpha\n");
+	      load_hibyte(f,&p->q2,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tpla\n");
+	      emit(f,"\tcpx\t%s\n",mregnames[r]);
+	    }
+	  }else{
+	    load_hibyte(f,&p->q1,t);
+	    if(c==TEST)
+	      emit(f,"\tcmp\t#0\n");
+	    else
+	      do_hibyte(f,"cmp",&p->q2,t);
+	  }
+	  if(bc==BEQ)
+	    emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(bc==BLT||bc==BLE){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+	  }else if(bc==BGE||bc==BGT){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  }else
+	    ierror(0);
+	  load_lobyte(f,&p->q1,t);
+	  if(c==TEST)
+	    emit(f,"\tcmp\t#0\n");
+	  else
+	    do_lobyte(f,"cmp",&p->q2,t);
+	  if(bc==BEQ)
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  else if(bc==BNE)
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  else if(bc==BLT)
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	  else if(bc==BGE)
+	    emit(f,"\tbcs\t%s%d\n",labprefix,bout);	
+	  else if(bc==BLE){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+	    emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+	  }else if(bc==BGT){
+	    emit(f,"\tbcc\t%s%d\n",labprefix,in);
+	    emit(f,"\tbne\t%s%d\n",labprefix,bout);
+	  }else
+	    ierror(0);
+	  if(in)
+	    emit(f,"%s%d:\n",labprefix,in);
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue;
+	}else{
+	  if(bc==BGT||bc==BLE){
+	    obj o;
+	    if(isacc(q1)){
+	      int r;
+	      if(pacc=cmp_get_acc(f,p,branch))
+		bout=++label;
+	      r=get_reg(f,p,CHAR);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_lobyte(f,&p->q2,t);
+	      emit(f,"\tcmp\t%s\n",mregnames[r]);
+	      emit(f,"\tstx\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q2,t);
+	      emit(f,"\tsbc\t%s\n",mregnames[r]);
+	      emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	      emit(f,"\teor\t#128\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      if(bc==BGT)
+		emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	      else
+		emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	      if(pacc){
+		reload_acc(f);
+		add_cmplist(bout,branch->typf,pacc);
+	      }
+	      continue;
+	    }else{
+	      o=p->q1;p->q1=p->q2;p->q2=o;
+	      if(bc==BGT) bc=BLT; else bc=BGE;
+	    }
+	  }
+	  if(pacc=cmp_get_acc(f,p,branch))
+	    bout=++label;
+	  if(ISLONG(t)){
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,"cmp",&p->q2,t);
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,"sbc",&p->q2,t);
+	    do_byte3(f,"lda",&p->q1,t);
+	    do_byte3(f,"sbc",&p->q2,t);
+	    do_byte4(f,"lda",&p->q1,t);
+	    do_byte4(f,"sbc",&p->q2,t);
+	  }else{
+	    load_lobyte(f,&p->q1,t);
+	    do_lobyte(f,"cmp",&p->q2,t);
+	    load_hibyte(f,&p->q1,t);
+	    do_hibyte(f,"sbc",&p->q2,t);
+	  }
+	  emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+	  emit(f,"\teor\t#128\n");
+	  emit(f,"%s%d:\n",labprefix,label);
+	  if(bc==BLT)
+	    emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+	  else if(bc==BGE)
+	    emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+	  else
+	    ierror(0);
+	  if(pacc){
+	    reload_acc(f);
+	    add_cmplist(bout,branch->typf,pacc);
+	  }
+	  continue; 
+	}
+	ierror(0);
+      }
+      if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&compare_objects(&p->q1,&p->z)&&!indirect(&p->q1)&&isconst(q2)&&!isacc(z)){
+	long l;
+	eval_const(&p->q2.val,q2typ(p));
+	l=zm2l(vmax);
+	if(c==ADDI2P/*&&(t2&NQ)==POINTER*/) {c=ADD;t=UNSIGNED|INT;}
+	if(c==SUBIFP/*&&(t2&NQ)==POINTER*/) {c=SUB;t=UNSIGNED|INT;}
+	if(c==SUB||c==SUBIFP) l=-l;
+	/*TODO: allow larger types */
+	if(l<3&&l>-3&&(t&NQ)<=INT){
+	  if(l<0){
+	    get_acc(f,p,CHAR);
+	    incmem(f,&p->z,t,SUB,-l);
+	  }else
+	    incmem(f,&p->z,t,ADD,l);
+	  continue;
+	}
+      }
+
+      if((c==LSHIFT||c==RSHIFT)&&isreg(q1)&&isreg(z)&&isconst(q2)&&p->q1.reg==p->z.reg&&p->z.reg!=ra&&p->z.reg!=rax){
+	long l;
+	eval_const(&p->q2.val,q2typ(p));
+	l=zm2l(vmax);
+	/*TODO: allow larger types */
+	if(l<5&&(t&NQ)<=INT){
+	  if(c==RSHIFT&&!(t&UNSIGNED))
+	    get_acc(f,p,CHAR);
+	  incmem(f,&p->z,t,c,l);
+	  continue;
+	}
+      }
+
+      if(c==LSHIFT||c==RSHIFT){
+	long l=-1;int loop=0,r,r2,r3,outl=0;
+	if(isconst(q2)){
+	  eval_const(&p->q2.val,q2typ(p));
+	  l=zm2l(vmax);
+	  loop=0;
+	}else
+	  loop=1;
+	if(l>=0&&optsize){
+	  if(c==LSHIFT&&(l&7)>6) 
+	    loop=1;
+	  else if(c==RSHIFT&&(t&UNSIGNED)&&(l&7)>3)
+	    loop=1;
+	  else if(c==RSHIFT&&!(t&UNSIGNED)&&(l&7)>2)
+	    loop=1;
+	}
+
+	if(!ISCHAR(t))
+	  r=get_reg(f,p,CHAR);
+	if(ISLONG(t)){
+	  r2=get_reg(f,p,CHAR);
+	  r3=get_reg(f,p,CHAR);
+	}
+	if(ISLONG(t)){
+	  get_acc(f,p,CHAR);
+	  if(l>=24){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	      emit(f,"\tsty\t%s\n",mregnames[r2]);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      do_byte4(f,"lda",&p->q1,t);
+
+	    }
+	  }else if(l>=16){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\tsty\t%s\n",mregnames[r]);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      do_byte3(f,"lda",&p->q1,t);
+
+	    }
+	  }else if(l>=8){
+	    if(c==LSHIFT){
+	      load_lobyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      emit(f,"\tlda\t#0\n");
+	    }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      sety(f,0);
+	      emit(f,"\tcmp\t#0\n");
+	      emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	      emit(f,"\tdey\n");
+	      emit(f,"%s%d:\n",labprefix,label);
+	      emit(f,"\ttya\n");
+	      yval=NOVAL;
+	    }else{
+	      emit(f,"\tlda\t#0\n");
+	      emit(f,"\tsta\t%s\n",mregnames[r3]);
+	      do_byte4(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r2]);
+	      do_byte3(f,"lda",&p->q1,t);
+	      emit(f,"\tsta\t%s\n",mregnames[r]);
+	      load_hibyte(f,&p->q1,t);
+
+	    }
+	  }else if(c==RSHIFT&&!(t&UNSIGNED)){
+	    load_lobyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r3]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r]);
+	    do_byte4(f,"lda",&p->q1,t);
+	  }else{
+	    do_byte4(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r3]);
+	    do_byte3(f,"lda",&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r2]);
+	    load_hibyte(f,&p->q1,t);
+	    emit(f,"\tsta\t%s\n",mregnames[r]);
+	    load_lobyte(f,&p->q1,t);
+	  }
+	}else
+	  get_acc(f,p,t);
+	if(!ISLONG(t)){
+	  if(l>=8){
+	    if(!ISSHORT(t)) ierror(0);
+	    if(c==LSHIFT){
+	      if(indirect(&p->q1)){
+		load_lobyte(f,&p->q1,t);
+		emit(f,"\ttax\n");
+		emit(f,"\tlda\t#0\n");
+	      }else{
+		if(isacc(q1))
+		  emit(f,"\ttax\n");
+		else
+		  do_lobyte(f,"ldx",&p->q1,t);
+		emit(f,"\tlda\t#0\n");
+	      }
+	    }else{
+	      load_hibyte(f,&p->q1,t);
+	      emit(f,"\tldx\t#0\n");
+	      if(!(t&UNSIGNED)){
+		emit(f,"\tcmp\t#0\n");
+		emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+		emit(f,"\tdex\n");
+		emit(f,"%s%d:\n",labprefix,label);
+	      }
+	    }
+	  }else
+	    load_acc(f,&p->q1,t);
+	}
+	if(ISSHORT(t))
+	  emit(f,"\tstx\t%s\n",mregnames[r]);
+	if(l>=0) l&=7;
+	if(loop){
+	  if(l>=0)
+	    sety(f,l);
+	  else{
+	    if(indirect(&p->q2)){
+	      emit(f,"\tpha\n");
+	      load_lobyte(f,&p->q2,q2typ(p));
+	      emit(f,"\ttay\n");
+	      emit(f,"\tpla\n");
+	      emit(f,"\tcpy\t#0\n");
+	    }else{
+	      emit(f,"\tldy\t");
+	      emit_lobyte(f,&p->q2,q2typ(p));
+	      emit(f,"\n");
+	    }
+	    outl=++label;
+	    emit(f,"\tbeq\t%s%d\n",labprefix,outl);
+	  }
+	  emit(f,"%s%d:\n",labprefix,++label);
+	}else{
+	  if(ISCHAR(t))
+	    l&=7;
+	  else if(ISSHORT(t))
+	    l&=15;
+	  else
+	    l&=31;
+	}
+	while(l>0||loop){
+	  if(c==LSHIFT){
+	    emit(f,"\tasl\n");
+	    if(!ISCHAR(t))
+	      emit(f,"\trol\t%s\n",mregnames[r]);
+	    if(ISLONG(t)){
+	      emit(f,"\trol\t%s\n",mregnames[r2]);
+	      emit(f,"\trol\t%s\n",mregnames[r3]);
+	    }
+	  }else if(t&UNSIGNED){
+	    emit(f,"\tclc\n");
+	    if(ISLONG(t)){
+	      emit(f,"\tror\t%s\n",mregnames[r3]);
+	      emit(f,"\tror\t%s\n",mregnames[r2]);
+	    }
+	    if(!ISCHAR(t))
+	      emit(f,"\tror\t%s\n",mregnames[r]);
+	    emit(f,"\tror\n");
+	  }else{
+	    if(ISLONG(t)){
+	      emit(f,"\tcmp\t#128\n");
+	      emit(f,"\tror\n");
+	      emit(f,"\tror\t%s\n",mregnames[r]);
+	      emit(f,"\tror\t%s\n",mregnames[r2]);
+	      emit(f,"\tror\t%s\n",mregnames[r3]);
+	    }else{
+	      if(!ISCHAR(t)){
+		emit(f,"\tcpx\t#128\n");
+		emit(f,"\tror\t%s\n",mregnames[r]);
+	      }else
+		emit(f,"\tcmp\t#128\n");
+	      emit(f,"\tror\n");
+	    }
+	  }
+	  if(loop){
+	    emit(f,"\tdey\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,label);
+	    if(outl) emit(f,"%s%d:\n",labprefix,outl);
+	    yval=0;
+	    break;
+	  }
+	  l--;
+	}
+	if(ISLONG(t)){
+	  if(c==RSHIFT&&!(t&UNSIGNED)){
+	    do_byte4(f,"sta",&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    do_byte3(f,"sta",&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r3]);
+	    store_lobyte(f,&p->z,t);
+	  }else{
+	    store_lobyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r]);
+	    store_hibyte(f,&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r2]);
+	    do_byte3(f,"sta",&p->z,t);
+	    emit(f,"\tlda\t%s\n",mregnames[r3]);
+	    do_byte4(f,"sta",&p->z,t);
+	  }
+	}else{
+	  if(!ISCHAR(t))
+	    emit(f,"\tldx\t%s\n",mregnames[r]);
+	  if(ISCHAR(t)||indirect(&p->z))
+	    store_acc(f,&p->z,t);
+	  else{
+	    store_lobyte(f,&p->z,t);
+	    if(!isreg(z)||p->z.reg!=rax){
+	      emit(f,"\tstx\t");
+	      emit_hibyte(f,&p->z,t);
+	      emit(f,"\n");
+	    }
+	  }
+	}
+	continue;
+      }
+
+      if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP){
+	char *s;int t2=t,pt=p->typf2;
+	if(!isacc(z))
+	  get_acc(f,p,CHAR);
+	if(c==ADDI2P||c==SUBIFP){
+	  if(c==ADDI2P) c=ADD; else c=SUB;
+	  t=UNSIGNED|INT;
+	  if((pt&NQ)==POINTER&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p->q1.val,POINTER);
+	    insert_const(&p->q1.val,UNSIGNED|INT);
+	  }
+	}
+	if(c>=OR&&c<=AND)
+	  s=logicals[c-OR];
+	else
+	  s=arithmetics[c-LSHIFT];
+      
+	if(ISFLOAT(t)){
+	  if(!ieee) ierror(0);
+	  t&=NQ;
+	  if(regs[LAST_PAIR]) ierror(0);
+	  get_acc(f,p,INT);
+	  regs[LAST_PAIR]=1;
+	  load_address(f,LAST_PAIR,&p->q1,t);
+	  BSET(regused,t3);
+	  BSET(regused,t4);
+	  emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->q2,t);
+	  emit(f,"\tjsr\t%s__f%s%c\n",idprefix,ename[c],(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  load_address(f,LAST_PAIR,&p->z,t);
+	  emit(f,"\tjsr\t%s__fstore%c\n",idprefix,(t==FLOAT?'s':'d'));
+	  yval=NOVAL;
+	  regs[LAST_PAIR]=0;
+	  continue;
+	}else if(ISLONG(t)){
+	  if(c==ADD) emit(f,"\tclc\n");
+	  if(c==SUB) emit(f,"\tsec\n");
+	  load_lobyte(f,&p->q1,t);
+	  do_lobyte(f,s,&p->q2,t);
+	  store_lobyte(f,&p->z,t);
+	  load_hibyte(f,&p->q1,t);
+	  do_hibyte(f,s,&p->q2,t);
+	  store_hibyte(f,&p->z,t);
+	  do_byte3(f,"lda",&p->q1,t);
+	  do_byte3(f,s,&p->q2,t);
+	  do_byte3(f,"sta",&p->z,t);
+	  do_byte4(f,"lda",&p->q1,t);
+	  do_byte4(f,s,&p->q2,t);
+	  do_byte4(f,"sta",&p->z,t);
+	  continue;
+	}else if(ISCHAR(t)){
+	  load_acc(f,&p->q1,t);
+	  if(c==ADD) emit(f,"\tclc\n");
+	  if(c==SUB) emit(f,"\tsec\n");
+	  do_lobyte(f,s,&p->q2,t);
+	  store_acc(f,&p->z,t);
+	}else if(c==ADD||c==SUB){
+	  int a,r;long l=1;
+	  if(isconst(q2)){
+	    eval_const(&p->q2.val,t2);
+	    l=zm2l(vmax);
+	    l&=0xff00;
+	  }
+	  if(isreg(z)&&p->z.reg==rax) a=1; else a=0;
+	  if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+	    emit(f,"\tldx\t#0\n");
+	  }
+	  if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+	    load_lobyte(f,&p->q2,t);
+	    emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+	    emit(f,"\tdex\n");
+	    emit(f,"%s%d:\n",labprefix,label);
+	    if(c==ADD){
+	      if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+	      do_lobyte(f,s,&p->q1,t);
+	      if(isacc(z))
+		emit(f,"\tpha\n");
+	      else
+		store_lobyte(f,&p->z,t);
+	      emit(f,"\ttxa\n");
+	      do_hibyte(f,s,&p->q1,t);
+	      store_hibyte(f,&p->z,t);
+	      if(ISFPOINTER(pt)&&!compare_objects(&p->q1,&p->z)){
+		do_byte3(f,"lda",&p->q1,pt);
+		do_byte3(f,"sta",&p->z,pt);
+	      }
+	      if(isacc(z))
+		emit(f,"\tpla\n");
+	      continue;
+	    }
+	    r=get_reg(f,p,CHAR);
+	    emit(f,"\tstx\t%s\n",mregnames[r]);
+	  }
+	  load_lobyte(f,&p->q1,t);
+	  if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+	  do_lobyte(f,s,&p->q2,t2);
+	  store_lobyte(f,&p->z,t);
+	  if(l==0&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+	    if(c==ADD){
+	      emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+	      if(a)
+		emit(f,"\tinx\n");
+	      else{
+		/*if(!reg_pair(p->z.reg,&rp)) ierror(0);*/
+		emit(f,"\tinc\t%s+1\n",mregnames[p->z.reg]);
+	      }
+	    }else{
+	      emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+	      if(a)
+		emit(f,"\tdex\n");
+	      else{
+		if(!reg_pair(p->z.reg,&rp)) ierror(0);
+		emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+	      }
+	    }
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }else{
+	    if(a==1) emit(f,"\tpha\n");
+	    if((t2&NQ)==CHAR){
+	      if(t2&UNSIGNED){
+		load_hibyte(f,&p->q1,t);
+		emit(f,"\t%s\t#0\n",s);
+	      }else{
+		load_hibyte(f,&p->q1,t);
+		if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+		  eval_const(&p->q2.val,t2);
+		  if(zmleq(Z0,vmax))
+		    emit(f,"\t%s\t#0\n",s);
+		  else
+		    emit(f,"\t%s\t#255\n",s);
+		}else{
+		  emit(f,"\t%s\t%s\n",s,mregnames[r]);
+		}
+	      }
+	    }else{
+	      load_hibyte(f,&p->q1,t);
+	      do_hibyte(f,s,&p->q2,t2);
+	    }
+	    store_hibyte(f,&p->z,t);
+	    if(a==1) emit(f,"\tpla\n");
+	    if(ISFPOINTER(pt)&&p->code!=SUBPFP){
+	      if(!compare_objects(&p->q1,&p->z)){
+		do_byte3(f,"lda",&p->q1,FPOINTER);
+		do_byte3(f,"sta",&p->z,FPOINTER);
+	      }
+	    }
+	  }
+	}else{
+	  if(isacc(q1))
+	    emit(f,"\tpha\n");
+	  load_hibyte(f,&p->q1,t);
+	  do_hibyte(f,s,&p->q2,t);
+	  store_hibyte(f,&p->z,t);
+	  if(isacc(q1))
+	    emit(f,"\tpla\n");
+	  load_lobyte(f,&p->q1,t);
+	  do_lobyte(f,s,&p->q2,t);
+	  store_lobyte(f,&p->z,t);
+	}
+	continue;
+      }
+      pric2(stdout,p);
+      ierror(0);
+    }
+
+    function_bottom(f,v,localsize);
+    
+    for(c=1;c<=MAXR;c++){
+      if(regsa[c]||regused[c]){
+	BSET(regs_modified,c);
+      }
+    }
+
+    if(stack_valid){
+      if(!v->fi) v->fi=new_fi();
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=stack;
+    }
+  }
+
+  free_IC(mi);
+
+  emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  if(code==COMPARE/*||code==MULT*/||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT/*||code==MINUS*/||code==KOMPLEMENT)
+    return 1;
+
+  return 0;
+}
+
+static int fattr(type *p,char *s)
+{
+  if(p->attr&&strstr(p->attr,s))
+    return 1;
+  if(p->next)
+    return fattr(p->next,s);
+  else
+    return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+
+  if(vararg)
+    return 0;
+  f=t->flags&NQ;
+  if(OLDFP&&ISFLOAT(f)) return 0;
+  if(d&&fattr(d,"__stackparms__"))
+    return 0;
+  if(d&&fattr(d,"__cc65__")){
+    m->regs++;
+    printf("arg=%d cnt=%d\n",m->regs,d->exact->count);
+    if(m->regs==d->exact->count-1){
+      if(ISCHAR(t->flags))
+	return ra;
+      if(ISSHORT(t->flags))
+	return rax;
+    }
+    return 0;
+  }
+  if(ISCHAR(f)){
+    if(!t->exact){
+      if(m->regs>=GPR_ARGS-1)
+	return 0;
+      f=FIRST_GPR+m->regs;
+      m->regs+=2;
+      return f;
+    }else{
+      if(m->regs>=GPR_ARGS)
+	return 0;
+      else
+	return FIRST_GPR+m->regs++;
+    }
+  }
+  if(ISSHORT(f)||f==POINTER){
+    if(m->regs>=GPR_ARGS-1)
+      return 0;
+    else{
+      if(m->regs&1) m->regs+=1;
+      m->regs+=2;
+      return FIRST_PAIR+m->regs/2-1;
+    }
+  }
+  if(f==FPOINTER||f==LONG||f==FLOAT||(!ieee&&(f==DOUBLE||f==LDOUBLE))){
+    if(m->bregs>=4)
+      return 0;
+    else
+      return FIRST_BIG+m->bregs++;
+  }
+  if(f==LLONG||(ieee&&(f==DOUBLE||f==LDOUBLE))){
+    if(m->bregs>=3)
+      return 0;
+    else{
+      if(m->bregs&1)  m->bregs++;
+      m->bregs+=2;
+      return FIRST_BIGP+m->bregs/2-1;
+    }
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+  static char sec[SECLEN];
+  int i;
+  if(sscanf(s,"section %127s",sec)==1){
+    if(!strcmp(sec,"default"))
+      use_sec=0;
+    else
+      use_sec=sec;
+    return 1;
+  }
+  if(sscanf(s,"bank %d",&i)==1){
+    use_bank=i;
+    return 1;
+  }
+}
+void cleanup_cg(FILE *f)
+{
+  int i;
+  struct fpconstlist *p=firstfpc;
+
+  if(f&&p){
+    emit(f,rodataname);emit(f,"\n");
+    section=RODATA;
+  }
+  while(p=firstfpc){
+    emit(f,"%s%d:\n\tword\t",labprefix,p->label);
+    if(ieee)
+      emit_ieee(f,&p->val,p->t);
+    else{
+      int words=zm2l(sizetab[p->t&NQ])/2;
+      eval_const(&p->val,p->t);
+      if(ISFLOAT(p->t)) cnv_fp();
+      for(i=0;i<words;i++){
+	emit(f,"%ld",zm2l(vmax)&0xffff);
+	if(i<words-1){emit(f,",");vmax=zmrshift(vmax,l2zm(16L));}
+      }
+      emit(f,"\n");
+      /*emit(f,"%ld,%ld\n",zm2l(vmax)&0xffff,zm2l(zmrshift(vmax,l2zm(16L)))&0xffff);*/
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+
+  emit(f,"\tzpage\t%s\n",mregnames[sp]);
+  for(i=FIRST_GPR;i<=LAST_GPR;i++)
+    emit(f,"\tzpage\t%s\n",mregnames[i]);
+  for(i=FIRST_BIG;i<=LAST_BIG;i++)
+    emit(f,"\tzpage\t%s\n",mregnames[i]);
+
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
+static char *zops[]={
+  "adc","and","asl","bit","eor","lda","ora",
+  "tax","txa","tay","tya","sbc"};
+
+static int setszflag(char *op)
+{
+  int i;
+  for(i=0;i<sizeof(zops)/sizeof(zops[0]);i++)
+    if(!strcmp(op,zops[i]))
+      return 1;
+  return 0;
+}
+
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+
+
+int emit_peephole(void)
+{
+  int entries,i,j;
+  char *asmline[EMIT_BUF_DEPTH];
+  char buf1[1024],buf2[1024];
+  char op1[8],op2[8];
+  static char ca[1024],cx[1024],cy[1024],cz[1024];
+  static int rm,disabled;
+
+  fprintf(stderr,"Called emit_peephole()\n");
+  
+  static struct peeps elim[]={
+    "lda","sta",0,NEEDSAME,
+    "ldx","stx",0,NEEDSAME,
+    "sta","sta",0,NEEDSAME,
+    "stx","stx",0,NEEDSAME,
+    "sta","lda",0,NEEDSAME,
+    "stx","ldx",0,NEEDSAME,
+    "txa","tax",0,0,
+    "tax","txa",0,0,
+    "lda","lda",0,REMOVE1ST,
+    "ldx","ldx",0,REMOVE1ST,
+    "ldy","ldy",0,REMOVE1ST,
+    "ldz","ldz",0,REMOVE1ST,
+    "lda","pla",0,REMOVE1ST,
+    "lda","txa",0,REMOVE1ST,
+    "lda","tya",0,REMOVE1ST,
+    "ldx","tax",0,REMOVE1ST,
+    "ldy","tay",0,REMOVE1ST,
+    "tay","ldy",0,REMOVE1ST,
+    "taz","ldz",0,REMOVE1ST,
+    "tax","ldx",0,REMOVE1ST,
+    "txa","lda",0,REMOVE1ST,
+    "tya","lda",0,REMOVE1ST,
+    "tza","lda",0,REMOVE1ST,
+    "lda","ldx","\ttax\n",NEEDSAME,
+    "lda","ldy","\ttay\n",NEEDSAME,
+    "ldx","lda","\ttxa\n",NEEDSAME,
+    "ldy","lda","\ttya\n",NEEDSAME,
+    "sta","ldx","\ttax\n",NEEDSAME,
+    "sta","ldy","\ttay\n",NEEDSAME,
+    "stx","lda","\ttxa\n",NEEDSAME,
+    "sty","lda","\ttya\n",NEEDSAME,
+
+  };
+
+  if(nopeep) return 0;
+
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+
+  if(!strcmp(asmline[0],";startinline\n")) disabled=1;
+  if(!strcmp(asmline[0],";endinline\n")) disabled=0;
+  if(disabled) return 0;
+
+  buf1[0]=0;op1[0]=0;
+  if((j=sscanf(asmline[0]," %6s %999s",op1,buf1))>=1){
+    printf("a=%s x=%s y=%s, z=%s\n",ca,cx,cy,cz);
+    printf("\t\t%s %s\n",op1,buf1);
+    if(!strcmp(op1,"sta")) {
+      // Work out when we are accessing variables on the stack
+      if (!strcmp(buf1,"(sp),y")) {
+	// We invalidate this when Y changes
+	snprintf(ca,1024,"(sp),y",cy);
+      } 
+    } else if(!strcmp(op1,"sta")){
+      // Remove writes to wherever A was loaded from
+      if (!strcmp(buf1,ca)) {
+	remove_asm();
+	return rm=1;
+      }
+    } else if(!strcmp(op1,"lda")){
+      if(buf1[0]=='#'){
+	if(!strcmp(buf1,ca)){remove_asm();return rm=1;}
+	strcpy(ca,buf1);
+      }else {
+	// Work out when we are accessing variables on the stack
+	if (!strcmp(buf1,"(sp),y")) {	 
+	  if(!strcmp(buf1,ca)){
+	    remove_asm();
+	    return rm=1;
+	  }
+	  snprintf(ca,1024,"(sp),y",cy);
+	}
+	// Similarly look for register loads
+	// We can sometimes remove some of those, too.
+	if ((strlen(buf1)>1)&&(buf1[0]=='r')) {
+	  if (strcmp(ca,buf1)) 
+	    snprintf(ca,1024,"%s",buf1);
+	  else {
+	    // Don't re-load A with the same contents it already has
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+    }else if(!strcmp(op1,"ldx")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cx)){remove_asm();return rm=1;}
+	strcpy(cx,buf1);
+      }else cx[0]=0;
+    }else if(!strcmp(op1,"ldy")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cy)){remove_asm();return rm=1;}
+	strcpy(cy,buf1);
+      }else cy[0]=0;
+    }else if(!strcmp(op1,"ldz")){
+      if(buf1[0]=='#'){
+	if(!rm&&!strcmp(buf1,cz)){remove_asm();return rm=1;}
+	strcpy(cz,buf1);
+      }else cz[0]=0;
+    }else{
+      // TODO: PGS: Add the AXYZ operations to the clobber lists.
+      //            Will we need to handle them specially?
+      static char clobbernone[]="clc cld cli clv cmp cpx cpy dec inc nop pha php plp sec sed sei sta stx sty stz";
+      static char clobbera[]="adc and asl eor lsr ora pla rol ror sbc txa tya tza neg";
+      static char clobberx[]="dex inx tax tsx";
+      static char clobbery[]="dey iny tay";
+      static char clobberz[]="dez inz taz";
+      if(strstr(clobbernone,op1)){
+	// Invalidate A holding a stack variable byte if SP changes
+	if (strstr(buf1,"sp")) {
+	  printf("buf1='%s'\n",buf1);
+	  if (strstr(ca,"(sp),y")) ca[0]=0;
+	}	
+      }else if(strstr(clobbera,op1))
+	ca[0]=0;
+      else if(strstr(clobberx,op1))
+	cx[0]=0;
+      else if(strstr(clobbery,op1)) {
+	cy[0]=0;
+	// Invalidate A holding a stack variable byte if Y changes
+	if (strstr(ca,"(sp),y")) ca[0]=0;
+      }
+      else if(strstr(clobberz,op1))
+	cz[0]=0;
+      else
+	ca[0]=cx[0]=cy[0]=cz[0]=0;
+    }
+  }else{
+    ca[0]=cx[0]=cy[0]=cz[0]=0;
+  }
+
+  rm=0;
+
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"and")&&!strcmp(buf1,"#0")){
+    strcpy(asmline[0],"\tlda\t#0\n");
+    return rm=1;
+  }
+
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+
+
+    if(!strcmp(asmline[0],"; volatile barrier\n")&&!strcmp(asmline[0],asmline[1])){
+      remove_asm();
+      return rm=1;
+    }
+
+    if(sscanf(asmline[0]," %6s",op1)==1&&!strcmp(op1,"rts")&&
+       sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&!strcmp(op2,"jsr")){
+      sprintf(asmline[1],"\tjmp\t%s\n",buf2);
+      remove_asm();
+      return rm=1;
+    }
+
+    for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+      if(elim[j].flags&NEEDSAME){
+	if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+	   sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+	   !strcmp(buf1,buf2)){
+	  if(elim[j].r){
+	    strcpy(asmline[0],elim[j].r);
+	  }else{
+	    if(elim[j].flags&REMOVE1ST)
+	      strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	  }
+	  return rm=1;
+	}
+      }else{
+	if(sscanf(asmline[1]," %6s",op1)==1&&
+	   sscanf(asmline[0]," %6s",op2)==1&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+	  if(elim[j].flags&REMOVE1ST)
+	    strcpy(asmline[1],asmline[0]);
+	  remove_asm();
+	  return rm=1;
+	}
+      }
+    }
+
+
+  }
+
+  if(entries>=3){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[2]=emit_buffer[i];
+    if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+#if 0
+      if(!strcmp(op1,"lda")&&buf1[0]=='#'){
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,"sta")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)==2&&
+	     !strcmp(op2,"lda")&&!strcmp(buf1,buf2)){
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+#endif
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+	   !strcmp(op1,"cmp")&&!strcmp(buf1,"#0")){
+	  if(sscanf(asmline[2]," %6s",op1)==1&&
+	     setszflag(op1)){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return rm=1;
+	  }
+	}
+      }
+    }
+  }
+  
+  return 0;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||(ISFLOAT(t)&&!ieee)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(ISSHORT(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+      return 0;
+    if(ISLONG(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+      return 0;
+
+    if(!ieee&&ISFLOAT(t)) t=FLOAT;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(!ieee&&ISFLOAT(t2)) t2=FLOAT;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==INT||(t&NQ)==LONG||(t&NQ)==LLONG||(!ieee&&ISFLOAT(t))){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+        if(t==(UNSIGNED|LLONG)&&(c==MULT||c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint64",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+        }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint32",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LONG){
+          sprintf(fname,"__%sint32",ename[c]);
+          ret=fname;
+        }else if(t==(UNSIGNED|INT)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint16",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==INT){
+          sprintf(fname,"__%sint16",ename[c]);
+          ret=fname;
+        }else{
+          sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+        }
+      }
+    }
+  }
+
+  return ret;
+}
+
+
+int pointer_varadr(Var *v)
+{
+  int b=bank(v);
+  if(b>=0&&b!=bankcnum&&!NOBANKVARS){
+    if(cur_funcv&&bank(cur_funcv)!=b)
+      return FPOINTER;
+  }
+  return pointer_type(v->vtyp);
+}
+
+int pointer_type(struct Typ *p)
+{
+  struct Typ *merk=p;
+  if(!p) ierror(0);
+  if(LARGE) return FPOINTER;
+  while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+  if(p->attr){
+    char *s;
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return POINTER;
+  }
+  return POINTER;
+}
+
+unsigned char cbmconv(unsigned char x)
+{
+  static unsigned char ctab[256]={
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+    0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0xBF,0x5D,0x5E,0xA4,
+    0xAD,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB3,0xDD,0xAB,0xB1,0xDF,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0x5F,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0x7D,0xAC,0x60,0xAE,0xAF,
+    0xB0,0x7E,0xB2,0x7B,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0x5C,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0xDC,0x7C,0xDE,0x7F,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+  };
+
+  static unsigned char atab[]={0xfd,8,0x7f,0x9b,11,0x7d};
+
+  if(cbmascii)
+    return ctab[x&255];
+  else if(atascii&&x>=7&&x<=12)
+    return atab[x-7];
+  else
+    return x;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+/*  *p = (union atyps) 0 ; /* rfi: clear unused bits */
+  t&=NU;
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==POINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==POINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==POINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==POINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+        if(strstr(attr,STR_NEAR))
+          p->flags=((p->flags&~NU)|POINTER);
+        if(strstr(attr,STR_FAR))
+          p->flags=((p->flags&~NU)|FPOINTER);
+        if(strstr(attr,STR_HUGE))
+          p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    p=p->next;
+  }
+}
+
+void add_var_hook_post(Var *v)
+{
+  if(use_sec&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+    char buf[SECLEN+32];
+    sprintf(buf,"section(\"%s\");",use_sec);
+    add_attr(&v->vattr,buf);
+  }
+  if(use_bank>=0&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+    char buf[64];
+    /*sprintf(buf,"section(\"bank%d\");bank(%d)",use_bank,use_bank);*/
+    sprintf(buf,"bank(%d)",use_bank);
+    add_attr(&v->vattr,buf);
+  }
+}
+
+int decide_reverse(zmax v)
+{
+  if(zmeqto(v,Z1)||zmeqto(v,l2zm(2L)))
+    return 1;
+  if(optspeed)
+    if(zmeqto(v,l2zm(4L))||zmeqto(v,l2zm(8L))||zmeqto(v,l2zm(256L))||zmeqto(v,l2zm(512L)))
+      return 1;
+  
+  return 0;
+}
+
+static int is_single_eff_ic(struct IC *p)
+{
+  struct Var *v,*idx;
+  if(p->code!=ADDI2P||(p->typf2&NQ)!=POINTER)
+    return 0;
+  if(!(p->q2.flags&KONST)){
+    if((p->typf&NU)!=(UNSIGNED|CHAR))
+      return 0;
+    if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+      return 0;
+    if(p->q2.v->storage_class!=AUTO&&p->q2.v->storage_class!=REGISTER)
+      return 0;
+    idx=p->q2.v;
+  }else{
+    idx=0;
+    eval_const(&p->q2.val,p->typf);
+    /* TODO: more precise check considering data type useful? */
+    if(!zmleq(vumax,l2zm(255L)))
+      return 0;
+    return 1;
+  }
+  if(p->q1.flags&DREFOBJ)
+    return 0;
+  if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+    return 0;
+  v=p->z.v;
+  for(p=p->next;p;p=p->next){
+    int c=p->code;
+    if(c==LABEL||(c>=BEQ&&c<=BRA))
+      return 1; /* TODO: how elaborate should we test? */
+    if((p->q1.flags&VAR)&&p->q1.v==v){
+      if(p->q1.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==v){
+      if(p->q2.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->z.flags&DREFOBJ)
+        return 1;
+      else
+        return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==idx)
+      return 0;
+  }
+  return 0;
+}
+
+void mark_eff_ics(void)
+{
+  struct IC *p;
+  for(p=first_ic;p;p=p->next){
+    if(is_single_eff_ic(p))
+      p->flags|=EFF_IC;
+    else
+      p->flags&=~EFF_IC;
+  }
+}
diff --git a/machines/m68k/machine.c b/machines/m68k/machine.c
new file mode 100644
index 0000000..3e96a31
--- /dev/null
+++ b/machines/m68k/machine.c
@@ -0,0 +1,5595 @@
+/*  $VER: vbcc (m68k/machine.c) $Revision: 1.139 $     */
+/*  Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2    */
+/*  and ColdFire.                                                           */
+/*  vasm, PhxAss and the GNU assembler is supported.                        */
+
+
+#include "supp.h"
+
+#define NEW_RET 0
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for m68k/ColdFire V1.15 (c) in 1995-2022 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+char *g_flags_name[MAXGF]={
+    "cpu","fpu","d2scratch","noa4","sc","sd","prof","const-in-data",
+    "use-framepointer","no-peephole","no-delayed-popping",
+    "gas","branch-opt","no-fp-return","no-mreg-return","hunkdebug",
+    "no-intz","old-peephole","conservative-sr","elf","use-commons",
+    "a2scratch","old-softfloat","amiga-softfloat","fastcall","fp2scratch",
+    "no-reserve-regs","phxass","clean-fattr","old-libcalls","vbcccall",
+    "float64"
+};
+
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[MAXR+1]={"noreg","a0","a1","a2","a3","a4","a5","a6","a7",
+                               "d0","d1","d2","d3","d4","d5","d6","d7",
+                        "fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7",
+                        "d0/d1","d2/d3","d4/d5","d6/d7"};
+
+static char *elfregnames[MAXR+1]={"noreg","%a0","%a1","%a2","%a3","%a4","%a5","%a6","%a7",
+			   "%d0","%d1","%d2","%d3","%d4","%d5","%d6","%d7",
+			   "%fp0","%fp1","%fp2","%fp3","%fp4","%fp5","%fp6","%fp7",
+			   "%d0/%d1","%d2/%d3","%d4/%d5","%d6/%d7"};
+
+static char *mregnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+type *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1]={0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
+			1,0,0,0};
+
+int reg_prio[MAXR+1]={0,4,4,3,3,3,3,3,0,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0};
+
+treg_handle empty_reg_handle={0,0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__far","__near","__chip","__saveds",
+                     "__interrupt","__amigainterrupt",0};
+#define FAR 1
+#define NEAR 2
+#define CHIP 4
+#define SAVEDS 8
+#define INTERRUPT 16
+#define AMIINTERRUPT 32
+#define STDARGS 64 /* not used, just for compatibility */
+
+int MINADDI2P=SHORT;
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+#define CPU             (g_flags_val[0].l)
+#define FPU             (g_flags_val[1].l)
+#define D2SCRATCH       (g_flags[2]&USEDFLAG)
+#define NOA4            (g_flags[3]&USEDFLAG)
+#define SMALLCODE       (g_flags[4]&USEDFLAG)
+#define SMALLDATA       (g_flags[5]&USEDFLAG)
+#define PROFILER        (g_flags[6]&USEDFLAG)
+#define CONSTINDATA     (g_flags[7]&USEDFLAG)
+#define USEFRAMEPOINTER (g_flags[8]&USEDFLAG)
+#define NOPEEPHOLE      (g_flags[9]&USEDFLAG)
+#define NODELAYEDPOP    (g_flags[10]&USEDFLAG)
+#define GAS             (g_flags[11]&USEDFLAG)
+#define BRANCHOPT       (g_flags[12]&USEDFLAG)
+#define NOFPRETURN      (g_flags[13]&USEDFLAG)
+#define NOMREGRETURN    (g_flags[14]&USEDFLAG)
+#define HUNKDEBUG       (g_flags[15]&USEDFLAG)
+#define NOINTZ          (g_flags[16]&USEDFLAG)
+#define OLDPEEPHOLE     (g_flags[17]&USEDFLAG)
+#define CONSERVATIVE_SR (g_flags[18]&USEDFLAG)
+#define ELF             (g_flags[19]&USEDFLAG)
+#define USE_COMMONS     (g_flags[20]&USEDFLAG)
+#define A2SCRATCH       (g_flags[21]&USEDFLAG)
+#define OLD_SOFTFLOAT   (g_flags[22]&USEDFLAG)
+#define AMI_SOFTFLOAT   (g_flags[23]&USEDFLAG)
+#define FASTCALL        (g_flags[24]&USEDFLAG)
+#define FP2SCRATCH      (g_flags[25]&USEDFLAG)
+#define RESERVEREGS     (g_flags[26]&USEDFLAG)
+#define PHXASS          (g_flags[27]&USEDFLAG)
+#define CLEANFATTR      (g_flags[28]&USEDFLAG)
+#define OLDLIBCALLS     (g_flags[29]&USEDFLAG)
+#define VBCCCALL        (g_flags[30]&USEDFLAG)
+#define FLOAT64         (g_flags[31]&USEDFLAG)
+
+
+static int use_sd;
+
+#ifdef M68K_16BIT_INT
+static long malign[MAX_TYPE+1]=  {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1};
+static long msizetab[MAX_TYPE+1]={0,1,2,2,4,8,4,8,8,0,4,0,0,0,4,0};
+#else
+static long malign[MAX_TYPE+1]=  {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1};
+static long msizetab[MAX_TYPE+1]={0,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+#endif
+
+static type ltyp={LONG},larray={ARRAY,&ltyp},lltyp={LLONG};
+
+static char cpu_macro[16],fpu_macro[16],*marray[16];
+
+static char pushreglist[200],popreglist[200];
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define SPECIAL 3
+
+static char *labprefix,*idprefix;
+
+static int reglabel,freglabel,section=-1;
+enum {
+  a0=1,a1,a2,a3,a4,a5,a6,a7,
+  d0,d1,d2,d3,d4,d5,d6,d7,
+  fp0,fp1,fp2,fp3,fp4,fp5,fp6,fp7,
+  d0d1,d2d3,d4d5,d6d7
+};
+static int sp=8,fbp=6,framesize;
+static int stack_valid;
+static char *codename,*bssname,*dataname;
+static char *m_bssname,*m_dataname;
+static char *rprefix;
+
+static void emit_obj(FILE *,obj *,int);
+static IC *do_refs(FILE *,IC *);
+static void pr(FILE *,IC *);
+static int get_reg(FILE *,int,IC *,int);
+static long pof2(zumax);
+static void function_top(FILE *,Var *,long);
+static void function_bottom(FILE *f,Var *,long);
+
+#define saveregs(x,y) saveregswfp(x,y,0)
+static void saveregswfp(FILE *,IC *,int);
+static void restoreregsa(FILE *,IC *);
+static void restoreregsd(FILE *,IC *);
+
+static void assign(FILE *,IC *,obj *,obj *,int,long,int);
+static int compare_objects(obj *o1,obj *o2);
+
+static char x_s[]={'0','b','w','3','l'};
+#ifdef M68K_16BIT_INT
+static char x_t[]={'?','b','w','w','l','L','s','d','d','v','l','a','s','u','e','f'};
+#else
+static char x_t[]={'?','b','w','l','l','L','s','d','d','v','l','a','s','u','e','f'};
+#endif
+
+static char *quick[2]={"","q"};
+static char *strshort[2]={"l","w"};
+
+static char *ubranch[]={"eq","ne","cs","cc","ls","hi"};
+
+static int pushedreg,stored_cc; /* pushedreg&2: aregsaved; 4: dreg; 8: freg */
+                                /* 16: durch RESTOREREGS gepushed           */
+static int comptyp;
+static int pushflag;
+static int geta4;
+static int dscratch=1,ascratch=1,fscratch=1;
+
+#define D16OFF 1024
+
+static int newobj=0;   /*  um zu erkennen, ob neue section erlaubt ist */
+
+static int cf;
+static int add_stdargs;
+
+static int isquickkonst(union atyps *,int),isquickkonst2(union atyps *,int),regavailable(int);
+static void move(FILE *,obj *,int,obj *,int,int);
+static void loadext(FILE *,int,obj *,int);
+static void add(FILE *,obj *,int,obj *,int,int);
+static void sub(FILE *,obj *,int,obj *,int,int);
+static void mult(FILE *,obj *,int,obj *,int,int,int,IC *);
+
+extern int static_cse;
+
+static void scratch_modified(void)
+{
+  BSET(regs_modified,a0);
+  BSET(regs_modified,a1);
+  BSET(regs_modified,d0);
+  BSET(regs_modified,d1);
+  if(FPU>68000){
+    BSET(regs_modified,fp0);
+    BSET(regs_modified,fp1);
+  }
+  if(D2SCRATCH) BSET(regs_modified,d2);
+  if(A2SCRATCH) BSET(regs_modified,a2);
+  if(FP2SCRATCH) BSET(regs_modified,fp2);
+
+}
+
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+    zumax p;int ln=1;
+    p=ul2zum(1UL);
+    while(ln<=32&&zumleq(p,x)){
+        if(zumeqto(x,p)) return ln;
+        ln++;p=zumadd(p,p);
+    }
+    return 0;
+}
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#ifdef M68K_16BIT_INT
+#define ISHWORD(x) ((x&NQ)<=INT)
+#else
+#define ISHWORD(x) ((x&NQ)<INT)
+#endif
+
+#define PEA -1
+#define LEA -2
+
+#define FUNCPREFIX(t) ((stdargs(t)&&rparmtype!=PARMVBCC)?idprefix:(rparmtype==PARMVBCC?"@$":"@"))
+
+static void emit_lword(FILE *,obj *);
+static void emit_hword(FILE *,obj *);
+static int addressing(IC *);
+static long notpopped,dontpop,stackoffset,loff,maxpushed,stack;
+static int offlabel,regoffset;
+/*  For keeping track of condition codes.   */
+static obj *cc_set,*cc_set_tst;
+static int cc_typ,cc_typ_tst;
+static int missing,savedemit,savedalloc;
+static int lastpush,unorderedpush,pushoff[MAXR+1];
+
+static int vsec(FILE *f,Var *v)
+{
+  char *type="bss";
+  if(!sec_per_obj||(v->tattr&CHIP)) return 0;
+  if(ISFUNC(v->vtyp->flags)||(v->clist&&is_const(v->vtyp))) type="code"; else if(v->clist) type="data";
+  emit(f,"\t%ssection\t\"DONTMERGE_%s.%s.%ld\"%s%s\n",GAS?".":"",type,v->identifier,v->storage_class==STATIC/*&&!ISFUNC(v->vtyp->flags)*/?(long)zm2l(v->offset):0L,GAS?"":",",GAS?"":type);
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static int special_section(FILE *f,Var *v)
+{
+  char *sec;
+  if(!v->vattr) return vsec(f,v);;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return vsec(f,v);;
+  sec+=strlen("section(");
+  if(GAS)
+    emit(f,"\t.section\t");
+  else
+    emit(f,"\tsection\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static enum{
+  PARMSTD,
+  PARMVBCC,
+  PARMSAS
+} rparmtype;
+
+static int stdargs(type *t)
+{
+  type *p;
+
+  if(VBCCCALL) rparmtype=PARMVBCC;
+  else if(FASTCALL) rparmtype=PARMSAS;
+  else rparmtype=PARMSTD;
+
+  for(p=t->next;p;p=p->next){
+    if(p->attr&&strstr(p->attr,"__stdargs")) {rparmtype=PARMSTD;return 1;}
+    if(p->attr&&strstr(p->attr,"__vbccargs")) {rparmtype=PARMVBCC;return 0;}
+    if(p->attr&&strstr(p->attr,"__regargs")) {rparmtype=PARMSAS;return 0;}
+    if(CLEANFATTR) break;
+  }
+  if((!FASTCALL&&!VBCCCALL)||add_stdargs) return 1;
+  if(t->flags==FUNKT&&is_varargs(t)) return 1;
+  return 0;
+}
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+  if(l-stackoffset>stack)
+    stack=l-stackoffset;
+}
+static void push(long l)
+{
+  stackoffset-=l;
+  if(stackoffset<maxpushed) 
+    maxpushed=stackoffset;
+  if(-maxpushed>stack)
+    stack=-maxpushed;
+}
+static void pop(long l)
+{
+  stackoffset+=l;
+}
+
+void title(FILE *f)
+{
+  static int done;
+  extern char *inname; /*grmpf*/
+  if(!done&&f){
+    done=1;
+    if(GAS)
+      emit(f,"\t.file\t\"%s\"\n",inname);
+    else
+      emit(f,"\tidnt\t\"%s\"\n",inname);
+  }
+}      
+
+static int is_arg_reg(IC *p,int r)
+{
+  int i,u;IC *a;
+  for(i=0;i<p->arg_cnt;i++){
+    a=p->arg_list[i];
+    u=0;
+    if((a->z.flags&(REG|DREFOBJ))==REG)
+      u=a->z.reg;
+    else if((a->z.flags&VAR)&&a->z.v->reg)
+      u=a->z.v->reg;
+    if(u){
+      if(r==u||(reg_pair(u,&rp)&&r==rp.r1||r==rp.r2)){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+static int am_uses_reg(IC *p,int i)
+{
+  if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i))
+     ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i))
+     ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i)))
+    return 1;
+  return 0;
+}
+
+/* check if register can be scratched */
+static int scratchreg(int r,IC *p)
+{
+  int c;
+  while(1){
+    p=p->next;
+    if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+    if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+    if((p->q1.flags&REG)&&p->q1.reg==r) return 0;
+    if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
+    if((p->z.flags&REG)&&p->z.reg==r) return 0;
+    if(am_uses_reg(p,r)) return 0;
+  }
+}
+
+
+
+static int pget_reg(FILE *f,int flag,IC *p,int useq1)
+{
+  int i;
+
+  flag=1+flag*8;
+
+  if(useq1){
+    if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p))
+      return p->q1.reg;
+  }
+
+  for(i=flag;i<flag+8;i++){
+    if(regs[i]==1&&(!p||(i!=p->q1.reg&&i!=p->q2.reg&&i!=p->z.reg))){
+      if(p){
+	if(am_uses_reg(p,i))
+	  continue;
+	if(p->code==CALL&&is_arg_reg(p,i))
+	  continue;
+      }
+      regs[i]|=8;
+      pushflag=1;
+      emit(f,"\tmove.l\t%s,%ld(%s)\n",mregnames[i],-stackoffset,mregnames[sp]);
+      if(i<d0) 
+	pushedreg|=2;
+      else if (i<fp0)
+	pushedreg|=4;
+      else
+	pushedreg|=8;
+      BSET(regs_modified,i);
+      return i;
+    }
+  }
+  ierror(0);
+}
+
+static int get_reg(FILE *f,int flag,IC *p,int useq1)
+/*  Gets a register: flag=0=areg, 1=dreg, 2=fpreg           */
+{
+  int i;
+
+  flag=1+flag*8;
+
+  if(useq1){
+    if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p))
+      return p->q1.reg;
+  }
+
+  for(i=flag;i<flag+8;i++){
+    if(regs[i]==0){
+      if(p){
+	if(am_uses_reg(p,i))
+	  continue;
+	if(p->code==CALL&&is_arg_reg(p,i))
+	  continue;
+      }
+      regs[i]=2;pushedreg|=1;
+      if(!regused[i]&&!regscratch[i]){regused[i]=1; }
+      BSET(regs_modified,i);
+      return i;
+    }
+  }
+  for(i=flag;i<flag+8;i++){
+    static rpair rp;
+    if(regs[i]==1){
+      if(p){
+	if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i))
+	   ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i))
+	   ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i))){
+	  continue;
+	}
+	if(p->code==CALL&&is_arg_reg(p,i))
+	  continue;
+	if(p->q1.flags&REG){
+	  if(p->q1.reg==i) continue;
+	  if(reg_pair(p->q1.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
+	}
+	if(p->q2.flags&REG){
+	  if(p->q2.reg==i) continue;
+	  if(reg_pair(p->q2.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
+	}
+	if(p->z.flags&REG){
+	  if(p->z.reg==i) continue;
+	  if(reg_pair(p->z.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
+	}
+      }
+      regs[i]+=4;
+      if(i<lastpush){
+	unorderedpush=1;
+	/*printf("%s %s\n",mregnames[lastpush],mregnames[i]);*/
+      }
+      if(i<fp0){
+	emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[i],mregnames[sp]);
+	push(4);
+	pushoff[i]=pushoff[lastpush]+4;
+      }else{
+	emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[i],mregnames[sp]);
+	push(12);
+	pushoff[i]=pushoff[lastpush]+12;
+      }
+      lastpush=i;
+      if(i<d0)
+	pushedreg|=2;
+      else if(i<fp0)
+	pushedreg|=4;
+      else
+	pushedreg|=8;
+      BSET(regs_modified,i);
+      return i;
+    }
+  }
+  ierror(0);
+}
+static int isquickkonst(union atyps *p,int t)
+/*  Returns 1 if constant is between -128 and 127.   */
+{
+    zmax zm;zumax zum;
+    if(ISFLOAT(t)) return 0;
+    eval_const(p,t);
+    if(t&UNSIGNED){
+        zum=ul2zum(127UL);
+        return zumleq(vumax,zum);
+    }else{
+        zm=l2zm(-129L);
+        if(zmleq(vmax,zm)) return 0;
+        zm=l2zm(127L);
+        return zmleq(vmax,zm);
+    }
+}
+static int isquickkonst2(union atyps *p,int t)
+/*  Returns 1 if constant is between 1 and 8.   */
+{
+    zmax zm;zumax zum;
+    if(ISFLOAT(t)) return 0;
+    eval_const(p,t);
+    if(t&UNSIGNED){
+        if(zumeqto(ul2zum(0UL),vumax)) return 0;
+        zum=ul2zum(8UL);
+        return zumleq(vumax,zum);
+    }else{
+        if(zmeqto(l2zm(0L),vmax)) return 0;
+        zm=l2zm(-1L);
+        if(zmleq(vmax,zm)) return 0;
+        zm=l2zm(8L);
+        return zmleq(vmax,zm);
+    }
+}
+
+static int pregavailable(IC *p,int art)
+/*  Returns true if matching register is available. Handles arglist*/
+{
+    int i;
+    art=1+art*8;
+    for(i=art+1;i<art+8;i++)
+      if(regs[i]==0&&!is_arg_reg(p,i)) return(1);
+    return 0;
+}
+
+static int regavailable(int art)
+/*  Returns true if matching register is available.     */
+{
+    int i;
+    art=1+art*8;
+    for(i=art+1;i<art+8;i++)
+        if(regs[i]==0) return(1);
+    return 0;
+}
+static int compare_objects(obj *o1,obj *o2)
+/*  Tests if two objects are equal.     */
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if((o1->flags&(KONST|VAR|DREFOBJ|REG|VARADR))==(o2->flags&(KONST|VAR|DREFOBJ|REG|VARADR))&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+static IC *do_refs(FILE *f,IC *p)
+/*  Loads DREFOBJs into address registers, if necessary.    */
+/*  Small constants are loaded into data registers if this  */
+/*  improves code.                                          */
+{
+    int reg,c=p->code,t=p->typf,equal;
+    if((p->q1.flags&DREFOBJ)&&!(p->q1.flags&KONST)&&(!(p->q1.flags&REG)||p->q1.reg<1||p->q1.reg>8)){
+        equal=0;
+        if(compare_objects(&p->q1,&p->q2)) equal|=1;
+        if(compare_objects(&p->q1,&p->z)) equal|=2;
+	if(p->code==PUSH&&!pregavailable(p,0))
+	  reg=pget_reg(f,0,p,0);
+	else if(p->code==CALL&&!pregavailable(p,0))
+	  return p;
+	else
+	  reg=get_reg(f,0,p,0);
+        p->q1.flags&=~DREFOBJ;
+        emit(f,"\tmove.l\t");emit_obj(f,&p->q1,POINTER);
+        p->q1.flags=REG|DREFOBJ;
+        p->q1.reg=reg;
+        emit(f,",%s\n",mregnames[p->q1.reg]);
+        if(equal&1) p->q2=p->q1;
+        if(equal&2) p->z=p->q1;
+	if(c==TEST) cc_set_tst=cc_set=0;
+    }
+    if((p->q2.flags&DREFOBJ)&&!(p->q2.flags&KONST)&&(!(p->q2.flags&REG)||p->q2.reg<1||p->q2.reg>8)){
+        if(compare_objects(&p->q2,&p->z)) equal=1; else equal=0;
+        reg=get_reg(f,0,p,0);
+        p->q2.flags&=~DREFOBJ;
+        emit(f,"\tmove.l\t");emit_obj(f,&p->q2,POINTER);
+        p->q2.flags=REG|DREFOBJ;
+        p->q2.reg=reg;
+        emit(f,",%s\n",mregnames[p->q2.reg]);
+        if(equal) p->z=p->q2;
+    }
+    if((p->z.flags&DREFOBJ)&&!(p->z.flags&KONST)&&(!(p->z.flags&REG)||p->z.reg<1||p->z.reg>8)){
+      reg=get_reg(f,0,p,0);
+        p->z.flags&=~DREFOBJ;
+        emit(f,"\tmove.l\t");emit_obj(f,&p->z,POINTER);
+        p->z.flags=REG|DREFOBJ;
+        p->z.reg=reg;
+        emit(f,",%s\n",mregnames[p->z.reg]);
+    }
+    if(CPU!=68040){
+    /*  Don't do it on 040 because it's slower. */
+        if(x_t[t&NQ]=='l'&&(t&NQ)!=FLOAT&&(c!=ASSIGN||!isreg(z))&&
+           c!=MULT&&c!=DIV&&c!=MOD&&c!=LSHIFT&&c!=RSHIFT&&c!=SETRETURN&&c!=PUSH&&c!=ADDI2P&&c!=SUBIFP&&
+           (!(p->z.flags&REG)||p->z.reg<d0||p->z.reg>d7)){
+            /*  Constants into registers.    */
+            if(isconst(q1)&&isquickkonst(&p->q1.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q1.val,t))){
+                eval_const(&p->q1.val,t);
+                if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&&regavailable(1)){
+		  reg=get_reg(f,1,p,0);
+		  move(f,&p->q1,0,0,reg,t);
+		  p->q1.flags=REG;p->q1.reg=reg;
+		  p->q1.val.vmax=l2zm(0L);
+                }
+            }
+            if(isconst(q2)&&isquickkonst(&p->q2.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q2.val,t))){
+                eval_const(&p->q2.val,t);
+                if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&&regavailable(1)){
+		  reg=get_reg(f,1,p,0);
+		  move(f,&p->q2,0,0,reg,t);
+		  p->q2.flags=REG;p->q2.reg=reg;
+		  p->q2.val.vmax=l2zm(0L);
+                }
+            }
+        }
+    }
+    return p;
+}
+static void pr(FILE *f,IC *p)
+/*  Release registers and pop them from stack if necessary. */
+{
+  int i,size=0;char *s="";
+    /*  To keep track of condition codes.   */
+#if 0
+  if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE)){
+    char *fp;IC *branch;
+    if(FPU>68000&&ISFLOAT(p->typf)) fp="f"; else fp="";
+    branch=p;
+    while(branch->code<BEQ||branch->code>=BRA) branch=branch->next;
+    /*FIXME*/
+    if((p->typf&UNSIGNED)||ISPOINTER(p->typf)){
+      emit(f,"\ts%s\t-2(%s)\n",ubranch[branch->code-BEQ],mregnames[sp]);
+    }else{
+      emit(f,"\t%ss%s\t-2(%s)\n",fp,ename[branch->code]+1,mregnames[sp]);
+    }
+    stored_cc=1;
+  }
+#endif
+  if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE||p->code==SETRETURN)){
+    s="m";
+    if(!GAS&&!PHXASS) emit(f,"\topt\tom-\n");
+  }
+  for(i=MAXR;i>0;i--){
+    if(regs[i]==2) regs[i]=0;
+    if(regs[i]&8){
+      regs[i]&=~8;
+      
+      emit(f,"\tmove%s.l\t%ld(%s),%s\n",s,-stackoffset,mregnames[sp],mregnames[i]);
+      if(i>=d0) cc_set=0;
+      if(cc_set&&(cc_set->flags&REG)&&cc_set->reg==i)
+	cc_set=0;
+      missing++;
+    }
+    if(regs[i]&4){
+      regs[i]&=~4;
+      if(i>=1&&i<=d7){
+	if(unorderedpush)
+	  emit(f,"\tmove%s.l\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
+	else{
+	  if(cf&&*s=='m'){
+	    emit(f,"\tmove%s.l\t(%s),%s\n\taddq.l\t#4,%s\n",s,mregnames[sp],mregnames[i],mregnames[sp]);
+	  }else{
+	    emit(f,"\tmove%s.l\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]);
+	  }
+	}
+	pop(4);size+=4;
+      }else if(i>=fp0&&i<=fp7){
+	if(unorderedpush)
+	  emit(f,"\tfmove%s.x\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
+	else
+	  emit(f,"\tfmove%s.x\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]);
+	pop(12);size+=12;
+      }else if(i>=25&&i<=28){
+	if(unorderedpush)
+	  emit(f,"\tmovem.l\t%d(%s),%s\n",pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
+	else{
+	  if(cf)
+	    emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#8,%s\n",mregnames[sp],mregnames[i],mregnames[sp]);
+	  else
+	    emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[i]);
+	}
+	pop(8);size+=8;
+      }else
+	ierror(0);
+      if(i>=d0) cc_set=0;
+      if(cc_set&&(cc_set->flags&REG)&&cc_set->reg==i)
+	cc_set=0;
+      missing++;
+    }
+  }
+  if(*s=='m'&&!GAS&&!PHXASS) emit(f,"\topt\tom+\n");
+#if 0
+  if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE))
+    emit(f,"\ttst.b\t-%d(%s)\n",size+2,mregnames[sp]);
+#endif
+  if(unorderedpush)
+    emit(f,"\tadd%s.%c\t#%d,%s\n",pushoff[lastpush]<=8?"q":"",cf?'l':'w',pushoff[lastpush],mregnames[sp]);
+  lastpush=0;
+  unorderedpush=0;
+}
+static void emit_obj(FILE *f,obj *p,int t)
+/*  Write object.   */
+{
+  if(p->am){
+    /*  Addressing modes.   */
+    if(NOPEEPHOLE) {ierror(0);p->am=0;return;}
+    if(p->am->skal>=0){
+      long l=0;
+      if(p->flags&D16OFF) l=zm2l(p->val.vmax);
+      emit(f,"(%ld",p->am->dist+l);
+      if(!GAS&&CPU>=68020&&((p->am->dist+l)>32767||(p->am->dist+l)<-32768))
+	emit(f,".l");
+      else if(!GAS&&CPU>=68020&&((p->am->dist+l)>127||(p->am->dist+l)<-128))
+	emit(f,".w");
+      emit(f,",%s",mregnames[p->am->basereg]);
+      if(p->am->dreg){
+	emit(f,",%s",mregnames[p->am->dreg&127]);
+	if(p->am->dreg&128) emit(f,".w"); else emit(f,".l");
+	if(p->am->skal) emit(f,"*%d",p->am->skal);
+      }
+      emit(f,")");
+      return;
+    }
+    if((p->flags&D16OFF)&&p->am->skal<0&&!zmeqto(l2zm(0L),p->val.vmax)) ierror(0);
+    if(p->am->skal==-1){
+      emit(f,"(%s)+",mregnames[p->am->basereg]);
+      return;
+    }
+    if(p->am->skal==-2){    /*  Noch nicht implementiert    */
+      emit(f,"-(%s)",mregnames[p->am->basereg]);
+      return;
+    }
+  }
+  if(p->flags&DREFOBJ){
+    if(p->flags&KONST){
+      emitval(f,&p->val,p->dtyp&NU);
+      return;
+    }
+    emit(f,"(");
+    if((p->flags&D16OFF)&&!zmeqto(l2zm(0L),p->val.vmax)){
+      emitval(f,&p->val,MAXINT);
+      if(!zmleq(p->val.vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),p->val.vmax))
+	emit(f,".l");
+      else if(!zmleq(p->val.vmax,l2zm(127L))||!zmleq(l2zm(-128L),p->val.vmax))
+	emit(f,".w");
+      emit(f,",");
+    }
+  }
+  if(p->flags&VARADR) emit(f,"#");
+  if(p->flags&VAR) {
+    if(p->flags&REG){
+      emit(f,"%s",mregnames[p->reg]);
+    }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      long os;
+      os=zm2l(p->val.vmax);
+      if(!USEFRAMEPOINTER&&!vlas){
+	if(!zmleq(l2zm(0L),p->v->offset)) 
+	  os=os+loff-zm2l(p->v->offset)+(PROFILER?16:0);
+	else
+	  os=os+zm2l(p->v->offset);
+	if(!GAS&&CPU>=68020&&(os-stackoffset)>0x7c00) /* +l%d max.1024? */
+	  emit(f,"((%ld+%s%d).l,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]);
+	else
+	  emit(f,"(%ld+%s%d,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]); 
+      }else{
+	if(!zmleq(l2zm(0L),p->v->offset))
+	  os=os-zm2l(p->v->offset)+4+(PROFILER?16:0);
+	else
+	  os=os-(zm2l(p->v->offset)+zm2l(szof(p->v->vtyp)));
+	emit(f,"(%ld",os);
+	if(!GAS&&CPU>=68020&&os>0x7fff)
+	  emit(f,".l");
+	emit(f,",%s)",mregnames[fbp]);
+      }
+    }else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+	emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+	if(ISFUNC(p->v->vtyp->flags))
+	  emit(f,"%s%s",FUNCPREFIX(p->v->vtyp),p->v->identifier);
+	else
+	  emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+      if(use_sd&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)
+	 &&!(p->v->tattr&(CHIP|FAR))&&(CONSTINDATA||!is_const(p->v->vtyp))
+	 &&zmleq(l2zm(0L),p->val.vmax)&&!zmleq(szof(p->v->vtyp),p->val.vmax))
+	emit(f,"(a4)");
+    }
+  }
+  if((p->flags&REG)&&!(p->flags&VAR)) emit(f,"%s",mregnames[p->reg]);
+  if(p->flags&KONST){
+    /*  This requires IEEE floats/doubles on the host compiler. */
+    if(ISFLOAT(t)){
+      unsigned char *ip=(unsigned char *)&p->val.vfloat;
+      char *s;
+      if(GAS) s="0x"; else s="$";
+      emit(f,"#%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	if(DEBUG&1) printf("doubleconst=%f\n",zld2d(zd2zld(p->val.vdouble)));
+	emit(f,"%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else{
+      emit(f,"#");emitval(f,&p->val,t&NU);
+    }
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+static void dwarf2_print_frame_location(FILE *f,Var *v)
+{
+  /*FIXME: needs a location list and correct register trabslation */
+  obj o;
+  o.flags=REG;
+  if(USEFRAMEPOINTER||vlas)
+    o.reg=fbp;
+  else
+    o.reg=sp;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+  if(r<=8)
+    return r+7;
+  else if(r<=d7)
+    return r-8;
+  else if(r<=fp7)
+    return r+1;
+  else
+    ierror(0);
+}
+static zmax dwarf2_fboffset(Var *v)
+{
+  long os;
+  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+  if(!USEFRAMEPOINTER&&!vlas){
+    if(!zmleq(l2zm(0L),v->offset)) 
+      os=loff-zm2l(v->offset);
+    else
+      os=zm2l(v->offset);
+    return l2zm(os+framesize);
+  }else{
+    if(!zmleq(l2zm(0L),v->offset)) 
+      return l2zm(-zm2l(v->offset)+4);
+    else
+      return l2zm(-(zm2l(v->offset)+zm2l(szof(v->vtyp))));
+  }
+}
+
+static char tsh[]={'w','l'};
+static int proflabel,stacksizelabel;
+static void function_top(FILE *f,Var *v,long offset)
+/*  Writes function header. */
+{
+    geta4=0;
+    if(GAS){
+    }else{
+        if(debug_info&&HUNKDEBUG) emit(f,"\tsymdebug\n");
+        if(CPU!=68000) emit(f,"\tmachine\t%ld\n",CPU);
+        if(cf) strshort[1]="l";
+        if(FPU>68000) emit(f,"\tfpu\t1\n");
+        if(SMALLCODE) emit(f,"\tnear\tcode\n");
+        if(use_sd) emit(f,"\tnear\ta4,-2\n");
+	if(PHXASS){
+	  emit(f,"\topt\t0\n\topt\tNQLPSM");
+	  if(CPU!=68040) emit(f,"R");
+	  if(1/*BRANCHOPT||(optflags&2)*/) emit(f,"BT");
+	  emit(f,"\n");
+	}else{
+	  emit(f,"\topt o+,ol+,op+,oc+,ot+,oj+,ob+,om+");
+	  if(CPU==68040) emit(f,",a-");
+	  emit(f,"\n");
+	}
+    }
+    if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+    if(PROFILER){
+        proflabel=++label;
+        if(GAS){
+            emit(f,"%s%d:\n\t.byte\t\"%s\",0\n",labprefix,proflabel,v->identifier);
+        }else{
+            emit(f,"%s%d\n\tdc.b\t\"%s\",0\n",labprefix,proflabel,v->identifier);
+        }
+    }
+    if(v->storage_class==EXTERN){
+      if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC){
+        if(GAS){
+	  emit(f,"\t.global\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
+        }else{
+	  emit(f,"\tpublic\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
+        }
+      }
+    }
+    if(v->storage_class==EXTERN){
+      if(GAS){
+        emit(f,"\t.align\t4\n%s%s:\n",FUNCPREFIX(v->vtyp),v->identifier);
+      }else{
+        emit(f,"\tcnop\t0,4\n%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
+      }
+    }else{
+      if(GAS){
+        emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
+      }else{
+        emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset));
+      }
+    }      
+    if(stack_check&&!(v->tattr&AMIINTERRUPT)){
+      stacksizelabel=++label;
+      if(GAS){
+	emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjbsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]);
+      }else{
+	emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]);
+      }
+    }      
+    if(PROFILER){
+        if(GAS){
+            emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\t.global\t__startprof\n\tjbsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]);
+        }else{
+            emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\tpublic\t__startprof\n\tjsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]);
+        }
+    }
+    offset=-((offset+4-1)/4)*4;
+    loff=-offset;offlabel=++label;
+    if(!USEFRAMEPOINTER&&!vlas){
+      if(offset<0) emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[offset>=-8],strshort[offset>=-32768],-offset,mregnames[sp]);
+    }else{
+      if(offset>=-32768||CPU>=68020){
+	emit(f,"\tlink.%c\t%s,#%ld\n",tsh[offset<-32768],mregnames[fbp],offset);
+      }else{
+	emit(f,"\tlink.w\t%s,#-32768\n",mregnames[fbp]);offset+=32768;
+	  emit(f,"\tsub.%c\t#%ld,%s\n",tsh[offset<-32768],offset,mregnames[fbp]);
+      }
+    }
+    if(FPU>68000&&float_used){
+        if(GAS){
+            emit(f,"\t.word\t0xf227,%s%d\n",labprefix,freglabel);
+        }else{
+            emit(f,"\tfmovem.x\t%s%d,-(%s)\n",labprefix,freglabel,mregnames[sp]);
+        }
+    }
+    if(cf){
+      emit(f,"\tsub.l\t#%s%d,%s\n",labprefix,offlabel,mregnames[sp]);
+      if(GAS){
+        emit(f,"\tmovem.l\t#%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]);
+      }else{
+        emit(f,"\tmovem.l\t%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]);
+      }
+    }else{
+      if(GAS){
+        emit(f,"\tmovem.l\t#%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]);
+      }else{
+        emit(f,"\tmovem.l\t%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]);
+      }
+    }
+    if((v->tattr&SAVEDS)&&use_sd) emit(f,"\txref\t_LinkerDB\n\tlea\t_LinkerDB,a4\n");
+    stack_valid=1;
+    stack=0;
+}
+static void function_bottom(FILE *f,Var *v,long offset)
+/*  Writes function footer. */
+{
+    int i,size=0;unsigned int pushval,popval;
+    *pushreglist=0;*popreglist=0;
+    pushval=popval=0;
+    if((v->tattr&SAVEDS)&&use_sd) geta4=1;
+    for(i=1;i<=16;i++){
+        if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])||(i==5&&geta4)||(i==d0&&pushflag)){
+            if(*pushreglist) strcat(pushreglist,"/");
+            strcat(pushreglist,mregnames[i]);
+	    if(i!=d0||(v->tattr&INTERRUPT)){
+	      if(*popreglist) strcat(popreglist,"/");
+	      strcat(popreglist,mregnames[i]);
+	    }
+            if(i<d0){
+	      pushval|=(256>>i);popval|=(128<<i);
+	    }else{
+	      pushval|=(0x8000>>(i-9));
+	      if(i!=d0) popval|=(1<<(i-9));
+	    }
+            size+=4;
+        }
+    }
+    if(pushflag){
+      emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]);
+      if(v->tattr&INTERRUPT) ierror(0);
+    }
+    if(cf){
+      if(GAS){
+        if(popval)
+	  emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s),#%u\n\tadd.l\t#%s%d%s,%s\n",labprefix,reglabel,pushval,mregnames[sp],popval,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]);
+        else
+	  emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel);
+      }else{
+        if(*pushreglist)
+	  emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist);
+	else
+	  emit(f,"%s%d\treg\n",labprefix,reglabel);
+	if(*popreglist)
+	  emit(f,"\tmovem.l\t(%s),%s\n\tadd.l\t#%s%d%s,%s\n",mregnames[sp],popreglist,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]);
+      }
+    }else{
+      if(GAS){
+        if(popval)
+	  emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s)+,#%u\n",labprefix,reglabel,pushval,mregnames[sp],popval);
+        else
+	  emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel);
+      }else{
+        if(*pushreglist)
+	  emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist);
+        else
+	  emit(f,"%s%d\treg\n",labprefix,reglabel);
+	if(*popreglist)
+	  emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],popreglist);
+      }
+    }
+    *pushreglist=0;*popreglist=0;pushval=0xe000;popval=0xd000;
+    for(i=fp0;i<=fp7;i++){
+      if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])){
+	if(*popreglist) strcat(popreglist,"/");
+	strcat(popreglist,mregnames[i]);
+	pushval|=(1<<(i-17));popval|=(0x80>>(i-17));
+	size+=12;
+      }
+    }
+    if(FPU>68000&&(float_used||(v->tattr&INTERRUPT))){
+      if(GAS){
+	if(popval!=0xd000)
+	  emit(f,"\t.equ\t%s%d,0x%x\n\t.word\t0xf21f,0x%x\n",labprefix,freglabel,(int)pushval,(int)popval);
+	else
+	  emit(f,"\t.equ\t%s%d,0xe000\n",labprefix,freglabel);
+      }else{
+	if(*popreglist)
+	  emit(f,"%s%d\tfreg\t%s\n\tfmovem.x\t(%s)+,%s%d\n",labprefix,freglabel,popreglist,mregnames[sp],labprefix,freglabel);
+	else
+	  emit(f,"%s%d\tfreg\n",labprefix,freglabel);
+        }
+    }
+    if(cf||(!USEFRAMEPOINTER&&!vlas)){
+      if(GAS){
+	emit(f,"\t.equ\t%s%d,%d\n",labprefix,offlabel,size);
+      }else{
+	emit(f,"%s%d\tequ\t%d\n",labprefix,offlabel,size);
+      }
+    }
+    if(!USEFRAMEPOINTER&&!vlas){
+      if(loff) emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[loff<=8],strshort[loff<32768],loff,mregnames[sp]);
+      framesize=size;
+    }else
+      emit(f,"\tunlk\t%s\n",mregnames[fbp]);
+    if(PROFILER){
+        if(GAS){
+            emit(f,"\tmove.l\t%s,-(%s)\n\t.global\t__endprof\n\tjbsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]);
+        }else{
+            emit(f,"\tmove.l\t%s,-(%s)\n\tpublic\t__endprof\n\tjsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]);
+        }
+    }
+    if(v->tattr&INTERRUPT)
+      emit(f,"\trte\n");
+    else
+      emit(f,"\trts\n");
+    if(stack_check&&!(v->tattr&AMIINTERRUPT)){
+      if(GAS)
+	emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stacksizelabel,size+loff-maxpushed);
+      else
+	emit(f,"%s%d\tequ\t%ld\n",labprefix,stacksizelabel,size+loff-maxpushed);
+    }
+    if(stack_valid){
+      if(!v->fi) v->fi=new_fi();
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=l2zm(size+loff+stack);
+      emit(f,"%c stacksize=%ld\n",GAS?'#':';',size+loff+stack);
+    }
+}
+static void move(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
+/*  erzeugt eine move Anweisung...Da sollen mal Optimierungen rein  */
+{
+    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+    if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg;
+    if(zreg==qreg&&zreg) return;
+    if(q&&(q->flags&VARADR)&&zreg>=1&&zreg<=8){
+        emit(f,"\tlea\t");
+        q->flags&=~VARADR;emit_obj(f,q,t);q->flags|=VARADR;
+        emit(f,",%s\n",mregnames[zreg]);
+	BSET(regs_modified,zreg);
+        return;
+    }
+    if(zreg>=d0&&zreg<fp0&&q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst(&q->val,t)){
+        emit(f,"\tmoveq\t");
+    }else{
+        if((zreg>=fp0&&zreg<=fp7)||(qreg>=fp0&&qreg<=fp7)){
+            if(qreg>=fp0&&qreg<=fp7&&zreg>=fp0&&zreg<=fp7) emit(f,"\tfmove.x\t");
+             else emit(f,"\tfmove.%c\t",x_t[t&NQ]);
+        }else{
+	  if(!cf||qreg||zreg)
+            emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]);
+        }
+    }
+    if(cf&&!qreg&&!zreg){
+        static IC dummy;
+        dummy.code=ASSIGN;
+        dummy.typf=t;
+        dummy.q1=*q;
+        dummy.q2.flags=0;
+        dummy.z=*z;
+        qreg=get_reg(f,1,&dummy,0);
+	emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]);
+        emit_obj(f,q,t);
+        emit(f,",%s\n\tmove.%c\t%s,",mregnames[qreg],x_s[msizetab[t&NQ]],mregnames[qreg]);
+        emit_obj(f,z,t);
+        emit(f,"\n");
+    }else{
+      if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
+      emit(f,",");
+      if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
+      emit(f,"\n");
+      if(zreg) BSET(regs_modified,zreg);
+    }
+}
+static void loadext(FILE *f,int r,obj *q,int t)
+/*  laedt Objekt q vom Typ t in Register r und erweitert auf long   */
+{
+    if(t&UNSIGNED){
+      if((q->flags&(REG|DREFOBJ))==REG&&q->reg==r)
+        emit(f,"\tand.l\t#%u,%s\n",((t&NQ)==CHAR?0xffu:0xffffu),mregnames[r]);
+      else
+        emit(f,"\tmoveq\t#0,%s\n",mregnames[r]);
+    }
+    move(f,q,0,0,r,t);
+#ifdef M68K_16BIT_INT
+    if((t&NU)==SHORT||(t&NU)==INT) emit(f,"\text.l\t%s\n",mregnames[r]);
+#else
+    if((t&NU)==SHORT) emit(f,"\text.l\t%s\n",mregnames[r]);
+#endif
+    if((t&NU)==CHAR){
+      if(cf||CPU>=68020)
+        emit(f,"\textb.l\t%s\n",mregnames[r]);
+      else
+        emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[r],mregnames[r]);
+    }
+}
+
+static void add(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
+/*  erzeugt eine add Anweisung...Da sollen mal Optimierungen rein   */
+{
+    if(!qreg&&!q) ierror(0);
+    if(!zreg&&!z) ierror(0);
+    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+    if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0);
+    if(!qreg&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){
+      emit(f,"\taddq.%c\t",cf?'l':x_t[t&NQ]);
+    }else{
+        /*  hier noch Abfrage, ob #c.w,ax   */
+      emit(f,"\tadd.%c\t",cf?'l':x_t[t&NQ]);
+    }
+    if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
+    emit(f,",");
+    if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
+    emit(f,"\n");
+}
+static void sub(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
+/*  erzeugt eine sub Anweisung...Da sollen mal Optimierungen rein   */
+{
+    if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0);
+    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+    if(q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){
+      emit(f,"\tsubq.%c\t",cf?'l':x_t[t&NQ]);
+    }else{
+        /*  hier noch Abfrage, ob #c.w,ax   */
+      emit(f,"\tsub.%c\t",cf?'l':x_t[t&NQ]);
+    }
+    if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
+    emit(f,",");
+    if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
+    emit(f,"\n");
+}
+static void mult(FILE *f,obj *q,int qreg,obj *z,int zreg, int t,int c,IC *p)
+/*  erzeugt eine mult Anweisung...Da sollen mal Optimierungen rein  */
+/*  erzeugt auch div/mod etc.                                       */
+{
+  int modreg;
+  if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg;
+  if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+  if(cf&&!qreg) {qreg=get_reg(f,1,p,0);move(f,q,0,0,qreg,t);}
+  if((c==MULT||c==DIV||c==MOD)&&CPU<68020&&!cf&&msizetab[t&NQ]==4){
+    if(c==MULT){
+      /*  ist das mit get_reg(.,.,0) ok? nochmal ueberdenken...   */
+      /*  ...die ganze Routine am besten...                       */
+      /*  ...es war nicht, deshalb ist es jetzt geaendert         */
+      int dx,dy,t1,t2;
+      if(zreg>=d0&&zreg<=d7){
+	dx=zreg;
+      }else{
+	dx=get_reg(f,1,p,0);
+	move(f,z,0,0,dx,t);
+      }
+      if(qreg>=d0&&qreg<=d7&&qreg!=dx){
+	dy=qreg;
+      }else{
+	dy=get_reg(f,1,p,0);
+	move(f,q,0,0,dy,t);
+      }
+      t1=get_reg(f,1,p,0);t2=get_reg(f,1,p,0);
+      if(t1==dx||t2==dx||t1==dy||t2==dy) ierror(0);
+      emit(f,"\tmove.l\t%s,%s\n",mregnames[dx],mregnames[t1]);
+      emit(f,"\tmove.l\t%s,%s\n",mregnames[dy],mregnames[t2]);
+      emit(f,"\tswap\t%s\n",mregnames[t1]);
+      emit(f,"\tswap\t%s\n",mregnames[t2]);
+      emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[t1]);
+      emit(f,"\tmulu.w\t%s,%s\n",mregnames[dx],mregnames[t2]);
+      emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[dx]);
+      emit(f,"\tadd.w\t%s,%s\n",mregnames[t2],mregnames[t1]);
+      emit(f,"\tswap\t%s\n",mregnames[t1]);
+      emit(f,"\tclr.w\t%s\n",mregnames[t1]);
+      emit(f,"\tadd.l\t%s,%s\n",mregnames[t1],mregnames[dx]);
+      if(zreg!=dx) move(f,0,t1,z,0,t);
+    }else ierror(0);
+    return;
+  }
+  if(c==MULT){
+    /*  das duerfte nur der Aesthetik dienen... */
+    if(t&UNSIGNED) 
+      emit(f,"\tmulu.%c\t",x_t[t&NQ]);
+    else 
+      emit(f,"\tmuls.%c\t",x_t[t&NQ]);
+    if((t&NQ)<=SHORT) cc_set=0;
+  }
+  if(c==DIV||(c==MOD&&ISHWORD(t))){
+    if(t&UNSIGNED){
+      if(ISHWORD(t)) emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
+      emit(f,"\tdivu.%c\t",x_t[t&NQ]);
+    }else{
+      if(ISHWORD(t)) emit(f,"\text.l\t%s\n",mregnames[zreg]);
+      emit(f,"\tdivs.%c\t",x_t[t&NQ]);
+    }
+  }  
+  if(qreg) 
+    emit(f,"%s",mregnames[qreg]); 
+  else 
+    emit_obj(f,q,t);
+  emit(f,",");
+  /*  eigentlich muss zreg!=0 sein...     */
+  if(zreg) 
+    emit(f,"%s",mregnames[zreg]); 
+  else 
+    emit_obj(f,z,t);
+  emit(f,"\n");
+  if(c==MOD){
+    emit(f,"\tswap\t%s\n",mregnames[zreg]);
+    cc_set=0;
+  }
+}
+static IC *am_freedreg[9],*am_shiftdreg[9];
+static IC *am_dist_ic[9],*am_dreg_ic[9],*am_use[9];
+/*  am_dist_ic und am_dreg_ic werden auch fuer (ax)+ benutzt    */
+static long am_dist[9],am_dreg[9],am_base[9],am_inc[9],am_skal[9],am_dbase[9];
+#define AMS sizeof(AddressingMode)
+
+static int mopsize(IC *p,int reg)
+/*  Liefert die Groesse in Bytes, mit der im IC auf (reg) zugegriffen wird. */
+{
+    int c=p->code;
+    if(c==ADDI2P||c==SUBIFP){
+        if((p->q2.flags&REG)&&p->q2.reg==reg)
+            return zm2l(sizetab[p->typf&NQ]);
+        return 4;
+    }
+    if(c==CONVERT){
+        if((p->z.flags&REG)&&p->z.reg==reg)
+          return zm2l(sizetab[p->typf&NQ]);
+        else
+          return zm2l(sizetab[p->typf2&NQ]);
+    }
+    return zm2l(sizetab[p->typf&NQ]);
+}
+static void clear_am(int reg)
+/*  loescht Werte fuer erweiterte Adressierungsarten fuer Register reg  */
+{
+    if(reg<0||reg>d7) ierror(0);
+    if(DEBUG&32) printf("clear_am(%s)\n",mregnames[reg]);
+    if(reg<=8){
+        am_dist_ic[reg]=am_dreg_ic[reg]=am_use[reg]=0;
+        am_dist[reg]=am_dreg[reg]=am_base[reg]=am_inc[reg]=0;
+    }else{
+        reg-=8;
+        am_freedreg[reg]=am_shiftdreg[reg]=0;
+        am_skal[reg]=am_dbase[reg]=0;
+    }
+}
+static void mod_reg(int r)
+{
+  int i;
+  for(i=1;i<=8;i++){
+    if((!am_use[i]&&am_base[i]==r)||(am_dreg[i]&127)==r)
+      clear_am(i);
+  }
+#if 0
+  if(r>=9&&r<=16){
+    for(i=9;i<=16;i++){
+      if(am_dbase[i-8]==r)
+	clear_am(i);
+    }
+  }
+#endif
+}
+/* return non-zero if IC is implemented by a function call */
+static int islibcall(IC *p)
+{
+  int c=p->code,t=p->typf/NQ;
+  if((c==DIV||c==MOD)&&CPU<68020)
+    return 1;
+  if(t==LLONG&&c!=ADD&&c!=SUB&&c!=OR&&c!=AND&&c!=XOR&&c!=COMPARE)
+    return 1;
+  if(ISFLOAT(t)&&FPU<=68000)
+    return 1;
+  if(c==CONVERT){
+    if(t==LLONG||ISFLOAT(t)) 
+      return 1;
+    t=p->typf2&NQ;
+    if(t==LLONG||ISFLOAT(t))
+      return 1;
+  }
+  return 0;
+}
+
+static int new_peephole(IC *first)
+{
+  int localused=0,c,r,t,c2;long sz;
+  IC *p,*p2;
+  AddressingMode *am;
+  for(p=first;p;p=p->next){
+    int c=p->code;
+    if(!localused){
+      if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset))
+	localused=1;
+      if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset))
+	localused=1;
+      if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset))
+	localused=1;
+      if(DEBUG&32&&localused==1) printf("localused=1\n");
+    }
+    /* -(ax) */
+    if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=8&&isconst(q2)){
+      r=p->q1.reg;
+      eval_const(&p->q2.val,q2typ(p));
+      sz=zm2l(vmax);
+      if(sz==1||sz==2||sz==4||sz==8){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)&&(c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
+	    t=(q1typ(p2)&NQ);
+	    if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+	      p2->q1.am=am=mymalloc(sizeof(*am));
+	      p2->q1.val.vmax=l2zm(0L);
+	      am->basereg=r;
+	      am->dist=0;
+	      am->skal=-2;
+	      am->dreg=0;
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)){
+	    t=(q2typ(p2)&NQ);
+	    if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+	      p2->q2.am=am=mymalloc(sizeof(*am));
+	      p2->q2.val.vmax=l2zm(0L);
+	      am->basereg=r;
+	      am->dist=0;
+	      am->skal=-2;
+	      am->dreg=0;
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)){
+	    t=(ztyp(p2)&NQ);
+	    if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+	      p2->z.am=am=mymalloc(sizeof(*am));
+	      p2->z.val.vmax=l2zm(0L);
+	      am->basereg=r;
+	      am->dist=0;
+	      am->skal=-2;
+	      am->dreg=0;
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	}
+      }
+    }
+    /* (ax)+ in q1 */
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg<=8&&(c!=CONVERT||(q1typ(p)&NQ)<=(ztyp(p)&NQ))){
+      t=(q1typ(p)&NQ);
+      sz=zm2l(sizetab[t]);
+      r=p->q1.reg;
+      if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
+	    eval_const(&p2->q2.val,q2typ(p2));
+	    if(zmeqto(vmax,l2zm(sz))){
+	      p->q1.am=am=mymalloc(sizeof(*am));
+	      p->q1.val.vmax=l2zm(0L);
+	      am->basereg=r;
+	      am->dist=0;
+	      am->skal=-1;
+	      am->dreg=0;
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	  if(p2->q1.am&&p2->q1.am->basereg==r) break;
+	  if(p2->q2.am&&p2->q2.am->basereg==r) break;
+	  if(p2->z.am&&p2->z.am->basereg==r) break;
+	}
+      }
+    }
+    /* (ax)+ in q2 */
+    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg<=8){
+      t=(q2typ(p)&NQ);
+      sz=zm2l(sizetab[t]);
+      r=p->q2.reg;
+      if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
+	    eval_const(&p2->q2.val,q2typ(p2));
+	    if(zmeqto(vmax,l2zm(sz))){
+	      p->q2.am=am=mymalloc(sizeof(*am));
+	      p->q2.val.vmax=l2zm(0L);
+	      am->basereg=r;
+	      am->dist=0;
+	      am->skal=-1;
+	      am->dreg=0;
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	  if(p2->q1.am&&p2->q1.am->basereg==r) break;
+	  if(p2->q2.am&&p2->q2.am->basereg==r) break;
+	  if(p2->z.am&&p2->z.am->basereg==r) break;
+	}
+      }
+    }
+    /* (ax)+ in z */
+    if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg<=8){
+      t=(ztyp(p)&NQ);
+      sz=zm2l(sizetab[t]);
+      r=p->z.reg;
+      if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
+	    eval_const(&p2->q2.val,q2typ(p2));
+	    if(zmeqto(vmax,l2zm(sz))){
+	      p->z.am=am=mymalloc(sizeof(*am));
+	      p->z.val.vmax=l2zm(0L);
+	      am->basereg=r;
+	      am->dist=0;
+	      am->skal=-1;
+	      am->dreg=0;
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	  if(p2->q1.am&&p2->q1.am->basereg==r) break;
+	  if(p2->q2.am&&p2->q2.am->basereg==r) break;
+	  if(p2->z.am&&p2->z.am->basereg==r) break;
+	}
+      }
+    }
+    /* d(ax) (+d(ax,dy)) */
+    if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&p->z.reg<=8&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base,idx=-1;zmax of;obj *o;
+      IC *idx_ic=0,*free_idx=0,*free_base=0,*use=0;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(CPU>=68020||(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L)))){
+	r=p->z.reg;
+	if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(!idx_ic&&c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg>=d0&&p2->q2.reg<fp0){
+	    if(CPU>=68020||(zmleq(of,l2zm(127L))&&zmleq(l2zm(-128L),of))){
+	      idx=p2->q2.reg;
+	      idx_ic=p2;
+	      continue;
+	    }
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(!use&&idx_ic&&c2==FREEREG&&p2->q1.reg==idx){
+	    free_idx=p2;
+	    continue;
+	  }
+	  if(!use&&c2==FREEREG&&p2->q1.reg==base){
+	    free_base=p2;
+	    continue;
+	  }
+	  if(idx_ic){
+	    if((p2->q1.flags&REG)&&p2->q1.reg==idx) break;
+	    if((p2->q2.flags&REG)&&p2->q2.reg==idx) break;
+	    if((p2->z.flags&REG)&&p2->z.reg==idx) break;
+	    if(p2->q1.am&&(p2->q1.am->dreg&127)==idx) break;
+	    if(p2->q2.am&&(p2->q2.am->dreg&127)==idx) break;
+	    if(p2->z.am&&(p2->z.am->dreg&127)==idx) break;
+	    if(c2==ALLOCREG&&p2->q1.reg==idx) break;
+	  }
+
+	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){
+	    if(o) break;
+	    o=&p2->q1;
+	    use=p2;
+	    continue;
+	  }
+
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	      use=p2;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	      use=p2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+
+	      if(o) break;
+	      if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break;
+	      o=&p2->z;
+	      use=p2;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		o->val.vmax=l2zm(0L);
+		am->basereg=base;
+		am->dist=zm2l(of);
+		am->skal=0;
+		if(free_base) move_IC(use,free_base);
+		if(idx_ic){
+		  am->dreg=idx;
+		  if(ISHWORD(idx_ic->typf)) am->dreg|=128;
+		  if(free_idx) move_IC(use,free_idx);
+		  idx_ic->code=NOP;
+		  idx_ic->q1.flags=idx_ic->q2.flags=idx_ic->z.flags=0;
+		}else
+		  am->dreg=0;
+		if(isreg(q1)&&p->q1.reg<=8){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+		if(!(o->flags&DREFOBJ)){
+		  o->flags|=DREFOBJ;
+		  if(use->code==PUSH)
+		    use->code=PEA;
+		  else if(use->code==ASSIGN)
+		    use->code=LEA;
+		  else
+		    ierror(0);
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* (ax,dy) (+d(ax,dy)) */
+    if(c==ADDI2P&&isreg(q2)&&p->q2.reg>=d0&&isreg(z)&&p->z.reg<=8&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;obj *o;
+      long dist=0;
+      IC *free_idx=0,*free_base=0,*use=0,*off=0;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+	if(!off&&(c2==ADDI2P||c2==SUBIFP)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	  eval_const(&p2->q2.val,p2->typf);
+	  if(c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	  if(CPU>=68020||(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax))){
+	    dist=zm2l(vmax);
+	    off=p2;
+	    continue;
+	  }
+	}
+	
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+
+
+
+	if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){
+	  if(o) break;
+
+	  o=&p2->q1;
+	  use=p2;
+	  continue;
+	}
+
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	if(c2==ALLOCREG&&(p->q1.reg==idx||p->q1.reg==base)) break;
+	if(!use&&c2==FREEREG&&p2->q1.reg==base) free_base=p2;
+	if(!use&&c2==FREEREG&&p2->q1.reg==idx) free_idx=p2;
+
+
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;use=p2;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;use=p2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+	    if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break;
+
+            o=&p2->z;use=p2;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+	    /* do not use addressing mode for libcalls */
+	    if(FPU<=68000&&o&&o==&use->z&&(ISFLOAT(use->typf)||ISFLOAT(use->typf2))&&use->code!=ASSIGN)
+	      break;
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+	      o->val.vmax=l2zm(0L);
+              am->basereg=base;
+              am->dreg=idx;
+	      am->dist=dist;
+	      am->skal=0;
+	      if(ISHWORD(q2typ(p))) am->dreg|=128;
+	      if(isreg(q1)&&p->q1.reg<=8){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+	      if(off){
+		off->code=NOP;
+		off->q1.flags=off->q2.flags=off->z.flags=0;
+	      }
+	      if(!use) ierror(0);
+	      if(free_idx) move_IC(use,free_idx);
+	      if(free_base) move_IC(use,free_base);
+	      if(free_idx&&use->next!=free_idx&&use->next->next!=free_idx) ierror(0);
+	      if(free_base&&use->next!=free_base&&use->next->next!=free_base) ierror(0);
+	      if(!(o->flags&DREFOBJ)){
+		o->flags|=DREFOBJ;
+		if(use->code==PUSH)
+		  use->code=PEA;
+		else if(use->code==ASSIGN)
+		  use->code=LEA;
+		else
+		  ierror(0);
+	      }		   
+	    }
+
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+    
+
+  }
+
+  /* do an additional pass to search for scaled addressing-modes */
+  if(CPU>=68020){
+    for(p=first;p;p=p->next){
+      c=p->code;t=p->typf;
+      if((c==MULT||c==LSHIFT)&&isconst(q2)&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(t)&&(t&NQ)<=LONG){
+	unsigned long ul;
+	r=p->z.reg;
+	eval_const(&p->q2.val,q2typ(p));
+	ul=zum2ul(vumax);
+	if(c==LSHIFT){
+	  if(ul<=3)
+	    ul=1<<ul;
+	  else
+	    ul=0;
+	}
+	if(ul==2||ul==4||ul==8){
+	  AddressingMode *amuse=0;
+	  IC *free_src=0,*free_rsrc=0,*use=0;
+	  int src_mod=0;
+	  for(p2=p->next;p2;p2=p2->next){
+	    c2=p2->code;
+	    if(!use&&p2->q1.am&&p2->q1.am->skal==0&&(p2->q1.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q2.flags&REG)||p2->q2.flags!=r)&&(!(p2->z.flags&REG)||p2->z.flags!=r)){
+	      amuse=p2->q1.am;
+	      use=p2;
+	      continue;
+	    }
+	    if(!use&&p2->q2.am&&p2->q2.am->skal==0&&(p2->q2.am->dreg&127)==r&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q1.flags&REG)||p2->q1.flags!=r)&&(!(p2->z.flags&REG)||p2->z.flags!=r)){
+	      amuse=p2->q2.am;
+	      use=p2;
+	      continue;
+	    }
+	    if(!use&&p2->z.am&&p2->z.am->skal==0&&(p2->z.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!(p2->q2.flags&REG)||p2->q2.flags!=r)&&(!(p2->z.flags&REG)||p2->z.flags!=r)){
+	      amuse=p2->z.am;
+	      use=p2;
+	      continue;
+	    }
+	    if(!use&&c2==FREEREG&&p2->q1.reg==r){
+	      free_src=p2;
+	      continue;
+	    }
+	    if(!use&&c2==FREEREG&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7&&p2->q1.reg==p->q1.reg){
+	      free_rsrc=p2;
+	      continue;
+	    }
+	    if(use&&((c2==FREEREG&&p2->q1.reg==r)||((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r))){
+	      amuse->skal=ul;
+	      if(!src_mod&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7){
+		amuse->dreg=p->q1.reg;
+		p->code=NOP;
+		p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=ASSIGN;
+		p->q2.flags=0;
+		p->q2.val.vmax=sizetab[p->typf&NQ];
+	      }
+	      if(free_src) move_IC(use,free_src);
+	      if(free_rsrc) move_IC(use,free_rsrc);
+	      break;
+	    }
+	    if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	    if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	    if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	    if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	    if(p2->q1.am&&(p2->q1.am->dreg&127)==r) break;
+	    if(p2->q2.am&&(p2->q2.am->dreg&127)==r) break;
+	    if(p2->z.am&&(p2->z.am->dreg&127)==r) break;
+	    if((p2->z.flags&(REG|DREFOBJ))==REG&&(p->q1.flags&(REG|DREFOBJ))&&p2->z.reg==p->q1.reg)
+	      src_mod=1;
+	  }
+	}
+      }
+    }	    
+  }
+
+  /* another pass to remove unnecessary ALLOCREGs */
+  for(p=first;p;p=p->next){
+    if(p->code==ALLOCREG){
+      r=p->q1.reg;
+      for(p2=p->next;p2;p2=p2->next){
+	c2=p2->code;
+	if(c2==ALLOCREG&&p2->q1.reg==r) ierror(0);
+	if(c2==FREEREG&&p2->q1.reg==r){
+	  p->code=NOP;
+	  p->q1.flags=0;
+	  p2->code=NOP;
+	  p2->q1.flags=0;
+	  savedalloc++;
+	  break;
+	}
+	if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	if((am=p2->q1.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
+	if((am=p2->q2.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
+	if((am=p2->z.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
+      }
+    }
+  }
+
+  return localused;
+}
+static int addressing(IC *p)
+/*  Untersucht ICs auf erweiterte Addresierungsarten    */
+{
+    int count,localused=0;
+    if(!OLDPEEPHOLE) return new_peephole(p);
+    if(DEBUG&32) printf("addressing() started\n");
+    for(count=1;count<=16;count++) clear_am(count);
+    for(count=0;p;p=p->next){
+        int c=p->code,q1reg,q2reg,zreg;
+        if(p->q1.flags&REG) q1reg=p->q1.reg; else q1reg=0;
+        if(p->q2.flags&REG) q2reg=p->q2.reg; else q2reg=0;
+        if(p->z.flags&REG) zreg=p->z.reg; else zreg=0;
+        if(c==ADDI2P) c=ADD;
+        if(c==SUBIFP) c=SUB;
+        if(DEBUG&32) pric2(stdout,p);
+        if(!localused){
+            if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset))
+                localused=1;
+            if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset))
+                localused=1;
+            if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset))
+                localused=1;
+            if(DEBUG&32&&localused==1) printf("localused=1\n");
+        }
+        if(c==ASSIGN&&isreg(q1)&&isreg(z)&&q1reg>=1&&q1reg<=8&&zreg>=1&&zreg<=8){
+        /*  fuer (ax)+  */
+            int i;
+            clear_am(q1reg);
+            for(i=1;i<=8;i++)
+                if(am_base[i]==zreg||am_base[i]==q1reg) clear_am(i);
+	    mod_reg(zreg);
+            clear_am(zreg);am_base[zreg]=q1reg;am_dreg_ic[zreg]=p;
+            if(DEBUG&32) printf("move %s,%s found\n",mregnames[q1reg],mregnames[zreg]);
+            continue;
+        }
+        if(c==MULT&&CPU>=68020&&isconst(q2)&&isreg(z)&&zreg>=d0&&zreg<=d7){
+        /*  dx=a*const, fuer Skalierung    */
+            int dreg=zreg-8;
+            if(dreg<1||dreg>8) ierror(0);
+            if(q1reg>=1&&q1reg<=d7){
+                if(isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg);
+                if((p->q1.flags&DREFOBJ)&&q1reg<=8&&am_use[q1reg]) clear_am(q1reg);
+            }
+            if(DEBUG&32) printf("mult x,const->dreg found\n");
+	    mod_reg(zreg);
+            if(am_skal[dreg]) {clear_am(zreg);continue;}
+            eval_const(&p->q2.val,p->typf);
+            am_skal[dreg]=zm2l(vmax);
+            if(am_skal[dreg]!=2&&am_skal[dreg]!=4&&am_skal[dreg]!=8)
+                {clear_am(zreg);continue;}
+            am_shiftdreg[dreg]=p;
+            if(isreg(q1)&&q1reg>=d0&&q1reg<=d7) am_dbase[dreg]=q1reg; else am_dbase[dreg]=zreg;
+	    if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)) clear_am(p->q1.reg);
+            if(DEBUG&32) printf("is usable\n");
+            continue;
+        }
+        if((c==ADD||c==SUB)&&isconst(q2)&&zreg>=1&&zreg<=8&&isreg(z)){
+        /*  add ax,#const,ax->az Test auf d8/16 fehlt noch (nicht mehr) */
+            long l;
+            if(zreg<1||zreg>8) ierror(0);
+            eval_const(&p->q2.val,p->typf);
+            l=zm2l(vmax);
+            if(c==SUB) l=-l;
+	    mod_reg(zreg);
+            if(q1reg==zreg&&isreg(q1)&&am_use[zreg]&&(l==1||l==2||l==4)){
+                if(l==mopsize(am_use[zreg],zreg)&&(am_use[zreg]->code!=CONVERT||zmleq(sizetab[am_use[zreg]->typf2&NQ],sizetab[am_use[zreg]->typf&NQ]))){
+                    IC *op=am_use[zreg];
+                    obj *o=0;
+                    if(DEBUG&32){ printf("found postincrement:\n");pric2(stdout,op);pric2(stdout,p);}
+                    if((op->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q1.reg==zreg){
+                        if(DEBUG&32) printf("q1\n");
+                        o=&op->q1;
+                    }
+                    if((op->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q2.reg==zreg){
+                        if(DEBUG&32) printf("q2\n");
+                        if(o) continue; else o=&op->q2;
+                    }
+                    if((op->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->z.reg==zreg){
+                        if(DEBUG&32) printf("z\n");
+                        if(o) continue; else o=&op->z;
+                    }
+                    o->am=mymalloc(AMS);
+                    o->am->basereg=zreg;
+                    o->am->skal=-1;
+                    o->am->dist=0;
+                    o->am->dreg=0;
+                    p=p->prev;
+                    remove_IC(p->next);
+                    clear_am(zreg);continue;
+                }
+            }
+            clear_am(q1reg);
+            if(am_dist[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Offset */
+            if(isreg(q1)&&q1reg==zreg&&(l==1||l==2||l==4)){
+            /*  ax+=const, fuer (ax)+   */
+                int i,f;
+                for(f=0,i=1;i<=8;i++){
+                    if(am_base[i]==zreg&&!am_dreg[i]&&!am_dist[i]){
+                        if(f) ierror(0);
+                        am_inc[i]=l;am_dist_ic[i]=p;f=i;
+                        if(DEBUG&32) printf("inc %s found\n",mregnames[i]);
+                    }
+                }
+                if(f) continue;
+            }
+            am_dist[zreg]=l;
+            if(DEBUG&32) printf("dist=%ld\n",am_dist[zreg]);
+            if(CPU<68020){
+            /*  bei <68020 darf der Offset nur 16bit oder 8bit bei dreg sein */
+                if((am_dreg[zreg]&&(am_dist[zreg]<-128||am_dist[zreg]>127))||am_dist[zreg]<-32768||am_dist[zreg]>32767)
+                    {clear_am(zreg);continue;}
+            }
+            am_dist_ic[zreg]=p;
+            if(am_base[zreg]){
+                if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;}
+            }else{
+                if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg;
+                if(DEBUG&32) printf("%s potential base for %s\n",mregnames[am_base[zreg]],mregnames[zreg]);
+            }
+            if(DEBUG&32) printf("add #const,%s found\n",mregnames[zreg]);
+            continue;
+        }
+        if(c==ADD&&q2reg>=d0&&q2reg<=d7&&isreg(q2)&&zreg>=1&&zreg<=8&&isreg(z)&&(p->q1.flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){
+        /*  add ax,dy->az   */
+            int i;
+            if(zreg<1||zreg>8) ierror(0);
+            for(i=1;i<=8;i++)
+                if(am_dreg[i]==q2reg){ clear_am(q2reg);clear_am(i);}
+            clear_am(q1reg);
+	    mod_reg(zreg);
+            if(am_dreg[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Regoffset */
+            if(CPU<68020&&(am_dist[zreg]<-128||am_dist[zreg]>127))
+                {clear_am(zreg);continue;} /* bei <68020 nur 8bit Offset */
+            am_dreg[zreg]=q2reg;
+            if(ISHWORD(p->typf)) am_dreg[zreg]|=128; /* dx.w statt dx.l */
+            am_dreg_ic[zreg]=p;
+            if(am_base[zreg]){
+                if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;}
+            }else{
+                if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg;
+            }
+            if(DEBUG&32) printf("add %s,%s found\n",mregnames[q2reg],mregnames[zreg]);
+            continue;
+        }
+        if(c==FREEREG){
+        /*  wir koennen den Modus tatsaechlich benutzen */
+            AddressingMode *am;IC *p1,*p2;int dreg,i;
+            if(DEBUG&32) printf("freereg %s found\n",mregnames[p->q1.reg]);
+            if(q1reg>=d0&&q1reg<=d7) {am_freedreg[q1reg-8]=p;if(DEBUG&32) printf("freedreg[%d]=%lx\n",q1reg-8,(long)p);}
+            if(q1reg>8) continue;
+            if(DEBUG&32) printf("use=%p,base=%p,dist=%p,dreg=%p\n",(void*)am_use[q1reg],(void*)am_base[q1reg],(void*)am_dist[q1reg],(void*)am_dreg[q1reg]);
+            for(i=1;i<=8;i++) if(am_base[i]==q1reg) clear_am(i);
+            if(!am_use[q1reg]||!am_base[q1reg]) continue;
+            if(am_inc[q1reg]&&am_inc[q1reg]!=mopsize(am_use[q1reg],q1reg))
+                {clear_am(q1reg);continue;}
+            if(!am_dist[q1reg]&&!am_dreg[q1reg]&&!am_inc[q1reg]) continue;
+            p1=am_dist_ic[q1reg];p2=am_dreg_ic[q1reg];
+            if(DEBUG&32){
+                printf("could really use %s\n",mregnames[q1reg]);
+                if(p1) pric2(stdout,p1);
+                if(p2) pric2(stdout,p2);
+            }
+            if(am_base[q1reg]==q1reg){
+                if(p1) {p1->q2.flags=0;p1->code=ASSIGN;p1->q2.val.vmax=l2zm(4L);p1->typf=POINTER;}
+                if(p2) {p2->q2.flags=0;p2->code=ASSIGN;p2->q2.val.vmax=l2zm(4L);p2->typf=POINTER;}
+            }else{
+                if(p1) remove_IC(p1);
+                if(p2) remove_IC(p2);
+            }
+            dreg=(am_dreg[q1reg]&127)-8;
+            am=mymalloc(AMS);
+            am->skal=0;
+            am->basereg=am_base[q1reg];
+            am->dist=am_dist[q1reg];
+            am->dreg=am_dreg[q1reg];
+            if(am_inc[q1reg]) am->skal=-1;
+            if(dreg>0){
+                /*  bei (d,ax,dy) das freereg dy nach hinten verschieben    */
+                if(dreg<1||dreg>8) ierror(0);
+                if(p1=am_freedreg[dreg]){
+                    if(DEBUG&32){
+                        printf("freereg %s moved from %p to %p\n",mregnames[dreg+8],(void*)p1,(void*)p);
+                        pric2(stdout,p1);
+                    }
+                    if(p1->code!=FREEREG){ierror(0);printf("freereg[%d]=%p\n",dreg,(void*)p1);continue;}
+                    if(!p1->next) {ierror(0);continue;}
+                    if(!p1->prev) {ierror(0);continue;}
+                    p1->prev->next=p1->next;
+                    p1->next->prev=p1->prev;
+                    p1->next=p->next;
+                    p1->prev=p;
+                    if(p->next) p->next->prev=p1;
+                    p->next=p1;
+                }
+                if(am_skal[dreg]){
+                /*  Skalierung bearbeiten   */
+                    if(p1){
+                        am->skal=am_skal[dreg];
+                        am->dreg=am_dbase[dreg];
+                        p1=am_shiftdreg[dreg];
+                        if(DEBUG&32) pric2(stdout,p1);
+                        if(am_dbase[dreg]==dreg+8){
+                            p1->code=ASSIGN;p1->q2.flags=0;p1->q2.val.vmax=sizetab[p1->typf&NQ];
+                        }else remove_IC(p1);
+                    }
+                    clear_am(dreg+8);
+                }
+            }
+            /*  das hier duerfte unnoetig sein, da die Adressierungsart in  */
+            /*  einem IC eigentlich hoechstens einmal vorkommen darf        */
+            if(q1reg<0||q1reg>8) ierror(0);
+            p1=am_use[q1reg];
+            if(DEBUG&32) pric2(stdout,p1);
+            if(p1->code==PUSH&&p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(REG))){
+                p1->q1.am=mymalloc(AMS);
+                memcpy(p1->q1.am,am,AMS);
+                p->q1.val.vmax=l2zm(0L);
+                p1->code=PEA;
+                if(DEBUG&32) printf("q1 patched\n");
+            }
+            if(p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
+                p1->q1.am=mymalloc(AMS);
+                memcpy(p1->q1.am,am,AMS);
+                p1->q1.val.vmax=l2zm(0L);
+                if(DEBUG&32) printf("q1 patched\n");
+            }
+            if(p1->q2.reg==q1reg&&((p1->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
+                p1->q2.am=mymalloc(AMS);
+                memcpy(p1->q2.am,am,AMS);
+                p1->q2.val.vmax=l2zm(0L);
+                if(DEBUG&32) printf("q2 patched\n");
+            }
+            if(p1->z.reg==q1reg&&((p1->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
+                p1->z.am=mymalloc(AMS);
+                memcpy(p1->z.am,am,AMS);
+                p1->z.val.vmax=l2zm(0L);
+                if(DEBUG&32) printf("z patched\n");
+            }
+            free(am);count++;
+            clear_am(q1reg);
+            continue;
+        }
+        if(c>=LABEL&&c<=BRA){
+            int i;      /*  ueber basic blocks hinweg unsicher  */
+            for(i=1;i<=16;i++) clear_am(i);
+            continue;
+        }
+        /*  Wenn Libraryaufrufe noetig sind (floating point ohne FPU oder   */
+        /*  32bit mul/div/mod ohne 020+) keine Addressierungsarten nutzen   */
+        if(FPU<=68000&&(ISFLOAT(p->typf)||(p->code==CONVERT&&ISFLOAT(p->typf2)))){
+            int i;
+            for(i=1;i<=16;i++) clear_am(i);
+            continue;
+        }
+        if(CPU<68020&&(c==DIV||c==MOD)){
+            int i;
+            for(i=1;i<=16;i++) clear_am(i);
+            continue;
+        }
+        if(c==PUSH&&((p->q1.flags&(DREFOBJ|REG))==REG&&q1reg<=8&&!am_use[q1reg]&&(am_inc[q1reg]||am_dist[q1reg]||am_dreg[q1reg]))){
+            if(q1reg<1||q1reg>8) ierror(0);
+            if(am_inc[q1reg]&&am_inc[q1reg]!=msizetab[p->typf&NQ]) clear_am(q1reg); else am_use[q1reg]=p;
+            if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]);
+            continue;
+        }
+        if(((p->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q1reg<=8)){
+            if(q1reg<1||q1reg>8) ierror(0);
+            if(am_use[q1reg]&&(am_use[q1reg]!=p||am_inc[q1reg])) clear_am(q1reg); else am_use[q1reg]=p;
+            if(am_inc[q1reg]&&am_inc[q1reg]!=sizetab[p->typf&NQ]) clear_am(q1reg);
+            if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]);
+        }
+        if(((p->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q2reg<=8)){
+            if(q2reg<1||q2reg>8) ierror(0);
+            if(am_use[q2reg]&&(am_use[q2reg]!=p||am_inc[q2reg])) clear_am(q2reg); else am_use[q2reg]=p;
+            if(am_inc[q2reg]&&am_inc[q2reg]!=sizetab[p->typf&NQ]) clear_am(q2reg);
+            if(DEBUG&32) printf("use of %s found\n",mregnames[q2reg]);
+        }
+        if(((p->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&zreg<=8)){
+            if(zreg<1||zreg>8) ierror(0);
+            if(am_use[zreg]&&(am_use[zreg]!=p||am_inc[zreg])) clear_am(zreg); else am_use[zreg]=p;
+            if(am_inc[zreg]&&am_inc[zreg]!=sizetab[p->typf&NQ]) clear_am(zreg);
+            if(DEBUG&32) printf("use of %s found\n",mregnames[zreg]);
+        }
+        if(c==ALLOCREG){
+        /*  allocreg zaehlt als zerstoerung von reg */
+            p->z.flags=REG;
+            p->z.reg=zreg=q1reg=p->q1.reg;
+        }
+        if(q1reg>=1&&q1reg<=d7&&isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg);
+        if(q2reg>=1&&q2reg<=d7&&isreg(q2)&&(q2reg>8||am_use[q2reg]!=p)) clear_am(q2reg);
+        if(zreg>=1&&zreg<=d7&&isreg(z)) clear_am(zreg);
+        if(isreg(z)&&zreg<=d7){
+        /*  schauen, ob eines der Register ueberschrieben wird  */
+        /*  wohl noch sehr langsam                              */
+	  mod_reg(zreg);
+        }
+        if(c==ALLOCREG) p->z.flags=0;
+    }
+    if(DEBUG&1) printf("%d addressingmodes used, localused=%d\n",count,localused);
+    return localused;
+}
+static int alignment(obj *o)
+/*  versucht rauszufinden, wie ein Objekt alignet ist   */
+{
+    /*  wenn es keine Variable ist, kann man nichts aussagen    */
+    long os;
+    if(o->am||!(o->flags&VAR)) return -1;
+    if((o->flags&DREFOBJ)){
+      if(!(o->v->flags&NOTTYPESAFE)||!ISPOINTER(o->v->vtyp->flags)||zmeqto(falign(o->v->vtyp->next),l2zm(1L)))
+	return -1;
+      else
+	return 0;
+    }
+    if(!o->v) ierror(0);
+    os=zm2l(o->val.vmax);
+    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+        if(!USEFRAMEPOINTER&&!vlas){
+            if(!zmleq(l2zm(0L),o->v->offset)) os=os+loff-zm2l(o->v->offset);
+             else              os=os+zm2l(o->v->offset);
+        }else{
+            if(!zmleq(l2zm(0L),o->v->offset)) os=os-zm2l(o->v->offset);
+             else              os=os-(zm2l(o->v->offset)+zm2l(szof(o->v->vtyp)));
+        }
+    }else{
+      if(!(o->v->flags&(TENTATIVE|DEFINED))&&zmeqto(falign(o->v->vtyp),l2zm(1L)))
+	return -1;
+    }
+    
+    return os&3;
+}
+static void stored0d1(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp)) ierror(0);
+    if(o->reg==25) return;
+    emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[rp.r1]);
+    emit(f,"\tmove.l\t%s,%s\n",mregnames[10],mregnames[rp.r2]);
+  }else{
+    if(cf&&(o->flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){
+      emit(f,"\tmove.l\t%s,",mregnames[d0]);
+      emit_obj(f,o,t);
+      emit(f,"\n");
+      emit(f,"\tmove.l\t%s,",mregnames[d1]);
+      o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+      emit_obj(f,o,t);
+      o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+      emit(f,"\n");
+    }else{
+      emit(f,"\tmovem.l\t%s,",mregnames[d0d1]);
+      emit_obj(f,o,t);
+      emit(f,"\n");
+    }
+  }
+}
+static void loadd0d1(FILE *f,obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp)) 
+      ierror(0);
+    if(o->reg==25) return;
+    emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r1],mregnames[d0]);
+    emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r2],mregnames[10]);
+  }else{
+    if(cf){
+      emit(f,"\tmove.l\t");
+      emit_obj(f,o,t);
+      emit(f,",%s\n",mregnames[d0]);
+      emit(f,"\tmove.l\t");
+      o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+      emit_obj(f,o,t);
+      o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+      emit(f,",%s\n",mregnames[d1]);
+    }else{
+      emit(f,"\tmovem.l\t");
+      emit_obj(f,o,t);
+      emit(f,",%s\n",mregnames[d0d1]);
+    }
+  }
+}
+static void assign(FILE *f,IC *p,obj *q,obj *z,int c,long size,int t)
+/*  Generiert Code fuer Zuweisungen und PUSH.   */
+{
+    /*  auch noch sehr fpu-spezifisch   */
+  if(FPU<=68000&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&!((q->flags&(KONST|DREFOBJ))==KONST))
+    t=LLONG;
+  if(ISFLOAT(t)){
+    if(q&&(q->flags&(KONST|DREFOBJ))==KONST){
+      if(z&&(z->flags&(DREFOBJ|REG))==REG&&z->reg>=fp0&&z->reg<=fp7){
+	/*  FP-Konstante->Register (muss immer reinpassen)  */
+	if(z->reg>=fp0) emit(f,"\tfmove"); else emit(f,"\tmove");
+	emit(f,".%c\t",x_t[t&NQ]);emit_obj(f,q,t);
+	emit(f,",%s\n",mregnames[z->reg]);
+      }else{
+	/*  FP-Konstante->Speicher (evtl. auf zweimal)  */
+	int m,r;unsigned char *ip=(unsigned char *)&q->val.vfloat; /* nicht sehr schoen  */
+	char *s;
+	if(cf&&c==ASSIGN) r=get_reg(f,1,p,0);
+	if(GAS) s="0x"; else s="$";
+	if(c==PUSH&&(t&NQ)!=FLOAT){
+	  emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,-(%s)\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[sp]);
+	  push(4);
+	}
+	emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[0],ip[1],ip[2],ip[3]);
+	if(c==ASSIGN){
+	  if(cf)
+	    emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]);
+	  if(isreg(z)&&reg_pair(p->z.reg,&rp))
+	    emit(f,"%s",mregnames[rp.r1]);
+	  else
+	    emit_obj(f,z,t);
+	}else{
+	  emit(f,"-(%s)",mregnames[sp]);
+	  push(4);
+	}
+	emit(f,"\n");
+	if((t&NQ)==FLOAT||c==PUSH) return;
+	m=0;
+	if(z&&(z->flags&REG)){
+	  m=1;z->flags|=D16OFF;
+	  z->val.vmax=l2zm(0L);
+	}
+	vmax=l2zm(4L);
+	z->val.vmax=zmadd(z->val.vmax,vmax);
+	emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[4],ip[5],ip[6],ip[7]);
+	if(cf)
+	  emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]);
+	if(isreg(z)&&reg_pair(p->z.reg,&rp))
+	  emit(f,"%s",mregnames[rp.r2]);
+	else
+	  emit_obj(f,z,t);
+	emit(f,"\n");
+	if(m){
+	  z->flags&=~D16OFF;vmax=l2zm(4L);
+	  z->val.vmax=zmsub(z->val.vmax,vmax);
+	}
+      }
+      return;
+    }
+    if((q&&(q->flags&REG)&&q->reg>=fp0)||(z&&(z->flags&REG)&&z->reg>=fp0)){
+      if(c==ASSIGN&&(q->flags&REG)&&(z->flags&REG)&&q->reg==z->reg) return;
+      if(c==ASSIGN){ move(f,q,0,z,0,t);return;}
+      emit(f,"\tfmove.%c\t",x_t[t&NQ]);
+      emit_obj(f,q,t);
+      emit(f,",");
+      if(c==PUSH){
+	emit(f,"-(%s)",mregnames[sp]);
+	push(size);
+      } else 
+	emit_obj(f,z,t);
+      emit(f,"\n");return;
+    }
+    if(size==8) t=LLONG;
+  }
+  if((t&NQ)==LLONG){
+    if(z&&compare_objects(q,z)) return;
+    if(((cf&&c==ASSIGN)||(q->flags&(REG|DREFOBJ))==REG)&&(!z||(z->flags&(REG|DREFOBJ))!=REG)){
+      if(cf){
+	if(c==ASSIGN){
+	  int r;
+	  if((q->flags&(REG|DREFOBJ))==REG){
+	    if(!reg_pair(q->reg,&rp)) ierror(0);
+	    r=rp.r2;
+	  }else{
+	    r=get_reg(f,1,p,0);
+	    emit(f,"\tmove.l\t");
+	    emit_lword(f,q);
+	    emit(f,",%s\n",mregnames[r]);
+	  }
+	  emit(f,"\tmove.l\t%s,",mregnames[r]);
+	  emit_lword(f,z);
+	  emit(f,"\n");
+	  if((q->flags&(REG|DREFOBJ))==REG){
+	    r=rp.r1;
+	  }else{
+	    emit(f,"\tmove.l\t");
+	    emit_hword(f,q);
+	    emit(f,",%s\n",mregnames[r]);
+	  }
+	  emit(f,"\tmove.l\t%s,",mregnames[r]);
+	  emit_hword(f,z);
+	  emit(f,"\n");
+	}else{
+	  emit(f,"\tsubq.l\t#8,%s\n",mregnames[sp]);
+	  push(8);
+	  emit(f,"\tmovem.l\t%s,(%s)\n",mregnames[q->reg],mregnames[sp]);
+	}
+      }else{
+	emit(f,"\tmovem.l\t%s,",mregnames[q->reg]);
+	if(c==ASSIGN){
+	  emit_obj(f,z,t);
+	}else{
+	  emit(f,"-(%s)",mregnames[sp]);
+	  push(8);
+	}
+	emit(f,"\n");
+      }
+      return;
+    }
+    if(!cf&&(q->flags&(REG|DREFOBJ))!=REG&&!((q->flags&(KONST|DREFOBJ))==KONST)&&z&&(z->flags&(REG|DREFOBJ))==REG){
+      emit(f,"\tmovem.l\t");
+      emit_obj(f,q,t);
+      emit(f,",%s\n",mregnames[z->reg]);
+      return;
+    }
+    emit(f,"\tmove.l\t");
+    emit_lword(f,q);
+    emit(f,",");
+    if(c==ASSIGN){
+      emit_lword(f,z);
+    }else{
+      emit(f,"-(%s)",mregnames[sp]);
+      push(4);
+    }
+    emit(f,"\n");
+    emit(f,"\tmove.l\t");
+    emit_hword(f,q);
+    emit(f,",");
+    if(c==ASSIGN){
+      emit_hword(f,z);
+    }else{
+      emit(f,"-(%s)",mregnames[sp]);
+      push(4);
+    }
+    emit(f,"\n");    
+    return;
+  }
+  if((size==1||size==2||size==4)&&!ISARRAY(t)&&(p->code!=PUSH||zm2l(p->z.val.vmax)!=3)&&((t&NQ)!=CHAR||size==1)){
+    if(ISSTRUCT(t)||ISUNION(t)){
+      if(p->code==PUSH&&!zmeqto(p->q2.val.vmax,p->z.val.vmax)){
+	if(size!=4&&size!=2) ierror(size);
+	emit(f,"\tsubq.%s\t#%d,%s\n",cf?"l":"w",size,mregnames[sp]);
+	push(size);
+	size=zm2l(p->z.val.vmax);
+	if(size!=1&&size!=2) ierror(0);
+	emit(f,"\tmove.%c\t",size==1?'b':'w');
+	emit_obj(f,q,(size==1?CHAR:SHORT));
+	emit(f,",(%s)\n",mregnames[sp]);
+	return;
+      }else{
+	if(size==1)
+	  t=CHAR;
+	else if(size==2)
+	  t=SHORT;
+	else
+	  t=LONG;
+      }
+    }
+    if(c==ASSIGN){move(f,q,0,z,0,t);return;}
+    /*  Sonderfall pea  */
+    if((q->flags&VARADR)&&c==PUSH){
+      emit(f,"\tpea\t");
+      q->flags&=~VARADR; emit_obj(f,q,t); q->flags|=VARADR;
+      emit(f,"\n"); 
+      push(size);
+      return;
+    }
+    emit(f,"\tmove.%c\t",x_s[size]);
+    emit_obj(f,q,t);
+    emit(f,",");
+    if(c==PUSH){
+      emit(f,"-(%s)",mregnames[sp]);
+      push(size);
+    } else 
+      emit_obj(f,z,t);
+    emit(f,"\n");return;
+  }else{
+    int a1,a2,qreg,zreg,dreg,loops,scratch=0,down=0;char *cpstr;
+    long s=size,osize=size;
+    IC *m;
+    for(m=p->next;m&&m->code==FREEREG;m=m->next){
+      if(q&&m->q1.reg==q->reg) scratch|=1;
+      if(z&&m->q1.reg==z->reg) scratch|=2;
+    }
+    a1=alignment(q);
+    if(c!=PUSH)  a2=alignment(z); else a2=0;
+    if(a1<0||a2<0) {a1=1;a2=2;}
+    if(p->typf2==2||p->typf2==4) {a1=a2=0;}
+    if((c==PUSH||(scratch&1))&&(q->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&q->reg>=1&&q->reg<=8&&!q->am){
+      qreg=q->reg;
+      if(c==PUSH&&(a1&1)==0&&(a2&1)==0)
+	emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[q->reg]);
+    }else{
+      if(c!=ASSIGN&&!regavailable(0))
+	qreg=pget_reg(f,0,p,0);
+      else
+	qreg=get_reg(f,0,p,0);
+      if(c==PUSH&&(a1&1)==0&&(a2&1)==0){
+	q->flags|=D16OFF; 
+	q->val.vmax=zmadd(q->val.vmax,l2zm((long)s));
+	emit(f,"\tlea\t");emit_obj(f,q,POINTER);
+	q->val.vmax=zmsub(q->val.vmax,l2zm((long)s));
+	emit(f,",%s\n",mregnames[qreg]);
+      }else{
+	emit(f,"\tlea\t");emit_obj(f,q,POINTER);
+	emit(f,",%s\n",mregnames[qreg]);
+      }	      
+    }
+    if(c==PUSH){
+      if((a1&1)==0&&(a2&1)==0){
+	zreg=8;
+      }else{
+	emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[sp]);
+	push(size);
+	size=0;
+	if(!regavailable(0))
+	  zreg=pget_reg(f,0,p,0);
+	else
+	  zreg=get_reg(f,0,p,0);
+	emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[zreg]);
+      }
+    }else{
+      if((scratch&2)&&(z->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&z->reg>=1&&z->reg<=8&&!z->am){
+	zreg=z->reg;
+      }else{
+	zreg=get_reg(f,0,p,0);
+	emit(f,"\tlea\t");emit_obj(f,z,POINTER);
+	emit(f,",%s\n",mregnames[zreg]);
+      }
+    }
+    /*  wenn Typ==CHAR, dann ist das ein inline_memcpy und wir nehmen   */
+    /*  das unguenstigste Alignment an                                  */
+    /*if((t&NQ)==CHAR){ a1=1;a2=2;}*/
+    
+    if(c==PUSH&&(a1&1)==0&&(a2&1)==0){
+      cpstr="\tmove.%c\t-(%s),-(%s)\n";
+      down=1;
+    }else
+      cpstr="\tmove.%c\t(%s)+,(%s)+\n";
+    
+    if((a1&1)&&(a2&1)){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;a1&=~1;a2&=~1;}
+    if((a1&2)&&(a2&2)){emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);s-=2;a1&=~2;a2&=~2;}
+    if(!(a1&1)&&!(a2&1)) loops=s/16-1; else loops=s/4-1;
+    if(loops>0){
+      if(c!=ASSIGN&&!regavailable(1)) dreg=pget_reg(f,1,p,0);
+      else dreg=get_reg(f,1,p,0);
+      emit(f,"\tmove%s.l\t#%d,%s\n%s%d:\n",quick[loops>=-128&&loops<=127],loops,mregnames[dreg],labprefix,++label);
+    }
+    if(loops>=0){
+      int t;
+      if(!(a1&1)&&!(a2&1)) t='l'; else t='b';
+      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+    }
+    if(loops>0){
+      if(!cf&&loops<=32767&&loops>=-32768){
+	emit(f,"\tdbra\t%s,%s%d\n",mregnames[dreg],labprefix,label);
+      }else{
+	emit(f,"\tsubq.l\t#1,%s\n\tbge\t%s%d\n",mregnames[dreg],labprefix,label);
+      }
+    }
+    if(!(a1&1)&&!(a2&1)){
+      if(s&8){
+	emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
+	emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
+      }
+      if(s&4) emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
+      if(s&2) emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);
+      if(s&1) emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);
+    }else{
+      s&=3;
+      while(s){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;}
+    }
+    if(c==PUSH&&qreg==q->reg&&(!(scratch&1))&&!down)
+      emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[osize<=8],strshort[osize<=32767],osize,regnames[qreg]);
+    if(c==PUSH) push(size);
+  }
+  return;
+}
+static int muststore(IC *p,int r)
+{
+  if(!regs[r])
+    return 0;
+#if 0
+  /* mal bei Gelegenheit testen */
+  while(p){
+    if(p->code==FREEREG&&p->q1.reg==r)
+      return 0;
+    if((p->q1.flags&REG)&&p->q1.reg==r)
+      return 1;
+    if(p->q1.am&&(p->q1.am->basereg==r||(p->q1.am->dreg&127)==r))
+      return 1;
+    if((p->q2.flags&REG)&&p->q2.reg==r)
+      return 1;
+    if(p->q2.am&&(p->q2.am->basereg==r||(p->q2.am->dreg&127)==r))
+      return 1;
+    if(p->z.am&&(p->z.am->basereg==r||(p->z.am->dreg&127)==r))
+      return 1;
+    if((p->z.flags&REG)&&p->z.reg==r)
+      return (p->z.flags&DREFOBJ)!=0;
+    if(p->code>=LABEL&&p->code<=BRA)
+      return 1;
+    p=p->next;
+  }
+  return 0;
+#else
+  return 1;
+#endif
+}
+
+static int store_saveregs;
+static void saveregswfp(FILE *f,IC *p,int storefp)
+{
+    int dontsave;
+    store_saveregs=0;
+    if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0;
+    if(dontsave!= d0&&dontsave!=25&&(muststore(p,d0)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d0],mregnames[sp]);push(4);store_saveregs|=1;}
+    if(dontsave!=10&&dontsave!=25&&(muststore(p,d1)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d1],mregnames[sp]);push(4);store_saveregs|=2;}
+    if(dontsave!= fp0&&muststore(p,fp0)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp0],mregnames[sp]);push(12);store_saveregs|=16;}
+    if(dontsave!= fp1&&muststore(p,fp1)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp1],mregnames[sp]);push(12);store_saveregs|=32;}
+    if(dontsave!= a0&&muststore(p,a0)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a0],mregnames[sp]);push(4);store_saveregs|=4;}
+    if(dontsave!= a1&&muststore(p,a1)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a1],mregnames[sp]);push(4);store_saveregs|=8;}
+
+}
+static void restoreregsa(FILE *f,IC *p)
+{
+    if(store_saveregs&8) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a1]);pop(4);}
+    if(store_saveregs&4) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a0]);pop(4);}
+}
+static void restoreregsd(FILE *f,IC *p)
+{
+    int dontsave;
+    if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0;
+    if(dontsave!=fp1&&(store_saveregs&32)){
+      emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp1]);
+      pop(12);
+    }
+    if(dontsave!=fp0&&(store_saveregs&16)){
+      emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp0]);
+      pop(12);
+    }
+    if(dontsave!=10&&(store_saveregs&2)){
+      if(!GAS&&!PHXASS)
+	emit(f,"\topt\tom-\n");
+      if(cf)
+        emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d1],mregnames[sp]);
+      else
+	emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d1]);
+      pop(4);
+      if(!GAS&&!PHXASS)
+	emit(f,"\topt\tom+\n");
+    }
+    if(dontsave!=d0 &&(store_saveregs&1)){
+      if(!GAS&&!PHXASS)
+	emit(f,"\topt\tom-\n");
+      if(cf)
+        emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d0],mregnames[sp]);
+      else
+	emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d0]);
+      pop(4);
+      if(!GAS&&!PHXASS)
+	emit(f,"\topt\tom+\n");
+    }
+}
+
+/* emits the low word of a long long object */
+static void emit_lword(FILE *f,obj *o)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp))
+      ierror(0);
+    emit(f,"%s",mregnames[rp.r2]);
+  }else if((o->flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&o->val,UNSIGNED|LLONG);
+    vumax=zumand(vumax,ul2zum(0xffffffff));
+    insert_const(&gval,UNSIGNED|MAXINT);
+    emit(f,"#");
+    emitval(f,&gval,UNSIGNED|MAXINT);
+  }else{
+    if(o->am||(o->flags&REG)){
+      o->flags|=D16OFF;
+      o->val.vmax=l2zm(0L);
+    }
+    o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+    emit_obj(f,o,LLONG);
+    o->flags&=~D16OFF;
+    o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+  }
+}
+/* emits the high word of a long long object */
+static void emit_hword(FILE *f,obj *o)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(o->reg,&rp)) 
+      ierror(0);
+    emit(f,"%s",mregnames[rp.r1]);
+  }else if((o->flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&o->val,UNSIGNED|MAXINT);
+    vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+    insert_const(&gval,UNSIGNED|MAXINT);
+    emit(f,"#");
+    emitval(f,&gval,UNSIGNED|MAXINT);
+  }else{
+    emit_obj(f,o,LONG);
+  }
+}
+/* process ICs with long long; return 1 if IC has been handled */
+static int handle_llong(FILE *f,IC *p)
+{
+  int c=p->code,r=0,t=p->typf&NU;
+  char *libfuncname;
+
+  if(c==ADDRESS) return 0;
+  
+  cc_set=0;
+  if(c==GETRETURN){
+    if(isreg(z)&&p->z.reg==25)
+      return 1;
+    emit(f,"\tmove.l\t%s,",mregnames[d1]);
+    emit_lword(f,&p->z);
+    emit(f,"\n");
+    emit(f,"\tmove.l\t%s,",mregnames[d0]);
+    emit_hword(f,&p->z);
+    emit(f,"\n");
+    return 1;
+  }
+  if(c==SETRETURN){
+    if(isreg(q1)&&p->q1.reg==25)
+      return 1;
+    emit(f,"\tmove.l\t");
+    emit_lword(f,&p->q1);
+    emit(f,",%s\n",mregnames[d1]);
+    emit(f,"\tmove.l\t");
+    emit_hword(f,&p->q1);
+    emit(f,",%s\n",mregnames[d0]);    
+    return 1;
+  }
+  if(c==CONVERT){
+    int told=q1typ(p),tnew=ztyp(p);
+    if(ISPOINTER(told)) told=UNSIGNED|LONG;
+    if(ISPOINTER(tnew)) tnew=UNSIGNED|LONG;
+    if(ISFLOAT(told)){
+      if(!OLD_SOFTFLOAT) ierror(0);
+      saveregs(f,p);
+      assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told);
+      scratch_modified();
+      if(GAS)
+	emit(f,"\t.global\t__flt%ldto%cint64\n\tjbsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]);
+      else
+	emit(f,"\tpublic\t__flt%ldto%cint64\n\tjsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]);
+      pop(msizetab[told]);
+      restoreregsa(f,p);
+      if(!isreg(z)||p->z.reg!=25){ /* d0/d1 */
+	emit(f,"\tmove.l\t%s,",mregnames[d1]);
+	emit_lword(f,&p->z);
+	emit(f,"\n");
+	emit(f,"\tmove.l\t%s,",mregnames[d0]);
+	emit_hword(f,&p->z);
+	emit(f,"\n");
+      }
+      restoreregsd(f,p);
+      return 1;
+    }
+    if(ISFLOAT(tnew)){
+      saveregswfp(f,p,1);
+      assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told);
+      scratch_modified();
+      if(GAS)
+	emit(f,"\t.global\t__%cint64toflt%ld\n\tjbsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]);
+      else
+	emit(f,"\tpublic\t__%cint64toflt%ld\n\tjsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]);
+      pop(msizetab[told&NQ]);
+      restoreregsa(f,p);
+      if(FPU>68000){
+	emit(f,"\tfmove.x\tfp0,");
+	emit_obj(f,&p->z,tnew);
+	emit(f,"\n");
+      }else if((tnew&NQ)==FLOAT){
+	emit(f,"\tmove.l\t%s,",mregnames[d0]);
+	emit_obj(f,&p->z,tnew);
+	emit(f,"\n");
+      }else{
+	emit(f,"\tmove.l\td1,");
+	emit_lword(f,&p->z);
+	emit(f,"\n");
+	emit(f,"\tmove.l\t%s,",mregnames[d0]);
+	emit_hword(f,&p->z);
+	emit(f,"\n");
+      }
+      restoreregsd(f,p);
+      return 1;
+    }
+    if((told&NQ)<LLONG){
+      int destreg=0;
+      if(ISHWORD(told)||!(told&UNSIGNED)){
+	if(isreg(z)){
+	  if(!reg_pair(p->z.reg,&rp)) ierror(0);
+	  r=rp.r2;
+	  destreg=1;
+	}else{
+	  r=get_reg(f,1,p,0);
+	}
+	loadext(f,r,&p->q1,told);
+	p->q1.flags=REG;
+	p->q1.reg=r;
+	p->q1.am=0;
+      }
+      if(!destreg){
+	emit(f,"\tmove.l\t");
+	emit_obj(f,&p->q1,told);
+	emit(f,",");
+	emit_lword(f,&p->z);
+	emit(f,"\n");
+      }
+      if(told&UNSIGNED){
+	emit(f,"\tmove.l\t#0,");
+	emit_hword(f,&p->z);
+	emit(f,"\n");
+      }else{
+	int tmp;
+	if(r==0)
+	  ierror(0);
+	if(destreg){
+	  emit(f,"\tmove.l\t%s,%s\n",mregnames[r],mregnames[rp.r1]);
+	  r=rp.r1;
+	}
+	tmp=get_reg(f,1,p,0);
+	emit(f,"\tmoveq\t#31,%s\n",mregnames[tmp]);
+	emit(f,"\tasr.l\t%s,%s\n",mregnames[tmp],mregnames[r]);
+	if(!destreg){
+	  emit(f,"\tmove.l\t%s,",mregnames[r]);
+	  emit_hword(f,&p->z);
+	  emit(f,"\n");
+	}
+      }
+      return 1;
+    }
+    if((tnew&NQ)<LLONG){
+      if((tnew&NQ)<INT&&!isreg(z)){
+	r=get_reg(f,1,p,0);
+	emit(f,"\tmove.l\t");
+	emit_lword(f,&p->q1);
+	emit(f,",%s\n",mregnames[r]);
+	emit(f,"\tmove.%c\t%s,",x_t[tnew&NQ],mregnames[r]);
+	emit_obj(f,&p->z,tnew);
+	emit(f,"\n");
+      }else{
+	emit(f,"\tmove.%c\t",x_t[tnew&NQ]);
+	p->q1.val.vmax=zmadd(p->q1.val.vmax,zmsub(sizetab[LONG],sizetab[tnew&NQ]));
+	emit_lword(f,&p->q1);
+	emit(f,",");
+	emit_obj(f,&p->z,tnew);
+	emit(f,"\n");
+      }
+      return 1;
+    }
+    assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
+    return 1;
+  }
+  if(c==ASSIGN){
+    assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
+    return 1;
+  }
+  if(c==PUSH){
+    dontpop+=zm2l(p->q2.val.vmax);
+    assign(f,p,&p->q1,0,PUSH,msizetab[t],t);
+    return 1;
+  }  
+  if(c==MINUS||c==KOMPLEMENT){
+    char *sl,*sh;
+    if(c==MINUS){
+      sl="neg.l";
+      sh="negx.l";
+    }else
+      sl=sh="not.l";
+    if(!cf&&compare_objects(&p->q1,&p->z)){
+      emit(f,"\t%s\t",sl);
+      emit_lword(f,&p->z);
+      emit(f,"\n");
+      emit(f,"\t%s\t",sh);
+      emit_hword(f,&p->z);
+      emit(f,"\n");      
+      return 1;
+    }
+    if(isreg(z)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
+      emit(f,"\t%s\t%s\n",sl,mregnames[rp.r2]);
+      emit(f,"\t%s\t%s\n",sh,mregnames[rp.r1]);
+      return 1;
+    }
+    r=get_reg(f,1,p,0);
+    emit(f,"\tmove.l\t");
+    emit_lword(f,&p->q1);
+    emit(f,",%s\n",mregnames[r]);
+    emit(f,"\t%s\t%s\n",sl,mregnames[r]);
+    emit(f,"\tmove.l\t%s,",mregnames[r]);
+    emit_lword(f,&p->z);
+    emit(f,"\n");
+    emit(f,"\tmove.l\t");
+    emit_hword(f,&p->q1);
+    emit(f,",%s\n",mregnames[r]);
+    emit(f,"\t%s\t%s\n",sh,mregnames[r]);
+    emit(f,"\tmove.l\t%s,",mregnames[r]);
+    emit_hword(f,&p->z);    
+    emit(f,"\n");
+    return 1;
+  }
+  if((c>=OR&&c<=AND)||c==ADD||c==SUB){
+    char *sl,*sh;int t2=0;
+    switch_IC(p);
+    if(c==ADD){sl="add.l";sh="addx.l";}
+    else if(c==SUB){sl="sub.l";sh="subx.l";}
+    else if(c==AND){sl=sh="and.l";}
+    else if(c==OR){sl=sh="or.l";}
+    else if(c==XOR){sl=sh="eor.l";}
+    else
+      ierror(0);
+    if(isreg(q1)&&isreg(q2)&&isreg(z)&&p->q1.reg==p->q2.reg&&p->q1.reg==p->z.reg){
+      if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+      emit(f,"\t%s\t%s,%s\n",sl,mregnames[rp.r2],mregnames[rp.r2]);
+      emit(f,"\t%s\t%s,%s\n",sh,mregnames[rp.r1],mregnames[rp.r1]);
+      return 1;
+    }
+    if(!isreg(z)&&compare_objects(&p->q1,&p->z)){
+      if(isreg(q2)||(isconst(q2)&&(c==ADD||c==SUB)&&!cf)){
+	if(!r) r=get_reg(f,1,p,0);
+	emit(f,"\t%s\t",sl);
+	emit_lword(f,&p->q2);
+      }else{
+	if(!r) r=get_reg(f,1,p,0);
+	emit(f,"\tmove.l\t");
+	emit_lword(f,&p->q2);
+	emit(f,",%s\n",mregnames[r]);
+	emit(f,"\t%s\t%s",sl,mregnames[r]);
+      }
+      emit(f,",");
+      emit_lword(f,&p->z);
+      emit(f,"\n");
+      if(!isreg(q2)||c==ADD||c==SUB||c==XOR){
+	emit(f,"\tmove.l\t");
+	emit_hword(f,&p->q1);
+	emit(f,",%s\n",mregnames[r]);
+	if(isreg(q2)){
+	  if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+	  t2=rp.r1;
+	}else{
+	  t2=get_reg(f,1,p,0);
+	  emit(f,"\tmove.l\t");
+	  emit_hword(f,&p->q2);
+	  emit(f,",%s\n",mregnames[t2]);
+	}
+	emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]);
+	emit(f,"\tmove.l\t%s,",mregnames[r]);
+	emit_hword(f,&p->z);
+	emit(f,"\n");
+      }else{
+	if(isreg(q2)){
+	  emit(f,"\t%s\t",sh);
+	  emit_hword(f,&p->q2);
+	}else{
+	  if(!r) r=get_reg(f,1,p,0);
+	  emit(f,"\tmove.l\t");
+	  emit_hword(f,&p->q2);
+	  emit(f,",%s\n",mregnames[r]);
+	  emit(f,"\t%s\t%s",sh,mregnames[r]);
+	}
+	emit(f,",");
+	emit_hword(f,&p->z);
+	emit(f,"\n");      
+      }
+      return 1;
+    }
+    if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      r=rp.r2;
+    }else{
+      r=get_reg(f,1,p,0);
+    }
+    if(!compare_objects(&p->q1,&p->z)){
+      emit(f,"\tmove.l\t");
+      emit_lword(f,&p->q1);
+      emit(f,",%s\n",mregnames[r]);
+    }
+    if(c==XOR){
+      t2=get_reg(f,1,p,0);
+      emit(f,"\tmove.l\t");
+      emit_lword(f,&p->q2);
+      emit(f,",%s\n",mregnames[t2]);
+      emit(f,"\t%s\t%s,%s\n",sl,mregnames[t2],mregnames[r]);
+    }else{
+      emit(f,"\t%s\t",sl);
+      emit_lword(f,&p->q2);
+      emit(f,",%s\n",mregnames[r]);
+    }
+    if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      r=rp.r1;
+    }else{
+      emit(f,"\tmove.l\t%s,",mregnames[r]);
+      emit_lword(f,&p->z);
+      emit(f,"\n");
+    }
+    if(!compare_objects(&p->q1,&p->z)){
+      emit(f,"\tmove.l\t");
+      emit_hword(f,&p->q1);
+      emit(f,",%s\n",mregnames[r]);
+    }
+    if(c==XOR||c==ADD||c==SUB){
+      if(isreg(q2)){
+	if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+	t2=rp.r1;
+      }else{
+	if(!t2) t2=get_reg(f,1,p,0);
+	emit(f,"\tmove.l\t");
+	emit_hword(f,&p->q2);
+	emit(f,",%s\n",mregnames[t2]);
+      }
+      emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]);
+    }else{
+      emit(f,"\t%s\t",sh);
+      emit_hword(f,&p->q2);
+      emit(f,",%s\n",mregnames[r]);
+    }
+    if(!isreg(z)||(isreg(q2)&&p->z.reg==p->q2.reg)){
+      emit(f,"\tmove.l\t%s,",mregnames[r]);
+      emit_hword(f,&p->z);
+      emit(f,"\n");
+    }      
+    return 1;
+  }
+  if(c==TEST){
+    p->code=c=COMPARE;
+    p->q2.flags=KONST;
+    if((t&NU)==LLONG)
+      p->q2.val.vllong=zm2zll(l2zm(0L));
+    else if((t&NU)==(UNSIGNED|LLONG))
+      p->q2.val.vullong=zum2zull(ul2zum(0UL));
+    else
+      ierror(0);
+  }
+  if(c==COMPARE){
+    int rl,rh,t2;
+    comptyp=p->typf;
+    rl=get_reg(f,1,p,0);
+    rh=get_reg(f,1,p,0);
+    emit(f,"\tmove.l\t");
+    emit_lword(f,&p->q1);
+    emit(f,",%s\n",mregnames[rl]);
+    emit(f,"\tmove.l\t");
+    emit_hword(f,&p->q1);
+    emit(f,",%s\n",mregnames[rh]);
+    if(isreg(q2)){
+      if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+      t2=rp.r1;
+    }else{
+      t2=get_reg(f,1,p,0);
+      emit(f,"\tmove.l\t");
+      emit_hword(f,&p->q2);
+      emit(f,",%s\n",mregnames[t2]);
+    }
+    emit(f,"\tsub.l\t");
+    emit_lword(f,&p->q2);
+    emit(f,",%s\n",mregnames[rl]);
+    emit(f,"\tsubx.l\t%s,%s\n",mregnames[t2],mregnames[rh]);
+    return 1;
+  }
+  saveregs(f,p);
+  if((c==LSHIFT||c==RSHIFT)&&(q2typ(p)&NQ)==LLONG){
+    emit(f,"\tmove.l\t");
+    emit_lword(f,&p->q2);
+    emit(f,",-(%s)\n",mregnames[sp]);
+    push(4);
+  }else
+    assign(f,p,&p->q2,0,PUSH,msizetab[q2typ(p)&NQ],q2typ(p));
+  assign(f,p,&p->q1,0,PUSH,msizetab[q1typ(p)&NQ],q1typ(p));
+  scratch_modified();
+  if(c==MULT){
+    if(CPU==68060)
+      libfuncname="__mulint64_060";
+    else if(CPU>=68020)
+      libfuncname="__mulint64_020";
+    else
+      libfuncname="__mulint64";
+  }else if(c==DIV){
+    if(t&UNSIGNED){
+      if(CPU==68060)
+	libfuncname="__divuint64_060";
+      else if(CPU>=68020)
+	libfuncname="__divuint64_020";
+      else
+	libfuncname="__divuint64";
+    }else{
+      if(CPU==68060)
+	libfuncname="__divsint64_060";
+      else if(CPU>=68020)
+	libfuncname="__divsint64_020";
+      else
+	libfuncname="__divsint64";
+    }
+  }else if(c==MOD){
+    if(t&UNSIGNED){
+      if(CPU==68060)
+	libfuncname="__moduint64_060";
+      else if(CPU>=68020)
+	libfuncname="__moduint64_020";
+      else
+	libfuncname="__moduint64";
+    }else{
+      if(CPU==68060)
+	libfuncname="__modsint64_060";
+      else if(CPU>=68020)
+	libfuncname="__modsint64_020";
+      else
+	libfuncname="__modsint64";
+    }
+  }else if(c==RSHIFT){
+    if(t&UNSIGNED)
+      libfuncname="__rshuint64";
+    else
+      libfuncname="__rshsint64";
+  }else if(c==LSHIFT)
+    libfuncname="__lshint64";
+  else{
+    printf("c=%d\n",c);
+    ierror(0);
+  }
+  if(GAS)
+    emit(f,"\t.global\t%s\n\tjbsr\t%s\n",libfuncname,libfuncname);
+  else
+    emit(f,"\tpublic\t%s\n\tjsr\t%s\n",libfuncname,libfuncname);
+  if(c==LSHIFT||c==RSHIFT){
+#ifdef M68K_16BIT_INT
+    emit(f,"\tadd.%s\t#10,%s\n",strshort[1],mregnames[sp]);
+    pop(10);
+#else
+    emit(f,"\tadd.%s\t#12,%s\n",strshort[1],mregnames[sp]);
+    pop(12);
+#endif
+  }else{
+    emit(f,"\tadd.%s\t#16,%s\n",strshort[1],mregnames[sp]);
+    pop(16);
+  }
+  restoreregsa(f,p);
+  if(!isreg(z)||p->z.reg!=25){
+    emit(f,"\tmove.l\t%s,",mregnames[d0]);
+    emit_hword(f,&p->z);
+    emit(f,"\n");
+    emit(f,"\tmove.l\t%s,",mregnames[10]);
+    emit_lword(f,&p->z);
+    emit(f,"\n");
+  }    
+  restoreregsd(f,p);
+  return 1;
+}
+
+/* generate inlines for Amiga IEEE softcalls */
+static char *ami_ieee(char *base,int off)
+{
+  char *s;
+  if(cf) ierror(0);
+  s=mymalloc(128);
+  sprintf(s,"\tmove.l\t%s,-(%s)\n\tmove.l\t%sMathIeee%sBase%s,%s\n\tjsr\t%d(%s)\n\tmove.l\t(%s)+,%s",mregnames[a6],mregnames[sp],idprefix,base,use_sd?"(a4)":"",mregnames[a6],off,mregnames[a6],mregnames[sp],mregnames[a6]);
+  return s;
+}
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+    int i;
+    larray.size=l2zm(3L);
+    /*  Initialize some values which cannot be statically initialized   */
+    /*  because they are stored in the target's arithmetic.             */
+    maxalign=l2zm(4L);
+    char_bit=l2zm(8L);
+    for(i=0;i<=MAX_TYPE;i++){
+        sizetab[i]=l2zm(msizetab[i]);
+        align[i]=l2zm(malign[i]);
+    }
+    for(i= 1;i<=16;i++) {regsize[i]=l2zm( 4L);regtype[i]=&ltyp;}
+    for(i=fp0;i<=fp7;i++) {regsize[i]=l2zm(12L);regtype[i]=&larray;}
+    for(i=25;i<=28;i++) {regsize[i]=l2zm( 8L);regtype[i]=&lltyp;}
+
+    if(ELF){
+      for(i=1;i<=MAXR;i++)
+	mregnames[i]=elfregnames[i];
+      idprefix="";
+      labprefix=".l";
+      rprefix="%";
+    }else{
+      for(i=1;i<=MAXR;i++)
+	mregnames[i]=regnames[i];
+      idprefix="_";
+      labprefix="l";
+      rprefix="";
+    }
+
+    if(SMALLDATA) use_sd=1;
+
+
+    /*  default CPU is 68000    */
+    if(!(g_flags[0]&USEDFLAG)) CPU=68000;
+    if(CPU==68040) static_cse=0; else static_cse=1;
+    if(CPU<68000) cf=1;
+    if(cf) MINADDI2P=INT; /* requires 32bit int! */
+    /*  no FPU by default       */
+    if(!(g_flags[1]&USEDFLAG)) FPU=0;
+    if(FPU<=68000) {x_t[FLOAT]='l';}
+    if(D2SCRATCH){regscratch[d2]=1;dscratch++;}
+    if(A2SCRATCH) {regscratch[a2]=1;ascratch++;}
+    if(FP2SCRATCH) {regscratch[fp2]=1;fscratch++;}
+
+    if(NOA4) regsa[5]=1;
+    if(GAS){
+        codename="\t.text\n";
+        bssname="";
+        dataname="\t.data\n";
+        if(use_sd) regsa[5]=1;
+    }else{
+        codename="\tsection\t\"CODE\",code\n";
+        if(use_sd){
+            /*  preparing small data    */
+            regsa[5]=1;
+            bssname= "\tsection\t\"__MERGED\",bss\n";
+            dataname="\tsection\t\"__MERGED\",data\n";
+        }else{
+            bssname= "\tsection\t\"BSS\",bss\n";
+            dataname="\tsection\t\"DATA\",data\n";
+        }
+    }
+    m_dataname=dataname;
+    m_bssname=bssname;
+    /*  a5 can be used if no framepointer is used.  */
+    if(!USEFRAMEPOINTER){ regsa[fbp]=0;/*fbp=sp;*/}
+    if(DEBUG&1) printf("CPU=%ld FPU=%ld\n",CPU,FPU);
+    /*  Initialize the min/max-settings. Note that the types of the     */
+    /*  host system may be different from the target system and you may */
+    /*  only use the smallest maximum values ANSI guarantees if you     */
+    /*  want to be portable.                                            */
+    /*  That's the reason for the subtraction in t_min[INT]. Long could */
+    /*  be unable to represent -2147483648 on the host system.          */
+    t_min[CHAR]=l2zm(-128L);
+    t_min[SHORT]=l2zm(-32768L);
+    t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+#ifdef M68K_16BIT_INT
+    t_min[INT]=t_min(SHORT);
+#else
+    t_min[INT]=t_min(LONG);
+#endif
+    t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+    t_min[MAXINT]=t_min(LLONG);
+    t_max[CHAR]=ul2zum(127L);
+    t_max[SHORT]=ul2zum(32767UL);
+    t_max[LONG]=ul2zum(2147483647UL);
+#ifdef M68K_16BIT_INT
+    t_max[INT]=t_max(SHORT);
+#else
+    t_max[INT]=t_max(LONG);
+#endif
+    t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+    t_max[MAXINT]=t_max(LLONG);
+    tu_max[CHAR]=ul2zum(255UL);
+    tu_max[SHORT]=ul2zum(65535UL);
+    tu_max[LONG]=ul2zum(4294967295UL);
+#ifdef M68K_16BIT_INT
+    tu_max[INT]=t_max(UNSIGNED|SHORT);
+#else
+    tu_max[INT]=t_max(UNSIGNED|LONG);
+#endif
+    tu_max[LLONG]=zumkompl(ul2zum(0UL));
+    tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+#ifdef M68K_16BIT_INT
+    stackalign=2;
+#endif
+
+    if(FLOAT64){
+      sizetab[FLOAT]=sizetab[DOUBLE];
+      align[FLOAT]=malign[DOUBLE];
+    }
+
+    marray[0]="__section(x)=__vattr(\"section(\"#x\")\")";
+    marray[1]="__M68K__";
+
+    if(CPU>=68000&&CPU<69000)
+      sprintf(cpu_macro,"__M%ld=1",CPU);
+    else
+      sprintf(cpu_macro,"__COLDFIRE=1");
+    marray[2]=cpu_macro;
+
+#ifdef M68K_16BIT_INT
+    marray[3]="__INTSIZE=16";
+#else
+    marray[3]="__INTSIZE=32";
+#endif
+
+    marray[4]="__stdargs=__attr(\"__stdargs;\")";
+    marray[5]="__regargs=__attr(\"__regargs;\")";
+    marray[6]="__vbccargs=__attr(\"__vbccargs;\")";
+    marray[7]="__fp0ret=__attr(\"__fp0ret;\")";
+    if(SMALLDATA) 
+      marray[8]="__SMALL_DATA__";
+    else
+      marray[8]="__LARGE_DATA__";
+
+    if(FPU==68881){
+      sprintf(fpu_macro,"__M68881=1");
+      marray[9]=fpu_macro;
+    }else if(FPU>68000&&FPU<69000){
+      sprintf(fpu_macro,"__M68882=1");
+      marray[9]=fpu_macro;
+    }else
+      marray[9]=0;
+    marray[10]=0;
+    target_macros=marray;
+
+    if(AMI_SOFTFLOAT&&!optsize){
+      declare_builtin("_ieeeaddl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-66));
+      declare_builtin("_ieeesubl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-72));
+      declare_builtin("_ieeemull",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-78));
+      declare_builtin("_ieeedivl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-84));
+      declare_builtin("_ieeenegl",FLOAT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-60));
+      declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-66));
+      declare_builtin("_ieeesubd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-72));
+      declare_builtin("_ieeemuld",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-78));
+      declare_builtin("_ieeedivd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-84));
+      declare_builtin("_ieeenegd",DOUBLE,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-60));
+      declare_builtin("_ieees2d",DOUBLE,FLOAT,d0,0,0,1,ami_ieee("DoubTrans",-108));
+      declare_builtin("_ieeed2s",FLOAT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubTrans",-102));
+      declare_builtin("_ieeefltsl",FLOAT,LONG,d0,0,0,1,ami_ieee("SingBas",-36));
+      declare_builtin("_ieeefltsd",DOUBLE,LONG,d0,0,0,1,ami_ieee("DoubBas",-36));
+      declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
+      declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+      declare_builtin("_ieeefixlsl",LONG,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
+      declare_builtin("_ieeefixlsw",SHORT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
+      declare_builtin("_ieeefixlsb",CHAR,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
+      declare_builtin("_ieeefixdsl",LONG,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
+      declare_builtin("_ieeefixdsw",SHORT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
+      declare_builtin("_ieeefixdsb",CHAR,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
+      declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
+      declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,0,0,0,1,0);
+      declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,0,0,0,1,0);
+      declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+      declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,0,0,0,1,0);
+      declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,0,0,0,1,0);
+      declare_builtin("_ieeecmpl",INT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-42));
+      declare_builtin("_ieeecmpd",INT,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-42));
+#if 0
+      declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0);
+#endif
+      declare_builtin("_ieeetstl",INT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-48));
+      declare_builtin("_ieeetstd",INT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-48));
+      declare_builtin("_flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+      declare_builtin("_flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+      declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+      declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+      declare_builtin("_sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+      declare_builtin("_sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+      declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+      declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+    }else{
+      int pd0,pd1,pd0d1;
+      if(VBCCCALL){
+	pd0=d0;pd1=d1;pd0d1=d0d1;
+      }else{
+	pd0=pd1=pd0d1=0;
+      }
+	
+      declare_builtin("_ieeeaddl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+      declare_builtin("_ieeesubl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+      declare_builtin("_ieeemull",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+      declare_builtin("_ieeedivl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+      declare_builtin("_ieeenegl",FLOAT,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+      declare_builtin("_ieeesubd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+      declare_builtin("_ieeemuld",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+      declare_builtin("_ieeedivd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+      declare_builtin("_ieeenegd",DOUBLE,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieees2d",DOUBLE,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeed2s",FLOAT,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefltsl",FLOAT,LONG,pd0,0,0,1,0);
+      declare_builtin("_ieeefltsd",DOUBLE,LONG,pd0,0,0,1,0);
+      declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,pd0,0,0,1,0);
+      declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,pd0,0,0,1,0);
+      declare_builtin("_ieeefixlsl",LONG,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeefixlsw",SHORT,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeefixlsb",CHAR,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeefixdsl",LONG,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefixdsw",SHORT,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefixdsb",CHAR,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_ieeecmpl",INT,FLOAT,pd0,FLOAT,pd1,1,0);
+      declare_builtin("_ieeecmpd",INT,DOUBLE,pd0d1,DOUBLE,0,1,0);
+#if 0
+      declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0);
+      declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0);
+      declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0);
+#endif
+      declare_builtin("_ieeetstl",INT,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_ieeetstd",INT,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_flt32tosint64",LLONG,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_flt64tosint64",LLONG,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,pd0,0,0,1,0);
+      declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,pd0d1,0,0,1,0);
+      declare_builtin("_sint64toflt32",FLOAT,LLONG,pd0d1,0,0,1,0);
+      declare_builtin("_sint64toflt64",DOUBLE,LLONG,pd0d1,0,0,1,0);
+      declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,pd0d1,0,0,1,0);
+      declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,pd0d1,0,0,1,0);
+    }
+    {
+      char *asm;
+      declare_builtin("_divs",LONG,LONG,d0,LONG,d1,1,0);
+      declare_builtin("_divu",LONG,LONG,d0,LONG,d1,1,0);
+#define SMODS "\tjsr\t__divs\n\tmove.l\td1,d0"
+#define SMODU "\tjsr\t__divu\n\tmove.l\td1,d0"
+      asm=mymalloc(strlen(SMODS)+1);
+      strcpy(asm,SMODS);
+      declare_builtin("_mods",LONG,LONG,d0,LONG,d1,1,asm);
+      asm=mymalloc(strlen(SMODU)+1);
+      strcpy(asm,SMODU);
+      declare_builtin("_modu",LONG,LONG,d0,LONG,d1,1,asm);
+    }
+    declare_builtin("_lshint64",LLONG,LLONG,0,INT,0,1,0);
+    declare_builtin("_rshsint64",LLONG,LLONG,0,INT,0,1,0);
+    declare_builtin("_rshuint64",(UNSIGNED|LLONG),(UNSIGNED|LLONG),0,INT,0,1,0);
+
+    return 1;
+}
+
+int freturn(type *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+    long l;int tu=t->flags&NQ;
+    if(t->attr&&ISFLOAT(tu)&&FPU>68000&&strstr(t->attr,"__fp0ret;")) return fp0;
+    if(tu==FLOAT&&FLOAT64) tu+=DOUBLE-FLOAT;
+    if(tu==FLOAT){
+        if(FPU>68000&&!NOFPRETURN)
+            return fp0;
+        else
+            return d0;
+    }
+    if(tu==DOUBLE||tu==LDOUBLE){
+        if(FPU>68000&&!NOFPRETURN){
+            return fp0;
+        }else{
+            if(NOMREGRETURN) return 0;
+#if NEW_RET
+            return d0d1;
+#else
+	    return d0;
+#endif
+        }
+    }
+    if(tu==STRUCT||tu==UNION){
+        if(!NOMREGRETURN){
+            l=zm2l(szof(t));
+#if NEW_RET
+	    if(l==4) return d0;
+	    if(l==8) return d0d1;
+	    /* alte Variante; unschoen */
+	    if(l==12) return d0;
+	    if(l==16) return d0;
+#else
+            if(l==4||l==8||l==12||l==16) return d0;
+#endif
+        }
+        return 0;
+    }
+    if(tu==LLONG)
+      return d0d1;
+    if(zmleq(szof(t),l2zm(4L))) return d0; else return 0;
+}
+int cost_savings(IC *p,int r,obj *o)
+{
+  int c=p->code;
+  if((r==a6||r==d7||r==d6d7||r==fp7)&&!RESERVEREGS) return -1;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(o->flags&VKONST){
+    int t;
+    if(CPU==68040) return 0;
+    t=o->v->ctyp&NQ;
+    if(ISFLOAT(t)) return 2;
+    if(t==CHAR&&r>=a0&&r<=a7) return 0/*INT_MIN*/;
+    if(t==LLONG) return 0;
+    if(cf&&(t<INT)&&p->q2.flags) return 0/*INT_MIN*/;
+    eval_const(&o->v->cobj.val,t);
+    if(zmeqto(vmax,Z0)) return 0;
+    if(o->flags&DREFOBJ) return 2;
+    if((p->code==ASSIGN&&o==&p->q1)||p->code==PUSH||p->code==SETRETURN){
+      if(p->code==PUSH||(p->z.flags&DREFOBJ)||
+	 ((p->z.flags&VAR)&&(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN))){
+	if(r>=d0&&r<=d7)
+	  return 2;
+	else
+	  return 1;
+      }
+      return 0;
+    }
+    if(c==ADDI2P||c==SUBIFP){
+      if(zmleq(vmax,l2zm(32767L))&&zmleq(l2zm(-32768L),vmax)) return 0;
+      if(r>=d0&&r<=d7)
+	return 3;
+      return CPU<68020?1:0;
+    }
+    if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==SUBPFP){
+      if(zmleq(vmax,l2zm(8L))&&zmleq(l2zm(-8L),vmax)) return 0;
+      if(p->flags&EFF_IC) return 0;
+      if(r>=d0&&r<=d7)
+	return 2;
+      else
+	return 1;
+    }
+    if(c==COMPARE){
+      if(r>=d0&&r<=d7)
+	return 2;
+      else
+	return 1;
+    }
+    if(r>=a0&&r<=a7) return INT_MIN;
+    /* TODO: which allocations are useful? */
+    return 0;
+  }
+  if(o->flags&DREFOBJ){
+    if(r>=a0&&r<=a7){
+      return 4;
+    }
+  }
+  if((c==ADDI2P||c==SUBIFP||c==ADDRESS)&&(o==&p->q1||o==&p->z)&&r>=a0&&r<=a7){
+    return 4;
+  }
+  if(r>=a0&&r<=a7){
+    if(o->flags&DREFOBJ) ierror(0);
+    if(c!=GETRETURN&&c!=SETRETURN&&c!=ASSIGN&&c!=PUSH&&c!=TEST&&c!=COMPARE&&c!=CONVERT){
+      if(c==ADDI2P||c==SUBIFP){
+	if(o==&p->q2)
+	  return INT_MIN;
+      }else if(c==SUBPFP){
+	if(o==&p->z)
+	  return INT_MIN;
+      }else{
+	return INT_MIN;
+      }
+    }
+    if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR||ISFLOAT(p->typf)||ISFLOAT(p->typf2)))
+      return INT_MIN;
+  }
+
+  if(c==TEST&&r>=d0&&r<=d7){
+    return 3;
+  }
+  if(o==&p->z&&(p->q1.flags&VKONST)){
+    eval_const(&p->q1.v->cobj.val,p->q1.v->ctyp&NQ);
+    if(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax)&&r>=d0&&r<=d7)
+      return 3;
+  }
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0) return 0;
+  t&=NQ;
+  if(ISFLOAT(t)){
+    if(FPU>68000){
+      if(r>=fp0&&r<=fp7) return(1); else return 0;
+    }else{
+      if(t==FLOAT&&!FLOAT64)
+	return (r>=d0&&r<=d7);
+      else
+	return (r>=25&&r<=28);
+    }
+  }
+  if(t==POINTER&&mode<=0&&r>=d0&&r<=d7) return 1;
+  if(t==POINTER&&r>=1&&r<=8) return 1;
+  if(t>=CHAR&&t<=LONG){
+    if((r>=d0&&r<=d7)||(mode==-1&&t>=SHORT&&r>=1&&r<=8)) return 1;
+  }
+  if(t==LLONG&&r>=25&&r<=28) return 1;
+  return 0;
+}
+
+int dangerous_IC(IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+{
+    int op=o&NQ,tp=t&NQ;
+    /*  All pointers have the same representation.  */
+    if(tp==POINTER&&op==POINTER) return 0;
+    /*  Pointer and int/long as well   */
+    if(const_expr){
+#ifdef M68K_16BIT_INT
+      if(tp==POINTER&&(op==LONG)) return 0;
+      if(op==POINTER&&(tp==LONG)) return 0;
+#else
+      if(tp==POINTER&&(op==INT||op==LONG)) return 0;
+      if(op==POINTER&&(tp==INT||tp==LONG)) return 0;
+#endif
+    }
+    /*  Signed und Unsigned integers with the same size, too.  */
+    if(op==tp) return 0;
+#ifdef M68K_16BIT_INT
+    /*  int==short   */
+    if((tp==INT&&op==SHORT)||(tp==SHORT&&op==INT)) return 0;
+#else
+    /*  int==long   */
+    if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return 0;
+#endif
+    if(FLOAT64&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+    /* long double==double */
+    if((op==DOUBLE||op==LDOUBLE)&&(tp==DOUBLE||tp==LDOUBLE)) return 0;
+    return 1;
+}
+
+void gen_ds(FILE *f,zmax size,type *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  title(f);
+  if(GAS){
+    if(newobj&&section!=SPECIAL)
+      emit(f,"%ld\n",zm2l(size));
+    else
+      emit(f,"\t.space\t%ld\n",zm2l(size));
+    newobj=0;
+  }else{
+    /*if(section!=BSS&&section!=SPECIAL&&newobj){emit(f,bssname);if(f) section=BSS;}*/
+    emit(f,"\tds.b\t%ld\n",zm2l(size));newobj=0;
+  }
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  title(f);
+  if(zm2l(align)>1){
+    if(GAS){
+      emit(f,"\t.align\t4\n");
+    }else{
+      emit(f,"\tcnop\t0,4\n");
+    }
+  }
+}
+void gen_var_head(FILE *f,Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  title(f);
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->tattr&(FAR|CHIP)){
+    if(v->tattr&CHIP){
+      dataname="\tsection\t\"CHIP_DATA\",data,chip\n";
+      bssname="\tsection\t\"CHIP_BSS\",bss,chip\n";
+    }else{
+      dataname="\tsection\t\"DATA\",data\n";
+      bssname="\tsection\t\"BSS\",bss\n";
+    }
+    if(f) section=-1;
+  }else{
+    dataname=m_dataname;
+    bssname=m_bssname;
+  }
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(GAS){
+      if(section!=BSS) emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
+      else emit(f,"\t.comm\t%s%ld,",labprefix,zm2l(v->offset));
+    }else{
+      emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset));
+    }
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    if(GAS){
+      emit(f,"\t.global\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier);
+    }else{
+      emit(f,"\tpublic\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier);
+    }
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+	if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(GAS){
+	if(section!=BSS)
+	  emit(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier);
+	else
+	  emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      }else{
+	emit(f,"\tcnop\t0,4\n%s%s\n",idprefix,v->identifier);
+      }
+      newobj=1;
+    }
+  }
+  if(v->tattr&(FAR|CHIP)) {if(f) section=-1;newobj=0;}
+}
+void gen_dc(FILE *f,int t,const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  char s;
+  title(f);
+  if(!p) ierror(0);
+/*    if(section!=DATA){emit(f,dataname);if(f) section=DATA;}*/
+  if(ISFLOAT(t)||(t&NQ)==LLONG) s='l'; else s=x_t[t&NQ];
+  if(GAS){
+    char *str;
+    if(s=='b') str="\t.byte\t";
+    else if(s=='w') str="\t.short\t";
+    else if(s=='l') str="\t.long\t";
+    else ierror(0);
+    emit(f,"%s",str);
+  }else{
+    emit(f,"\tdc.%c\t",s);
+  }
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;char *s;
+      ip=(unsigned char *)&p->val.vdouble;
+      if(GAS) s="0x"; else s="$";
+      emit(f,"%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	emit(f,",%s%02x%02x%02x%02x",s,ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else if((t&NQ)==LLONG){
+      zumax tmp;
+      eval_const(&p->val,t);
+      tmp=vumax;
+      vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); 
+      gval.vulong=zum2zul(vumax);
+      emitval(f,&gval,UNSIGNED|LONG);
+      emit(f,",");
+      vumax=zumand(tmp,ul2zum(0xffffffff)); 
+      gval.vulong=zum2zul(vumax);
+      emitval(f,&gval,UNSIGNED|LONG);
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    int m,m2,m3;
+    p->tree->o.am=0;
+    m=p->tree->o.flags;
+    p->tree->o.flags&=~VARADR;
+    m2=g_flags[5];
+    g_flags[5]&=~USEDFLAG;
+    m3=use_sd;
+    use_sd=0;
+    emit_obj(f,&p->tree->o,t&NU);
+    p->tree->o.flags=m;
+    g_flags[5]=m2;
+    use_sd=m3;
+  }
+  emit(f,"\n");newobj=0;
+}
+
+static void allocreg(int r)
+{
+  if(reg_pair(r,&rp)){
+    regs[rp.r1]=1;
+    regs[rp.r2]=1;
+  }
+  regs[r]=1;
+}
+
+static void freereg(int r)
+{
+  if(reg_pair(r,&rp)){
+    regs[rp.r1]=0;
+    regs[rp.r2]=0;
+  }
+  regs[r]=0;
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,IC *p,Var *v,zmax offset)
+{
+  int c,t;char fp[2]="\0\0";
+  int act_line=0;char *act_file=0;
+  int shiftisdiv;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  if(!NOPEEPHOLE){
+    /*  Adressierungsarten benutzen */
+    if(!addressing(p)) offset=l2zm(0L);
+  }
+  title(f);
+  if(debug_info){
+    if(HUNKDEBUG){
+      if(!GAS){
+	act_line=1;
+	emit(f,"\tdsource\t\"%s\"\n",filename);
+	emit(f,"\tdebug\t%d\n",act_line);
+      }
+    }
+  }
+  reglabel=++label;freglabel=++label;
+  function_top(f,v,zm2l(offset));
+  cc_set=cc_set_tst=0;
+  stackoffset=notpopped=dontpop=maxpushed=0;
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+  for(;p;pr(f,p),p=p->next){
+    if(debug_info){
+      if(HUNKDEBUG){
+	if(p->file&&p->file!=act_file){
+	  act_file=p->file;
+	  if(!GAS) emit(f,"\tdsource\t\"%s\"\n",act_file);
+	}
+	if(p->line&&p->line!=act_line){
+	  act_line=p->line;
+	  if(!GAS) emit(f,"\tdebug\t%d\n",act_line);
+	}
+      }else{
+	dwarf2_line_info(f,p);
+      }
+    }
+
+    if(FLOAT64){
+      if(p->code==CONVERT)
+	if((q1typ(p)&NQ)==FLOAT) p->typf2+=DOUBLE-FLOAT;
+      if((ztyp(p)&NQ)==FLOAT) p->typf+=DOUBLE-FLOAT;
+    }
+
+    c=p->code;t=p->typf;
+    if(c==NOP) continue;
+    cc_set_tst=cc_set;
+    cc_typ_tst=cc_typ;
+    shiftisdiv=0;
+    if(cc_set_tst&&(DEBUG&512)){emit(f,"; cc_set_tst=");emit_obj(f,cc_set_tst,t);emit(f,"\n");}
+    if(cc_set&&(DEBUG&512)){emit(f,"; cc_set=");emit_obj(f,cc_set,t);emit(f,"\n");}
+    pushedreg&=16;if(c==RESTOREREGS) pushedreg=0;
+    if(DEBUG&256){emit(f,"; "); pric2(f,p);}
+    if(DEBUG&512) emit(f,"; stackoffset=%ld, notpopped=%ld, pushedreg=%d, dontpop=%ld\n",stackoffset,notpopped,pushedreg,dontpop);
+    /*  muessen wir Argumente poppen?   */
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+	emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]);
+	pop(notpopped);notpopped=0;/*cc_set_tst=cc_set=0;*/
+      }
+    }
+    /*  na, ob das hier ok ist..?   */
+    if(c==SUBPFP) c=SUB;
+    if(c==PMULT) c=MULT;
+    if(c==ALLOCREG){
+      allocreg(p->q1.reg);
+      continue;
+    }
+    if(c==FREEREG){
+      freereg(p->q1.reg);
+      continue;
+    }
+    if(c==LABEL){
+      if(debug_info&&HUNKDEBUG) act_line=0;
+      if(GAS){
+	emit(f,"%s%d:\n",labprefix,t);
+      }else{
+	emit(f,"%s%d\n",labprefix,t);
+      }
+      cc_set=0;continue;
+    }
+    if(c==BRA){emit(f,"\t%sbra\t%s%d\n",(GAS?"j":""),labprefix,t);continue;}
+    if(c>=BEQ&&c<BRA){
+      if(GAS){
+	if(stored_cc){emit(f,"\tjne\t%s%d\n",labprefix,t);stored_cc=0;continue;}
+	if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){
+	  emit(f,"\tj%s\t%s%d\n",ubranch[c-BEQ],labprefix,t);
+	}else{
+	  emit(f,"\t%sj%s\t%s%d\n",fp,ename[c]+1,labprefix,t);
+	}
+      }else{
+	if(stored_cc){emit(f,"\tbne\t%s%d\n",labprefix,t);stored_cc=0;continue;}
+	if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){
+	  emit(f,"\tb%s\t%s%d\n",ubranch[c-BEQ],labprefix,t);
+	}else{
+	  emit(f,"\t%s%s\t%s%d\n",fp,ename[c],labprefix,t);
+	}
+      }
+      continue;
+    }
+#if 0
+    if(CPU>=68020&&(c==LSHIFT||c==MULT)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(p->typf)){
+      int l=0;
+      eval_const(&p->q2.val,q2typ(p));
+      if(c==LSHIFT&&zmeqto(vmax,l2zm(1L))) l=2;
+      if(c==LSHIFT&&zmeqto(vmax,l2zm(2L))) l=4;
+      if(c==LSHIFT&&zmeqto(vmax,l2zm(3L))) l=8;
+      if(c==MULT&&zmeqto(vmax,l2zm(2L))) l=2;
+      if(c==MULT&&zmeqto(vmax,l2zm(4L))) l=4;
+      if(c==MULT&&zmeqto(vmax,l2zm(8L))) l=8;
+      if(l!=0){
+	IC *p2=p->next;
+	while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
+	if((p2->code==ADD||p2->code==ADDI2P)&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==p->z.reg&&(p2->typf&NU)==(p->typf&NU)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg>=a0&&p2->q1.reg<=a7&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg>=a0&&p2->z.reg<=a7){
+	  IC *p3=p2->next;
+	  while(p3&&p3->code==FREEREG) if(p3&&p3->q1.reg==p->z.reg) break;
+	  if(p3&&p3->code==FREEREG&&p3->q1.reg==p->z.reg){
+	    int r;
+	    if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7)
+	      r=p->q1.reg;
+	    else{
+	      move(f,&p->q1,0,0,p->z.reg,p->typf);
+	      r=p->z.reg;
+	    }
+	    emit(f,"\tlea\t(%s,%s.%c*%d),%s\n",mregnames[p2->q1.reg],mregnames[r],sizetab[p->typf&NQ]==2?'w':'l',l,mregnames[p2->z.reg]);
+	    p->code=NOP;
+	    p->q1.flags=p->q2.flags=p->z.flags=0;
+	    p2->code=NOP;
+	    p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	    continue;
+	  }
+	}
+      }
+    }
+#endif
+    if(c==COMPARE&&isconst(q2)&&!cf&&(t&NQ)!=LLONG){
+      case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
+      IC *p2;
+      if(ct&&(ct->num>=JUMP_TABLE_LENGTH||(!isreg(q1)&&ct->num>=JUMP_TABLE_LENGTH/2))){
+	int r,defl,tabl=++label,rts=0,i,ar=0;
+	if(ct->next_ic->code==BRA)
+	  defl=ct->next_ic->typf;
+	else
+	  defl=++label;
+	for(r=d0;r<=d7;r++)
+	  if(!regs[r]) break;
+	if(r>d7){
+	  if((!(p->q1.flags&REG))||p->q1.reg!=d0)
+	    r=d0;
+	  else
+	    r=d1;
+	  emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]);
+	  emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[r],mregnames[sp]);
+	  push(8);
+	}else{
+	  regused[r]=1;
+	  BSET(regs_modified,r);
+	}
+	if(!regs[r]||(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+	  for(ar=1;ar<sp;ar++)
+	    if(!regs[ar]) break;
+	  if(ar>=sp){
+	    ar=a0;
+	    if(!regs[r]){
+	      emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]);
+	      push(4);
+	    }
+	    emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[ar],mregnames[sp]);
+	    push(4);
+	  }else{
+	    regused[ar]=1;
+	    BSET(regs_modified,ar);
+	  }
+	}
+	if(regs[r]||(ar&&regs[ar])) defl=++label;
+	if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+	  p->q1.flags&=~DREFOBJ;
+	  move(f,&p->q1,0,0,ar,POINTER);
+	  p->q1.flags|=(REG|DREFOBJ);
+	  p->q1.flags&=~VAR;
+	  p->q1.reg=ar;
+	}
+	if((t&NU)==(UNSIGNED|CHAR))
+	  emit(f,"\tmoveq\t#0,%s\n",mregnames[r]);
+	move(f,&p->q1,0,0,r,t);
+	if((t&NU)==CHAR){
+	  emit(f,"\text.w\t%s\n",mregnames[r]);
+	  t=SHORT;
+	}
+	if((t&NU)==(UNSIGNED|CHAR))
+	  t=(UNSIGNED|SHORT);
+	if(((t&UNSIGNED)&&!zumeqto(ct->min.vumax,ul2zum(0UL)))||
+	   (!(t&UNSIGNED)&&!zmeqto(ct->min.vmax,l2zm(0L)))){
+	  emit(f,"\tsub.%c\t#",x_t[t&NQ]);
+	  if(t&UNSIGNED)
+	    emitzum(f,ct->min.vumax);
+	  else
+	    emitzm(f,ct->min.vmax);
+	  emit(f,",%s\n",mregnames[r]);
+	}
+	emit(f,"\tcmp.%c\t#",x_t[t&NQ]);
+	emitzum(f,ct->diff);
+	emit(f,",%s\n",mregnames[r]);
+	if(regs[r]||regs[ar])
+	  emit(f,"\tbhi\t%s%d\n",labprefix,++label);
+	else
+	  emit(f,"\tbhi\t%s%d\n",labprefix,defl);
+	if(CPU<68020)
+	  emit(f,"\tlsl.%c\t#2,%s\n",x_t[t&NQ],mregnames[r]);
+	for(i=MAXR;i>=1;i--)
+	  if(regs[i]&4) rts=1;
+	if(regs[r]||regs[ar]){
+	  int off;
+	  if(regs[r]) off=4; else off=0;
+	  if(ar&&regs[ar]) off+=4;
+	  if(CPU>=68020)
+	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]);
+	  else
+	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]);
+	  if(ar&&regs[ar]){
+	    emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]);
+	    pop(4);
+	  }	      
+	  if(regs[r]){
+	    emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]);
+	    pop(4);
+	  }
+	  emit(f,"\trts\n");
+	  pop(4);
+	}else{
+	  if(CPU>=68020)
+	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]);
+	  else
+	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]);
+	  emit(f,"\tjmp\t(%s)\n",mregnames[ar]);
+	}
+	if(GAS){
+	  emit(f,"\t.align\t2\n");
+	  emit(f,"%s%d:\n",labprefix,tabl);
+	  emit_jump_table(f,ct,"\t.long\t","l",defl);
+	}else{
+	  emit(f,"\tcnop\t0,4\n");
+	  emit(f,"%s%d\n",labprefix,tabl);
+	  emit_jump_table(f,ct,"\tdc.l\t","l",defl);
+	}
+	if(ct->next_ic->code!=BRA||regs[r]||(ar&&regs[ar])){
+	  if(regs[r]||(ar&&regs[ar])){
+	    emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
+	    if(ar&&regs[ar])
+	      emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]);
+	    if(regs[r])
+	      emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]);
+	    emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]);
+	  }
+	  emit(f,"%s%d%s\n",labprefix,defl,GAS?":":"");
+	  p2=ct->next_ic->prev;
+	}else
+	  p2=ct->next_ic;
+	if(p->prev) p=p->prev;
+	do{
+	  p=p->next;
+	  if(p->code==ALLOCREG)
+	    allocreg(p->q1.reg);
+	  if(p->code==FREEREG)
+	    freereg(p->q1.reg);
+	}while(p!=p2);
+	continue;
+      }
+    }
+    if(p->q1.am){
+      if(!regs[p->q1.am->basereg]){
+	pric2(stdout,p);printf("%s\n",mregnames[p->q1.am->basereg]); ierror(0);
+      }
+      if(p->q1.am->dreg&&!regs[p->q1.am->dreg&127]){
+	printf("Register %s:\n",mregnames[p->q1.am->dreg&127]);
+	ierror(0);
+      }
+    }
+    if(p->q2.am){
+      if(!regs[p->q2.am->basereg]) {pric2(stdout,p);ierror(0);}
+      if(p->q2.am->dreg&&!regs[p->q2.am->dreg&127]) {printf("Register %s:\n",mregnames[p->q2.am->dreg&127]);ierror(0);}
+    }
+    if(p->z.am){
+      if(!regs[p->z.am->basereg]) {pric2(stdout,p);printf("am=%p b=%s,i=%s,o=%ld,s=%d\n",(void*)p->z.am,mregnames[p->z.am->basereg],mregnames[p->z.am->dreg&127],p->z.am->dist,p->z.am->skal);ierror(0);}
+      if(p->z.am->dreg&&!regs[p->z.am->dreg&127]) {printf("Register %s:\n",mregnames[p->z.am->dreg&127]);ierror(0);}
+    }
+    if((p->q1.flags&REG)&&!regs[p->q1.reg]&&p->code!=MOVEFROMREG&&(!reg_pair(p->q1.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){
+      printf("Register %s:\n",mregnames[p->q1.reg]);pric2(stdout,p);terror("illegal use of register");}
+    if((p->q2.flags&REG)&&!regs[p->q2.reg]&&(!reg_pair(p->q2.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->q2.reg]);pric2(stdout,p);terror("illegal use of register");}
+    if((p->z.flags&REG)&&!regs[p->z.reg]&&p->code!=MOVETOREG&&(!reg_pair(p->z.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->z.reg]);if(reg_pair(p->z.reg,&rp)) printf("%s=%d %s=%d\n",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]);pric2(stdout,p);terror("illegal use of register");}
+    /*        if((p->q2.flags&REG)&&(p->z.flags&REG)&&p->q2.reg==p->z.reg){pric2(stdout,p);ierror(0);}*/
+    /*if((p->q2.flags&VAR)&&(p->z.flags&VAR)&&p->q2.v==p->z.v&&compare_objects(&p->q2,&p->z)){pric2(stdout,p);ierror(0);}*/
+    /*  COMPARE #0 durch TEST ersetzen (erlaubt, da tst alle Flags setzt)   */
+    if(c==COMPARE&&isconst(q2)){
+      eval_const(&p->q2.val,t);
+      if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+	c=p->code=TEST;p->q2.flags=0;
+      }
+    }
+    if(c==COMPARE&&isconst(q1)){
+      eval_const(&p->q1.val,t);
+      if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+	IC *bp=p->next;int bc;
+	c=p->code=TEST;p->q1=p->q2;p->q2.flags=0;p->q2.am=0;
+	/*  Nachfolgenden Branch umdrehen   */
+	while(bp&&bp->code==FREEREG) bp=bp->next;
+	bc=bp->code;
+	if(!bp||bc<BEQ||bc>BGT) ierror(0);
+	if(bc==BLT) bp->code=BGT;
+	if(bc==BGT) bp->code=BLT;
+	if(bc==BLE) bp->code=BGE;
+	if(bc==BGE) bp->code=BLE;
+      }
+    }
+    /*  gesetzte ConditionCodes merken  */
+    if(p->z.flags&&(!isreg(z)||p->z.reg>=d0)&&(c!=CONVERT||!ISFLOAT(p->typf2))&&((!ISFLOAT(t))||FPU>68000)){
+      cc_set=&p->z;cc_typ=p->typf;
+    }else{
+      cc_set=0;
+    }
+    if(c==LEA){
+      if(!isreg(z)||p->z.reg>8) ierror(0);
+      emit(f,"\tlea\t");emit_obj(f,&p->q1,t);
+      emit(f,",%s\n",mregnames[p->z.reg]);
+      continue;
+    }
+    if(c==PEA){
+      emit(f,"\tpea\t");emit_obj(f,&p->q1,t);emit(f,"\n");
+      push(zm2l(p->q2.val.vmax));
+      dontpop+=zm2l(p->q2.val.vmax);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      if(p->q1.reg<fp0)
+	emit(f,"\tmove.l\t%s,",mregnames[p->q1.reg]);
+      else if(p->q1.reg<25)
+	emit(f,"\tfmove.x\t%s,",mregnames[p->q1.reg]);
+      else
+	emit(f,"\tmovem.l\t%s,",mregnames[p->q1.reg]);
+      emit_obj(f,&p->z,t);emit(f,"\n");
+      continue;
+    }
+    if(c==MOVETOREG){
+      if(p->z.reg<fp0)
+	emit(f,"\tmove.l\t");
+      else if(p->z.reg<25)
+	emit(f,"\tfmove.x\t");
+      else
+	emit(f,"\tmovem.l\t");
+      emit_obj(f,&p->q1,t);emit(f,",%s\n",mregnames[p->z.reg]);
+      continue;
+    }
+    if(NOPEEPHOLE){
+      if(p->q1.am||p->q2.am||p->z.am){
+	ierror(0);
+	p->q1.am=p->q2.am=p->z.am=0;
+      }
+    }
+    p=do_refs(f,p);
+    if((p->q1.flags&&(q1typ(p)&NQ)==LLONG)||(p->q2.flags&&(q2typ(p)&NQ)==LLONG&&p->code!=LSHIFT&&p->code!=RSHIFT)||(p->z.flags&&(ztyp(p)&NQ)==LLONG)){
+      if(handle_llong(f,p)){
+	*fp=0;
+	continue;
+      }
+    }
+    if(NOPEEPHOLE){
+      if(p->q1.am||p->q2.am||p->z.am){
+	ierror(0);
+	p->q1.am=p->q2.am=p->z.am=0;
+      }
+    }
+#ifdef M68K_16BIT_INT
+    if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==POINTER)){
+      p->code=c=ASSIGN;
+      p->q2.val.vmax=sizetab[LONG];
+    }                 
+#else
+    if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==INT||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==INT||(p->typf2&NQ)==POINTER)){
+      p->code=c=ASSIGN;
+      p->q2.val.vmax=sizetab[LONG];
+    }                 
+#endif
+    if(c==CONVERT){
+      int to;
+      if((t&NQ)==POINTER) t=(UNSIGNED|LONG);
+      if((t&NQ)==LDOUBLE) t=DOUBLE;
+      to=p->typf2&NU;
+      if(to==POINTER) to=UNSIGNED|LONG;
+      if(to==LDOUBLE) to=DOUBLE;
+#ifdef M68K_16BIT_INT
+      if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT)||to==(UNSIGNED|INT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ))
+	cc_set=0;
+#else
+      if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ))
+	cc_set=0;
+#endif
+      if(ISFLOAT(t)||ISFLOAT(to)){
+	if(FPU>68000){
+	  int zreg=0,freg=0;
+	  if(ISFLOAT(t)&&ISFLOAT(to)){
+	    if(isreg(q1)&&isreg(z)){
+	      if(p->q1.reg!=p->z.reg)
+		emit(f,"\tfmove.x\t%s,%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]);
+	      continue;
+	    }
+	  }
+	  if(isreg(z)&&p->z.reg>=fp0)
+	    zreg=p->z.reg;
+	  if(isreg(q1)&&p->q1.reg>=fp0){
+	    if(!zreg&&(t&UNSIGNED)&&!ISHWORD(t))
+	      zreg=p->q1.reg; 
+	    else 
+	      zreg=freg=get_reg(f,2,p,1);}
+	  if(!zreg) zreg=freg=get_reg(f,2,p,0);
+	  if((to&UNSIGNED)&&x_t[to&NQ]!='l'){
+	    int dreg=get_reg(f,1,p,0);
+	    emit(f,"\tmoveq\t#0,%s\n",mregnames[dreg]);
+	    move(f,&p->q1,0,0,dreg,to);
+	    move(f,0,dreg,0,zreg,LONG);
+	  }else{
+	    if(!isreg(q1)||p->q1.reg!=zreg)
+	      move(f,&p->q1,0,0,zreg,to);
+	  }
+	  if(!ISFLOAT(t)){
+	    if((t&UNSIGNED)&&!ISHWORD(t)){
+	      char *s;
+	      int dreg1,dreg2;
+	      int l1=++label,l2=++label;
+	      if(GAS) s="0x"; else s="$";
+	      if(isreg(z)) 
+		dreg1=p->z.reg;
+	      else
+		dreg1=get_reg(f,1,p,0);
+	      if(FPU==68040)
+		dreg2=get_reg(f,1,p,0);
+	      if(!freg){
+		if(!(isreg(q1)&&p->next&&p->next->code==FREEREG&&p->next->q1.reg==zreg)){
+		  freg=get_reg(f,2,p,1);
+		  emit(f,"\tfmove.x\t%s,%s\n",mregnames[zreg],mregnames[freg]);
+		  zreg=freg;
+		}		
+	      }
+	      emit(f,"\tfcmp.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]);
+	      emit(f,"\tfbge\t%s%d\n",labprefix,l1);
+	      if(FPU==68040){
+		emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
+		emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
+		emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
+		emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
+		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
+	      }else{
+		emit(f,"\tfintrz\t%s\n",mregnames[zreg]);
+	      }
+	      emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
+	      emit(f,"\tbra\t%s%d\n",labprefix,l2);
+	      emit(f,"%s%d:\n",labprefix,l1);
+	      emit(f,"\tfsub.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]);
+	      if(FPU==68040){
+		emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
+		emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
+		emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
+		emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
+		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
+	      }else{
+		emit(f,"\tfintrz\t%s\n",mregnames[zreg]);
+	      }
+	      emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
+	      emit(f,"\tbchg\t#31,%s\n",mregnames[dreg1]);
+	      emit(f,"%s%d:\n",labprefix,l2);
+	      if(FPU==68040)
+		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix);
+	      move(f,0,dreg1,&p->z,0,t);
+	      continue;
+	    }	      
+	    /*  nach integer, d.h. Kommastellen abschneiden */
+	    if(FPU==68040/*||FPU==68060*/){
+	      /*  bei 040 emuliert    */
+	      int dreg1,dreg2;
+	      if(!NOINTZ){
+		if(isreg(z))
+		  dreg1=p->z.reg;
+		else
+		  dreg1=get_reg(f,1,p,0);
+		dreg2=get_reg(f,1,p,0);
+		emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
+		emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
+		emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
+		emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
+		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
+	      }else{
+		dreg1=get_reg(f,1,p,0);
+	      }
+	      if((t&UNSIGNED)&&ISHWORD(t)){
+		emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
+		emit(f,"\tmove.%c\t%s,",x_t[t&NQ],mregnames[dreg1]);
+	      }else{
+		emit(f,"\tfmove.%c\t%s,",x_t[t&NQ],mregnames[zreg]);
+	      }
+	      emit_obj(f,&p->z,t);emit(f,"\n");
+	      if(!NOINTZ)
+		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix);
+	      continue;
+	    }else{
+	      if(!NOINTZ){
+		if(!isreg(q1)||p->q1.reg!=zreg){
+		  emit(f,"\tfintrz.x\t%s\n",mregnames[zreg]);
+		}else{
+		  int nreg=get_reg(f,2,p,1);
+		  emit(f,"\tfintrz.x\t%s,%s\n",mregnames[zreg],mregnames[nreg]);
+		  zreg=nreg;
+		}
+	      }
+	      if((t&UNSIGNED)&&ISHWORD(t)){
+		int r;
+		if(isreg(z)) r=p->z.reg; else r=get_reg(f,1,p,0);
+		move(f,0,zreg,0,r,LONG);
+		move(f,0,r,&p->z,0,t);
+	      }else{
+		move(f,0,zreg,&p->z,0,t);
+	      }
+	      continue;
+	    }
+	  }
+	  if((to&UNSIGNED)&&x_t[to&NQ]=='l'){
+	    int nlabel;
+	    emit(f,"\ttst.%c\t",x_t[to&NQ]);
+	    emit_obj(f,&p->q1,to);emit(f,"\n");
+	    nlabel=++label;
+	    emit(f,"\tbge.s\t%s%d\n",labprefix,nlabel);
+	    emit(f,"\tfadd.d\t#4294967296,%s\n",mregnames[zreg]);
+	    emit(f,"%s%d:\n",labprefix,nlabel);
+	  }
+	  if(!(p->z.reg)||p->z.reg!=zreg){
+	    move(f,0,zreg,&p->z,0,t);
+	  }
+	}else{
+	  cc_set=0;
+	  if((to&NQ)==(t&NQ)){
+	    assign(f,p,&p->q1,&p->z,ASSIGN,sizetab[to&NQ],t);
+	    continue;
+	  }
+	  if((to&NQ)==FLOAT&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)){
+	    if(!OLD_SOFTFLOAT)
+	      ierror(0);
+	    saveregs(f,p);
+	    assign(f,p,&p->q1,0,PUSH,msizetab[FLOAT],FLOAT);
+	    scratch_modified();
+	    if(GAS){
+	      emit(f,"\t.global\t__ieees2d\n\tjbsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
+	    }else{
+	      emit(f,"\tpublic\t__ieees2d\n\tjsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
+	    }
+	    pop(4);
+	    restoreregsa(f,p);
+	    stored0d1(f,&p->z,t);
+	    restoreregsd(f,p);
+	    continue;
+	  }
+	  if(((to&NQ)==DOUBLE||(to&NQ)==LDOUBLE)&&(t&NQ)==FLOAT){
+	    if(!OLD_SOFTFLOAT) ierror(0);
+	    saveregs(f,p);
+	    assign(f,p,&p->q1,0,PUSH,msizetab[DOUBLE],DOUBLE);
+	    scratch_modified();
+	    if(GAS){
+	      emit(f,"\t.global\t__ieeed2s\n\tjbsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
+	    }else{
+	      emit(f,"\tpublic\t__ieeed2s\n\tjsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
+	    }
+	    pop(8);
+	    restoreregsa(f,p);
+	    move(f,0,d0,&p->z,0,t);
+	    restoreregsd(f,p);
+	    continue;
+	  }
+	  if(ISFLOAT(to)){
+	    int uns;
+	    if(!OLD_SOFTFLOAT) ierror(0);
+	    saveregs(f,p);
+	    if(t&UNSIGNED) uns='u'; else uns='s';
+	    assign(f,p,&p->q1,0,PUSH,sizetab[to&NQ],to);
+	    scratch_modified();
+	    if(GAS){
+	      emit(f,"\t.global\t__ieeefix%c%c\n\tjbsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]);
+	    }else{
+	      emit(f,"\tpublic\t__ieeefix%c%c\n\tjsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]);
+	    }
+	    pop(sizetab[to&NQ]);
+	    restoreregsa(f,p);
+	    move(f,0,d0,&p->z,0,t);
+	    restoreregsd(f,p);
+	    continue;
+	  }else{
+	    int uns,xt=x_t[to&NQ];
+	    if(!OLD_SOFTFLOAT) ierror(0);
+	    saveregs(f,p);
+	    if(to&UNSIGNED) uns='u'; else uns='s';
+	    if(xt!='l'){
+	      emit(f,"\tsubq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
+	      push(4);
+	    }
+	    emit(f,"\tmove.%c\t",xt);
+	    emit_obj(f,&p->q1,to);
+	    if(xt!='l')
+	      emit(f,",(%s)\n",mregnames[sp]); 
+	    else{
+	      emit(f,",-(%s)\n",mregnames[sp]);
+	      push(4);
+	    }
+	    scratch_modified();
+	    if(GAS){
+	      emit(f,"\t.global\t__ieeeflt%c%c%c\n\tjbsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]);
+	    }else{
+	      emit(f,"\tpublic\t__ieeeflt%c%c%c\n\tjsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]);
+	    }
+	    pop(4);
+	    restoreregsa(f,p);
+	    if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)
+	      stored0d1(f,&p->z,t);
+	    else
+	      move(f,0,d0,&p->z,0,t);
+	    restoreregsd(f,p);
+	    continue;
+	  }
+	}
+	continue;
+      }
+      if((to&NQ)<(t&NQ)){
+	int zreg;
+	if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7){
+	  zreg=p->z.reg;
+	}else{
+	  zreg=get_reg(f,1,p,0);
+	}
+	if(sizetab[t&NQ]!=sizetab[LONG]||sizetab[to&NQ]!=sizetab[LONG]){
+	  /*  aufpassen, falls unsigned und Quelle==Ziel  */
+	  if((to&UNSIGNED)&&isreg(q1)&&zreg==p->q1.reg){
+	    unsigned long l;
+	    if((to&NQ)==CHAR) l=0xff; else l=0xffff;
+	    emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]);
+	    continue;
+	  }
+	  if((to&UNSIGNED)&&p->q1.am&&(zreg==p->q1.am->basereg||zreg==(p->q1.am->dreg&127))){
+	    /*  aufpassen, falls unsigned und Ziel im am  */
+	    unsigned long l;
+	    if((to&NQ)==CHAR) l=0xff; else l=0xffff;
+	    move(f,&p->q1,0,0,zreg,to);
+	    emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]);
+	  }else{
+	    if(to&UNSIGNED)
+	      emit(f,"\tmoveq\t#0,%s\n",mregnames[zreg]);
+	    move(f,&p->q1,0,0,zreg,to);
+	  }
+	  if(!(to&UNSIGNED)){
+#ifdef M68K_16BIT_INT
+	    if((to&NQ)==CHAR&&((t&NQ)==SHORT||(t&NQ)==INT)) emit(f,"\text.w\t%s\n",mregnames[zreg]);
+	    if(((to&NQ)==SHORT||(to&NQ)==INT)&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]);
+#else
+	    if((to&NQ)==CHAR&&(t&NQ)==SHORT) emit(f,"\text.w\t%s\n",mregnames[zreg]);
+	    if((to&NQ)==SHORT&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]);
+#endif
+	    if((to&NQ)==CHAR&&msizetab[t&NQ]==4){
+	      if(cf||CPU>=68020)
+		emit(f,"\textb.l\t%s\n",mregnames[zreg]);
+	      else
+		emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[zreg],mregnames[zreg]);
+	    }
+	  }
+	}
+	if(!isreg(z)||p->z.reg!=zreg){
+	  move(f,0,zreg,&p->z,0,t);
+	}
+      }else{
+	long diff;int m;
+	m=0;
+	if(p->q1.flags&REG){
+	  p->q1.val.vmax=l2zm(0L);
+	  p->q1.flags|=D16OFF;m=1;
+	}
+	diff=msizetab[to&NQ]-msizetab[t&NQ];
+	vmax=l2zm(diff);
+	p->q1.val.vmax=zmadd(p->q1.val.vmax,vmax);
+	move(f,&p->q1,0,&p->z,0,t);
+	vmax=l2zm(diff);
+	p->q1.val.vmax=zmsub(p->q1.val.vmax,vmax);
+	if(m) p->q1.flags&=~D16OFF;
+	if(compare_objects(&p->q1,&p->z))
+	  cc_set=0;
+      }
+      continue;
+    }
+    if(ISFLOAT(t)&&FPU>68000) *fp='f'; else *fp=0;
+    if(c==MINUS||c==KOMPLEMENT){
+      int zreg;
+      if(ISFLOAT(t)){
+	if(FPU>68000){
+	  if(isreg(z)) zreg=p->z.reg; else zreg=get_reg(f,2,p,1);
+	  emit(f,"\tfneg.");
+	  if(isreg(q1)) emit(f,"x\t%s",mregnames[p->q1.reg]);
+	  else    {emit(f,"%c\t",x_t[t&NQ]);emit_obj(f,&p->q1,t);}
+	  emit(f,",%s\n",mregnames[zreg]);
+	  if(!isreg(z)||p->z.reg!=zreg){
+	    move(f,0,zreg,&p->z,0,t);
+	  }
+	  continue;
+	}else{
+	  if(!OLD_SOFTFLOAT) ierror(0);
+	  saveregs(f,p);
+	  assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+	  scratch_modified();
+	  if(GAS){
+	    emit(f,"\t.global\t__ieeeneg%c\n\tjbsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+	  }else{
+	    emit(f,"\tpublic\t__ieeeneg%c\n\tjsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+	  }
+	  pop(msizetab[t&NQ]);
+	  restoreregsa(f,p);
+	  if((t&NQ)!=FLOAT)
+	    stored0d1(f,&p->z,t);
+	  else
+	    move(f,0,d0,&p->z,0,t);
+	  restoreregsd(f,p);
+	  continue;
+	}
+      }
+      if(!cf&&compare_objects(&p->q1,&p->z)){
+	emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]);
+	emit_obj(f,&p->q1,t);emit(f,"\n");
+	continue;
+      }
+      if(isreg(z)&&p->z.reg>=d0/*&&p->z.reg<=d7*/)
+	zreg=p->z.reg; else zreg=get_reg(f,1,p,1);
+      if(!isreg(q1)||p->q1.reg!=zreg){
+	move(f,&p->q1,0,0,zreg,t);
+      }
+      emit(f,"\t%s.%c\t%s\n",ename[c],x_t[t&NQ],mregnames[zreg]);
+      if(!isreg(z)||p->z.reg!=zreg){
+	move(f,0,zreg,&p->z,0,t);
+      }
+      continue;
+    }
+    if(c==SETRETURN){
+      /*  Returnwert setzen - q2.val.vmax==size, z.reg==Returnregister */
+      if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&p->z.reg==d0){
+	BSET(regs_modified,d0);BSET(regs_modified,10);
+	if(isconst(q1)){
+	  unsigned char *ip=(unsigned char *)&p->q1.val.vdouble;
+	  char *s;
+	  if(GAS) s="0x"; else s="$";
+	  emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[0],ip[1],ip[2],ip[3],mregnames[d0]);
+	  emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[d1]);
+	  continue;
+	}
+	if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){
+	  emit(f,"\tfmove.d\t%s,-(%s)\n\tmovem.l\t(%s)+,%s\n",mregnames[p->q1.reg],mregnames[sp],mregnames[sp],mregnames[d0d1]);
+	}else{
+	  loadd0d1(f,&p->q1,t);
+	}
+	continue;
+      }
+      if((ISSTRUCT(t)||ISUNION(t))&&p->z.reg==d0){
+	long l=zm2l(p->q2.val.vmax);
+	emit(f,"\tmovem.l\t");emit_obj(f,&p->q1,t);
+	emit(f,",%s",mregnames[d0]);BSET(regs_modified,d0);
+	if(l>=8) {emit(f,"/%s",mregnames[d1]);BSET(regs_modified,d1);}
+	if(l>=12) {emit(f,"/%s",mregnames[a0]);BSET(regs_modified,a0);}
+	if(l>=16) {emit(f,"/%s",mregnames[a1]);BSET(regs_modified,a1);}
+	emit(f,"\n");
+	continue;
+      }
+      /*  Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig    */
+      if(p->z.reg){
+	move(f,&p->q1,0,0,p->z.reg,p->typf);
+	BSET(regs_modified,p->z.reg);
+	if(v->tattr&AMIINTERRUPT){
+	  /* if necessary, set condition-codes */
+	  if(p->z.reg!=d0) ierror(0);
+	  if(isreg(q1)&&p->q1.reg==d0)
+	    emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[d0]);
+	}
+      }
+      continue;
+    }
+    if(c==GETRETURN){
+      /*  Returnwert holen - q2.val.vmax==size, q1.reg==Returnregister     */
+      if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&(p->q1.reg==d0||p->q1.reg==d0d1)){
+	if(isreg(z)&&p->z.reg>=fp0&&p->z.reg<=fp7){
+	  emit(f,"\tmovem.l\t%s,-(%s)\n\tfmove.d\t(%s)+,%s\n",mregnames[d0d1],mregnames[sp],mregnames[sp],mregnames[p->z.reg]);
+	}else{
+	  stored0d1(f,&p->z,t);
+	}
+	continue;
+      }
+      if((ISSTRUCT(t)||ISUNION(t))&&p->q1.reg==d0){
+	long l=zm2l(p->q2.val.vmax);
+	emit(f,"\tmovem.l\t");
+	emit(f,"%s",mregnames[d0]);
+	if(l>=8) emit(f,"/%s",mregnames[d1]);
+	if(l>=12) emit(f,"/%s",mregnames[a0]);
+	if(l>=16) emit(f,"/%s",mregnames[a1]);
+	emit(f,",");emit_obj(f,&p->z,t);emit(f,"\n");
+	continue;
+      }
+
+      /*  Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig    */
+      cc_set=0;
+      if(p->q1.reg){
+	move(f,0,p->q1.reg,&p->z,0,p->typf);
+	if(!(p->z.flags&REG)||(p->z.reg!=p->q1.reg&&p->z.reg>=d0)){ cc_set=&p->z;cc_typ=p->typf;}
+      }
+      continue;
+    }
+    if(c==CALL){
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	int sr=(USEFRAMEPOINTER||vlas)?fbp:sp;
+	long va_off=0;
+	if(USEFRAMEPOINTER||vlas){
+	  emit(f,"\tmove.l\t%s,%s\n",mregnames[fbp],mregnames[d0]);
+	  emit(f,"\tadd.l\t#%ld,%s\n",(long)(8+zm2l(va_offset(v)))+(PROFILER?16:0),mregnames[d0]);
+	}else{
+	  emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[d0]);
+	  emit(f,"\tadd.l\t#%s%d+%ld,%s\n",labprefix,offlabel,(long)(4+zm2l(va_offset(v)))+loff+(PROFILER?16:0),mregnames[d0]);
+	}
+	BSET(regs_modified,d0);
+	continue;
+      }
+      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
+	  callee_push(zum2ul(p->q1.v->fi->stack1));
+	else
+	  stack_valid=0;
+      }else{
+	if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+	  if(1/*CPU<68020*/){
+	    emit(f,"\tpea\t%s%d(pc)\n",labprefix,++label);
+	    emit(f,"\tmove.l\t");
+	  }else
+	    emit(f,"\t%s\t([",GAS?"jbsr":"jsr");
+	  p->q1.flags&=~DREFOBJ;
+	  emit_obj(f,&p->q1,POINTER);
+	  p->q1.flags|=DREFOBJ;
+	  if(1/*CPU<68020*/){
+	    emit(f,",-(%s)\n",mregnames[sp]);
+	    emit(f,"\trts\n");
+	    emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
+	  }else
+	    emit(f,"])\n");
+	}else{
+	  if(GAS){
+	    emit(f,"\tjbsr\t");
+	  }else{
+	    emit(f,"\tjsr\t");
+	  }
+	  /*  Wenn geta4() aufgerufen wurde, merken.  */
+	  if(use_sd&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"geta4")&&p->q1.v->storage_class==EXTERN)
+	    geta4=1;
+	  if((p->q1.flags&(DREFOBJ|REG|KONST))==DREFOBJ) ierror(0);
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+	push(4);
+	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
+	  callee_push(zum2ul(p->q1.v->fi->stack1));
+	else
+	  stack_valid=0;
+	pop(4);
+      }
+      if(debug_info&&HUNKDEBUG) act_line=0;
+      if(!zmeqto(p->q2.val.vmax,l2zm(0L))){
+	notpopped+=zm2l(p->q2.val.vmax);
+	dontpop-=zm2l(p->q2.val.vmax);
+	if(!NODELAYEDPOP&&!(pushedreg&30)&&!vlas&&stackoffset==-notpopped){
+	  /*  Entfernen der Parameter verzoegern  */
+	}else{
+	  if(debug_info&&HUNKDEBUG&&!GAS){ act_line=p->line; emit(f,"\tdebug\t%d\n",act_line);}
+	  emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[zm2l(p->q2.val.vmax)<=8],strshort[zm2l(p->q2.val.vmax)<32768],zm2l(p->q2.val.vmax),mregnames[sp]);
+	  pop(zm2l(p->q2.val.vmax));
+	  notpopped-=zm2l(p->q2.val.vmax);
+	}
+      }
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+	int i;
+	for(i=1;i<=MAXR;i++){
+	  if(regscratch[i])
+	    if(i<fp0||i>fp7||FPU>68000) 
+	      BSET(regs_modified,i);
+	}
+      }
+      continue;
+    }
+    if(c==TEST){
+      /*  ConditionCodes schon gesetzt?   */
+      cc_set=&p->q1;cc_typ=t;
+      comptyp=t;
+      if(cc_set_tst&&t==cc_typ_tst){
+	IC *branch;
+	if(t&UNSIGNED){
+	  branch=p->next;
+	  while(branch&&(branch->code<BEQ||branch->code>BGT))
+	    branch=branch->next;
+	  if(!branch) continue;
+	  if(branch->code==BLE) branch->code=BEQ;
+	  if(branch->code==BGT) branch->code=BNE;
+	  if(branch->code==BGE) {branch->code=BRA;continue;}
+	  if(branch->code==BLT) {branch->code=NOP;continue;}
+	}
+	if(compare_objects(&p->q1,cc_set_tst)&&p->q1.am==cc_set_tst->am&&zmeqto(p->q1.val.vmax,cc_set_tst->val.vmax)){
+	  if(DEBUG&512){emit(f,"; tst eliminated: cc=");emit_obj(f,cc_set_tst,t);
+	  emit(f,", q1=");emit_obj(f,&p->q1,t);emit(f,"\n");}
+	  continue;
+	}
+      }
+      if(CPU<68020&&isreg(q1)&&p->q1.reg>=1&&p->q1.reg<=8){
+	/*  tst ax gibt es nicht bei <68000 :-( */
+	if(regavailable(1)){
+	  emit(f,"\tmove.%c\t%s,%s\n",x_t[t&NQ],mregnames[p->q1.reg],mregnames[get_reg(f,1,p,0)]);
+	}else{
+	  emit(f,"\tcmp.%c\t#0,%s\n",cf?'l':'w',mregnames[p->q1.reg]);
+	}
+	continue;
+      }
+      if(ISFLOAT(t)&&FPU<=68000){
+	/*  nicht sehr schoen   */
+	int result=get_reg(f,1,p,0);
+	if(!OLD_SOFTFLOAT) ierror(0);
+	saveregs(f,p);
+	assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+	scratch_modified();
+	if(GAS){
+	  emit(f,"\t.global\t__ieeetst%c\n\tjbsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+	}else{
+	  emit(f,"\tpublic\t__ieeetst%c\n\tjsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+	}
+	pop(msizetab[t&NQ]);
+	restoreregsa(f,p);
+	if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]);
+	emit(f,"\ttst.l\t%s\n",mregnames[result]);
+	restoreregsd(f,p);
+	continue;
+      }
+      if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){
+	emit(f,"\tftst.x\t%s\n",mregnames[p->q1.reg]);
+      }else if(p->q1.flags&(VARADR|KONST)){
+	int r=get_reg(f,1,p,0);
+	emit(f,"\tmove.%c\t",x_t[t&NQ]);
+	emit_obj(f,&p->q1,t);
+	emit(f,",%s\n",mregnames[r]);
+      }else{
+	emit(f,"\t%stst.%c\t",fp,x_t[t&NQ]);emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(c==ASSIGN&&compare_objects(&p->q1,&p->z)) cc_set=0;
+      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+      assign(f,p,&p->q1,&p->z,c,zm2l(p->q2.val.vmax),t);
+      continue;
+    }
+    if(c==ADDRESS){
+      int zreg;
+      if(isreg(z)&&p->z.reg>=1&&p->z.reg<=8)
+	zreg=p->z.reg; else zreg=get_reg(f,0,p,0);
+      emit(f,"\tlea\t");emit_obj(f,&p->q1,t);
+      emit(f,",%s\n",mregnames[zreg]);
+      if(!isreg(z)||p->z.reg!=zreg){
+	move(f,0,zreg,&p->z,0,POINTER);
+      }
+      continue;
+    }
+    if(c==COMPARE){
+      int zreg;
+      comptyp=t;
+      if(isconst(q1)||isreg(q2)){
+	/*  evtl. Argumente von cmp und nachfolgendes bcc umdrehen  */
+	IC *n;obj m;
+	n=p->next;
+	while(n){
+	  if(n->code>=BEQ&&n->code<BRA){
+	    if(!p->z.flags){
+	      if(DEBUG&1) printf("arguments of cmp exchanged\n");
+	      m=p->q1;p->q1=p->q2;p->q2=m;
+	      p->z.flags=1;
+	    }
+	    /*  nachfolgenden Branch umdrehen   */
+	    switch(n->code){
+	    case BGT: n->code=BLT;break;
+	    case BLT: n->code=BGT;break;
+	    case BGE: n->code=BLE;break;
+	    case BLE: n->code=BGE;break;
+	    }
+	    break;
+	  }
+	  if(n->code==FREEREG) n=n->next; else break; /*  compare ohne branch => leerer Block o.ae.   */
+	}
+      }
+      if(ISFLOAT(t)){
+	if(FPU>68000){
+	  if(isreg(q1)&&p->q1.reg>=fp0){
+	    zreg=p->q1.reg;
+	  }else{
+	    zreg=get_reg(f,2,p,0);
+	    move(f,&p->q1,0,0,zreg,t);
+	  }
+	  if(isreg(q2)){emit(f,"\tfcmp.x\t%s,%s\n",mregnames[p->q2.reg],mregnames[zreg]);continue;}
+	  emit(f,"\tfcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+	  emit(f,",%s\n",mregnames[zreg]);
+	  continue;
+	}else{
+	  /*  nicht sehr schoen   */
+	  int result=get_reg(f,1,p,0);
+	  if(!OLD_SOFTFLOAT) ierror(0);
+	  saveregs(f,p);
+	  assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t);
+	  assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+	  scratch_modified();
+	  if(GAS){
+	    emit(f,"\t.global\t__ieeecmp%c\n\tjbsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+	  }else{
+	    emit(f,"\tpublic\t__ieeecmp%c\n\tjsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+	  }
+	  pop(2*msizetab[t&NQ]);
+	  restoreregsa(f,p);
+	  if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]);
+	  emit(f,"\ttst.l\t%s\n",mregnames[result]);
+	  restoreregsd(f,p);
+	  continue;
+	}
+      }
+      if(cf&&x_t[t&NQ]!='l'){
+	if(isreg(q1)) zreg=p->q1.reg; else zreg=get_reg(f,1,p,0);
+	loadext(f,zreg,&p->q1,t);
+	if(isconst(q2)){
+	  emit(f,"\tcmp.l\t");
+	  emit_obj(f,&p->q2,t);
+	}else{
+	  int r;
+	  if(isreg(q2)) r=p->q2.reg; else r=get_reg(f,1,p,0);
+	  loadext(f,r,&p->q2,t);
+	  emit(f,"\tcmp.l\t%s",mregnames[r]);
+	}
+	emit(f,",%s\n",mregnames[zreg]);
+	continue;
+      }
+      if((p->q2.flags&(KONST|VARADR))&&!(p->q1.flags&(KONST|VARADR))&&(!cf||isreg(q1))){
+	emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+	emit(f,",");emit_obj(f,&p->q1,t);emit(f,"\n");
+	continue;
+      }
+      if(isreg(q1)){
+	zreg=p->q1.reg;
+      }else{
+	zreg=get_reg(f,1,p,1);    /* hier evtl. auch Adressregister nehmen */
+	move(f,&p->q1,0,0,zreg,t);
+      }
+      emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+      emit(f,",%s\n",mregnames[zreg]);
+      continue;
+    }
+    if(c==ADDI2P||c==SUBIFP){
+      int zreg=-1,r;
+
+      /*  hier die zweite Alternative mit isreg() schreiben?  */
+      if((((p->q2.flags&REG)&&(p->z.flags&REG)&&p->q2.reg==p->z.reg&&(!(p->q1.flags&REG)||p->q1.reg!=p->z.reg))||
+	 (compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q1,&p->z)))){
+	obj m;
+	if(c==ADDI2P&&x_t[t&NQ]=='l'){
+	  m=p->q1;p->q1=p->q2;p->q2=m;
+	}else{
+	  if(!cf&&x_t[t&NQ]=='l'&&isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
+	    m=p->q1;p->q1=p->q2;p->q2=m;
+	    c=ADDI2P;
+	    emit(f,"\tneg.%c\t",x_t[t&NQ]);
+	    emit_obj(f,&p->q1,t);emit(f,"\n");
+	  }else{
+	    zreg=get_reg(f,0,p,0);
+	  }
+	}
+      }
+
+      if(isreg(q1)&&p->q1.reg<=8&&isreg(z)&&p->z.reg<=8&&p->q1.reg!=p->z.reg){
+	/*  q1 und z Adressregister => lea nehmen   */
+	if(isconst(q2)){
+	  eval_const(&p->q2.val,t);
+	  if(c==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	  if(CPU>=68020||(zmleq(vmax,l2zm(32767))&&zmleq(l2zm(-32768),vmax))){
+	    emit(f,"\tlea\t(%ld",zm2l(vmax));
+	    if(!GAS&&zm2l(vmax)>0x7fff)
+	      emit(f,".l");
+	    emit(f,",%s),%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]);
+	    continue;
+	  }
+	}else if(c==ADDI2P&&isreg(q2)){
+	  emit(f,"\tlea\t(%s,%s.%c),%s\n",mregnames[p->q1.reg],mregnames[p->q2.reg],x_t[t&NQ],mregnames[p->z.reg]);
+	  continue;
+	}
+      }
+      if(compare_objects(&p->q1,&p->z)){
+	if(isconst(q2)&&(!cf||isquickkonst2(&p->q2.val,t))){
+	  if(c==ADDI2P)
+	    emit(f,"\tadd%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
+	  else
+	    emit(f,"\tsub%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
+	  emit_obj(f,&p->q2,t);emit(f,",");
+	  emit_obj(f,&p->z,POINTER);emit(f,"\n");
+	  continue;
+	}
+	if(isreg(q1)&&(x_t[t&NQ]=='l'||p->q1.reg<=8)){
+	  if(c==ADDI2P)
+	    emit(f,"\tadd.%c\t",x_t[t&NQ]);
+	  else
+	    emit(f,"\tsub.%c\t",x_t[t&NQ]);
+	  emit_obj(f,&p->q2,t);emit(f,",%s\n",mregnames[p->z.reg]);
+	  continue;
+	}
+	if(isreg(q2)&&p->q2.reg>=9&&p->q2.reg<=16){
+	  r=p->q2.reg;
+	}else{
+	  r=get_reg(f,1,p,0);
+	  move(f,&p->q2,0,0,r,t);
+	}
+	if(x_t[t&NQ]!='l'&&(!isreg(z)||p->z.reg<1||p->z.reg>8)){
+	  /*  wenn Ziel kein Adressregister, muss short erst auf long */
+	  /*  char darf hier nicht auftreteten und long passt schon   */
+	  if(t&UNSIGNED){
+	    if(CPU>=68040)
+	      emit(f,"\tand.l\t#65535,%s\n",mregnames[r]);
+	    else
+	      emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[r],mregnames[r],mregnames[r]);
+	  }else 
+	    emit(f,"\text.l\t%s\n",mregnames[r]);
+	  t=POINTER;
+	}
+	/*                if(c==ADDI2P)
+			  emit(f,"\tadd.%c\t%s,",x_t[t&NQ],mregnames[r]);
+			  else
+			  emit(f,"\tsub.%c\t%s,",x_t[t&NQ],mregnames[r]);
+			  emit_obj(f,&p->z,t);emit(f,"\n");*/
+	if(c==ADDI2P) 
+	  add(f,0,r,&p->z,0,t);
+	else
+	  sub(f,0,r,&p->z,0,t);
+	continue;
+      }
+      if(isreg(z)&&zreg==-1&&p->z.reg>=1&&p->z.reg<=d7)
+	zreg=p->z.reg; 
+      else 
+	zreg=get_reg(f,0,p,0);
+      /*  Spezialfall, falls Ziel Datenregister und short */
+      /*  nicht schoen, aber auf die Schnelle...          */
+      if(x_t[t&NQ]!='l'&&zreg>8){
+	move(f,&p->q2,0,0,zreg,t);
+	if(t&UNSIGNED){
+	  if(CPU>=68040)
+	    emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
+	  else
+	    emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[zreg],mregnames[zreg],mregnames[zreg]);
+	}else
+	  emit(f,"\text.l\t%s\n",mregnames[zreg]);
+	if(c==SUBIFP) emit(f,"\tneg.l\t%s\n",mregnames[zreg]);
+	add(f,&p->q1,0,0,zreg,POINTER);
+	if(!isreg(z)||p->z.reg!=zreg)
+	  move(f,0,zreg,&p->z,0,POINTER);
+	continue;
+      }
+      if(!isreg(q1)||p->q1.reg!=zreg){
+	move(f,&p->q1,0,0,zreg,POINTER);
+      }
+      if(c==ADDI2P)
+	add(f,&p->q2,0,0,zreg,t);
+      else 
+	sub(f,&p->q2,0,0,zreg,t);
+      if(!isreg(z)||p->z.reg!=zreg){
+	move(f,0,zreg,&p->z,0,POINTER);
+      }
+      continue;
+    }
+    if((c>=OR&&c<=AND)||c==MULT||c==ADD){
+      if(!isreg(q1)&&!isreg(z)&&isreg(q2)){
+	obj o;
+	o=p->q1;p->q1=p->q2;p->q2=o;
+      }
+    }
+    switch_IC(p);
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+      int zreg,q1reg,q2reg;
+      if(isconst(q2)&&
+	 (!(p->q1.flags&REG)||!(p->z.flags&REG)||p->q1.reg!=p->z.reg)&&
+	 (!(p->q1.flags&VAR)||!(p->z.flags&VAR)||p->q1.v!=p->z.v)&&
+	 ((c>=OR&&c<=AND)||c==ADD||c==MULT)){
+	obj o;
+	if(c==MULT){
+	  eval_const(&p->q2.val,t);
+	  if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)&&!pof2(vumax)){
+	    o=p->q1;p->q1=p->q2;p->q2=o;
+	  }
+	}else{
+	  if(!cf||!ISHWORD(t)){
+	    o=p->q1;p->q1=p->q2;p->q2=o;
+	  }
+	}
+      }
+      if(ISFLOAT(t)){
+	if(FPU>68000){
+	  if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){
+	    obj m;
+	    if(c==ADD||c==MULT){
+	      m=p->q1;p->q1=p->q2;p->q2=m;
+	    }else{
+	      if(isreg(q2)){
+		if(c==SUB){
+		  emit(f,"\tfneg.x\t%s\n",mregnames[p->q2.reg]);
+		  m=p->q1;p->q1=p->q2;p->q2=m;
+		  p->code=c=ADD;
+		}else{
+		  int tmp=get_reg(f,2,p,0);
+		  move(f,&p->q2,0,0,tmp,t);
+		  p->q2.reg=tmp;
+		  p->q2.flags=REG;
+		}
+	      }
+	    }
+	  }
+	  if(isreg(z)&&p->z.reg>=fp0)
+	    zreg=p->z.reg;
+	  else 
+	    zreg=get_reg(f,2,p,1);
+	  if(!isreg(q1)||p->q1.reg!=p->z.reg)
+	    move(f,&p->q1,0,0,zreg,t);
+	  emit(f,"\tf%s.",ename[c]);
+	  if(isreg(q2))
+	    emit(f,"x\t");
+	  else
+	    emit(f,"%c\t",x_t[t&NQ]);
+	  emit_obj(f,&p->q2,t);
+	  emit(f,",%s\n",mregnames[zreg]);
+	  if(!isreg(z)||p->z.reg!=zreg){
+	    move(f,0,zreg,&p->z,0,t);
+	  }
+	  continue;
+	}else{
+	  if(!OLD_SOFTFLOAT) ierror(0);
+	  saveregs(f,p);
+	  assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t);
+	  assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+	  scratch_modified();
+	  if(GAS){
+	    emit(f,"\t.global\t__ieee%s%c\n\tjbsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+	  }else{
+	    emit(f,"\tpublic\t__ieee%s%c\n\tjsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+	  }
+	  pop(2*msizetab[t&NQ]);
+	  restoreregsa(f,p);
+	  if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)
+	    stored0d1(f,&p->z,t);
+	  else
+	    move(f,0,d0,&p->z,0,t);
+	  restoreregsd(f,p);
+	  continue;
+	}
+      }
+      if(((c==MULT||c==DIV)||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
+	/*  ersetzt mul etc. mit Zweierpotenzen     */
+	/*  hier evtl. noch Fehler                  */
+	long ln;
+	eval_const(&p->q2.val,t);
+	if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	  if(ln=pof2(vumax)){
+	    if(c==MOD){
+	      vmax=zmsub(vmax,l2zm(1L));
+	      p->code=AND;
+	    }else{
+	      vmax=l2zm(ln-1);
+	      if(c==DIV){
+		p->code=RSHIFT;
+		shiftisdiv=1;
+	      }else
+		p->code=LSHIFT;
+	    }
+	    c=p->code;
+	    gval.vmax=vmax;
+	    eval_const(&gval,MAXINT);
+	    if(c==AND){
+	      insert_const(&p->q2.val,t);
+	    }else{
+	      insert_const(&p->q2.val,INT);
+	      p->typf2=INT;
+	    }
+	  }
+	}
+      }
+      if(c==DIV||c==MOD){
+	if(x_t[t&NQ]=='l'&&CPU<68020){
+	  /*  das hier ist auch nicht allzu schoen  */
+	  char *fname;
+	  cc_set=0;   /*  Library-Funktionen setzen cc nicht immer */
+	  saveregs(f,p);
+	  emit(f,"\tmove.l\t"); emit_obj(f,&p->q2,t);
+	  emit(f,",-(%s)\n",mregnames[sp]);
+	  push(4);
+	  emit(f,"\tmove.l\t"); emit_obj(f,&p->q1,t);
+	  emit(f,",-(%s)\n",mregnames[sp]);
+	  push(4);
+	  if(t&UNSIGNED) fname="divu"; else fname="divs";
+	  scratch_modified();
+	  if(GAS){
+	    emit(f,"\t.global\t__l%s\n\tjbsr\t__l%s\n",fname,fname);
+	  }else{
+	    emit(f,"\tpublic\t__l%s\n\tjsr\t__l%s\n",fname,fname);
+	  }
+	  emit(f,"\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
+	  if(c==MOD) emit(f,"\tmove.l\td1,d0\n");
+	  pop(8);
+	  restoreregsa(f,p);
+	  move(f,0,d0,&p->z,0,t);
+	  restoreregsd(f,p);
+	  continue;
+	}
+
+      }
+      /*  hier die zweite Alternative mit isreg() schreiben?  */
+      if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){
+	obj m;
+	if((c>=OR&&c<=AND)||c==ADD||c==SUB){
+	  if(c!=SUB){
+	    m=p->q1;p->q1=p->q2;p->q2=m;
+	  }else{
+	    if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
+	      m=p->q1;p->q1=p->q2;p->q2=m;
+	      c=ADD;
+	      emit(f,"\tneg.%c\t",x_t[t&NQ]);
+	      emit_obj(f,&p->q1,t);emit(f,"\n");
+	    }
+	  }
+	}
+      }
+      if(compare_objects(&p->q1,&p->z)){
+	if((c>=OR&&c<=AND)||c==ADD||c==SUB){
+	  int r;
+	  if(isconst(q2)&&(!cf||isreg(z)||((c==ADD||c==SUB)&&isquickkonst2(&p->q2.val,t&NQ)))){
+	    if(cf&&((t&NQ)==CHAR||ISHWORD(t))){
+	      if(isreg(q1)) r=p->q1.reg; else r=get_reg(f,1,p,1);
+	      loadext(f,r,&p->q1,t);
+	      emit(f,"\t%s.l\t",ename[c]);
+	      emit_obj(f,&p->q2,t);
+	      emit(f,",%s\n",mregnames[r]);
+	      move(f,0,r,&p->z,0,t);
+	      continue;
+	    }else{
+	      if(c==ADD) {add(f,&p->q2,0,&p->z,0,t);continue;}
+	      if(c==SUB) {sub(f,&p->q2,0,&p->z,0,t);continue;}
+	      emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]);
+	      emit_obj(f,&p->q2,t);emit(f,",");
+	      emit_obj(f,&p->z,t);emit(f,"\n");
+	    }
+	    continue;
+	  }
+	  if(!isreg(z)&&(!cf||x_t[t&NQ]=='l')){
+	    if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7)
+	      r=p->q2.reg; else r=get_reg(f,1,p,0);
+	    if(!isreg(q2)||p->q2.reg!=r){
+	      move(f,&p->q2,0,0,r,t);
+	    }
+	    emit(f,"\t%s.%c\t%s,",ename[c],x_t[t&NQ],mregnames[r]);
+	    emit_obj(f,&p->z,t);emit(f,"\n");
+	    continue;
+	  }
+	}
+      }
+      /*  bei xor oder asl (ausser 0<=const<=8) muss q2 in Register   */
+      if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
+	q2reg=p->q2.reg;
+      }else{
+	if(c==LSHIFT||c==RSHIFT||c==XOR){
+	  int t2=q2typ(p)&NU;
+	  eval_const(&p->q2.val,t2);
+	  if(c==XOR||!isconst(q2)||!isquickkonst2(&p->q2.val,t2)){
+	    if((c==LSHIFT||c==RSHIFT)&&(p->typf2&NQ)==LLONG){
+	      if(!isreg(q2)){
+		q2reg=get_reg(f,1,p,0);
+		emit(f,"\tmove.l\t");
+		emit_lword(f,&p->q2);
+		emit(f,",%s\n",mregnames[q2reg]);
+	      }else{
+		if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+		q2reg=rp.r2;
+	      }
+	    }else{
+	      q2reg=get_reg(f,1,p,0);
+	      move(f,&p->q2,0,0,q2reg,t2);
+	    }
+	  }else q2reg=0;
+	}else{
+	  q2reg=0;
+	}
+      }
+      if(c==MOD&&!ISHWORD(t)){
+	int modreg;
+	if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&p->z.reg!=q2reg)
+	  zreg=p->z.reg; else zreg=get_reg(f,1,p,0);
+	modreg=get_reg(f,1,p,1);
+	if(modreg==zreg) modreg=get_reg(f,1,p,0);
+	move(f,&p->q1,0,0,modreg,t);
+	if(0 /*CPU==68060*/){
+	  /*  div?l.l wird da emuliert?   */
+	  emit(f,"\tsmi\t%s\n\textb.l\t%s\n",mregnames[zreg],mregnames[zreg]);
+	  if(t&UNSIGNED) emit(f,"\tdivu.%c\t",x_t[t&NQ]); else emit(f,"\tdivs.%c\t",x_t[t&NQ]);
+	}else{
+	  if(t&UNSIGNED) emit(f,"\tdivul.%c\t",x_t[t&NQ]); else emit(f,"\tdivsl.%c\t",x_t[t&NQ]);
+	}
+	emit_obj(f,&p->q2,t);
+	emit(f,",%s:%s\n",mregnames[zreg],mregnames[modreg]);
+	move(f,0,zreg,&p->z,0,t);
+	cc_set=0;
+	continue;
+      }
+      if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&(p->z.reg!=q2reg||(isreg(q1)&&p->q1.reg==q2reg)))
+	zreg=p->z.reg; else zreg=get_reg(f,1,p,1);
+      if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7)
+	q1reg=p->q1.reg; else q1reg=0;
+      if(q1reg!=zreg){
+	move(f,&p->q1,0,0,zreg,t);
+      }
+      if(c!=MULT&&c!=DIV&&c!=MOD&&c!=ADD&&c!=SUB){
+	if(cf&&c==RSHIFT){
+	  if(cf&&(t&NU)==CHAR)
+	    emit(f,"\textb.l\t%s\n",mregnames[zreg]);
+	  else if(cf&&(t&NU)==SHORT)
+	    emit(f,"\text.w\t%s\n",mregnames[zreg]);
+	  if(cf&&(t&NU)==(UNSIGNED|CHAR))
+	    emit(f,"\tand.l\t#255,%s\n",mregnames[zreg]);
+	  else if(cf&&(t&NU)==(UNSIGNED|SHORT))
+	    emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
+	}
+	if(shiftisdiv&&!(t&UNSIGNED)){
+	  unsigned long l;
+	  eval_const(&p->q2.val,p->typf2);
+	  l=(1<<zum2ul(vumax))-1;
+	  if(isreg(q1)&&p->q1.reg==zreg)
+	    emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[zreg]);
+	  emit(f,"\tbge\t%s%d\n",labprefix,++label);
+	  emit(f,"\tadd%s.%c\t#%ld,%s\n",(l<=7?"q":""),x_t[t&NQ],l,mregnames[zreg]);
+	  emit(f,"%s%d:\n",labprefix,label);
+	}
+	if(c==RSHIFT&&!(t&UNSIGNED))
+	  emit(f,"\tasr.%c\t",cf?'l':x_t[t&NQ]);
+	else
+	  emit(f,"\t%s.%c\t",ename[c],cf?'l':x_t[t&NQ]);
+	if(q2reg)
+	  emit(f,"%s",mregnames[q2reg]);
+	else 
+	  emit_obj(f,&p->q2,q2typ(p));
+	emit(f,",%s\n",mregnames[zreg]);
+      }else{
+	if(c==ADD) add(f,&p->q2,q2reg,0,zreg,t);
+	if(c==SUB) sub(f,&p->q2,q2reg,0,zreg,t);
+	if(c==MULT||c==DIV||c==MOD) mult(f,&p->q2,q2reg,0,zreg,t,c,p);
+      }
+      if((!isreg(z)||p->z.reg!=zreg)){
+	move(f,0,zreg,&p->z,0,t);
+      }
+      continue;
+    }
+    ierror(0);
+  }
+  if(notpopped){
+    emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]);
+    pop(notpopped);notpopped=0;
+  }
+  function_bottom(f,v,zm2l(offset));
+  if(debug_info&&!HUNKDEBUG){
+    emit(f,"%s%d:\n",labprefix,++label);
+    dwarf2_function(f,v,label);
+    if(f) section=-1;
+  }
+  pushflag=0;
+}
+
+/*FIXME*/
+int shortcut(int code,int typ)
+{
+  if(!cf&&(code==COMPARE||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT)) return(1);
+  if(!cf&&code==MULT&&(typ&NQ)!=CHAR) return 1;
+
+  return 0;
+}
+void init_db(FILE *f)
+{
+  if(!HUNKDEBUG){
+    if(GAS)
+      dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte","l","_",".section");
+    else
+      dwarf2_setup(sizetab[POINTER],"dc.b","dc.w","dc.l","dc.l","l","_","section");
+    dwarf2_print_comp_unit_header(f);
+  }
+}
+void cleanup_db(FILE *f)
+{
+  if(!HUNKDEBUG&&f){
+    dwarf2_cleanup(f);
+    if(f) section=-1;
+  }
+}
+void cleanup_cg(FILE *f)
+{
+  title(f);
+  if(f&&stack_check){
+    if(GAS)
+      emit(f,"\t.global\t___stack_check\n");
+    else
+      emit(f,"\tpublic\t___stack_check\n");
+  }
+  /*printf("pushed %d, saved %d, removed allocreg %d\n",missing,savedemit,savedalloc);*/
+  return;
+}
+
+/* mark instructions which can (probably) be implemented with faster
+   machine-code than the IC migh suggest, e.g. an addition which can
+   be merged with a load bz use of target addressing-modes;
+   the optimizer should hesitate to modifz such instructions if it's not
+   a definite win */
+
+static int is_single_eff_ic(IC *p)
+{
+  Var *v;
+  if(p->code!=ADDI2P&&p->code!=SUBIFP)
+    return 0;
+  if(!isconst(q2)){
+    if(CONSERVATIVE_SR){
+      if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+	return 0;
+      if(p->q2.v->storage_class==STATIC||p->q2.v->storage_class==EXTERN)
+	return 0;
+    }else
+      return 0;
+  }
+  if((p->q1.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)
+    return 0;
+  if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+    return 0;
+  v=p->z.v;
+  for(p=p->next;p;p=p->next){
+    int c=p->code;
+    if(c==LABEL||(c>=BEQ&&c<=BRA))
+      return 0;
+    if((p->q1.flags&VAR)&&p->q1.v==v){
+      if(p->q1.flags&DREFOBJ)
+	return 1;
+      else
+	return 0;
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==v){
+      if(p->q2.flags&DREFOBJ)
+	return 1;
+      else
+	return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->z.flags&DREFOBJ)
+	return 1;
+      else
+	return 0;
+    }
+  }
+}
+void mark_eff_ics(void)
+{
+  IC *p;
+  for(p=first_ic;p;p=p->next){
+    if(is_single_eff_ic(p))
+      p->flags|=EFF_IC;
+    else
+      p->flags&=~EFF_IC;
+  }
+}
+
+int reg_pair(int r,rpair *p)
+     /* Returns 0 if the register is no register pair. If r  */
+     /* is a register pair non-zero will be returned and the */
+     /* structure pointed to p will be filled with the two   */
+     /* elements.                                            */
+{
+  if(r<=fp7) return 0;
+  if(p){
+    switch(r){
+    case d0d1: p->r1=d0;p->r2=d1;break;
+    case d2d3: p->r1=d2;p->r2=d3;break;
+    case d4d5: p->r1=d4;p->r2=d5;break;
+    case d6d7: p->r1=d6;p->r2=d7;break;
+    default: ierror(0);
+    }
+  }
+  return 1;
+}
+
+int emit_peephole(void)
+{
+  int entries,i,r1,r2,r3,r4;
+  char *asmline[EMIT_BUF_DEPTH],c1,c2,c3,c4,e;
+
+  if(OLDPEEPHOLE) return 0;
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+    if(sscanf(asmline[1],"\tmove.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&&
+       sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&&
+       c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){
+      sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1);
+      remove_asm();
+      savedemit++;
+      return 1;
+    }
+    if(sscanf(asmline[1],"\tmovem.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&&
+       sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&&
+       c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){
+      sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1);
+      remove_asm();
+      savedemit++;
+      return 1;
+    }
+
+    if(sscanf(asmline[1],"\tmove.l\t%c%d,%c%d\n%c",&c1,&r1,&c2,&r2,&e)==4&&
+       sscanf(asmline[0],"\tmove.l\t%c%d,%c%d\n%c",&c3,&r3,&c4,&r4,&e)==4&&
+       c1==c4&&r1==r4&&c2==c3&&r2==r3&&r1>=0&&r1<=7&&r2>=0&&r2<=7&&
+       (c1=='a'||c1=='d')&&(c2=='a'||c2=='d')){
+      /* create tst instruction if condition codes of address register are needed */
+      if(c1=='d'&&c2=='a'&&cc_set!=0&&(cc_set->flags&(REG|DREFOBJ))==REG&&cc_set->reg==a0+r2)
+	sprintf(asmline[0],"\ttst.l\t%s\n",mregnames[d0+r1]);
+      else
+	remove_asm();
+      savedemit++;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[32];
+  char *ret=0;
+  int f;
+
+  t&=NU;
+  t2&=NU;
+
+  if(c==LSHIFT&&((t&NQ)==LLONG)) return "_lshint64";
+  if(c==RSHIFT&&t==LLONG) return "_rshsint64";
+  if(c==RSHIFT&&t==(UNSIGNED|LLONG)) return "_rshuint64";
+
+
+  if(FPU>68000){
+    if(c!=CONVERT) return 0;
+    if((!ISFLOAT(t)||(t2&NQ)!=LLONG)&&
+       (!ISFLOAT(t2)||(t&NQ)!=LLONG))
+      return 0;
+  }
+  if(OLD_SOFTFLOAT) return 0;
+
+  if(t==LDOUBLE) t=DOUBLE;
+  if(t2==LDOUBLE) t2=DOUBLE;
+  if(FLOAT64){
+    if(t==FLOAT) t=DOUBLE;
+    if(t2==FLOAT) t2=DOUBLE;
+  }
+
+  if(c==COMPARE){
+    if(ISFLOAT(t)){
+      sprintf(fname,"_ieeecmp%c",x_t[t]);
+      ret=fname;
+    }
+  }else if(c==CONVERT){
+    if(t2==INT) t2=(zm2l(sizetab[INT])==4?LONG:SHORT);
+    if(t2==(UNSIGNED|INT)) t2=(sizetab[INT]==4?(UNSIGNED|LONG):(UNSIGNED|SHORT));
+    if(t==FLOAT&&t2==DOUBLE) return "_ieeed2s";
+    if(t==DOUBLE&&t2==FLOAT) return "_ieees2d";
+    if(t==DOUBLE&&t2==DOUBLE) return 0;
+    if(t==FLOAT||t==DOUBLE){
+      if((t2&NQ)==LLONG)
+	sprintf(fname,"_%cint64toflt%s",(t2&UNSIGNED)?'u':'s',t==FLOAT?"32":"64");
+      else
+	sprintf(fname,"_ieeeflt%c%c",(t2&UNSIGNED)?'u':'s',x_t[t]);
+      ret=fname;
+    }
+    if(t2==FLOAT||t2==DOUBLE){
+      if((t&NQ)==LLONG)
+	sprintf(fname,"_flt%sto%cint64",t2==FLOAT?"32":"64",(t&UNSIGNED)?'u':'s');
+      else
+	sprintf(fname,"_ieeefix%c%c%c",x_t[t2],(t2&UNSIGNED)?'u':'s',x_t[t&NQ]);
+      ret=fname;
+    }
+  }else if(ISFLOAT(t)){
+    if(c==MINUS){
+      sprintf(fname,"_ieeeneg%c",x_t[t&NQ]);
+      ret=fname;
+    }else if(c>=ADD&&c<=DIV){
+      sprintf(fname,"_ieee%s%c",ename[c],x_t[t&NQ]);
+      ret=fname;
+    }
+    if(c==TEST){
+      sprintf(fname,"_ieeetst%c",x_t[t&NQ]);
+      ret=fname;
+    }
+  }else if(CPU<68020&&!OLDLIBCALLS){
+    if((c==DIV||c==MOD)&&ISINT(t)&&zm2l(sizetab[t&NQ])==4){
+      sprintf(fname,"_%s%c",ename[c],(t&UNSIGNED)?'u':'s');
+      ret=fname;
+    }
+  }
+  return ret;
+}
+
+
+int reg_parm(treg_handle *p,type *t,int mode,type *fkt)
+{
+  int f;
+
+  if(!fkt||fkt->flags!=FUNKT)
+    ierror(0);
+
+  if(!fkt->next)
+    ierror(0);
+
+  if(stdargs(fkt))
+     return 0;
+
+  f=t->flags&NQ;
+  if(mode/*||f==LLONG||!ISSCALAR(f)*/)
+    return 0;
+  if(ISPOINTER(f)){
+    if(p->ar>ascratch)
+      return 0;
+    else
+      return a0+p->ar++;
+  }
+  if(ISFLOAT(f)||f==LLONG){
+    if(FPU<=68000||f==LLONG){
+      if(rparmtype==PARMSAS) return 0;
+      if(f!=FLOAT){
+	if(p->dr!=0) return 0;
+	p->dr+=2;
+	return d0d1;
+      }
+      if(p->dr>dscratch)
+	return 0;
+      else
+	return d0+p->dr++;
+    }else{
+      if(p->fr>fscratch)
+	return 0;
+      else
+	return fp0+p->fr++;
+    }
+  }
+  if(!ISINT(f)) return 0;
+  if(p->dr>dscratch)
+    return 0;
+  else
+    return d0+p->dr++;
+}
+
+int handle_pragma(const char *s)
+{
+  if(!strncmp("stdargs-on",s,10)){
+    add_stdargs=1;
+    return 1;
+  }
+  if(!strncmp("stdargs-off",s,11)){
+    add_stdargs=0;
+    return 1;
+  }
+  return 0;
+}
+
+void add_var_hook_pre(const char *identifier, type *t, int storage_class,const_list *clist)
+{
+  if(!add_stdargs) return;
+  if(ISFUNC(t->flags))
+    add_attr(&t->next->attr,"__stdargs");
+}
diff --git a/machines/m68k/machine.dt b/machines/m68k/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/m68k/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/m68k/machine.h b/machines/m68k/machine.h
new file mode 100644
index 0000000..c9d2afe
--- /dev/null
+++ b/machines/m68k/machine.h
@@ -0,0 +1,118 @@
+/*  $VER: vbcc (m68k/machine.h) $Revision: 1.13 $     */
+
+#include "dt.h"
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+typedef struct AddressingMode{
+    int basereg;
+    long dist;
+    int skal;
+    int dreg;
+} AddressingMode;
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 28
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 35
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+extern int MINADDI2P;
+
+/*  This specifies the smallest unsigned type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDUI2P (UNSIGNED|INT)
+
+
+/*  This specifies the biggest integer type that can be added to a  */
+/*  pointer.                                                        */
+#define MAXADDI2P LONG
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 1
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 256
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we have a mark_eff_ics function */
+#define HAVE_TARGET_EFF_IC 1
+
+/* we have register-pairs */
+#define HAVE_REGPAIRS 1
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+  int dr,ar,fr;
+};
+
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 8
+
+/* support for variable-length arrays */
+#define ALLOCVLA_REG 9
+#define ALLOCVLA_INLINEASM "\taddq.l\t#3,d0\n\tand.b\t#252,d0\n\tsub.l\td0,a7\n\tmove.l\ta7,d0"
+#define FREEVLA_REG 0
+/* TODO: find a better solution some time */
+#define FREEVLA_INLINEASM "\tmove.l\t(a7),a7\n\tsubq.l\t#4,a7"
+#define OLDSPVLA_INLINEASM "\tmove.l\ta7,d0"
+#define FPVLA_REG 6
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We have a target-specific add_var hook */
+#define HAVE_TARGET_VARHOOK_PRE
+
+#define HAVE_POF2OPT 1
+
+#ifndef M68K_16BIT_INT
+#define HAVE_INT_SIZET 1
+#endif
diff --git a/machines/m68ks/machine.c b/machines/m68ks/machine.c
new file mode 100755
index 0000000..ca342b5
--- /dev/null
+++ b/machines/m68ks/machine.c
@@ -0,0 +1,7 @@
+/*  Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2    */
+/*  and ColdFire.                                                           */
+/*  PhxAss and the GNU assembler is supported.                              */
+
+/*  stub for ST version with 16bit int  */
+
+#include "machines/m68k/machine.c"
diff --git a/machines/m68ks/machine.dt b/machines/m68ks/machine.dt
new file mode 100755
index 0000000..44544a2
--- /dev/null
+++ b/machines/m68ks/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/m68ks/machine.h b/machines/m68ks/machine.h
new file mode 100755
index 0000000..ac3ee6a
--- /dev/null
+++ b/machines/m68ks/machine.h
@@ -0,0 +1,14 @@
+/*  Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2    */
+/*  and ColdFire.                                                           */
+/*  PhxAss and the GNU assembler is supported.                              */
+
+/*  stub for ST version with 16bit int  */
+
+#define M68K_16BIT_INT
+
+#define PTRDIFF_T(x) LONG
+
+#define BESTCOPYT LONG
+
+#include "dt.h"
+#include "../m68k/machine.h"
diff --git a/machines/mark/machine.c b/machines/mark/machine.c
new file mode 100644
index 0000000..f4859dc
--- /dev/null
+++ b/machines/mark/machine.c
@@ -0,0 +1,1526 @@
+#include "supp.h"
+//#define DEBUG_MARK
+
+static char FILE_[]=__FILE__;
+
+//#include "version.h"
+char cg_copyright[]="not for public release";
+
+int g_flags[MAXGF]={};
+char *g_flags_name[MAXGF]={};
+union ppi g_flags_val[MAXGF];
+
+struct reg_handle empty_reg_handle={0};
+
+extern int handle_pragma(const char * c){return 0;}
+
+//support for ISR
+char *g_attr_name[] = {"__interrupt", 0};
+#define INTERRUPT 1
+
+/*
+ * Define registers codes
+ */
+
+#define R0 1  //zero register
+#define R1 2  //reserved for compiler
+#define R2 3  //reserved for compiler
+#define R3 4  //reserved for compiler
+#define R4 5  //condition codes
+#define R5 6  //return value
+#define R6 7
+#define R7 8
+#define R8 9
+#define R9 10
+#define R10 11
+#define R11 12
+#define R12 13
+#define FP 14 //frame pointer
+#define PC 15 //program counter
+#define SP 16 //stack pointer
+
+/*
+ * Custom function
+ */
+
+//evalue compare IC and prepare condition codes in R3 (COMPARE IC is followed by BRANCH allways)
+void compare(FILE *f, struct IC *p);
+//helper function for loading obj o into register dest_reg
+void load_into_reg(FILE *f, int dest_reg, struct obj *o, int type, int tmp_reg);
+//store reg into obj o
+void store_from_reg(FILE *f, int source_reg, struct obj *o, int type, int tmp_reg, int tmp_reg_b);
+//take care about all arithmetic IC
+void arithmetic(FILE *f, struct IC *p);
+//load constant into register
+void load_cons(FILE *f, int reg, long int value);
+
+/*
+ * Data Types
+ */
+zmax char_bit; // CHAR_BIT for the target machine.
+zmax align[MAX_TYPE+1]; //  Alignment-requirements for all types in bytes.
+zmax maxalign; //  Alignment that is sufficient for every object.
+zmax sizetab[MAX_TYPE+1]; //  sizes of the basic types (in bytes)
+
+//  Minimum and Maximum values each type can have.
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+
+/*
+ * Register  Set
+ */
+
+/*
+ * Names of all registers. will be initialized in init_cg(),
+ * register number 0 is invalid, valid registers start at 1
+ */
+char *regnames[MAXR+1];
+
+/*
+ *  The Size of each register in bytes.
+ */
+zmax regsize[MAXR+1];
+
+/*
+ *   Specifies which registers may be scratched by functions.
+ */
+int regscratch[MAXR+1];
+
+/*
+ *   a type which can store each register.
+ */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should
+ *  not be used by the compiler pass.
+ */
+int regsa[MAXR+1];
+
+/*
+ * specifies the priority for the register-allocator, if the same
+ * estimated cost-saving can be obtained by several registers, the
+ * one with the highest priority will be used
+ */
+int reg_prio[MAXR+1];
+
+
+/*
+ * Does necessary initializations for the code-generator. Gets called
+ * once at the beginning and should return 0 in case of problems.
+ */
+int init_cg(void){
+
+    #ifdef DEBUG_MARK
+    printf("Called init_cg()\n");
+    #endif
+
+    int i;
+
+    maxalign=l2zm(1L);
+    char_bit=l2zm(32L);
+
+    for(i=0;i<=MAX_TYPE;i++){
+        align[i] = l2zm(1L);
+        sizetab[i] = l2zm(1L);
+    }
+
+    t_min[CHAR] = zmsub(l2zm(-2147483647L),l2zm(1L));
+    t_min[SHORT] = t_min[CHAR];
+    t_min[INT] = t_min[CHAR];
+    t_min[LONG] = t_min[CHAR];
+    t_min[LLONG] = t_min[CHAR];
+    t_min[MAXINT] = t_min[CHAR];
+
+    t_max[CHAR] = ul2zum(2147483647UL);
+    t_max[SHORT] = t_max[CHAR];
+    t_max[INT] = t_max[CHAR];
+    t_max[LONG] = t_max[CHAR];
+    t_max[LLONG] = t_max[CHAR];
+    t_max[MAXINT] = t_max[CHAR];
+
+    tu_max[CHAR]=ul2zum(4294967295UL);
+    tu_max[SHORT] = tu_max[CHAR];
+    tu_max[INT] = tu_max[CHAR];
+    tu_max[LONG] = tu_max[CHAR];
+    tu_max[LLONG] = tu_max[CHAR];
+    tu_max[MAXINT] = tu_max[CHAR];
+
+
+    regnames[0] = "noreg";
+    reg_prio[0] = 0;
+    regscratch[0] = 0;
+    regsa[0] = 0;
+
+    //zero register
+    regnames[1] = "R0";
+    reg_prio[1] = 0;
+    regscratch[1] = 0;
+    regsa[1] = 1;
+
+    //R1 reserved for backed
+    regnames[2] = "R1";
+    reg_prio[2] = 0;
+    regscratch[2] = 0;
+    regsa[2] = 1;
+
+    //R2 reserved for backed
+    regnames[3] = "R2";
+    reg_prio[3] = 0;
+    regscratch[3] = 0;
+    regsa[3] = 1;
+
+    //R3 reserved for backed
+    regnames[4] = "R3";
+    reg_prio[4] = 0;
+    regscratch[4] = 0;
+    regsa[4] = 1;
+
+    //R4 condition codes
+    regnames[5] = "R4";
+    reg_prio[5] = 0;
+    regscratch[5] = 0;
+    regsa[5] = 1;
+
+    //R5 return value for function
+    regnames[6] = "R5";
+    reg_prio[6] = 0;
+    regscratch[6] = 0;
+    regsa[6] = 1;
+
+    regnames[7] = "R6";
+    reg_prio[7] = 0;
+    regscratch[7] = 0;
+    regsa[7] = 0;
+
+    regnames[8] = "R7";
+    reg_prio[8] = 0;
+    regscratch[8] = 0;
+    regsa[8] = 0;
+
+    regnames[9] = "R8";
+    reg_prio[9] = 0;
+    regscratch[9] = 0;
+    regsa[9] = 0;
+
+    regnames[10] = "R9";
+    reg_prio[10] = 0;
+    regscratch[10] = 0;
+    regsa[10] = 0;
+
+    regnames[11] = "R10";
+    reg_prio[11] = 0;
+    regscratch[11] = 0;
+    regsa[11] = 0;
+
+    regnames[12] = "R11";
+    reg_prio[12] = 0;
+    regscratch[12] = 0;
+    regsa[12] = 0;
+
+    regnames[13] = "R12";
+    reg_prio[13] = 0;
+    regscratch[13] = 0;
+    regsa[13] = 0;
+
+    // Frame pointer
+    regnames[FP] = "R13";
+    reg_prio[14] = 0;
+    regscratch[14] = 0;
+    regsa[14] = 1;
+
+    // Program counter
+    regnames[15] = "PC";
+    reg_prio[15] = 0;
+    regscratch[15] = 0;
+    regsa[15] = 1;
+
+    // Stack pointer
+    regnames[16] = "SP";
+    reg_prio[16] = 0;
+    regscratch[16] = 0;
+    regsa[16] = 1;
+
+
+    for(i=0;i<=MAXR;i++){
+        regsize[i] = l2zm(1L);
+    }
+
+    // Use multiple ccs
+    multiple_ccs = 0;
+
+    return 1;
+}
+
+void cleanup_cg(FILE *f){
+    #ifdef DEBUG_MARK
+    printf("Called cleanup_cg()\n");
+    #endif
+}
+
+/*
+ * Returns the register in which variables of type t are returned.
+ * If the value cannot be returned in a register returns 0.
+ */
+int freturn(struct Typ *t){
+    return R5;
+}
+
+/*
+ * Returns 0 if register r cannot store variables of
+ * type t. If t==POINTER and mode!=0 then it returns
+ * non-zero only if the register can store a pointer
+ * and dereference a pointer to mode.
+ */
+int regok(int r,int t,int mode){
+    return 1;
+}
+
+/*
+ *  Returns zero if the IC p can be safely executed
+ *  without danger of exceptions or similar things.
+ *  vbcc may generate code in which non-dangerous ICs
+ *  are sometimes executed although control-flow may
+ *  never reach them (mainly when moving computations
+ *  out of loops).
+ *  Typical ICs that generate exceptions on some
+ *  machines are:
+ *      - accesses via pointers
+ *      - division/modulo
+ *      - overflow on signed integer/floats
+ */
+int dangerous_IC(struct IC *p){
+    return 0;
+}
+
+/*
+ *  Returns zero if code for converting np to type t
+ *  can be omitted.
+ *  On the PowerPC cpu pointers and 32bit
+ *  integers have the same representation and can use
+ *  the same registers.
+ */
+int must_convert(int o,int t,int const_expr){
+    return 0;
+}
+
+int shortcut(int code,int typ){
+    return 0;
+}
+
+/*
+ *  The main code-generation routine.
+ *  f is the stream the code should be written to.
+ *  p is a pointer to a doubly linked list of ICs
+ *  containing the function body to generate code for.
+ *  v is a pointer to the function.
+ *  offset is the size of the stackframe the function
+ *  needs for local variables.
+ */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset){
+    #ifdef DEBUG_MARK
+    printf("Called gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)\n");
+    printf("\tIdentifier: %s", v->identifier);
+    #endif
+
+    //emit function head
+    if(v->storage_class==EXTERN){
+        if( (v->flags & (INLINEFUNC|INLINEEXT)) != INLINEFUNC ){
+            emit(f,".EXPORT \t %s \n",v->identifier);
+        }
+        emit(f,"%s: \n",v->identifier);
+    }
+    else{
+        emit(f,"L_%ld:\n",zm2l(v->offset));
+    }
+
+    //emit function prologue
+    emit(f, "\tPUSH \t %s\n", regnames[FP]);  //push FP
+    emit(f, "\tOR   \t %s %s %s\n",regnames[R0], regnames[SP], regnames[FP]); //MOVE SP -> FP
+
+    //make space for auto variables at stack
+    for(int i = 0; i < zm2l(offset); i++){
+        emit(f, "\tDEC \t %s %s\n", regnames[SP], regnames[SP]);
+    }
+
+    //store backend registers
+    emit(f, "\tPUSH \t R1\n\tPUSH \t R2\n\tPUSH \t R3\n\tPUSH \t R4\n");
+
+    //find used registers
+    int saved_regs[7] = {0, 0, 0, 0, 0, 0, 0};
+
+    struct IC *ps = p;
+    for(;ps;ps=ps->next){
+        if( ((ps->code) != FREEREG) && ((ps->code) != ALLOCREG) ){
+            if(((ps->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+                if(((ps->q1.reg) > R5) && ((ps->q1.reg) < FP)){
+                    saved_regs[(ps->q1.reg) - 7] = 1;
+                }
+            }
+            if(((ps->q2.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+                if(((ps->q2.reg) > R5) && ((ps->q2.reg) < FP)){
+                    saved_regs[(ps->q2.reg) - 7] = 1;
+                }
+            }
+            if(((ps->z.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+                if(((ps->z.reg) > R5) && ((ps->z.reg) < FP)){
+                    saved_regs[(ps->z.reg) - 7] = 1;
+                }
+            }
+        }
+    }
+
+    //save used registers
+    for(int i = 0; i < 7; i++){
+        if(saved_regs[i] == 1){
+            emit(f, "\tPUSH \t %s\n", regnames[i + 7]);
+        }
+    }
+
+    //emit function body
+    for(;p;p=p->next){
+        int c = p->code;
+
+        #ifdef DEBUG_MARK
+        emit(f, "\n\t;p->code: %d\n", p->code);
+        #endif
+
+        switch(p->code){
+            case ASSIGN:
+                #ifdef DEBUG_MARK
+                printf("\n\tASSIGN\n\tz.flags:%d\tq1.flags:%d\ttypf:%d\n", p->z.flags, p->q1.flags, p->typf);
+                #endif
+
+                //we can simplify assign when both operands are in registers
+                if((((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG) &&
+                   (((p->z.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG) ){
+                    emit(f, "\tOR   \t %s %s %s",regnames[R0], regnames[p->q1.reg], regnames[p->z.reg]);
+                }
+
+                //this is another optimalization, if have to assign zero; then
+                //zero is read from R0 insted pushing constant into register
+                else if(
+                (((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == KONST) &&
+                ((p->q1.val.vmax) == 0)
+                ){
+                    store_from_reg(f, R0, &(p->z), p->typf, R2, R3);
+                }
+
+                else{
+                    load_into_reg(f, R1, &(p->q1), p->typf, R2);
+                    store_from_reg(f, R1, &(p->z), p->typf, R2, R3);
+                }
+
+                break;
+            case OR:
+                #ifdef DEBUG_MARK
+                printf("\n\tOR\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case XOR:
+                #ifdef DEBUG_MARK
+                printf("\n\tXOR\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case AND:
+                #ifdef DEBUG_MARK
+                printf("\n\tAND\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case LSHIFT:
+                #ifdef DEBUG_MARK
+                printf("\n\tLSHIFT\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case RSHIFT:
+                #ifdef DEBUG_MARK
+                printf("\n\tRSHIFT\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case ADD:
+                #ifdef DEBUG_MARK
+                printf("\n\tADD\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case SUB:
+                #ifdef DEBUG_MARK
+                printf("\n\tSUB\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case MULT:
+                #ifdef DEBUG_MARK
+                printf("\n\tMULT\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case DIV:
+                #ifdef DEBUG_MARK
+                printf("\n\tDIV\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case MOD:
+                #ifdef DEBUG_MARK
+                printf("\n\tMOD\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case KOMPLEMENT:
+                #ifdef DEBUG_MARK
+                printf("\n\tKOMPLEMENT\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case MINUS:
+                #ifdef DEBUG_MARK
+                printf("\n\tMINUS\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case ADDRESS:
+                #ifdef DEBUG_MARK
+                printf("\n\tADDRESS\n");
+                #endif
+
+                if(
+                (((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == VAR) &&
+                (((p->q1.v->storage_class) & (AUTO|REGISTER|STATIC|EXTERN)) == AUTO)
+                ){
+                    if(ISARRAY(p->q1.v->flags)){
+                        load_cons(f, R1, zm2l(p->q1.v->offset)+zm2l(p->q1.val.vmax));
+                    }
+                    else{
+                        load_cons(f, R1, zm2l(p->q1.v->offset));
+                    }
+                    emit(f, "\tADD \t R1 R13 R1\n");
+                    store_from_reg(f, R1, &(p->z), p->typf, R2, R3);
+                }
+                else{
+                    ierror(0);
+                }
+
+                break;
+            case CALL:
+                #ifdef DEBUG_MARK
+                printf("\n\tCALL\n\tq1.flags: %d\n", p->q1.flags);
+                #endif
+
+                if((p->q1.flags & (VAR|DREFOBJ)) == VAR && p->q1.v->fi && p->q1.v->fi->inline_asm){
+                    emit_inline_asm(f,p->q1.v->fi->inline_asm);
+                }
+                else{
+
+                    if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == VAR){
+
+                        #ifdef DEBUG_MARK
+                        printf("\tq1.v->storage_class: %d\n", p->q1.v->storage_class);
+                        #endif
+
+                        switch((p->q1.v->storage_class) & (AUTO|REGISTER|STATIC|EXTERN)){
+                            case EXTERN:
+                                emit(f, "\tCALL \t %s\n", p->q1.v->identifier);
+                                for(int i = 0; i < (p->q2.val.vmax); i++){
+                                    emit(f, "\tINC \t %s %s\n", regnames[SP], regnames[SP]);
+                                }
+                                break;
+                            case STATIC:
+                                emit(f, "\tCALL \t L_%ld\n", zm2l(p->q1.v->offset));
+                                for(int i = 0; i < (p->q2.val.vmax); i++){
+                                    emit(f, "\tINC \t %s %s\n", regnames[SP], regnames[SP]);
+                                }
+                                break;
+                            default:
+                                #ifdef DEBUG_MARK
+                                printf("\tThis is not implemented!\n");
+                                #else
+                                ierror(0);
+                                #endif
+                                break;
+                        }
+
+                    }
+                    else if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == (VAR|DREFOBJ)){
+                        #ifdef DEBUG_MARK
+                        printf("\tq1.v->storage_class: %d\n", p->q1.v->storage_class);
+                        #endif                        
+                        load_into_reg(f, R1, &(p->q1), p->typf, R3);
+                        emit(f, "\tCALLI\t %s\n", regnames[R1]);                        
+                        emit(f, "\tINC \t %s %s\n", regnames[SP], regnames[SP]);                        
+                    }
+                    else{
+                        #ifdef DEBUG_MARK
+                        printf("\tThis is not implemented!\n");
+                        #else
+                        ierror(0);
+                        #endif
+                    }
+                }
+                break;
+            case CONVERT:
+                #ifdef DEBUG_MARK
+                printf("\n\tCONVERT\n");
+                #endif
+
+                break;
+            case ALLOCREG:
+                #ifdef DEBUG_MARK
+                printf("\n\tALLOCREG\n");
+                #endif
+
+                regs[p->q1.reg] = 1;
+                break;
+            case FREEREG:
+                #ifdef DEBUG_MARK
+                printf("\n\tFREEREG\n");
+                #endif
+
+                regs[p->q1.reg] = 0;
+                break;
+            case COMPARE:
+                #ifdef DEBUG_MARK
+                printf("\n\tCOMPARE\n");
+                #endif
+
+                compare(f, p);
+                break;
+            case TEST:
+                #ifdef DEBUG_MARK
+                printf("\n\tTEST\n");
+                #endif
+
+                compare(f, p);
+                break;
+            case LABEL:
+                #ifdef DEBUG_MARK
+                printf("\n\tLABEL\n");
+                #endif
+
+                emit(f,"L_%d:\n",p->typf);
+                break;
+            case BEQ:
+                #ifdef DEBUG_MARK
+                printf("\n\tBEQ\n");
+                #endif
+
+                emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+                break;
+            case BNE:
+                #ifdef DEBUG_MARK
+                printf("\n\tBNE\n");
+                #endif
+
+                emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+                break;
+            case BLT:
+                #ifdef DEBUG_MARK
+                printf("\n\tBLT\n");
+                #endif
+
+                emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+                break;
+            case BGE:
+                #ifdef DEBUG_MARK
+                printf("\n\tBGE\n");
+                #endif
+
+                emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+                break;
+            case BLE:
+                #ifdef DEBUG_MARK
+                printf("\n\tBLE\n");
+                #endif
+
+                emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+                break;
+            case BGT:
+                #ifdef DEBUG_MARK
+                printf("\n\tBGT\n");
+                #endif
+
+                emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+                break;
+            case BRA:
+                #ifdef DEBUG_MARK
+                printf("\n\tBRA\n");
+                #endif
+
+                emit(f, "\tBZ   \t R0 L_%d\n", p->typf);
+                break;
+            case PUSH:
+                #ifdef DEBUG_MARK
+                printf("\n\tPUSH\n");
+                #endif
+
+                load_into_reg(f, R1, &(p->q1), p->typf, R2);
+                emit(f, "\tPUSH \t R1\n");
+                break;
+            case ADDI2P:
+                #ifdef DEBUG_MARK
+                printf("\n\tADDI2P\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case SUBIFP:
+                #ifdef DEBUG_MARK
+                printf("\n\tSUBIFP\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case SUBPFP:
+                #ifdef DEBUG_MARK
+                printf("\n\tSUBPFP\n");
+                #endif
+                arithmetic(f, p);
+                break;
+            case GETRETURN:
+                #ifdef DEBUG_MARK
+                printf("\n\tGETRETURN\n");
+                #endif
+                if((p->q1.reg) != 0){
+                    store_from_reg(f, p->q1.reg, &(p->z), p->typf, R2, R3);
+                }
+                else{
+                    #ifdef DEBUG_MARK
+                    printf("\tq1.reg == 0, didn't know how to dealt with it!");
+                    #else
+                    ierror(0);
+                    #endif
+                }
+                break;
+            case SETRETURN:
+                #ifdef DEBUG_MARK
+                printf("\n\tSETRETURN\n\tz.flags:%d\n", p->z.flags);
+                #endif
+                if((p->z.reg) != 0){
+                    load_into_reg(f, p->z.reg, &(p->q1), p->typf, R1);
+                }
+                else{
+                    #ifdef DEBUG_MARK
+                    printf("\tz.reg == 0, didn't know how to dealt with it!");
+                    #else
+                    ierror(0);
+                    #endif
+                }
+                break;
+            case MOVEFROMREG:
+                #ifdef DEBUG_MARK
+                printf("\n\tMOVEFROMREG\n");
+                #endif
+
+                store_from_reg(f, p->q1.reg, &(p->z), p->typf, R1, R3);
+                break;
+            case MOVETOREG:
+                #ifdef DEBUG_MARK
+                printf("\n\tMOVETOREG\n");
+                #endif
+
+                load_into_reg(f, p->z.reg, &(p->q1), p->typf, R1);
+                break;
+            case NOP:
+                #ifdef DEBUG_MARK
+                printf("\n\tNOP\n");
+                #endif
+                break;
+            default:
+                #ifdef DEBUG_MARK
+                printf("\tSomething is wrong in gencode()!\n");
+                #else
+                ierror(0);
+                #endif
+                break;
+        }
+    }
+
+    //restore used registers
+    for(int i = 6; i >= 0; i--){
+        if(saved_regs[i] == 1){
+            emit(f, "\tPOP \t %s\n", regnames[i + 7]);
+        }
+    }
+
+    //restore backend registers
+    emit(f, "\tPOP \t R4\n\tPOP \t R3\n\tPOP \t R2\n\tPOP \t R1\n");
+
+    //emit function epilogue
+    emit(f, "\tOR  \t %s %s %s\n",regnames[R0], regnames[FP], regnames[SP]); //restore SP from FP
+    emit(f, "\tPOP \t %s\n", regnames[FP]); //restore old FP from stack
+
+    //return
+    if((v->tattr)&INTERRUPT){
+        emit(f, "\tRETI\n");
+    }
+    else{
+        emit(f, "\tRET\n");
+    }
+}
+
+/*
+ *  This function has to create <size> bytes of storage
+ *  initialized with zero.
+ */
+void gen_ds(FILE *f,zmax size,struct Typ *t){
+    #ifdef DEBUG_MARK
+    printf("Called gen_ds(FILE *f,zmax size,struct Typ *t)\n");
+    #endif
+    emit(f, "\t.DS \t%ld\n", zm2l(size));
+}
+
+/*
+ *  This function has to make sure the next data is
+ *  aligned to multiples of <align> bytes.
+ */
+void gen_align(FILE *f,zmax align){}
+
+/*
+ *  This function has to create the head of a variable
+ *  definition, i.e. the label and information for
+ *  linkage etc.
+ */
+void gen_var_head(FILE *f,struct Var *v){
+    #ifdef DEBUG_MARK
+    printf("Called gen_var_head(FILE *f,struct Var *v)\n");
+    #endif
+
+    switch((v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+        case STATIC:
+            #ifdef DEBUG_MARK
+            printf("\tHave to emit static variable head.\n");
+            #endif
+            emit(f,"L_%ld:\n", zm2l(v->offset));
+            break;
+        case EXTERN:
+            #ifdef DEBUG_MARK
+            printf("\tHave to emit extern variable head.\n");
+            #endif
+
+            if(v->flags&(DEFINED|TENTATIVE)){
+                emit(f,".EXPORT \t %s\n", v->identifier);
+                emit(f,"%s:\n", v->identifier);
+            }
+            else{
+                emit(f,".IMPORT \t %s\n", v->identifier);
+            }
+            break;
+        default:
+            #ifdef DEBUG_MARK
+            printf("\tCant generate head, unknown storage class: %d\n", v->storage_class);
+            #else
+            ierror(0);
+            #endif
+            break;
+    }
+}
+
+/*
+ *  This function has to create static storage
+ *  initialized with const-list p.
+ */
+void gen_dc(FILE *f,int t,struct const_list *p){
+    #ifdef DEBUG_MARK
+    printf("Called gen_dc(FILE *f,int t,struct const_list *p)\n");
+    #endif
+
+    if(!p->tree){
+        if(ISFLOAT(t)){
+            emit(f,"\t.DAT \t ");
+            emit(f,"0x%x", *(unsigned int*)&p->val);
+            emit(f,"\n");
+        }
+        else{
+            emit(f,"\t.DAT \t ");
+            emitval(f,&p->val,t&NU);
+            emit(f,"\n");
+        }
+    }
+    else{
+        emit(f,"\t.DAT \t ");
+        struct const_list *p_next = p;
+        for(;p_next;p_next=p_next->next){
+            emitval(f,&p_next->val,t&NU);
+            emit(f, " ");
+        }
+        emit(f, "\n");
+    }
+}
+
+//this is for debug, not needed now
+void init_db(FILE *f){}
+void cleanup_db(FILE *f){}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d){
+    //this will put all arguments into stack
+    return 0;
+}
+
+/*
+ * Returns 0 if the register is no register pair. If r
+ * is a register pair non-zero will be returned and the
+ * structure pointed to p will be filled with the two
+ * elements.
+ */
+int reg_pair(int r,struct rpair *p){
+    return 0;
+}
+
+void compare(FILE *f, struct IC *p){
+
+    int q1reg = 0;
+    int q2reg = 0;
+
+    //load operands into R1 and R2
+    if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) != REG){
+        load_into_reg(f, R1, &(p->q1), p->typf, R3);
+        q1reg = R1;
+    }
+    else{
+        q1reg = p->q1.reg;
+    }
+
+    if((p->code) != TEST){
+        if(((p->q2.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) != REG){
+            load_into_reg(f, R2, &(p->q2), p->typf, R3);
+            q2reg = R2;
+        }
+        else{
+            q2reg = p->q2.reg;
+        }
+    }
+    else{
+        q2reg = R2;
+        emit(f, "\tOR  \t %s %s %s\n",regnames[R0], regnames[R0], regnames[R2]);
+    }
+
+    //find branch IC
+    struct IC *branch_ic;
+    branch_ic = p->next;
+    while(branch_ic && ((branch_ic->code) == FREEREG) ) {
+        branch_ic = branch_ic->next;
+    }
+
+    //emit compare code
+    if (((p->typf) & FLOAT) == FLOAT || ((p->typf) & DOUBLE) == DOUBLE || ((p->typf) & LDOUBLE) == LDOUBLE){
+        switch(branch_ic->code){
+            case BEQ:
+                emit(f, "\tCMPF \t EQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BNE:
+                emit(f, "\tCMPF \t NEQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BLT:
+                emit(f, "\tCMPF \t L %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BGE:
+                emit(f, "\tCMPF \t GE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BLE:
+                emit(f, "\tCMPF \t LE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BGT:
+                emit(f, "\tCMPF \t G %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            default:
+                ierror(0);
+                break;
+        }
+    }
+    else{
+        switch(branch_ic->code){
+            case BEQ:
+                emit(f, "\tCMPI \t EQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BNE:
+                emit(f, "\tCMPI \t NEQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                break;
+            case BLT:
+                if((p->typf & UNSIGNED) == UNSIGNED){
+                    emit(f, "\tCMPI \t LU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                else{
+                    emit(f, "\tCMPI \t L %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                break;
+            case BGE:
+                if((p->typf & UNSIGNED) == UNSIGNED){
+                    emit(f, "\tCMPI \t GEU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                else{
+                    emit(f, "\tCMPI \t GE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                break;
+            case BLE:
+                if((p->typf & UNSIGNED) == UNSIGNED){
+                    emit(f, "\tCMPI \t LEU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                else{
+                    emit(f, "\tCMPI \t LE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                break;
+            case BGT:
+                if((p->typf & UNSIGNED) == UNSIGNED){
+                    emit(f, "\tCMPI \t GU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                else{
+                    emit(f, "\tCMPI \t G %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+                }
+                break;
+            default:
+                ierror(0);
+                break;
+        }
+    }
+}
+
+void load_into_reg(FILE *f, int dest_reg, struct obj *o, int type, int tmp_reg){
+    switch((o->flags) & (KONST|VAR|REG|DREFOBJ|VARADR)){
+        case KONST:
+            load_cons(f, dest_reg, o->val.vmax);
+            break;
+        case (KONST|DREFOBJ):
+            //place memory location constant point to into register
+            emit(f, "\tLD  \t ");
+            emitval(f, &(o->val), type);
+            emit(f, " %s\n", regnames[dest_reg]);
+            break;
+        case REG:
+            //move between registers
+            if((o->reg) != dest_reg){
+                emit(f, "\tOR  \t %s %s %s\n",regnames[R0], regnames[o->reg], regnames[dest_reg]);
+            }
+            break;
+        case VAR:
+            //put value of variable into register
+
+            switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+                case STATIC:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s L_%ld\n", regnames[dest_reg], zm2l(o->v->offset));
+                        load_cons(f, tmp_reg, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[tmp_reg]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                    }
+                    else{
+                        emit(f, "\tLD \t L_%ld %s\n", zm2l(o->v->offset), regnames[dest_reg]);
+                    }
+                    break;
+                case EXTERN:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s %s\n", regnames[dest_reg], o->v->identifier);
+                        load_cons(f, tmp_reg, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[tmp_reg]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                    }
+                    else{
+                        emit(f, "\tLD \t %s %s\n", o->v->identifier , regnames[dest_reg]);
+                    }
+                    break;
+                case AUTO:
+                    if((o->v->offset) < 0){
+                        //this is argument
+                        load_cons(f, dest_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg],regnames[FP], regnames[tmp_reg]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                    }
+                    else{
+                        //this is auto variable
+                        int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+
+                        if(offset == 0){
+                            emit(f, "\tLDI \t %s %s\n", regnames[FP], regnames[dest_reg]);
+                        }
+                        else if(offset == 1){
+                            emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg]);
+                            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                        }
+                        else{
+                            load_cons(f, dest_reg, offset);
+                            emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[dest_reg], regnames[tmp_reg]);
+                            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                        }
+
+                    }
+                    break;
+                default:
+                    #ifdef DEBUG_MARK
+                    printf("\tHave to load variable that is not static, extern or auto, this is not implemented!\n");
+                    #else
+                    ierror(0);
+                    #endif
+                    break;
+            }
+
+            break;
+        case (VAR|REG):
+            if((o->reg) != dest_reg){
+                emit(f, "\tOR  \t %s %s %s\n", regnames[R0], regnames[o->reg], regnames[dest_reg]);
+            }
+            break;
+        case (REG|DREFOBJ):
+            //point into memory with register value
+
+            emit(f, "\tLDI \t %s %s\n", regnames[o->reg], regnames[dest_reg]);
+            break;
+        case (VAR|DREFOBJ):
+            //use variable value as pointer to memory
+
+            switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+                case STATIC:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s L_%ld\n", regnames[dest_reg], zm2l(o->v->offset));
+                        load_cons(f, tmp_reg, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[dest_reg]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[dest_reg], regnames[tmp_reg]);
+                    }
+                    else{
+                        emit(f, "\tLD  \t L_%ld %s\n", zm2l(o->v->offset), regnames[tmp_reg]);
+                    }
+                    emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                    break;
+                case EXTERN:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s %s\n", regnames[dest_reg], o->v->identifier);
+                        load_cons(f, tmp_reg, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[dest_reg]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[dest_reg], regnames[tmp_reg]);
+                    }
+                    else{
+                        emit(f, "\tLD \t %s %s\n", o->v->identifier , regnames[tmp_reg]);
+                    }
+                    emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                    break;
+                case AUTO:
+                    if((o->v->offset) < 0){
+                        //this is argument
+                        load_cons(f, dest_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg],regnames[FP], regnames[tmp_reg]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                    }
+                    else{
+                        //this is auto variable
+                        int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+
+                        if(offset == 0){
+                            emit(f, "\tLDI \t %s %s\n", regnames[FP], regnames[dest_reg]);
+                        }
+                        else if(offset == 1){
+                            emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg]);
+                            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                        }
+                        else{
+                            load_cons(f, dest_reg, offset);
+                            emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[dest_reg], regnames[tmp_reg]);
+                            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+                        }
+
+                    }
+                    break;
+                default:
+                    #ifdef DEBUG_MARK
+                    printf("\tHave to load variable that is not static, extern or auto, this is not implemented!\n");
+                    #else
+                    ierror(0);
+                    #endif
+                    break;
+            }
+
+            emit(f, "\tLDI \t %s %s\n", regnames[dest_reg], regnames[tmp_reg]);
+            emit(f, "\tOR  \t R0 %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+
+            break;
+        case (VAR|REG|DREFOBJ):
+            if((o->reg) != dest_reg){
+                emit(f, "\tOR  \t %s %s %s\n",regnames[R0], regnames[o->reg], regnames[tmp_reg]);
+            }
+            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+            break;
+        case (VAR|VARADR):
+            //into dest_reg store address of variable
+            switch((o->v->storage_class) & (STATIC|EXTERN)){
+                case EXTERN:
+                    emit(f, "\tMVIA \t %s %s\n", regnames[dest_reg], o->v->identifier);
+                    break;
+                case STATIC:
+                    emit(f, "\tMVIA \t %s L_%ld\n", regnames[dest_reg], zm2l(o->v->offset));
+                    break;
+                default: //this is pointless storage_class can be only static or extern with VARADR
+                    ierror(0);
+            }            
+            //this is useful when object is array and we want adres of nonfirst element
+            if(o->val.vmax > 0){
+                load_cons(f, tmp_reg, o->val.vmax);
+                emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[dest_reg]);              
+            }
+            
+            break;
+        default:
+            #ifdef DEBUG_MARK
+            printf("\tSomething is wrong while acuring operand!\n");
+            #else
+            ierror(0);
+            #endif
+            break;
+    }
+}
+
+void store_from_reg(FILE *f, int source_reg, struct obj *o, int type, int tmp_reg, int tmp_reg_b){
+    switch((o->flags) & (KONST|VAR|REG|DREFOBJ|VARADR)){
+        case KONST:
+            //How can I store register into KONST?!
+            ierror(0);
+            break;
+        case (KONST|DREFOBJ):
+            //use konstant as pointer into memory
+            emit(f, "\tST  \t %s ", regnames[source_reg]);
+            emitval(f, &(o->val), type);
+            emit(f, "\n");
+            break;
+        case REG:
+            //move from register into register
+            if(source_reg != (o->reg)){
+                emit(f, "\tOR  \t %s %s %s\n",regnames[R0], regnames[source_reg], regnames[o->reg]);
+            }
+            break;
+        case VAR:
+            //load register into variable
+            switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+                case STATIC:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s L_%ld\n", regnames[tmp_reg], zm2l(o->v->offset));
+                        load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg]);
+                        emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    }
+                    else{
+                        emit(f, "\tST  \t %s L_%ld\n", regnames[source_reg], zm2l(o->v->offset));
+                    }
+                    break;
+                case EXTERN:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s %s\n", regnames[tmp_reg], o->v->identifier);
+                        load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg]);
+                        emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    }
+                    else{
+                        emit(f, "\tST  \t %s %s\n", regnames[source_reg], o->v->identifier);
+                    }
+                    break;
+                case AUTO:
+                    if((o->v->offset) < 0){
+                        //function argument
+                        load_cons(f, tmp_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg],regnames[FP], regnames[tmp_reg]);
+                        emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    }
+                    else{
+                        //auto variable
+                        int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+                        if (offset == 0){
+                            emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[FP]);
+                        }
+                        else if(offset == 1){
+                            emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg]);
+                            emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                        }
+                        else{
+                            load_cons(f, tmp_reg, offset);
+                            emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[tmp_reg], regnames[tmp_reg]);
+                            emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                        }
+                    }
+                    break;
+                default:
+                    #ifdef DEBUG_MARK
+                    printf("\tHave to store into variable that is not static, extern or auto, this is not implemented!\n");
+                    #else
+                    ierror(0);
+                    #endif
+                    break;
+            }
+            break;
+        case (VAR|REG):
+            emit(f, "\tOR   \t %s %s %s\n", regnames[R0], regnames[source_reg], regnames[o->reg]);
+            break;
+        case (REG|DREFOBJ):
+            //use value in register as pointer into memory
+            emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[o->reg]);
+            break;
+        case (VAR|DREFOBJ):
+            //use value in variable as pointer into memory
+            switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+                case STATIC:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s L_%ld\n", regnames[tmp_reg], zm2l(o->v->offset));
+                        load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg_b]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+                    }
+                    else{
+                        emit(f, "\tLD  \t L_%ld %s\n", zm2l(o->v->offset), regnames[tmp_reg]);
+                    }
+                    emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    break;
+                case EXTERN:
+                    if(zm2l(o->val.vmax) != 0){
+                        emit(f, "\tMVIA \t %s %s\n", regnames[tmp_reg], o->v->identifier);
+                        load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg_b]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+                    }
+                    else{
+                        emit(f, "\tLD  \t %s %s\n", o->v->identifier, regnames[tmp_reg] );
+                    }
+                    emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    break;
+                case AUTO:
+                    if((o->v->offset) < 0){
+                        //function argument
+                        load_cons(f, tmp_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+                        emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg],regnames[FP], regnames[tmp_reg_b]);
+                        emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+                        emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    }
+                    else{
+                        //auto variable
+                        int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+                        if(offset == 0){
+                            emit(f, "\tLDI \t %s %s\n", regnames[FP], regnames[tmp_reg_b]);
+                        }
+                        else if(offset == 1){
+                            emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg_b]);
+                            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+                        }
+                        else{
+                            load_cons(f, tmp_reg, offset);
+                            emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[tmp_reg], regnames[tmp_reg]);
+                            emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b]);
+                        }
+                        emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg_b]);
+                    }
+                    break;
+                default:
+                    #ifdef DEBUG_MARK
+                    printf("\tHave to store into variable that is not static, extern or auto, this is not implemented!\n");
+                    #else
+                    ierror(0);
+                    #endif
+                    break;
+            }
+            break;
+        case (VAR|REG|DREFOBJ):
+            emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[o->reg]);
+            break;
+        case (VAR|VARADR): //use variable address as pointer
+            switch(o->v->storage_class){
+                case STATIC:
+                    emit(f, "\tMVIA \t %s L_%ld\n", regnames[tmp_reg], zm2l(o->v->offset));
+                    emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    break;
+                case EXTERN:
+                    emit(f, "\tMVIA \t %s %s\n", regnames[tmp_reg], o->v->identifier);
+                    emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+                    break;
+                default: //can be only static or extern
+                    ierror(0);
+                    break;
+            }
+            break;
+        default:
+            #ifdef DEBUG_MARK
+            printf("\tCant store reg into object, unknown object!\n");
+            #else
+            ierror(0);
+            #endif
+            break;
+    }
+}
+
+void arithmetic(FILE *f, struct IC *p){
+    int q1reg = 0;
+    int q2reg = 0;
+
+    int zreg = 0;
+    int movez = 0;
+
+    int unary = 0;
+
+    int isunsigned = 0;
+    if (((p->typf) & UNSIGNED) == UNSIGNED){
+        isunsigned = 1;
+    }
+
+    if(((p->code) == MINUS) || ((p->code) == KOMPLEMENT)){
+        unary = 1;
+    }
+
+    //load first operand
+    if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+        q1reg = p->q1.reg;
+    }
+    else{
+        load_into_reg(f, R1, &(p->q1), p->typf, R3);
+        q1reg = R1;
+    }
+
+    //load second operand
+    if(unary != 1){
+        if(((p->q2.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+            q2reg = p->q2.reg;
+        }
+        else{
+            load_into_reg(f, R2, &(p->q2), p->typf, R3);
+            q2reg = R2;
+        }
+    }
+
+    //prepare target register
+    if(((p->z.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+        zreg = p->z.reg;
+    }
+    else{
+        zreg = R1;
+        movez = 1;
+    }
+
+    if (((p->typf) & FLOAT) == FLOAT || ((p->typf) & DOUBLE) == DOUBLE || ((p->typf) & LDOUBLE) == LDOUBLE){
+        switch(p->code){
+            case ADD:
+                emit(f, "\tFADD \t ");
+                break;
+            case SUB:
+                emit(f, "\tFSUB \t ");
+                break;
+            case MULT:
+                emit(f, "\tFMUL \t ");
+                break;
+            case DIV:
+                emit(f, "\tFDIV \t ");
+                break;
+            case MINUS:
+                load_cons(f, R2, 0x3f800000);
+                emit(f, "\tSUB \t ");
+                unary = 0;
+                q2reg = R2;
+                break;
+            default:
+                #ifdef DEBUG_MARK
+                printf("This is not implemented!\n");
+                #else
+                ierror(0);
+                #endif
+                break;
+        }
+    }
+    else{
+
+        //emit instruction opcode
+        switch(p->code){
+            case OR:
+                emit(f, "\tOR  \t ");
+                break;
+            case XOR:
+                emit(f, "\tXOR \t ");
+                break;
+            case AND:
+                emit(f, "\tAND \t ");
+                break;
+            case LSHIFT:
+                emit(f, "\tLSL \t ");
+                break;
+            case RSHIFT:
+                if(isunsigned == 1) {
+                    emit(f, "\tLSR \t ");
+                }
+                else{
+                    emit(f, "\tASR \t ");
+                }
+                break;
+            case ADD:
+                emit(f, "\tADD \t ");
+                break;
+            case SUB:
+                emit(f, "\tSUB \t ");
+                break;
+            case MULT:
+                if(isunsigned == 1) {
+                    emit(f, "\tMULU \t ");
+                }
+                else{
+                    emit(f, "\tMUL \t ");
+                }
+                break;
+            case DIV:
+                if(isunsigned == 1) {
+                    emit(f, "\tDIVU \t ");
+                }
+                else{
+                    emit(f, "\tDIV \t ");
+                }
+                break;
+            case MOD:
+                if(isunsigned == 1) {
+                    emit(f, "\tREMU \t ");
+                }
+                else{
+                    emit(f, "\tREM \t ");
+                }
+                break;
+            case ADDI2P:
+                emit(f, "\tADD \t ");
+                break;
+            case SUBIFP:
+                emit(f, "\tSUB \t ");
+                break;
+            case SUBPFP:
+                emit(f, "\tSUB \t ");
+                break;
+            case MINUS:
+                emit(f, "\tDEC \t ");
+                break;
+            case KOMPLEMENT:
+                emit(f, "\tNOT \t ");
+                break;
+            default:
+                #ifdef DEBUG_MARK
+                printf("\tPassed invalid IC into arithmetic()\n\tp->code: %d\n", p->code);
+                #else
+                ierror(0);
+                #endif
+                break;
+        }
+    }
+
+    //emit instruction arguments
+    if(unary != 1){
+        emit(f, "%s %s %s\n", regnames[q1reg], regnames[q2reg], regnames[zreg]);
+    }
+    else{
+        emit(f, "%s %s\n", regnames[q1reg], regnames[zreg]);
+    }
+
+    if(movez == 1){
+        store_from_reg(f, R1, &(p->z), p->typf, R2, R3);
+    }
+}
+
+void load_cons(FILE *f, int reg, long int value){
+    if(value == 0){
+        emit(f, "\tOR  \t R0 R0 %s\n", regnames[reg]);
+    }
+    else if((16777216 > value) && (value > 0)){
+        emit(f, "\tMVIA \t %s %ld\n", regnames[reg], value);
+    }
+    else if (value > 0){
+        emit(f, "\t.MVI \t %s %ld\n", regnames[reg], value);
+    }
+    else{
+        emit(f, "\t.MVI \t %s 0x%x\n", regnames[reg], value);
+    }
+}
diff --git a/machines/mark/machine.dt b/machines/mark/machine.dt
new file mode 100644
index 0000000..230a53c
--- /dev/null
+++ b/machines/mark/machine.dt
@@ -0,0 +1,15 @@
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BIEEELE S32BIEEEBE
+S32BIEEELE S32BIEEEBE
+S32BIEEELE S32BIEEEBE
+S32BULE S32BUBE
+
diff --git a/machines/mark/machine.h b/machines/mark/machine.h
new file mode 100644
index 0000000..013e6ea
--- /dev/null
+++ b/machines/mark/machine.h
@@ -0,0 +1,93 @@
+#include "dt.h"
+
+//bez speciálních adresních modu
+struct AddressingMode {
+    int never_used;
+};
+
+struct reg_handle {
+  int gpr;
+};
+
+// sem nacpat počet registrů, ale co SP, PC a Zero reg? To jsou spec. registry
+// které kompilátor nemůže jen tak používat
+#define MAXR 16
+
+// počet argumentů, nemám žádné ale doku tvrdí že t i tak musí být MAXGF 1
+#define MAXGF 1
+
+//může být druhý operand IC stejný jako cíl? 0-ano 1-ne
+#define USEQ2ASZ 0
+
+//A co mám jako kurva dát sem?! Zkusím CHAR když to nebude fungovat dej tam INT!
+#define MINADDI2P CHAR
+
+// další wtf! Moje arch tohle neřeší, tak tam prostě prskneme malého indiána
+#define BIGENDIAN 0
+#define LITTLEENDIAN 1
+
+//switche chci compilovat na COMPARE/BEQ nikoliv na SUB/TEST/BEQ
+#define SWITCHSUBS 0
+
+// obšlehnuto z generic, tady toho je vůbec hodně obšlehnutého
+#define INLINEMEMCPY 1024
+
+// reverse argument push order
+//#define ORDERED_PUSH 0
+
+// argumenty klidně do registrů
+#define HAVE_REGPARMS 1
+
+//nemám registrové páry
+#undef HAVE_REGPAIRS
+
+//nó, ale zvhledem k tomu že long a int je na mej arch stejný tak je to asi k prdu ale budiž
+#undef HAVE_INT_SIZET
+
+// a teď ty sračky pro peephole optimalizace, ty dělat nebudu tak jsem tohle obšlehl z generic
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+
+// tohle je zatím k hovnu později se to ale může hodit
+#define HAVE_TARGET_ATTRIBUTES
+#define HAVE_TARGET_PRAGMAS
+
+#undef HAVE_REGS_MODIFIED //nepodporuji interprocedural register allocation
+
+//tohle je dobrý pro CPU s registrama co mají pevně danou funkci, moje arch je ortogonální až běda tak to nemusím řešit
+#undef HAVE_TARGET_RALLOC
+
+// pro mě zbytečné, je to pro aptimalizaci
+#undef HAVE_EXT_IC
+
+//tohle je sranda, doku se tu odkazuje na kapitolu která není napsaná, nicméně, externí typy nepotřebujeme
+#undef HAVE_EXT_TYPES
+
+#undef HAVE_TGT_PRINTVAL //tohle je stejná  sračka jako ta vejš, kdo ví k čemu to je ale nechci to
+
+// no, nemám páru jak to nastavit tak je to obšlehnuté
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 12
+
+/* toto je pro variable lenght arrays (nutno použít -c99) zatím to jebu, spousta architektur to taky nemá
+#define ALLOCVLA_REG <reg>
+#define ALLOCVLA_INLINEASM <inline asm>
+#define FREEVLA_REG <reg>
+#define FREEVLA_INLINEASM <inline asm>
+#define OLDSPVLA_INLINEASM <inline asm>
+#define FPVLA_REG <reg>
+*/
+
+//tohle je pro nahrazení složitějších operací voláím do knihoven - super věc ale zatím to jebu a budu generovat makra
+#undef HAVE_LIBCALLS
+
+// who cares?
+#define AVOID_FLOAT_TO_UNSIGNED 1
+#define AVOID_UNSIGNED_TO_FLOAT 1
diff --git a/machines/messiahtron/machine.c b/machines/messiahtron/machine.c
new file mode 100755
index 0000000..675df3f
--- /dev/null
+++ b/machines/messiahtron/machine.c
@@ -0,0 +1,2717 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC

+CPU.

+

+Configurable at build-time are:

+- number of (32bit) general-purpose-registers

+- number of (64bit) floating-point-registers

+- number of (8bit) condition-code-registers

+- mechanism for stack-arguments (moving ot fixed sp)

+

+It allows to select as run-time-options:

+- two- or three-address code

+- memory operands or load-store-architecture

+- number of register-arguments

+- number of caller-save-registers

+*/                                                                             

+

+#include "../../supp.h"

+

+static char FILE_[]=__FILE__;

+

+/*  Public data that MUST be there.                             */

+

+/* Name and copyright. */

+char cg_copyright[]="vbcc Messiahtron code-generator "__DATE__" (c) in 2008 by Andrew Price";

+

+/*  Commandline-flags the code-generator accepts:

+0: just a flag

+VALFLAG: a value must be specified

+STRINGFLAG: a string can be specified

+FUNCFLAG: a function will be called

+apart from FUNCFLAG, all other versions can only be specified once */

+int g_flags[MAXGF]={0,0,

+VALFLAG,VALFLAG,VALFLAG,

+0,0,

+VALFLAG,VALFLAG,0};

+

+/* the flag-name, do not use names beginning with l, L, I, D or U, because

+they collide with the frontend */

+char *g_flags_name[MAXGF]={"three-addr","load-store",

+"volatile-gprs","volatile-fprs","volatile-ccrs",

+"imm-ind","gpr-ind",

+"gpr-args","fpr-args","use-commons"};

+

+/* the results of parsing the command-line-flags will be stored here */

+union ppi g_flags_val[MAXGF];

+

+/*  Alignment-requirements for all types in bytes.              */

+zmax align[MAX_TYPE+1];

+

+/*  Alignment that is sufficient for every object.              */

+zmax maxalign;

+

+/*  CHAR_BIT for the target machine.                            */

+zmax char_bit;

+

+/*  sizes of the basic types (in bytes) */

+zmax sizetab[MAX_TYPE+1];

+

+/*  Minimum and Maximum values each type can have.              */

+/*  Must be initialized in init_cg().                           */

+zmax t_min[MAX_TYPE+1];

+zumax t_max[MAX_TYPE+1];

+zumax tu_max[MAX_TYPE+1];

+

+/*  Names of all registers. will be initialized in init_cg(),

+register number 0 is invalid, valid registers start at 1 */

+char *regnames[MAXR+1];

+

+/*  The Size of each register in bytes.                         */

+zmax regsize[MAXR+1];

+

+/*  a type which can store each register. */

+struct Typ *regtype[MAXR+1];

+

+/*  regsa[reg]!=0 if a certain register is allocated and should */

+/*  not be used by the compiler pass.                           */

+int regsa[MAXR+1];

+

+/*  Specifies which registers may be scratched by functions.    */

+int regscratch[MAXR+1];

+

+/* specifies the priority for the register-allocator, if the same

+estimated cost-saving can be obtained by several registers, the

+one with the highest priority will be used */

+int reg_prio[MAXR+1];

+

+/* an empty reg-handle representing initial state */

+struct reg_handle empty_reg_handle={0,0};

+

+/* Names of target-specific variable attributes.                */

+char *g_attr_name[]={"__interrupt",0};

+

+

+/****************************************/

+/*  Private data and functions.         */

+/****************************************/

+

+#define THREE_ADDR (g_flags[0]&USEDFLAG)

+#define LOAD_STORE (g_flags[1]&USEDFLAG)

+//#define VOL_FIXED   NUM_FIXED

+#define VOL_16BIT   ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_16BIT/2)

+#define VOL_32BIT   ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_32BIT/2)

+#define VOL_64BIT   ((g_flags[4]&USEDFLAG)?g_flags_val[5].l:NUM_64BIT/2)

+#define VOL_8BIT   ((g_flags[4]&USEDFLAG)?g_flags_val[6].l:NUM_8BIT/2)

+#define IMM_IND    ((g_flags[5]&USEDFLAG)?1:0)

+#define GPR_IND    ((g_flags[6]&USEDFLAG)?2:0)

+//#define ARGS8   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:1)

+//#define ARGS16   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)

+//#define ARGS32   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)

+//#define ARGS64   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)

+// #define FPR_ARGS   ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)

+//#define USE_COMMONS (g_flags[9]&USEDFLAG)

+

+

+/* alignment of basic data-types, used to initialize align[] */

+static long malign[MAX_TYPE+1]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};

+/* sizes of basic data-types, used to initialize sizetab[] */

+static long msizetab[MAX_TYPE+1]={0,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};

+

+/* used to initialize regtyp[] */

+static struct Typ llong={LLONG},ltyp={LONG},lshort={SHORT},lchar={CHAR};

+

+/* macros defined by the backend */

+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",

+"__GENERIC__",

+0};

+

+/* special registers */

+static int sp;                     /*  Stackpointer                        */

+static int t8bit1,t8bit2;               /*  temporary gprs */

+static int t16bit1,t16bit2;

+static int t32bit1,t32bit2;

+static int t64bit1,t64bit2;

+

+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])

+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};

+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};

+

+/* sections */

+#define DATA 0

+#define BSS 1

+#define CODE 2

+#define RODATA 3

+#define SPECIAL 4

+

+static long stack;

+static int stack_valid;

+static int section=-1,newobj;

+static char *codename=".resetlocals\n;code\n",

+*dataname=";data\n",

+*bssname=";bss\n",

+*rodataname=";read only data\n";

+

+/* return-instruction */

+static char *ret;

+

+/* label at the end of the function (if any) */

+static int exit_label;

+

+/* assembly-prefixes for labels and external identifiers */

+static char *labprefix="l",*idprefix="_";

+

+/* variables to keep track of the current stack-offset in the case of

+a moving stack-pointer */

+static long loff,stackoffset,notpopped,dontpop,maxpushed,stack;

+static pushorder=2;

+

+static long localsize,rsavesize,argsize;

+

+/* pushed on the stack by a callee, no pop needed */

+static void callee_push(long l)

+{

+}

+

+static void push(long l)

+{

+	stackoffset-=l;

+	if(stackoffset<maxpushed)

+		maxpushed=stackoffset;

+}

+static void pop(long l)

+{

+	stackoffset+=l;

+}

+

+static void emit_obj(FILE *f,struct obj *p,int t);

+

+/* calculate the actual current offset of an object relativ to the

+stack-pointer; we use a layout like this:

+------------------------------------------------

+| arguments to this function                   |

+------------------------------------------------

+| return-address [size=4]                      |

+------------------------------------------------

+| caller-save registers [size=rsavesize]       |

+------------------------------------------------

+| local variables [size=localsize]             |

+------------------------------------------------

+| arguments to called functions [size=argsize] |

+------------------------------------------------

+All sizes will be aligned as necessary.

+In the case of FIXED_SP, the stack-pointer will be adjusted at

+function-entry to leave enough space for the arguments and have it

+aligned to 16 bytes. Therefore, when calling a function, the

+stack-pointer is always aligned to 16 bytes.

+For a moving stack-pointer, the stack-pointer will usually point

+to the bottom of the area for local variables, but will move while

+arguments are put on the stack.

+

+This is just an example layout. Other layouts are also possible.

+*/

+

+static long real_offset(struct obj *o)

+{

+	long off=zm2l(o->v->offset);

+	if(off<0){

+		/* function parameter */

+		off=localsize+rsavesize+4-off-zm2l(maxalign);

+	}

+

+	off+=4;

+

+	off+=stackoffset;

+	off+=zm2l(o->val.vmax);

+	return off;

+}

+

+/*  Initializes an addressing-mode structure and returns a pointer to

+that object. Will not survive a second call! */

+static struct obj *cam(int flags,int base,long offset)

+{

+	static struct obj obj;

+	static struct AddressingMode am;

+	obj.am=&am;

+	am.flags=flags;

+	am.base=base;

+	am.offset=offset;

+	return &obj;

+}

+

+/* changes to a special section, used for __section() */

+static int special_section(FILE *f,struct Var *v)

+{

+	char *sec;

+	if(!v->vattr) return 0;

+	sec=strstr(v->vattr,"section(");

+	if(!sec) return 0;

+	sec+=strlen("section(");

+	emit(f,"; section");

+	while(*sec&&*sec!=')') emit_char(f,*sec++);

+	emit(f,"\n");

+	if(f) section=SPECIAL;

+	return 1;

+}

+

+/* generate code to load the address of a variable into register r */

+static void load_address(FILE *f,int r,struct obj *o,int type)

+/*  Generates code to load the address of a variable into register r.   */

+{

+	if(!(o->flags&VAR))

+		ierror(0);

+	if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)

+	{

+		long off=real_offset(o);

+		emit(f,"\tmov\t%s %s ; load_address %s\n",regnames[r],regnames[sp],dt(POINTER));

+		if(off)

+		{

+			emit(f,"\tmov\tb30 %ld ; %s\n",off,dt(POINTER));

+			emit(f,"\tsub\t%s b30 ; %s\n",regnames[r],dt(POINTER));

+		}

+	}

+	else

+	{

+		emit(f,"\tmov\t%s ",regnames[r]);

+		emit_obj(f,o,type);

+		emit(f," ;%s\n", dt(POINTER));

+	}

+}

+/* Generates code to load a memory object into register r. tmp is a

+general purpose register which may be used. tmp can be r. */

+static void load_reg(FILE *f,int r,struct obj *o,int type)

+{

+	type&=NU;

+	if(o->flags&VARADR)

+	{

+		load_address(f,r,o,POINTER);

+	}

+	else

+	{

+		if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)

+			return;

+		if((o->flags&VAR)&&!(o->flags&REG))

+		{

+			if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)

+			{

+				unsigned long offset = real_offset(o);

+				if(offset == 0)

+				{

+					emit(f,"\tmov\t%s\t[z2] ;%s\n",regnames[r],dt(type));

+				}

+				else

+				{

+					emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+					emit(f,"\tmov\tb29\tz2\n");

+					emit(f,"\tsub\tb29\tb28\n");

+					if(ISFLOAT(type))

+						emit(f,"\tmovf\t%s\t[b29] ;%s\n",regnames[r],dt(type));

+					else if((type & UNSIGNED) || type == POINTER || type == STRUCT)

+						emit(f,"\tmov\t%s\t[b29] ;%s\n",regnames[r],dt(type));

+					else

+						emit(f,"\tmovs\t%s\t[b29] ;%s\n",regnames[r],dt(type));

+				}

+

+				return;

+			}

+		}

+

+		if(ISFLOAT(type))

+			emit(f,"\tmovf \t%s ",regnames[r]);

+		else if((type & UNSIGNED) || type == POINTER || type == STRUCT)

+			emit(f,"\tmov \t%s ",regnames[r]);

+		else

+			emit(f,"\tmovs \t%s ",regnames[r]);

+		emit_obj(f,o,type);

+		emit(f," ;%s\n",dt(type));

+	}

+}

+

+/*  Generates code to store register r into memory object o. */

+static void store_reg(FILE *f,int r,struct obj *o,int type)

+{

+	type&=NQ;

+

+	if((o->flags&VAR)&&!(o->flags&REG))

+	{

+

+		if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)

+		{

+			unsigned long offset = real_offset(o);

+

+			if(offset == 0)

+			{

+				if(ISFLOAT(type))

+					emit(f,"\tmovf\t[z2]\t%s ;%s\n",regnames[r],dt(type));

+				else if((type & UNSIGNED) || type == POINTER || type == STRUCT)

+					emit(f,"\tmov\t[z2]\t%s ;%s\n",regnames[r],dt(type));

+				else

+					emit(f,"\tmovs\t[z2]\t%s ;%s\n",regnames[r],dt(type));

+			}

+			else

+			{

+				emit(f,"\tmov\tb28\t%ld ; mov to stack\n", offset);

+				emit(f,"\tmov\tb29\tz2\n");

+				emit(f,"\tsub\tb29\tb28\n");

+				if(ISFLOAT(type))

+					emit(f,"\tmovf\t[b29]\t%s ;%s\n",regnames[r],dt(type));

+				else if((type & UNSIGNED) || type == POINTER || type == STRUCT)

+					emit(f,"\tmov\t[b29]\t%s ;%s\n",regnames[r],dt(type));

+				else

+					emit(f,"\tmovs\t[b29]\t%s ;%s\n",regnames[r],dt(type));

+			}

+			return;

+		}

+	}

+	if(r == 0)

+		emit(f, ";");

+

+	if(ISFLOAT(type))

+		emit(f,"\tmovf\t");

+	else if(type & UNSIGNED)

+		emit(f,"\tmov\t");

+	else

+		emit(f,"\tmovs\t");

+

+	emit_obj(f,o,type);

+	emit(f,"\t%s ;%s\n",regnames[r],dt(type));

+}

+

+/*  Yields log2(x)+1 or 0. */

+static long pof2(zumax x)

+{

+	zumax p;int ln=1;

+	p=ul2zum(1L);

+	while(ln<=32&&zumleq(p,x)){

+		if(zumeqto(x,p)) return ln;

+		ln++;p=zumadd(p,p);

+	}

+	return 0;

+}

+

+static struct IC *preload(FILE *,struct IC *);

+

+static void function_top(FILE *,struct Var *,long);

+static void function_bottom(FILE *f,struct Var *,long);

+

+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)

+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)

+

+static int q1reg,q2reg,zreg;

+

+/* Does some pre-processing like fetching operands from memory to

+registers etc. */

+static struct IC *preload(FILE *f,struct IC *p)

+{

+	int r;

+

+	if(isreg(q1))

+		q1reg=p->q1.reg;

+	else

+		q1reg=0;

+

+	if(isreg(q2))

+		q2reg=p->q2.reg;

+	else

+		q2reg=0;

+

+//	emit(f," ; Preload register type %d\t%d z:%d\t%d\t ", q1typ(p), q1typ(p) & NQ, ztyp(p), ztyp(p) & NQ);

+

+	if(isreg(z))

+	{

+		zreg=p->z.reg;

+//		emit(f," is a reg ");

+	}

+	else

+	{

+		if((ztyp(p) & NQ) == CHAR)

+		{

+//			emit(f," is a 8 bit reg (1) ");

+			zreg=t8bit1;

+		}

+		else if((ztyp(p) & NQ) == SHORT)

+		{

+//			emit(f," is a 16 bit reg (1) ");

+			zreg=t16bit1;

+		}

+		else if((ztyp(p) & NQ) == LDOUBLE || (ztyp(p) & NQ) == LLONG || (ztyp(p) & NQ) == DOUBLE)

+		{

+//			emit(f," is a 64 bit reg (1) ");

+			zreg=t64bit1;

+		}

+		else

+		{

+//			emit(f," is a 32 bit reg (1) ");

+			zreg=t32bit1;

+		}

+	}

+

+	if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){

+		p->q1.flags&=~DREFOBJ;

+		if((q1typ(p) & NQ) == CHAR)

+		{

+			load_reg(f,t8bit1,&p->q1,q1typ(p));

+			p->q1.reg=t8bit1;

+//			emit(f," is a 8 bit reg (2) ");

+		}

+		else if((q1typ(p) & NQ) == SHORT)

+		{

+			load_reg(f,t16bit1,&p->q1,q1typ(p));

+			p->q1.reg=t16bit1;

+//			emit(f," is a 16 bit reg (2) ");

+		}

+		else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)

+		{

+			load_reg(f,t64bit1,&p->q1,q1typ(p));

+			p->q1.reg=t64bit1;

+//			emit(f," is a 64 bit reg (2) ");

+		}

+		else

+		{

+			load_reg(f,t32bit1,&p->q1,q1typ(p));

+			p->q1.reg=t32bit1;

+//			emit(f," is a 32 bit reg (2) ");

+		}

+		p->q1.flags|=(REG|DREFOBJ);

+	}

+	if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){

+		if((q1typ(p) & NQ) == CHAR)

+		{

+			q1reg=t8bit1;

+//			emit(f," is a 8 bit reg (3) ");

+		}

+		else if((q1typ(p) & NQ) == SHORT)

+		{

+			q1reg=t16bit1;

+//			emit(f," is a 16 bit reg (3) ");

+		}

+		else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)

+		{

+			q1reg=t64bit1;

+//			emit(f," is a 64 bit reg (3) ");

+		}

+		else

+		{

+			q1reg=t32bit1;

+//			emit(f," is a 32 bit reg (3) ");

+		}

+		load_reg(f,q1reg,&p->q1,q1typ(p));

+		p->q1.reg=q1reg;

+		p->q1.flags=REG;

+	}

+

+	if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){

+		p->q2.flags&=~DREFOBJ;

+		if((q1typ(p) & NQ) == CHAR)

+		{

+			load_reg(f,t8bit1,&p->q2,q2typ(p));

+			p->q2.reg=t8bit1;

+//			emit(f," is a 8 bit reg (4) ");

+		}

+		else if((q1typ(p) & NQ) == SHORT)

+		{

+			load_reg(f,t16bit1,&p->q2,q2typ(p));

+			p->q2.reg=t16bit1;

+//			emit(f," is a 16 bit reg (4) ");

+		}

+		else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)

+		{

+			load_reg(f,t64bit1,&p->q2,q2typ(p));

+			p->q2.reg=t64bit1;

+//			emit(f," is a 64 bit reg (4) ");

+		}

+		else

+		{

+			load_reg(f,t32bit1,&p->q2,q2typ(p));

+			p->q2.reg=t32bit1;

+//			emit(f," is a 32 bit reg (4) ");

+		}

+

+		p->q2.flags|=(REG|DREFOBJ);

+	}

+	if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){

+		if((q1typ(p) & NQ) == CHAR)

+		{

+			q2reg=t8bit1;

+//			emit(f," is a 8 bit reg (5) ");

+		}

+		else if((q1typ(p) & NQ) == SHORT)

+		{

+			q2reg=t16bit1;

+//			emit(f," is a 16 bit reg (5) ");

+		}

+		else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)

+		{

+			q2reg=t64bit1;

+//			emit(f," is a 64 bit reg (5) ");

+		}

+		else

+		{

+			q2reg=t32bit1;

+//			emit(f," is a 32 bit reg (5) ");

+		}

+

+		load_reg(f,q2reg,&p->q2,q2typ(p));

+		p->q2.reg=q2reg;

+		p->q2.flags=REG;

+	}

+

+//	emit(f,"\n");

+	return p;

+}

+

+/* save the result (in zreg) into p->z */

+void save_result(FILE *f,struct IC *p)

+{

+	if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){

+		p->z.flags&=~DREFOBJ;

+		if((p->typf & NQ) == CHAR)

+		{

+			load_reg(f,t8bit2,&p->z,POINTER);

+			p->z.reg=t8bit2;

+		}

+		else if((p->typf & NQ) == SHORT)

+		{

+			load_reg(f,t16bit2,&p->z,POINTER);

+			p->z.reg=t16bit2;

+		}

+		else if((p->typf & NQ) == LDOUBLE || (p->typf & NQ) == LLONG || (p->typf & NQ) == DOUBLE)

+		{

+			load_reg(f,t64bit2,&p->z,POINTER);

+			p->z.reg=t64bit2;

+		}

+		else

+		{

+			load_reg(f,t32bit2,&p->z,POINTER);

+			p->z.reg=t32bit2;

+		}

+		p->z.flags|=(REG|DREFOBJ);

+		//printf("setting reg to %s\n", regnames[p->z.reg]);

+	}

+

+	if(isreg(z)){

+		if(p->z.reg!=zreg)

+			emit(f,"\tmov\t%s %s ;%s\n",regnames[p->z.reg],regnames[zreg],dt(ztyp(p)));

+	}else{

+		store_reg(f,zreg,&p->z,ztyp(p));

+	}

+}

+

+/* prints an object */

+static void emit_obj(FILE *f,struct obj *p,int t)

+{

+	//printf("type = %i\n", t);

+	if((p->flags&(DREFOBJ|KONST))==(DREFOBJ|KONST))

+	{

+		emitval(f,&p->val,p->dtyp&NU);

+		return;

+	}

+	if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG))

+		emit(f,"[");

+

+	if((p->flags&VAR)&&!(p->flags&REG))

+	{

+		if(!zmeqto(l2zm(0L),p->val.vmax))

+		{

+			emitval(f,&p->val,LONG);

+			emit(f,"+");

+		}

+		if(p->v->storage_class==STATIC)

+		{

+			emit(f,"%s%ld", labprefix, zm2l(p->v->offset));

+		}

+		else

+		{

+			if(t == FUNKT)

+				emit(f,"%s%s", idprefix, p->v->identifier);

+			else if(p->flags&VARADR)

+				emit(f,"%s%s", idprefix, p->v->identifier);

+			else

+				emit(f,"[%s%s]", idprefix, p->v->identifier);

+		}

+	}

+	if(p->flags&REG)

+	{

+		emit(f, "%s", regnames[p->reg]);

+	}

+	if(p->flags&KONST)

+	{

+		if(ISFLOAT(t))

+		{

+			//			case FLOAT:

+			char *values = (char *)&p->val.vfloat;

+			// swap the order

+			char tmp = values[0];

+			values[0] = values[3];

+			values[3] = tmp;

+			tmp = values[1];

+			values[1] = values[2];

+			values[2] = tmp;

+

+			emit(f, "0x%1X", *(unsigned int *)values);

+			//				break;

+

+			//			case DOUBLE:

+			//				fprintf(fp, "[double #%08X]", obj->val.vdouble);

+			//			emit(f,"0f%e",/*labprefix,*/p->val.vfloat);

+			//			emit(f,"0f");

+			//			emitval(f,&p->val,t&NU);

+		}

+		else if(t & UNSIGNED)

+		{

+			//			emit(f, "0u");

+			emitval(f,&p->val,t&NU);

+		}

+		else

+		{

+			emit(f,"0s");

+			emitval(f,&p->val,t&NU);

+		}

+	}

+	if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG))

+		emit(f,"]");

+}

+

+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.

+Used by peephole. */

+static int exists_freereg(struct IC *p,int reg)

+{

+	while(p&&(p->code==FREEREG||p->code==ALLOCREG))

+	{

+		if(p->code==FREEREG&&p->q1.reg==reg)

+			return 1;

+		p=p->next;

+	}

+	return 0;

+}

+

+/* search for possible addressing-modes */

+static void peephole(struct IC *p)

+{

+	int c,c2,r;

+	struct IC *p2;

+	struct AddressingMode *am;

+

+	for(;p;p=p->next)

+	{

+		c=p->code;

+		if(c != FREEREG && c != ALLOCREG && (c != SETRETURN || !isreg(q1) || p->q1.reg != p->z.reg))

+			exit_label=0;

+		if(c==LABEL)

+			exit_label=p->typf;

+

+		/* Try const(reg) */

+		if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST)

+		{

+			int base;zmax of;struct obj *o;

+			eval_const(&p->q2.val,p->typf);

+			if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;

+			if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/)

+			{

+				r=p->z.reg;

+				if(isreg(q1))

+					base=p->q1.reg;

+				else

+					base=r;

+				o=0;

+				for(p2=p->next;p2;p2=p2->next)

+				{

+					c2=p2->code;

+					if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA))

+						break;

+					if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r)

+						break;

+					if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r)

+						break;

+					if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/)

+					{

+						if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r)

+						{

+							if(o) break;

+							o=&p2->q1;

+						}

+						if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r)

+						{

+							if(o) break;

+							o=&p2->q2;

+						}

+						if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r)

+						{

+							if(o) break;

+							o=&p2->z;

+						}

+					}

+					if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG)

+					{

+						int m;

+						if(c2==FREEREG)

+							m=p2->q1.reg;

+						else

+							m=p2->z.reg;

+						if(m==r)

+						{

+							if(o)

+							{

+								o->am=am=mymalloc(sizeof(*am));

+								am->flags=IMM_IND;

+								am->base=base;

+								am->offset=zm2l(of);

+								if(isreg(q1))

+								{

+									p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;

+								}

+								else

+								{

+									p->code=c=ASSIGN;p->q2.flags=0;

+									p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];

+								}

+							}

+							break;

+						}

+						if(c2!=FREEREG&&m==base)

+							break;

+						continue;

+					}

+				}

+			}

+		}

+		/* Try reg,reg */

+		if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg))

+		{

+			int base,idx;struct obj *o;

+			r=p->z.reg;idx=p->q2.reg;

+			if(isreg(q1)) base=p->q1.reg; else base=r;

+			o=0;

+			for(p2=p->next;p2;p2=p2->next)

+			{

+				c2=p2->code;

+				if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA))

+					break;

+				if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r)

+					break;

+				if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r)

+					break;

+				if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r)

+					break;

+

+				if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/)

+				{

+					if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r)

+					{

+						if(o||(q1typ(p2)&NQ)==LLONG) break;

+						o=&p2->q1;

+					}

+					if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r)

+					{

+						if(o||(q2typ(p2)&NQ)==LLONG) break;

+						o=&p2->q2;

+					}

+					if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r)

+					{

+						if(o||(ztyp(p2)&NQ)==LLONG) break;

+						o=&p2->z;

+					}

+				}

+				if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG)

+				{

+					int m;

+					if(c2==FREEREG)

+						m=p2->q1.reg;

+					else

+						m=p2->z.reg;

+					if(m==r)

+					{

+						if(o)

+						{

+							o->am=am=mymalloc(sizeof(*am));

+							am->flags=GPR_IND;

+							am->base=base;

+							am->offset=idx;

+							if(isreg(q1))

+							{

+								p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;

+							}

+							else

+							{

+								p->code=c=ASSIGN;p->q2.flags=0;

+								p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];

+							}

+						}

+						break;

+					}

+					if(c2!=FREEREG&&m==base) break;

+					continue;

+				}

+			}

+		}

+	}

+}

+

+static void pr(FILE *f,struct IC *p)

+{

+	int i;

+	for(;pushorder>2;pushorder>>=1)

+	{

+		for(i=1;i<=8;i++)

+		{

+			if(regs[i]&pushorder)

+			{

+				if(p->code==PUSH||p->code==CALL)

+				{

+					//emit(f,"\tmovl\t%ld(%s),%s\n",loff-4-stackoffset,regnames[sp],regnames[i]);

+				}

+				else

+				{

+					emit(f,"\tpop\t%s\n",regnames[i]);

+					pop(4);

+				}

+				regs[i]&=~pushorder;

+			}

+		}

+	}

+	for(i=1;i<=8;i++)

+		if(regs[i]&2) regs[i]&=~2;

+}

+

+/* generates the function entry code */

+static void function_top(FILE *f,struct Var *v,long offset)

+{

+	rsavesize=0;

+	if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 

+	if(v->storage_class==EXTERN)

+	{

+		if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)

+			emit(f,".global ");

+		//      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);

+		emit(f,"%s%s:\n",idprefix,v->identifier);

+	}

+	else

+		emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));

+

+	// reserve enough in stack for local functions

+	if(offset > 0)

+	{

+		emit(f,"\tmov\tb28\t%d\n", offset);

+		emit(f,"\tadd\tz2\tb28 ;reserve %d on stack\n", offset);

+	}

+}

+/* generates the function exit code */

+static void function_bottom(FILE *f,struct Var *v,long offset)

+{

+	// reserve enough in stack for local functions

+	if(offset > 0)

+	{

+		emit(f,"\tmov\tb28\t%d\n", offset);

+		emit(f,"\tsub\tz2\tb28 ;reserve %d on stack\n", offset);

+	}

+

+	emit(f,ret);

+}

+

+/****************************************/

+/*  End of private data and functions.  */

+/****************************************/

+

+/*  Does necessary initializations for the code-generator. Gets called  */

+/*  once at the beginning and should return 0 in case of problems.      */

+int init_cg(void)

+{

+	int i;

+	/*  Initialize some values which cannot be statically initialized   */

+	/*  because they are stored in the target's arithmetic.             */

+	maxalign=l2zm(1L);

+	char_bit=l2zm(8L);

+

+	for(i=0;i<=MAX_TYPE;i++)

+	{

+		sizetab[i]=l2zm(msizetab[i]);

+		align[i]=l2zm(malign[i]);

+	}

+

+	regnames[0]="noreg";

+	regtype[0]=mymalloc(sizeof(struct Typ));

+	//	for(i=FIRST_FIXED;i<=LAST_FIXED;i++)

+	//	{

+	//		regnames[i]=mymalloc(10);

+	//		sprintf(regnames[i],"b%d",(i-FIRST_FIXED) + 27);

+	//		regsize[i]=4;

+	//		regtype[i]=&ltyp;

+	//	}

+

+	// static struct Typ lltype={LLONG},ltyp={LONG},lshort={SHORT},lchar={CHAR};

+

+	for(i=FIRST_16BIT;i<=LAST_16BIT;i++)

+	{

+		regnames[i]=mymalloc(10);

+		sprintf(regnames[i],"a%d",i-FIRST_16BIT);

+		regsize[i]=2;

+		regtype[i]=mymalloc(sizeof(struct Typ));

+	}

+

+	for(i=FIRST_32BIT;i<=LAST_32BIT;i++)

+	{

+		regnames[i]=mymalloc(10);

+		sprintf(regnames[i],"b%d",(i-FIRST_32BIT) + 5);

+		regsize[i]=4;

+		regtype[i]=mymalloc(sizeof(struct Typ));

+	}

+

+	for(i=FIRST_64BIT;i<=LAST_64BIT;i++)

+	{

+		regnames[i]=mymalloc(10);

+		sprintf(regnames[i],"c%d",(i-FIRST_64BIT) + 9);

+		regsize[i]=8;

+		regtype[i]=mymalloc(sizeof(struct Typ));

+	}

+

+	for(i=FIRST_8BIT;i<=LAST_8BIT;i++)

+	{

+		regnames[i]=mymalloc(10);

+		sprintf(regnames[i],"h%d",(i-FIRST_8BIT));

+		regsize[i]=1;

+		//regtype[i]=&lchar;

+		regtype[i]=mymalloc(sizeof(struct Typ));

+	}

+

+	regnames[STACK_POINTER]=mymalloc(10);

+	sprintf(regnames[STACK_POINTER],"z2");

+	regsize[STACK_POINTER]=4;

+	regtype[STACK_POINTER]=&ltyp;

+	regtype[STACK_POINTER]=mymalloc(sizeof(struct Typ));

+

+	/*  Use multiple ccs.   */

+	multiple_ccs=0;

+

+	/*  Initialize the min/max-settings. Note that the types of the     */

+	/*  host system may be different from the target system and you may */

+	/*  only use the smallest maximum values ANSI guarantees if you     */

+	/*  want to be portable.                                            */

+	/*  That's the reason for the subtraction in t_min[INT]. Long could */

+	/*  be unable to represent -2147483648 on the host system.          */

+	t_min[CHAR]=l2zm(-128L);

+	t_min[SHORT]=l2zm(-32768L);

+	t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));

+	t_min[LONG]=t_min(INT);

+	t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));

+	t_min[MAXINT]=t_min(LLONG);

+	t_max[CHAR]=ul2zum(127L);

+	t_max[SHORT]=ul2zum(32767UL);

+	t_max[INT]=ul2zum(2147483647UL);

+	t_max[LONG]=t_max(INT);

+	t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));

+	t_max[MAXINT]=t_max(LLONG);

+	tu_max[CHAR]=ul2zum(255UL);

+	tu_max[SHORT]=ul2zum(65535UL);

+	tu_max[INT]=ul2zum(4294967295UL);

+	tu_max[LONG]=t_max(UNSIGNED|INT);

+	tu_max[LLONG]=zumkompl(ul2zum(0UL));

+	tu_max[MAXINT]=t_max(UNSIGNED|LLONG);

+

+	for(i=FIRST_16BIT;i<=LAST_16BIT-VOL_16BIT;i++)

+		regscratch[i]=1;

+	for(i=FIRST_32BIT;i<=LAST_32BIT-VOL_32BIT;i++)

+		regscratch[i]=1;

+	for(i=FIRST_64BIT;i<=LAST_64BIT-VOL_64BIT;i++)

+		regscratch[i]=1;

+	for(i=FIRST_8BIT;i<=LAST_8BIT-VOL_8BIT;i++)

+		regscratch[i]=1;

+

+	/*  Reserve a few registers for use by the code-generator.      */

+	/*  This is not optimal but simple.                             */

+	sp=STACK_POINTER;

+	t8bit1=FIRST_8BIT;

+	t8bit2=FIRST_8BIT+1;

+	t16bit1=FIRST_16BIT;

+	t16bit2=FIRST_16BIT+1;

+	t32bit1=FIRST_32BIT;

+	t32bit2=FIRST_32BIT+1;

+	t64bit1=FIRST_64BIT;

+	t64bit2=FIRST_64BIT+1;

+	regsa[t8bit1]=regsa[t8bit2]=1;

+	regsa[t16bit1]=regsa[t16bit2]=1;

+	regsa[t32bit1]=regsa[t32bit2]=1;

+	regsa[t64bit1]=regsa[t64bit2]=1;

+	regsa[sp]=1;

+	regscratch[t8bit1]=regscratch[t8bit2]=0;

+	regscratch[t16bit1]=regscratch[t16bit2]=0;

+	regscratch[t32bit1]=regscratch[t32bit2]=0;

+	regscratch[t64bit1]=regscratch[t64bit2]=0;

+	regscratch[sp]=0;

+

+	//	for(i=FIRST_FIXED;i<=LAST_FIXED-VOL_FIXED;i++)

+	//		regscratch[i]=1;

+	target_macros=marray;

+

+	return 1;

+}

+

+void init_db(FILE *f)

+{

+}

+

+int freturn(struct Typ *t)

+/*  Returns the register in which variables of type t are returned. */

+/*  If the value cannot be returned in a register returns 0.        */

+/*  A pointer MUST be returned in a register. The code-generator    */

+/*  has to simulate a pseudo register if necessary.                 */

+{

+	if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 

+		return 0;

+	if(t->size == 1)

+		return FIRST_8BIT+3;

+	if(t->size == 2)

+		return FIRST_16BIT+3;

+	if(t->size == 4)

+		return FIRST_32BIT+3;

+	if(t->size == 8)

+		return FIRST_64BIT+3;

+

+	return 0;

+}

+

+int reg_pair(int r,struct rpair *p)

+/* Returns 0 if the register is no register pair. If r  */

+/* is a register pair non-zero will be returned and the */

+/* structure pointed to p will be filled with the two   */

+/* elements.                                            */

+{

+	return 0;

+}

+

+/* estimate the cost-saving if object o from IC p is placed in

+register r */

+int cost_savings(struct IC *p,int r,struct obj *o)

+{

+	int c=p->code;

+	if(o->flags&VKONST)

+	{

+		if(!LOAD_STORE)

+			return 0;

+		if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))

+			return 4;

+		else

+			return 2;

+	}

+	if(o->flags&DREFOBJ)

+		return 4;

+	if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ))

+		return 3;

+	if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ))

+		return 3;

+	return 2;

+}

+

+int regok(int r,int t,int mode)

+/*  Returns 0 if register r cannot store variables of   */

+/*  type t. If t==POINTER and mode!=0 then it returns   */

+/*  non-zero only if the register can store a pointer   */

+/*  and dereference a pointer to mode.                  */

+{

+	if(r==0)

+		return 0;

+	t&=NQ;

+

+	if(r>=FIRST_8BIT&&r<=LAST_8BIT)

+	{

+//		printf("8 bit register: ");

+		if(t == CHAR)

+		{

+//			printf(" can fit\n");

+			return 1;

+		}

+//		else

+//			printf(" can't fit\n");

+	}

+	else if(r>=FIRST_16BIT&&r<=LAST_16BIT)

+	{

+//		printf("16 bit register: ");

+		if(t == SHORT)

+		{

+//			printf(" can fit\n");

+			return 1;

+		}

+//		else

+//			printf(" can't fit\n");

+	}

+	else if(r>=FIRST_32BIT&&r<=LAST_32BIT)

+	{

+//		printf("32 bit register: ");

+		if(t == INT || t == LONG || t == FLOAT

+			||t == POINTER)

+		{

+//			printf(" can fit\n");

+			return 1;

+		}

+//		etse

+//			printf(" can't fit\n");

+	}

+	else if(r>=FIRST_64BIT&&r<=LAST_64BIT)

+	{

+//		printf("64 bit register: ");

+		if(t == LDOUBLE || t == DOUBLE || t == LLONG)

+		{

+//			printf(" can fit\n");

+			return 1;

+		}

+//		else

+//			printf(" can't fit\n");;

+	}

+

+	return 0;

+

+

+	/*#define CHAR 1

+	#define SHORT 2

+	#define INT 3

+	#define LONG 4

+	#define LLONG 5

+	#define FLOAT 6

+	#define DOUBLE 7

+	#define LDOUBLE 8

+	#define VOID 9

+	#define POINTER 10

+	#define ARRAY 11

+	#define STRUCT 12

+	#define UNION 13

+	#define ENUM 14*/

+}

+

+int dangerous_IC(struct IC *p)

+/*  Returns zero if the IC p can be safely executed     */

+/*  without danger of exceptions or similar things.     */

+/*  vbcc may generate code in which non-dangerous ICs   */

+/*  are sometimes executed although control-flow may    */

+/*  never reach them (mainly when moving computations   */

+/*  out of loops).                                      */

+/*  Typical ICs that generate exceptions on some        */

+/*  machines are:                                       */

+/*      - accesses via pointers                         */

+/*      - division/modulo                               */

+/*      - overflow on signed integer/floats             */

+{

+	int c=p->code;

+	if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))

+		return 1;

+	if((c==DIV||c==MOD)&&!isconst(q2))

+		return 1;

+	return 0;

+}

+

+int must_convert(int o,int t,int const_expr)

+/*  Returns zero if code for converting np to type t    */

+/*  can be omitted.                                     */

+/*  On the PowerPC cpu pointers and 32bit               */

+/*  integers have the same representation and can use   */

+/*  the same registers.                                 */

+{

+	int op=o&NQ,tp=t&NQ;

+

+	if(op == LONG || op == POINTER)

+		op = INT;

+

+	if(tp==LONG || tp ==POINTER)

+		tp = INT;

+

+	if(op == tp) // same type

+		if((o & NQ)== (t & NQ)) // same signess

+			return 0; // no code needed

+

+	return 1;

+}

+

+void gen_ds(FILE *f,zmax size,struct Typ *t)

+/*  This function has to create <size> bytes of storage */

+/*  initialized with zero.                              */

+{

+	if(newobj&&section!=SPECIAL)

+		emit(f," data %ld\n",zm2l(size));

+	else

+		emit(f," data %ld\n",zm2l(size));

+	newobj=0;

+}

+

+void gen_align(FILE *f,zmax align)

+/*  This function has to make sure the next data is     */

+/*  aligned to multiples of <align> bytes.              */

+{

+	if(zm2l(align)>1)

+		emit(f,"; NOT IMPLEMENTED - \t.align\t%d\n", align);

+}

+

+void gen_var_head(FILE *f,struct Var *v)

+/*  This function has to create the head of a variable  */

+/*  definition, i.e. the label and information for      */

+/*  linkage etc.                                        */

+{

+	int constflag;

+	char *sec;

+	if(v->clist) constflag=is_const(v->vtyp);

+	if(v->storage_class==STATIC)

+	{

+		if(ISFUNC(v->vtyp->flags))

+			return;

+		if(!special_section(f,v))

+		{

+			if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}

+			if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}

+			if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}

+		}

+		if(v->clist||section==SPECIAL)

+		{

+			gen_align(f,falign(v->vtyp));

+			emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));

+		}

+		else

+			emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));

+		newobj=1;

+	}

+	if(v->storage_class==EXTERN)

+	{

+		//  emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);

+		if(v->flags&(DEFINED|TENTATIVE))

+		{

+			if(!special_section(f,v))

+			{

+				if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA)

+				{

+					emit(f,dataname);

+					if(f)

+						section=DATA;

+				}

+				if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA)

+				{

+					emit(f,rodataname);

+					if(f)

+						section=RODATA;

+				}

+				if(!v->clist&&section!=BSS)

+				{

+					emit(f,bssname);

+					if(f)

+						section=BSS;

+				}

+			}

+			if(v->clist||section==SPECIAL)

+			{

+				gen_align(f,falign(v->vtyp));

+				//        emit(f,"%s%s:\n",idprefix,v->identifier);

+			}

+			else

+				emit(f,".global %s%s:",/*(USE_COMMONS?"":"l"),*/idprefix,v->identifier);

+			newobj=1;

+		}

+	}

+}

+

+void gen_dc(FILE *f,int t,struct const_list *p)

+/*  This function has to create static storage          */

+/*  initialized with const-list p.                      */

+{

+	//emit(f,"\tdc.%s\t",dt(t&NQ));

+	int o = t&NQ;

+	int size = 4;

+	if(o == CHAR)

+		size = 1;

+	if(o == SHORT)

+		size = 2;

+	if(o == LLONG || t == DOUBLE)

+		size = 8;

+

+	emit(f,"\tdata\t%i\t",size);

+	if(!p->tree)

+	{

+		if(ISFLOAT(t))

+		{

+			/*  auch wieder nicht sehr schoen und IEEE noetig   */

+			unsigned char *ip;

+			ip=(unsigned char *)&p->val.vdouble;

+			emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);

+			if((t&NQ)!=FLOAT){

+				emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);

+			}

+		}

+		else if(o & UNSIGNED)

+		{

+			emitval(f,&p->val,t);

+		}

+		else

+		{

+			emit(f, "0s");

+			emitval(f,&p->val,t);

+		}

+	}

+	else

+	{

+		emit_obj(f,&p->tree->o,t);

+	}

+	emit(f,"\n");

+	newobj=0;

+}

+

+

+/*  The main code-generation routine.                   */

+/*  f is the stream the code should be written to.      */

+/*  p is a pointer to a doubly linked list of ICs       */

+/*  containing the function body to generate code for.  */

+/*  v is a pointer to the function.                     */

+/*  offset is the size of the stackframe the function   */

+/*  needs for local variables.                          */

+

+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)

+/*  The main code-generation.                                           */

+{

+	int c,t,i,lastcomp=0;

+	struct IC *m;

+	argsize=0;

+	if(DEBUG&1)

+		printf("gen_code()\n");

+	for(c=1;c<=MAXR;c++)

+		regs[c]=regsa[c];

+	maxpushed=0;

+

+	/*FIXME*/

+	ret="\tret\n";

+

+	struct IC *p_test = 0;

+	char test_handled = 0;

+	int test_reg = 0;

+	int test_reg2 = 0;

+

+	for(m=p;m;m=m->next)

+	{

+		c=m->code;t=m->typf;

+		if(c==ALLOCREG)

+		{

+			regs[m->q1.reg]=1;

+			continue;

+		}

+		if(c==FREEREG)

+		{

+			regs[m->q1.reg]=0;

+			continue;

+		}

+

+		/* convert MULT/DIV/MOD with powers of two */

+		if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED))))

+		{

+			eval_const(&m->q2.val,t);

+			i=pof2(vmax);

+			if(i)

+			{

+				if(c==MOD)

+				{

+					vmax=zmsub(vmax,l2zm(1L));

+					m->code=AND;

+				}

+				else

+				{

+					vmax=l2zm(i-1);

+					if(c==DIV)

+						m->code=RSHIFT;

+					else

+						m->code=LSHIFT;

+				}

+				c=m->code;

+				gval.vmax=vmax;

+				eval_const(&gval,MAXINT);

+				if(c==AND)

+				{

+					insert_const(&m->q2.val,t);

+				}

+				else

+				{

+					insert_const(&m->q2.val,INT);

+					p->typf2=INT;

+				}

+			}

+		}

+#if FIXED_SP

+		if(c==CALL&&argsize<zm2l(m->q2.val.vmax))

+			argsize=zm2l(m->q2.val.vmax);

+#endif

+	}

+	peephole(p);

+

+	for(c=1;c<=MAXR;c++)

+	{

+		if(regsa[c]||regused[c])

+		{

+			BSET(regs_modified,c);

+		}

+	}

+

+	localsize=(zm2l(offset)+3)/4*4;

+#if FIXED_SP

+	/*FIXME: adjust localsize to get an aligned stack-frame */

+#endif

+

+	function_top(f,v,localsize);

+

+	stackoffset=notpopped=dontpop=0;

+

+	for(;p;p=p->next)

+	{

+		c=p->code;t=p->typf;

+		if(c==NOP)

+		{

+			p->z.flags=0;

+			continue;

+		}

+

+		if(c==ALLOCREG)

+		{

+			regs[p->q1.reg]=1;

+			continue;

+		}

+

+		if(c==FREEREG)

+		{

+			regs[p->q1.reg]=0;

+			continue;

+		}

+		if(c==LABEL)

+		{

+			emit(f,"%s%d:\n",labprefix,t);

+			continue;

+		}

+

+		if(notpopped&&!dontpop)

+		{

+			if(c==LABEL||c==COMPARE||c==TEST||c==BRA)

+			{

+				emit(f,"\taddl\t$%ld,%%esp\n",notpopped);

+				pop(notpopped);

+				notpopped=0;

+			}

+		}

+		if(c==BRA)

+		{

+			emit(f,"\tmov b29 %s%d\n", labprefix, t);

+			emit(f,"\tjmp\tb29\n");

+

+			//emit(f,"\tmov b29\t");

+			//if(isreg(q1)){

+			//emit_obj(f,&p->q1,0);

+			//emit(f,",");

+			//}

+			//emit(f,"%s%d;\n",labprefix,t);

+			continue;

+		}

+

+		if(c==MOVETOREG)

+		{

+			//printf("reg: %s\n", regnames[p->z.reg]);

+			if(p->z.reg <= MAXR)

+				load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);

+			else

+				emit(f," ; move non existant reg in to %s\n",regnames[p->q1.reg]);

+			continue;

+		}

+		if(c==MOVEFROMREG)

+		{

+			//			printf("reg: %s\n", regnames[p->z.reg]);

+			if(p->z.reg <= MAXR)

+				store_reg(f, p->z.reg, &p->q1, regtype[p->z.reg]->flags);

+			continue;

+		}

+		if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1)))

+		{

+			ierror(0);

+		}

+		p=preload(f,p);

+		c=p->code;

+		if(c==SUBPFP)

+			c=SUB;

+		if(c==ADDI2P)

+			c=ADD;

+		if(c==SUBIFP)

+			c=SUB;

+		if(c==CONVERT)

+		{

+			load_reg(f,zreg,&p->q1,p->typf2);

+			if(ISFLOAT(p->typf)) // convert to float

+			{

+				if(ISFLOAT(p->typf2)) // from float

+				{					

+					//					emit(f,"\tmovf\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+				}

+				else if(!(p->typf2 & UNSIGNED)) // from signed

+				{

+					//					emit(f,"\tmovs\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+					emit(f,"\tstf\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));

+				}

+				else if(p->typf2 & UNSIGNED) // from unsigned

+				{

+					//					emit(f,"\tmov\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+					emit(f,"\tutf\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));

+				}

+			}

+			else if(!(p->typf & UNSIGNED)) // convert to signed

+			{

+				if(ISFLOAT(p->typf2)) // from float

+				{

+					//					emit(f,"\tmovf\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+					emit(f,"\tfts\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));

+				}

+				else if(!(p->typf2 & UNSIGNED)) // from signed

+				{

+					//					emit(f,"\tmovs\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+				}

+				else if(p->typf2 & UNSIGNED) // from unsigned

+				{

+					//					emit(f,"\tmov\t%s\t", regnames[zreg]);

+					//					emit_obj(f,&p->q1,p->typf2);

+//					emit(f,"\n\tuts\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));

+				}

+			}

+			else if(p->typf & UNSIGNED) // convert to unsigned

+			{

+				if(ISFLOAT(p->typf2)) // from float

+				{

+					//					emit(f,"\tmovf\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+					emit(f,"\tftu\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));

+				}

+				else if(!(p->typf2 & UNSIGNED)) // from signed

+				{

+					//					emit(f,"\tmovs\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+//					emit(f,"\tstu\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));

+				}

+				else if(p->typf2 & UNSIGNED) // from unsigned

+				{

+					//					emit(f,"\tmov\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);

+				}

+			}

+			save_result(f,p);

+			continue;

+		}

+		if(c==KOMPLEMENT)

+		{

+			load_reg(f,zreg,&p->q1,t);

+			emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+		if(c==SETRETURN)

+		{

+			load_reg(f,p->z.reg,&p->q1,t);

+			BSET(regs_modified,p->z.reg);

+			continue;

+		}

+		if(c==GETRETURN)

+		{

+			if(p->q1.reg)

+			{

+				zreg=p->q1.reg;

+				save_result(f,p);

+			}

+			else

+				p->z.flags=0;

+			continue;

+		}

+		if(c==CALL)

+		{

+			int reg;

+			/*FIXME*/

+#if 0      

+			if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))

+			{

+				if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)

+					stack=framesize+zum2ul(p->q1.v->fi->stack1);

+			}else

+				stack_valid=0;

+#endif

+			if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm)

+			{

+				emit_inline_asm(f,p->q1.v->fi->inline_asm);

+			}

+			else

+			{

+				emit(f, "\tmov\tb29\t");

+				emit_obj(f,&p->q1,t);

+				emit(f,"\n");

+				emit(f,"\tcall\tb29\n");

+			}

+			/*FIXME*/

+#if FIXED_SP

+			pushed-=zm2l(p->q2.val.vmax);

+#endif

+			if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS))

+			{

+				bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);

+			}

+			else

+			{

+				int i;

+				for(i=1;i<=MAXR;i++)

+				{

+					if(regscratch[i]) BSET(regs_modified,i);

+				}

+			}

+			continue;

+		}

+		if(c==ASSIGN||c==PUSH)

+		{

+			if(t==0)

+				ierror(0);

+			if(c==PUSH)

+			{

+				emit(f,"\tpush\t"/*,dt(t)*/);

+				emit_obj(f,&p->q1,t);

+				emit(f,"\n");

+				push(zm2l(p->q2.val.vmax));

+				continue;

+			}

+			if(c==ASSIGN)

+			{

+				load_reg(f,zreg,&p->q1,t);

+				if(q2reg != 0)

+					load_reg(f,q2reg,&p->q2,t);

+				save_result(f,p);

+			}

+			continue;

+		}

+		if(c==ADDRESS)

+		{

+			load_address(f,zreg,&p->q1,POINTER);

+			save_result(f,p);

+			continue;

+		}

+		if(c==MINUS)

+		{

+			load_reg(f,zreg,&p->q1,t);

+			emit(f,"\tneg\t%s ; %s\n",dt(t),regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+		if(c >= BEQ && c < BRA)

+		{

+

+			char *ccu[]={"cmp","nequ","gt","!gte","gte","!gt"};

+			char *ccs[]={"cmps","nequs","gts","!gtes","gtes","!gts"};

+			char *ccf[]={"cmpf","nequf","gtf","!gtef","gtef","!gtf"};

+			if(p_test == 0)

+			{

+				printf("Calling %s without a test!\n",ccs[c-BEQ]);

+				emit(f,"Calling %s without a test!\n",ccs[c-BEQ]);

+				continue;

+			}

+

+			struct IC *p_old = p;

+			p = p_test;

+			t=p->typf;

+

+			if(test_handled == 0)

+			{

+				if(ISFLOAT(t))

+				{

+					if(isreg(q2))

+					{

+						char instruction[10];

+						sprintf(instruction, "%s", ccf[c-BEQ]);

+						if(instruction[0] == '!')

+						{

+							instruction[0] = ' ';

+							emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg],regnames[test_reg2]);

+						}

+						else

+							emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg2],regnames[test_reg]);

+

+						save_result(f,p);

+					}

+					else

+					{

+						if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+						{

+							unsigned long offset = real_offset(&p->q2);

+							if(offset == 0)

+							{

+								emit(f,"\tmovf\tb28\t[z2]\n");

+							}

+							else

+							{

+								emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+								emit(f,"\tmov\tb29\tz2\n");

+								emit(f,"\tsub\tb29\tb28\n");

+								emit(f,"\tmovf\tb28\t[b29]\n");

+							}

+						}

+						else

+						{

+							emit(f,"\tmovf\tb28\t");

+							emit_obj(f,&p->q2,t);

+							emit(f,"\n");

+						}

+

+						char instruction[10];

+						sprintf(instruction, "%s", ccf[c-BEQ]);

+						if(instruction[0] == '!')

+						{

+							instruction[0] = ' ';

+							emit(f,"\n\t%s\t%s\tb28\n",instruction,regnames[test_reg]);

+						}

+						else

+							emit(f,"\n\t%s\tb28\t%s\n",instruction,regnames[test_reg]);

+					}

+				}

+				else if(t & UNSIGNED)

+				{

+					if(isreg(q2))

+					{

+						char instruction[10];

+						sprintf(instruction, "%s", ccu[c-BEQ]);

+						if(instruction[0] == '!')

+						{

+							instruction[0] = ' ';

+							emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg2],regnames[test_reg]);

+						}

+						else

+							emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg],regnames[test_reg2]);

+						save_result(f,p);

+						continue;

+					}

+					else

+					{

+						if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+						{

+							unsigned long offset = real_offset(&p->q2);

+							if(offset == 0)

+							{

+								emit(f,"\tmov\tb28\t[z2]\n");

+							}

+							else

+							{

+								emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+								emit(f,"\tmov\tb29\tz2\n");

+								emit(f,"\tsub\tb29\tb28\n");

+								emit(f,"\tmov\tb28\t[b29]\n");

+							}

+						}

+						else

+						{

+							emit(f,"\tmov\tb28\t");

+							emit_obj(f,&p->q2,t);

+							emit(f,"\n");

+						}

+

+						char instruction[10];

+						sprintf(instruction, "%s", ccu[c-BEQ]);

+						if(instruction[0] == '!')

+						{

+							instruction[0] = ' ';

+							emit(f,"\n\t%s\t%s\tb28\n",instruction,regnames[test_reg]);

+						}

+						else

+							emit(f,"\n\t%s\tb28\t%s\n",instruction,regnames[test_reg]);

+					}

+				}

+				else

+				{

+					if(isreg(q2))

+					{

+						char instruction[10];

+						sprintf(instruction, "%s", ccs[c-BEQ]);

+						if(instruction[0] == '!')

+						{

+							instruction[0] = ' ';

+							emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg],regnames[test_reg2]);

+						}

+						else

+							emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[p->q2.reg],regnames[test_reg]);

+

+						save_result(f,p);

+						continue;

+					}

+					else

+					{

+						if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+						{

+							unsigned long offset = real_offset(&p->q2);

+							if(offset == 0)

+							{

+								emit(f,"\tmovs\tb28\t[z2]\n");

+							}

+							else

+							{

+								emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+								emit(f,"\tmov\tb29\tz2\n");

+								emit(f,"\tsub\tb29\tb28\n");

+								emit(f,"\tmovs\tb28\t[b29]\n");

+							}

+						}

+						else

+						{

+							emit(f,"\tmovs\tb28\t");

+							emit_obj(f,&p->q2,t);

+							emit(f,"\n");

+						}

+

+						char instruction[10];

+						sprintf(instruction, "%s", ccs[c-BEQ]);

+						if(instruction[0] == '!')

+						{

+							instruction[0] = ' ';

+							emit(f,"\n\t%s\t%s\tb28\n",instruction,regnames[test_reg]);

+						}

+						else

+							emit(f,"\n\t%s\tb28\t%s\n",instruction,regnames[test_reg]);

+					}

+				}

+

+				//emit(f,"\tj%s\t",ccs[c-BEQ]);

+				//if(isreg(q1))

+				//{

+				//emit_obj(f,&p->q1,0);

+				//emit(f,",");

+				//}

+				//emit(f,"%s%d ;\n",labprefix,t);

+

+				// next

+

+			}

+			else

+			{

+				if(p_old->code == BEQ)

+				{

+					emit(f,"\n\trz\t%s\n",regnames[test_reg]);

+				}

+				else if(p_old->code == BNE)

+				{

+					emit(f,"\n\trnz\t%s\n",regnames[test_reg]);

+				}

+				else

+					emit(f,"not sure what to do with %d\n", p_old->code);

+			}

+

+			p = p_old;

+			t=p->typf;

+

+			test_handled = 0;

+

+			emit(f,"\tmov\tb28\t%s%d\n",labprefix,t);

+			emit(f,"\tjnz\tz0\tb28\n");

+			continue;

+		}	

+		if(c==TEST)

+		{

+			// printf("found test");

+/*			emit(f,"\ttst\t");

+			if(multiple_ccs)

+				emit(f,"%s,",regnames[zreg]);

+			emit_obj(f,&p->q1,t);

+			emit(f," ; %s\n",dt(t));

+			if(multiple_ccs)

+				save_result(f,p); */

+

+			test_reg = zreg;

+			test_reg2 = q2reg;

+

+			if(!isreg(q1))

+					load_reg(f,test_reg,&p->q1,t);

+

+			p_test = p;

+			test_handled = 1;

+

+			continue;

+		}

+		if(c==COMPARE)

+		{

+			test_reg = zreg;

+			test_reg2 = q2reg;

+			

+			if(!isreg(q1))

+					load_reg(f,zreg,&p->q1,t);

+

+			p_test = p;

+			test_handled = 0;

+//			emit(f, "; compare %s\n", regnames[zreg]);

+			continue;

+		}

+		if(c==OR)

+		{

+			emit(f,"\tmov\tb28\t");

+			emit_obj(f,&p->q2,t);

+

+			emit(f,"\n\tor\t%s b28\n",/*dt(t),*/regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+		if(c==XOR)

+		{

+			emit(f,"\tmov\tb28\t");

+			emit_obj(f,&p->q2,t);

+

+			emit(f,"\n\txor\t%s b28\n",/*dt(t),*/regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+		if(c==AND)

+		{

+			emit(f,"\tmov\tb28\t");

+			emit_obj(f,&p->q2,t);

+

+			emit(f,"\n\tand\t%s b28\n",/*dt(t),*/regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+

+		if(c==LSHIFT)

+		{

+			emit(f,"\tmov\tb28\t");

+			emit_obj(f,&p->q2,t);

+

+			emit(f,"\n\tsal\t%s b28\n",/*dt(t),*/regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+

+		if(c==RSHIFT)

+		{

+			emit(f,"\tmov\tb28\t");

+			emit_obj(f,&p->q2,t);

+

+			emit(f,"\n\tsar\t%s b28\n",/*dt(t),*/regnames[zreg]);

+			save_result(f,p);

+			continue;

+		}

+

+		if(c==ADD) ///////////////////////////////////////// ADDITION

+		{

+			if(!isreg(q1))

+				load_reg(f,zreg,&p->q1,t);

+

+			if(p->q2.flags&KONST)

+			{

+				if(ISFLOAT(t))

+				{

+					char *ds = (char *)&p->q2.val.vfloat;

+					char tmp = ds[0];

+					ds[0] = ds[3];

+					ds[3] = tmp;

+					tmp = ds[1];

+					ds[1] = ds[2];

+					ds[2] = tmp;

+

+					if((*(float *)ds) == 1.0f)

+					{

+						emit(f,"\tincf\t%s\n", regnames[zreg]);

+						save_result(f,p);

+						continue;

+					}

+				}

+				else if(t & UNSIGNED)

+				{

+					if(*(unsigned int *)&p->q2.val == 1)

+					{

+						emit(f,"\tinc\t%s\n", regnames[zreg]);

+						save_result(f,p);

+						continue;

+					}

+				}

+				else

+				{

+					if(*(unsigned int *)&p->q2.val == 1)

+					{

+						emit(f,"\tincs\t%s\n", regnames[zreg]);

+						save_result(f,p);

+						continue;

+					}

+				}

+			}

+

+			if(ISFLOAT(t))

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\taddf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovf\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovf\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovf\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\taddf\t%s b28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else if(t & UNSIGNED)

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tadd\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmov\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmov\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmov\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tadd\t%s b28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tadds\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovs\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovs\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovs\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tadds\t%s b28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+		}

+

+		if(c==SUB)

+		{

+			if(!isreg(q1))

+				load_reg(f,zreg,&p->q1,t);

+

+			if(p->q2.flags&KONST)

+			{

+				if(ISFLOAT(t))

+				{

+					char *ds = (char *)&p->q2.val.vfloat;

+					char tmp = ds[0];

+					ds[0] = ds[3];

+					ds[3] = tmp;

+					tmp = ds[1];

+					ds[1] = ds[2];

+					ds[2] = tmp;

+

+					if((*(float *)ds) == 1.0f)

+					{

+						emit(f,"\tdecf\t%s\n", regnames[zreg]);

+						save_result(f,p);

+						continue;

+					}

+				}

+				else if(t & UNSIGNED)

+				{

+					if(*(unsigned int *)&p->q2.val == 1)

+					{

+						emit(f,"\tdec\t%s\n", regnames[zreg]);

+						save_result(f,p);

+						continue;

+					}

+				}

+				else

+				{

+					if(*(unsigned int *)&p->q2.val == 1)

+					{

+						emit(f,"\tdecs\t%s\n", regnames[zreg]);

+						save_result(f,p);

+						continue;

+					}

+				}

+			}

+			if(ISFLOAT(t))

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tsubf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovf\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovf\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovf\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tsubf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else if(t & UNSIGNED)

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tsub\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmov\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmov\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmov\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tsub\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tsubs\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovs\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovs\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovs\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tsubs\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+		}

+

+		if(c==MULT)

+		{

+			if(ISFLOAT(t))

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tmulf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovf\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovf\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovf\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tmulf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else if(t & UNSIGNED)

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tmul\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmov\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmov\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmov\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tmul\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tmuls\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovs\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovs\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovs\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tmuls\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+

+			continue;

+		}

+

+		if(c==DIV)

+		{

+			if(ISFLOAT(t))

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tdivf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovf\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovf\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovf\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tdivf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else if(t & UNSIGNED)

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tdiv\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmov\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmov\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmov\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tdiv\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tdivs\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovs\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovs\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovs\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tdivs\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+		}

+

+		if(c==MOD)

+		{

+			if(ISFLOAT(t))

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tmodf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovf\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovf\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovf\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tmodf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else if(t & UNSIGNED)

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tmod\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmov\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmov\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmov\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tmod\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+			else

+			{

+				if(isreg(q2))

+				{

+					emit(f,"\n\tmods\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);

+					save_result(f,p);

+					continue;

+				}

+

+				if(((p->q2.flags&VAR)&&!(p->q2.flags&REG)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))

+				{

+					unsigned long offset = real_offset(&p->q2);

+					if(offset == 0)

+					{

+						emit(f,"\tmovs\tb28\t[z2]\n");

+					}

+					else

+					{

+						emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);

+						emit(f,"\tmov\tb29\tz2\n");

+						emit(f,"\tsub\tb29\tb28\n");

+						emit(f,"\tmovs\tb28\t[b29]\n");

+					}

+				}

+				else

+				{

+					emit(f,"\tmovs\tb28\t");

+					emit_obj(f,&p->q2,t);

+					emit(f,"\n");

+				}

+

+				emit(f,"\n\tmods\t%s\tb28\n",/*dt(t),*/regnames[zreg]);

+				save_result(f,p);

+				continue;

+			}

+		}

+

+		pric2(stdout,p);

+		ierror(0);

+	}

+	function_bottom(f,v,localsize);

+	if(stack_valid)

+	{

+		if(!v->fi)

+			v->fi=new_fi();

+		v->fi->flags|=ALL_STACK;

+		v->fi->stack1=stack;

+	}

+	emit(f," ; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");

+}

+

+int shortcut(int code,int typ)

+{

+	return 1;

+}

+

+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)

+{

+	int f;

+	f=t->flags&NQ;

+	if(f==CHAR)

+	{

+		if(m->regs8>=NUM_8BIT)

+			return 0;

+		else

+			return FIRST_8BIT+m->regs8++;

+	}

+	if(f==SHORT)

+	{

+		if(m->regs16>=NUM_16BIT)

+			return 0;

+		else

+			return FIRST_16BIT+m->regs16++;

+	}

+	if(f==INT || f==LONG || f==POINTER || f==FLOAT)

+	{

+		if(m->regs32>=NUM_32BIT)

+			return 0;

+		else

+			return FIRST_32BIT+m->regs32++;

+	}

+	if(f==DOUBLE || f==LDOUBLE || f==LLONG){

+		if(m->regs64>=NUM_64BIT)

+			return 0;

+		else

+			return FIRST_64BIT+m->regs64++;

+	}

+	return 0;

+}

+

+int handle_pragma(const char *s)

+{

+	return 0;

+}

+

+void cleanup_cg(FILE *f)

+{

+	if(!f)

+		return;

+

+}

+

+void cleanup_db(FILE *f)

+{

+	if(f)

+		section=-1;

+}

+

+/*

+C registers:

+b28 - temp - store var during calculation/comparison

+b29 - temp - store address during jump

+b30 - temp store address of parameters

+b31 - temp store addresses to jump to

+

+a0 - 16 bit					4

+a1 - 16 bit					5

+a2 - 16 bit					6

+a3 - 16 bit					7

+a4 - 16 bit					8

+a5 - 16 bit					9

+a6 - 16 bit					10

+a7 - 16 bit					11

+a8 - 16 bit					12

+a9 - 16 bit					13

+b5 - 32 bit					14

+b6 - 32 bit					15

+b7 - 32 bit					16

+b8 - 32 bit					17

+b9 - 32 bit					18

+b10 - 32 bit					19

+b11 - 32 bit					20

+b12 - 32 bit					21

+b13 - 32 bit					22

+b14 - 32 bit					23

+b15 - 32 bit					24

+b16 - 32 bit					25

+b17 - 32 bit					26

+c9  - 64 bit					27

+c10 - 64 bit					28

+c11 - 64 bit					29

+c12 - 64 bit					30

+c13 - 64 bit					31

+

+h0 - 8bit					32

+h1 - 8bit					33

+h2 - 8bit					34

+h3 - 8bit					35

+*/

diff --git a/machines/messiahtron/machine.dt b/machines/messiahtron/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/messiahtron/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/messiahtron/machine.h b/machines/messiahtron/machine.h
new file mode 100755
index 0000000..acab9ae
--- /dev/null
+++ b/machines/messiahtron/machine.h
@@ -0,0 +1,184 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+    CPU.
+
+    Configurable at build-time are:
+    - number of (32bit) general-purpose-registers
+    - number of (64bit) floating-point-registers
+    - number of (8bit) condition-code-registers
+    - mechanism for stack-arguments (moving ot fixed sp)
+
+    It allows to select as run-time-options:
+    - two- or three-address code
+    - memory operands or load-store-architecture
+    - number of register-arguments
+    - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define ARRAY 11
+#define STRUCT 12
+#define UNION 13
+#define ENUM 14
+#define FUNKT 15
+#define MAXINT 16 /* should not be accesible to application */
+#define MAX_TYPE MAXINT
+
+
+//#define NUM_FIXED 4
+#define NUM_16BIT 10
+#define NUM_32BIT 13
+#define NUM_64BIT 5
+#define NUM_8BIT  4
+
+#include "dt.h"
+
+/* internally used by the backend */
+//#define FIRST_FIXED 1
+//#define LAST_FIXED (FIRST_FIXED+NUM_FIXED-1)
+#define FIRST_16BIT 1//(LAST_FIXED+1)
+#define LAST_16BIT (FIRST_16BIT+NUM_16BIT-1)
+#define FIRST_32BIT (LAST_16BIT+1)
+#define LAST_32BIT (FIRST_32BIT+NUM_32BIT-1)
+#define FIRST_64BIT (LAST_32BIT+1)
+#define LAST_64BIT (FIRST_64BIT+NUM_64BIT-1)
+#define FIRST_8BIT (LAST_64BIT+1)
+#define LAST_8BIT (FIRST_8BIT+NUM_8BIT-1)
+#define STACK_POINTER (LAST_8BIT+1)
+
+// #define FIXED_SP 1
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR NUM_16BIT+NUM_32BIT+NUM_64BIT+NUM_8BIT+1
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P CHAR
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH 1
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long regs8;
+    unsigned long regs16;
+	unsigned long regs32;
+	unsigned long regs64;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
diff --git a/machines/minx/machine.c b/machines/minx/machine.c
new file mode 100755
index 0000000..2417521
--- /dev/null
+++ b/machines/minx/machine.c
@@ -0,0 +1,1021 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+ 
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+ 
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+ */                                                                             
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc generic code-generator V0.01 for Minx (c) in 2001 by zoranc";
+
+/*  Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+  VALFLAG,VALFLAG,VALFLAG,
+  0,0,
+  VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+  "volatile-gprs","volatile-fprs","volatile-ccrs",
+  "imm-ind","gpr-ind",
+  "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS   ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS   ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS   ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND    ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND    ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS   ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS   ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+  "__GENERIC__",
+  0};
+
+/* special registers */
+static int sp;                     /*  Stackpointer                        */
+static int t1,t2,t3;               /*  temporary gprs */
+static int f1,f2,f3;               /*  temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+*dataname="\t.data\n",
+*bssname="",
+*rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function                   |
+ ------------------------------------------------
+ | return-address [size=4]                      |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize]       |
+ ------------------------------------------------
+ | local variables [size=localsize]             |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+ 
+ This is just an example layout. Other layouts are also possible.
+ */
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize+4-off-zm2l(maxalign);
+  }
+  
+#if FIXED_SP
+  off+=argsize;
+#else
+  off+=stackoffset;
+#endif
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if(!(o->flags&VAR)) ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    if(THREE_ADDR){
+      emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+    }else{
+      emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+      if(off)
+        emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+    }
+  }else{
+    emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NU;
+  if(o->flags&VARADR){
+    load_address(f,r,o,POINTER);
+  }else{
+    if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+      return;
+    emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NQ;
+  emit(f,"\tmov.%s\t",dt(type));
+  emit_obj(f,o,type);
+  emit(f,",%s\n",regnames[r]);
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r;
+  
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+  
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+  
+  if(isreg(z)){
+    zreg=p->z.reg;
+  }else{
+    if(ISFLOAT(ztyp(p)))
+      zreg=f1;
+    else
+      zreg=t1;
+  }
+  
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q1,q1typ(p));
+    p->q1.reg=t1;
+    p->q1.flags|=(REG|DREFOBJ);
+  }
+  if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+    if(ISFLOAT(q1typ(p)))
+      q1reg=f1;
+    else
+      q1reg=t1;
+    load_reg(f,q1reg,&p->q1,q1typ(p));
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+  
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q2,q2typ(p));
+    p->q2.reg=t1;
+    p->q2.flags|=(REG|DREFOBJ);
+  }
+  if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+    if(ISFLOAT(q2typ(p)))
+      q2reg=f2;
+    else
+      q2reg=t2;
+    load_reg(f,q2reg,&p->q2,q2typ(p));
+    p->q2.reg=q2reg;
+    p->q2.flags=REG;
+  }
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->z,POINTER);
+    p->z.reg=t2;
+    p->z.flags|=(REG|DREFOBJ);
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+    if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  rsavesize=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  if(offset)
+    emit(f,"\tsub.i\tgpr0,%ld\n", offset);
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  if(offset)
+    emit(f,"\tadd.i\tgpr0,%ld\n", offset);
+  emit(f,ret);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  char_bit=l2zm(8L);
+  
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  
+  regnames[0]="noreg";
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+    regsize[i]=l2zm(4L);
+    regtype[i]=&ltyp;
+  }
+  for(i=FIRST_FPR;i<=LAST_FPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+    regsize[i]=l2zm(8L);
+    regtype[i]=&ldbl;
+  }
+  for(i=FIRST_CCR;i<=LAST_CCR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+    regsize[i]=l2zm(1L);
+    regtype[i]=&lchar;
+  }
+  
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+  
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(31L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  sp=FIRST_GPR;
+  t1=FIRST_GPR+1;
+  t2=FIRST_GPR+2;
+  f1=FIRST_FPR;
+  f2=FIRST_FPR+1;
+  regsa[t1]=regsa[t2]=1;
+  regsa[f1]=regsa[f2]=1;
+  regsa[sp]=1;
+  regscratch[t1]=regscratch[t2]=0;
+  regscratch[f1]=regscratch[f2]=0;
+  regscratch[sp]=0;
+  
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+    regscratch[i]=1;
+  
+  target_macros=marray;
+  
+  
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) 
+    return FIRST_FPR+2;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 
+    return 0;
+  if(zmleq(szof(t),l2zm(4L))) 
+    return FIRST_GPR+3;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    if(!LOAD_STORE)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  t&=NQ;
+  if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+    return 1;
+  if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+    return 1;
+  if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(v->clist||section==SPECIAL){
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+        if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+        if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+        if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||section==SPECIAL){
+        gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\tdc.%s\t",dt(t&NQ));
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+        emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *m;
+  argsize=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  maxpushed=0;
+  
+  /*FIXME*/
+  ret="\trts\n";
+  
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+    
+    /* convert MULT/DIV/MOD with powers of two */
+    if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+        gval.vmax=vmax;
+        eval_const(&gval,MAXINT);
+        if(c==AND){
+          insert_const(&m->q2.val,t);
+        }else{
+          insert_const(&m->q2.val,INT);
+          p->typf2=INT;
+        }
+      }
+    }
+#if FIXED_SP
+    if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+  }
+  
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+  
+  localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+  /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+  
+  function_top(f,v,localsize);
+
+#if FIXED_SP
+  pushed=0;
+#endif
+  
+  for(;p;p=p->next){
+    c=p->code;t=p->typf;
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(t==exit_label)
+        emit(f,ret);
+      else
+        emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      emit(f,"\tb%s\t",ccs[c-BEQ]);
+      if(isreg(q1)){
+        emit_obj(f,&p->q1,0);
+        emit(f,",");
+      }
+      emit(f,"%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      ierror(0);
+    }
+    p=preload(f,p);
+    c=p->code;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+      if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+        if(q1typ(p)&UNSIGNED)
+          emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+        else
+          emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+      }
+      save_result(f,p);
+      continue;
+    }
+    if(c==KOMPLEMENT){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==SETRETURN){
+      load_reg(f,p->z.reg,&p->q1,t);
+      BSET(regs_modified,p->z.reg);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+        save_result(f,p);
+      }else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      int reg;
+      /*FIXME*/
+#if 0      
+      if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+        if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+          stack=framesize+zum2ul(p->q1.v->fi->stack1);
+      }else
+        stack_valid=0;
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+        emit(f,"\tcall\t");
+        emit_obj(f,&p->q1,t);
+        emit(f,"\n");
+      }
+      /*FIXME*/
+#if FIXED_SP
+      pushed-=zm2l(p->q2.val.vmax);
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+        bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+        int i;
+        for(i=1;i<=MAXR;i++){
+          if(regscratch[i]) BSET(regs_modified,i);
+        }
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(c==PUSH){
+#if FIXED_SP
+        emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+        emit_obj(f,&p->q1,t);
+        emit(f,"\n");
+        pushed+=zm2l(p->q2.val.vmax);
+#else
+        emit(f,"\tpush.%s\t",dt(t));
+        emit_obj(f,&p->q1,t);
+        emit(f,"\n");
+        /*pushed += zm2l(p->q2.val.vmax);*/
+#endif
+        continue;
+      }
+      if(c==ASSIGN){
+        load_reg(f,zreg,&p->q1,t);
+        save_result(f,p);
+      }
+      continue;
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      save_result(f,p);
+      continue;
+    }
+    if(c==MINUS){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==TEST){
+      emit(f,"\ttst.%s\t",dt(t));
+      if(multiple_ccs)
+        emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+        save_result(f,p);
+      continue;
+    }
+    if(c==COMPARE){
+      emit(f,"\tcmp.%s\t",dt(t));
+      if(multiple_ccs)
+        emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,",");
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+        save_result(f,p);
+      continue;
+    }
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+      if(!THREE_ADDR)
+        load_reg(f,zreg,&p->q1,t);
+      if(c>=OR&&c<=AND)
+        emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+      else
+        emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+      if(THREE_ADDR){
+        emit_obj(f,&p->q1,t);
+        emit(f,",");
+      }
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      save_result(f,p);
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  function_bottom(f,v,localsize);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=stack;
+  }
+  emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int c, int typ)
+{
+  if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+  f=t->flags&NQ;
+  if(f<=LONG||f==POINTER){
+    if(m->gregs>=GPR_ARGS)
+      return 0;
+    else
+      return FIRST_GPR+3+m->gregs++;
+  }
+  if(ISFLOAT(f)){
+    if(m->fregs>=FPR_ARGS)
+      return 0;
+    else
+      return FIRST_FPR+2+m->fregs++;
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
diff --git a/machines/minx/machine.dt b/machines/minx/machine.dt
new file mode 100755
index 0000000..736fdec
--- /dev/null
+++ b/machines/minx/machine.dt
@@ -0,0 +1,14 @@
+S8BS
+S8BU
+S8BS
+S8BU
+S16BSLE
+S16BULE
+S32BSLE
+S32BULE
+S32BSLE
+S32BULE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S32BULE
diff --git a/machines/minx/machine.h b/machines/minx/machine.h
new file mode 100755
index 0000000..25626fa
--- /dev/null
+++ b/machines/minx/machine.h
@@ -0,0 +1,136 @@
+/*  Example backend for vbcc, it models a generic 32bit RISC or CISC
+    CPU.
+
+    Configurable at build-time are:
+    - number of (32bit) general-purpose-registers
+    - number of (64bit) floating-point-registers
+    - number of (8bit) condition-code-registers
+    - mechanism for stack-arguments (moving ot fixed sp)
+
+    It allows to select as run-time-options:
+    - two- or three-address code
+    - memory operands or load-store-architecture
+    - number of register-arguments
+    - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 4
+#define NUM_FPRS 1
+#define NUM_CCRS 1
+#define FIXED_SP 1
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
diff --git a/machines/pm/emit.h b/machines/pm/emit.h
new file mode 100755
index 0000000..aa11b2e
--- /dev/null
+++ b/machines/pm/emit.h
@@ -0,0 +1,7 @@
+
+/* automaticaly generated by process_all.h; do not edit it */
+
+#include "emit_mult.h"
+#include "emit_div_mod.h"
+#include "emit_start.h"
+#include "emit_end.h"
diff --git a/machines/pm/emit_div_mod.h b/machines/pm/emit_div_mod.h
new file mode 100755
index 0000000..c9c6129
--- /dev/null
+++ b/machines/pm/emit_div_mod.h
@@ -0,0 +1,69 @@
+
+/* automaticaly generated from the file div_mod.asm do not modify */
+
+static void emit_div_mod(FILE *f)
+{
+	emit(f,"vbcc___div_mod16x16_16:\n");
+	emit(f,"\tpush\tx\n");
+	emit(f,"\tpush\ty\n");
+	emit(f,"\tmov\tx, 0\n");
+	emit(f,"\tcmp\tba, 0\n");
+	emit(f,"\tjns\tvbcc___dm_banotneg\n");
+	emit(f,"\tnot\ta\n");
+	emit(f,"\tnot\tb\n");
+	emit(f,"\tinc\tba\n");
+	emit(f,"\tadd\tx, 0x0011\n");
+	emit(f,"vbcc___dm_banotneg:\n");
+	emit(f,"\txchg\tba, hl\n");
+	emit(f,"\tcmp\tba, 0\n");
+	emit(f,"\tjns\tvbcc___dm_hlnotneg\n");
+	emit(f,"\tnot\ta\n");
+	emit(f,"\tnot\tb\n");
+	emit(f,"\tinc\tba\n");
+	emit(f,"\tinc\tx\n");
+	emit(f,"vbcc___dm_hlnotneg:\n");
+	emit(f,"\txchg\tba, hl\n");
+	emit(f,"\tpush\tx\n");
+	emit(f,"\tmov\tx, 0\n");
+	emit(f,"\tmov\ty, 1\n");
+	emit(f,"vbcc___dm_shiftloop:\n");
+	emit(f,"\tshl\ta\n");
+	emit(f,"\trolc\tb\n");
+	emit(f,"\txchg\tba, x\n");
+	emit(f,"\trolc\ta\n");
+	emit(f,"\trolc\tb\n");
+	emit(f,"\txchg\tba, x\n");
+	emit(f,"\tsub\tx, hl\n");
+	emit(f,"\tjns\tvbcc___dm_resnotneg\n");
+	emit(f,"\tadd\tx, hl\n");
+	emit(f,"vbcc___dm_resnotneg:\n");
+	emit(f,"\txchg\tba, y\n");
+	emit(f,"\trolc\ta\n");
+	emit(f,"\trolc\tb\n");
+	emit(f,"\txchg\tba, y\n");
+	emit(f,"\tjc\tvbcc___dm_done\n");
+	emit(f,"\tjmp\tvbcc___dm_shiftloop\n");
+	emit(f,"vbcc___dm_done:\n");
+	emit(f,"\tpop\tba\n");
+	emit(f,"\ttst\ta, 0x10\n");
+	emit(f,"\txchg\tba, x\n");
+	emit(f,"\tjz\tvbcc___dm_modnotneg\n");
+	emit(f,"\tnot\ta\n");
+	emit(f,"\tnot\tb\n");
+	emit(f,"\tinc\tba\n");
+	emit(f,"vbcc___dm_modnotneg:\n");
+	emit(f,"\tmov\thl, ba\n");
+	emit(f,"\tmov\tba, x\n");
+	emit(f,"\ttst\ta, 0x01\n");
+	emit(f,"\tmov\tba, y\n");
+	emit(f,"\tjz\tvbcc___dm_resnonegate\n");
+	emit(f,"\tinc\tba\n");
+	emit(f,"\tjmp\tvbcc___dm_resnegate\n");
+	emit(f,"vbcc___dm_resnonegate:\n");
+	emit(f,"\tnot\tb\n");
+	emit(f,"\tnot\ta\n");
+	emit(f,"vbcc___dm_resnegate:\n");
+	emit(f,"\tpop\ty\n");
+	emit(f,"\tpop\tx\n");
+	emit(f,"\tret\n");
+}
diff --git a/machines/pm/emit_end.h b/machines/pm/emit_end.h
new file mode 100755
index 0000000..2a77b2e
--- /dev/null
+++ b/machines/pm/emit_end.h
@@ -0,0 +1,20 @@
+
+/* automaticaly generated from the file end.asm do not modify */
+
+static void emit_end(FILE *f)
+{
+	if(!used_interrupt[15]) {
+	emit(f, "%s15:\n", int_handler_prefix);
+	used_interrupt[15] = (1);
+	}
+	emit(f,"\tmovb\t[nn+0x29], (1<<7)\n");
+	emit(f,"\ttest\t[nn+0x52], (1<<7)\n");
+	emit(f,"\tjnz\tvbcc___noturnoff\n");
+	emit(f,"\tcint\t0x24\n");
+	emit(f,"vbcc___noturnoff:\n");
+	emit(f,"\treti\n");
+	emit_unised_irq_labels(f);
+	emit(f,"\treti\n");
+	emit_mult(f);
+	emit_div_mod(f);
+}
diff --git a/machines/pm/emit_mult.h b/machines/pm/emit_mult.h
new file mode 100755
index 0000000..35012be
--- /dev/null
+++ b/machines/pm/emit_mult.h
@@ -0,0 +1,23 @@
+
+/* automaticaly generated from the file mult.asm do not modify */
+
+static void emit_mult(FILE *f)
+{
+	emit(f,"vbcc___mul16x16_16:\n");
+	emit(f,"\tpush\thl\n");
+	emit(f,"\tmul\tl, a\n");
+	emit(f,"\tpush\thl\n");
+	emit(f,"\tmov\thl,[sp+3]\n");
+	emit(f,"\tmul\tl, a\n");
+	emit(f,"\tmov\ta, b\n");
+	emit(f,"\tmov\tb, l\n");
+	emit(f,"\tmov\thl, [sp+2]\n");
+	emit(f,"\tmul\tl, a\n");
+	emit(f,"\tmov\ta, l\n");
+	emit(f,"\tadd\ta, b\n");
+	emit(f,"\tmov\tb, a\n");
+	emit(f,"\txor\ta, a\n");
+	emit(f,"\tpop\thl\n");
+	emit(f,"\tadd\tba, hl\n");
+	emit(f,"\tpop\thl\n");
+	emit(f,"\tret\n");}
diff --git a/machines/pm/emit_start.h b/machines/pm/emit_start.h
new file mode 100755
index 0000000..6d7d79e
--- /dev/null
+++ b/machines/pm/emit_start.h
@@ -0,0 +1,44 @@
+
+/* automaticaly generated from the file start.asm do not modify */
+
+static void emit_start(FILE *f)
+{
+	emit(f,".org 0x2100\n");
+	emit(f,".db \"MN\"\n");
+	emit_irq_vectors(f);
+	emit(f,".orgfill 0x21A4\n");
+	emit(f,".db \"NINTENDO\"\n");
+	emit(f,".db \"%s\"\n", game_id);
+	emit(f,".db \"%s\"\n", game_name);
+	emit(f,".orgfill 0x21BC\n");
+	emit(f,".db \"2P\"\n");
+	emit(f,".orgfill 0x21D0\n");
+	emit(f,"vbcc___start_rom_vars:\n");
+	emit(f,".org 0x1000\n");
+	emit(f,"vbcc___start_ram_vars:\n");
+	emit(f,".org 0x2000\n");
+	emit(f,"vbcc___end_ram_vars:\n");
+	emit(f,".org 0x31D0\n");
+	emit(f,".equ  vbcc___ram_vars_offset %d - 0x1000\n", start_ram_vars);
+	emit(f, "%s0:\n", int_handler_prefix);
+	emit(f,"\tmov\t\tx, vbcc___start_rom_vars + vbcc___ram_vars_offset\n");
+	emit(f,"\tmov\t\ty, vbcc___start_ram_vars + vbcc___ram_vars_offset\n");
+	emit(f,"\tmov\t\thl, vbcc___end_ram_vars\n");
+	emit(f,"vbcc__copy_vars_loop:\n");
+	emit(f,"\tmov\t\ta,[x]\n");
+	emit(f,"\tmov\t\t[y],a\n");
+	emit(f,"\tinc\t\tx\n");
+	emit(f,"\tinc\t\ty\n");
+	emit(f,"\tcmp\t\thl, y\n");
+	emit(f,"\tjnz\t\tvbcc__copy_vars_loop\n");
+	emit(f,"\tmovw\tsp, 0x2000\n");
+	emit(f,"\tmovw\tnn, 0x2000\n");
+	emit(f,"\tmovb\t[nn+0x21], 0x0C\n");
+	emit(f,"\tmovb\t[nn+0x25], (1<<7)\n");
+	emit(f,"\tmovb\tflags, 0\n");
+	emit(f,"\tmovb\t[nn+0x80], 0b00001000\n");
+	emit(f,"\tmovb\t[nn+0x81], 0b00001001\n");
+	emit(f,"\tcall\tmain\n");
+	emit(f,"vbcc___infinite_loop:\n");
+	emit(f,"\tjmp\tvbcc___infinite_loop\n");
+}
diff --git a/machines/pm/machine.c b/machines/pm/machine.c
new file mode 100755
index 0000000..81ca077
--- /dev/null
+++ b/machines/pm/machine.c
@@ -0,0 +1,1412 @@
+
+#include "supp.h"
+
+
+static debug_prints = 0;
+
+static char FILE_[]=__FILE__;
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for Pokemon Mini V0.019 (c) in 2011 by zoranc";
+
+
+/*  Commandline-flags the code-generator accepts:
+    0: just a flag
+    VALFLAG: a value must be specified
+    STRINGFLAG: a string can be specified
+    FUNCFLAG: a function will be called
+    apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]= { FUNCFLAG, STRINGFLAG, STRINGFLAG, STRINGFLAG };
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF] = { "h", "ram-vars", "id", "name" };
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+#define HELP_DUMP      (g_flags[0]&USEDFLAG)
+#define RAM_VARS_ADDR  ((g_flags[1]&USEDFLAG)?address_number(g_flags_val[1].p):0x14E0)
+#define GAME_ID        ((g_flags[2]&USEDFLAG)?g_flags_val[2].p:"PKCC")
+#define GAME_NAME      ((g_flags[3]&USEDFLAG)?g_flags_val[3].p:"PokeCCbyZC")
+
+
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Names of all registers.                                     */
+char *regnames[]={"noreg","x","y", "ba", "hl"};
+char *regnames_low[]={"noreg","noreg","noreg", "a", "l"};
+char *regnames_high[]={"noreg","noreg","noreg", "b", "h"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1};
+
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,4,4,4,8,8,0,2,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+static int ix = 1,iy = 2;
+static int q1reg,q2reg,zreg;
+static int ba = 3,hl = 4;               /*  temporary gprs */
+
+
+/* return-instruction */
+static char *ret;
+
+static char *marray[]={"__POKEMINI__",0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT)
+
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="vbcc___l",*idprefix="";
+
+/* has to be 4 bytes long */
+static char game_id[10] = "PKCC";
+/* can be up to 12 bytes long */
+static char game_name[20] = "PokeCCbyZC";
+
+static void emit_irq_vectors(FILE *f);
+static void emit_unised_irq_labels(FILE *f);
+static int used_interrupt[26];
+static char *int_handler_prefix="vbcc___interrupt_handler_";
+
+static int start_ram_vars = 0x14E0;
+static int ram_rom_distance = 0x11D0;
+static int end_ram_vars;
+static int last_was_rom = 1;
+static int ram_vars_initialized = 0;
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt", "__rom", "__align8", "__align64", 0};
+#define INTERRUPT 1
+#define ROM 2
+#define ALIGN8 4
+#define ALIGN64 8
+
+#include "emit.h"
+
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+
+//static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *ccs2[]={"nz","z","ge","l","g","le",""};
+//static char *uccs2[]={"nzb","zb","ge","l","g","le",""};
+static char *uccs2[]={"nz","z","nc","c","c","nc",""};
+//static char *uccs2[]={"nzb","zb","no","o","ns","s",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+static long localsize, rsavesize, /*argsize,*/ pushed;
+
+#define NOT_IMP() not_implemented((f),(__LINE__))
+void not_implemented(FILE *f, int line)
+{
+	emit(f, ";\tNOT IMPLEMENTED: %s LINE: %d !!!\n", __FILE__, line);
+}
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function                   |
+ ------------------------------------------------
+ | return-address [size=3]                      |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize]       |
+ ------------------------------------------------
+ | local variables [size=localsize]             |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+ 
+ This is just an example layout. Other layouts are also possible.
+ */
+
+static long real_offset(struct obj *o)
+{
+	long off=zm2l(o->v->offset);
+
+	if(off<0){
+		/* function parameter */
+		off=localsize+rsavesize+3-off-zm2l(maxalign);
+	}
+
+	off+=pushed;
+
+	off+=zm2l(o->val.vmax);
+
+	return off;
+}
+
+static void emit_irq_vectors(FILE *f)
+{
+	int i;
+	for(i=0; i<26; i++)
+	{
+		emit(f, ".orgfill 0x%x\n", 0x2102 + 6 * i);
+		emit(f, "\tjmp\t%s%d\n", int_handler_prefix, i);
+	}
+	
+	used_interrupt[0] = 1;
+}
+
+static void emit_unised_irq_labels(FILE *f)
+{
+	int i;
+	for(i=0; i<26; i++)
+	{
+		if(!used_interrupt[i])
+			emit(f, "%s%d:\n", int_handler_prefix, i);
+	}
+}
+
+char *flags_verbose(int flags, char *str)
+{
+	static char *flag_str[] = {"KONST", "VAR", "", "", "", "DREFOBJ", "REG", "VARADR"};
+	int i;
+	
+	strcpy(str, "");
+	
+	for(i=0; i<8; i++)
+	{
+		if(flags & (1 << i))
+		{
+			if(strlen(str)!=0 && strlen(flag_str[i])!=0)
+				strcat(str, "|");
+			strcat(str, flag_str[i]);
+		}
+	}
+	
+	return str;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  char str[100];
+  if(debug_prints)
+   	emit(f, ";\tload_address(reg:%s, flags:%s, type:%s)\n", regnames[r], flags_verbose(o->flags, str), typname[type&NQ]);
+  if(!(o->flags&VAR)) ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+  {
+    long off=real_offset(o);
+    emit(f,"\tmov\t%s,sp\n",regnames[r]);
+    if(off)
+      emit(f,"\tadd\t%s,%ld\n",regnames[r],off);
+  }
+  else
+  {
+    emit(f,"\tmov\t%s,",regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f, int r, struct obj *o, int type, int type2)
+{
+  char str[100];
+  if(debug_prints)
+    emit(f, ";\tload_reg(reg:%s, flags:%s, type:%s, type2:%s)\n", regnames[r], flags_verbose(o->flags, str), typname[type&NQ], (type2&NQ)?typname[type2&NQ]:"");
+  type&=NU;
+  if(o->flags&VARADR)
+  {
+    load_address(f,r,o,POINTER);
+  }
+  else
+  {
+    if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+      return;
+    if( msizetab[(type&NQ)] == 1 && 
+         !((o->flags==VAR) /*&& (o->v->storage_class==AUTO||o->v->storage_class==REGISTER)*/))
+    {
+    	/* TODO */
+    	/* optimise this like in the store_reg() */
+		int is_16_reg = ((o->flags&(REG|DREFOBJ)) == REG) && msizetab[type2&NQ] == 2;
+		if(r == ba || r == hl)
+    	{
+			/* handle case of transfer 16-bit reg -> 8-bit reg*/
+			emit(f,"\tmov\t%s,",is_16_reg?regnames[r]:regnames_low[r]);
+			emit_obj(f,o,type);
+			emit(f,"\n");
+		}
+		else if(r==ix && ((o->flags&(REG|DREFOBJ)) == REG))
+		{
+			if(!is_16_reg)
+				emit(f, "\tmov\t%s, 0\n", regnames_high[o->reg]); // or maybe expand sign?
+			emit(f, "\tmov\tx,");
+			emit_obj(f,o,type);
+			emit(f,"\n");
+		}
+		else
+			NOT_IMP();
+    }
+    else
+    {
+		if((o->flags==VAR) && type==ARRAY)
+		{
+			emit(f,"\tmov\t%s,",regnames[r]);
+			o->flags |= VARADR;
+			emit_obj(f,o,type);
+			o->flags &= ~VARADR;
+			emit(f,"\n");
+		}
+		else
+		{
+			emit(f,"\tmov\t%s,",regnames[r]);
+			emit_obj(f,o,type);
+			emit(f,"\n");
+		}
+    }
+  }
+}
+
+static int free_index_reg()
+{
+	if(!regs[ix]) return ix;
+	if(!regs[iy]) return iy;
+	return 0;
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+	char str[100];
+    if(debug_prints)
+    	emit(f, ";\tstore_reg(reg:%s, flags:%s, type:%s)\n", regnames[r], flags_verbose(o->flags, str), typname[type&NQ]);
+	type&=NQ;
+   if( msizetab[(type&NQ)] == 1 )
+   {
+    	if(r == ba)
+    	{
+			if((o->flags==VAR) && (o->v->storage_class==AUTO||o->v->storage_class==REGISTER))
+			{
+				int ind_reg = free_index_reg();
+				long off = real_offset(o);
+				
+				if(off == 0)
+				{
+					emit(f, "\tinc\tsp\n");
+					emit(f, "\tpush\ta\n");
+				}
+				else if(ind_reg)
+				{
+					emit(f, "\tmov\t%s,sp\n", regnames[ind_reg]);
+					emit(f, "\tmov\t[%s+%ld],%s\n", regnames[ind_reg], off, regnames_low[r]);
+				}
+				else
+				{
+					emit(f,"\tmov\thl,sp\n");
+					emit(f,"\tadd\thl,%ld\n",off);
+					emit(f,"\tmov\t[hl],%s\n", regnames_low[r]);
+				}
+			}
+			else
+			{
+				emit(f,"\tmov\t");
+				emit_obj(f,o,type);
+				emit(f,",%s\n",regnames_low[r]);
+			}
+		}
+		else if(r==ix && (o->flags==VAR))
+		{
+			emit(f, "\tmov\thl,");
+			emit_obj(f,o,type);
+			emit(f, "\n");
+			emit(f, "\tmov\th, 0\n"); // maybe extend sign?
+			emit(f, "\tmov\tx,hl\n");
+		}
+		else
+			NOT_IMP();
+   }
+	else
+	{
+		emit(f,"\tmov\t");
+		emit_obj(f,o,type);
+		emit(f,",%s\n",regnames[r]);
+	}
+}
+
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(debug_prints)
+    emit(f, ";\tpreload() - start\n");
+  
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+  
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+  
+  if(isreg(z) && ADD <= p->code && p->code <= SUB)
+  {
+    zreg=p->z.reg;
+  }
+  else
+  {
+    /*
+    if(ISFLOAT(ztyp(p)))
+      zreg=f1;
+    else
+    */
+      zreg=ba;
+  }
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am)
+  {
+    if(debug_prints)
+      emit(f, ";\tpreload() - q1\n");
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,hl,&p->q1,POINTER,0);
+    p->q1.reg=hl;
+    p->q1.flags|=(REG|DREFOBJ);
+	 p->q1.flags&=~KONST;
+  }
+  if(p->q1.flags/* &&LOAD_STORE */&&!isreg(q1))
+  {
+    if(debug_prints)
+      emit(f, ";\tpreload() - q1a\n");
+    /*
+    if(ISFLOAT(q1typ(p)))
+      q1reg=f1;
+    else
+    */
+      q1reg=ba;
+    load_reg(f,q1reg,&p->q1,q1typ(p),0);
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+  
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am)
+  {
+    if(debug_prints)
+      emit(f, ";\tpreload() - q2\n");
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,hl,&p->q2,POINTER, 0);
+    p->q2.reg=hl;
+    p->q2.flags|=(REG|DREFOBJ);
+	 p->q1.flags&=~KONST;
+  }
+  if(p->q2.flags/* &&LOAD_STORE */&&!isreg(q2))
+  {
+    if(debug_prints)
+      emit(f, ";\tpreload() - q2a\n");
+    /*
+    if(ISFLOAT(q2typ(p)))
+      q2reg=f2;
+    else
+    */
+      q2reg=hl;
+    load_reg(f,q2reg,&p->q2,q2typ(p), 0);
+    p->q2.reg=q2reg;
+    p->q2.flags=REG;
+  }
+  
+  if(debug_prints)
+    emit(f, ";\tpreload() - end\n");
+  
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  char str[100];
+  if(debug_prints)
+   	emit(f, ";\tsave_result(flags:%s)\n", flags_verbose(p->z.flags, str));
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,hl,&p->z,POINTER, 0);
+    p->z.reg=hl;
+    p->z.flags|=(REG|DREFOBJ);
+	p->z.flags&=~KONST;
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov\t%s,%s\n",regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+	/*
+	if(p->am){
+	if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+	if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+	return;
+	}
+	*/
+	if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ))
+	{
+		emitval(f,&p->val,p->dtyp&NU);
+		return;
+	}
+	if((p->flags&DREFOBJ)||(p->flags&(VAR|VARADR))==VAR) emit(f,"[");
+	if(p->flags&REG)
+	{
+		emit(f,"%s",regnames[p->reg]);
+	}
+	else if(p->flags&VAR) 
+	{
+		//emit(f,"{%d,%d}", p->v->storage_class, p->flags);
+		if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+			emit(f,"sp+%ld",real_offset(p));
+		else
+		{
+			//emit(f,"[");
+			if(!zmeqto(l2zm(0L),p->val.vmax))
+			{
+				emitval(f,&p->val,LONG);
+				emit(f,"+");
+			}
+			if(p->v->storage_class==STATIC)
+			{
+				emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+			}
+			else
+			{
+				emit(f,"%s%s",idprefix,p->v->identifier);
+			}
+			//emit(f,"]");
+		}
+	}
+	if(p->flags&KONST)
+	{
+		emitval(f,&p->val,t&NU);
+	}
+	if((p->flags&DREFOBJ)||(p->flags&(VAR|VARADR))==VAR) emit(f,"]");
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+/* emit a logical instruction */
+static void emit_logical(FILE *f, int c, struct obj *q, int t)
+{
+	if(zreg==ba)
+	{
+		emit(f, "\tpush\t%s\n", regnames[q->reg]);
+		emit(f, "\tmov\thl,sp\n");
+		emit(f, "\t%s\ta,[hl]\n", logicals[c-OR]);
+		emit(f, "\txchg\ta,b\n");
+		emit(f, "\tinc\thl\n");
+		emit(f, "\t%s\ta,[hl]\n", logicals[c-OR]);
+		emit(f, "\txchg\ta,b\n");
+		emit(f, "\tpop\t%s\n", regnames[q->reg]);
+	}
+	else
+	{
+		NOT_IMP();
+		emit(f,";\t%s\t%s,",logicals[c-OR],regnames[zreg]);
+		emit_obj(f,q,t);
+		emit(f,"\n");
+	}
+}
+
+/* emit a shift instruction */
+static void emit_shift(FILE *f, int c, struct obj *q, int t)
+{
+	int l1, l2, l3;
+	l1 = ++label;
+	l2 = ++label;
+	l3 = ++label;
+	if(zreg==ba)
+	{
+		emit(f, "\tcmp\t%s,16\n",regnames[q->reg]); 
+		emit(f, "\tjc\t%s%d\n",labprefix,l1);
+		if(c == RSHIFT && !(t&UNSIGNED))
+			emit(f, "\tmov\tba,0xffff\n");
+		else
+			emit(f, "\tmov\tba, 0\n");
+		emit(f, "\tjmp\t%s%d\n",labprefix,l3);
+		emit(f, "%s%d:\n",labprefix,l1);
+		emit(f, "\tcmp\t%s,0\n",regnames[q->reg]); 
+		emit(f, "\tjz\t%s%d\n",labprefix,l3);
+		emit(f, "%s%d:\n",labprefix,l2);
+		if(c == LSHIFT)
+		{
+			emit(f, "\tshl\ta\n");
+			emit(f, "\trolc\tb\n");
+		}
+		else
+		{
+			if (t&UNSIGNED)
+				emit(f, "\tshr\tb\n");
+			else
+				emit(f, "\tsar\tb\n");
+			emit(f, "\trorc\ta\n");
+		}
+		emit(f, "\tdec\t%s\n", regnames[q->reg]);
+		emit(f, "\tjnz\t%s%d\n",labprefix,l2);
+		emit(f, "%s%d:\n",labprefix,l3);
+	}
+	else
+	{
+		NOT_IMP();
+		emit(f,";\t%s\t%s,", arithmetics[c-LSHIFT], regnames[zreg]);
+		emit_obj(f,q,t);
+		emit(f,"\n");
+	}
+}
+static void emit_move_array(FILE *f, struct obj *z, struct obj *q, int size)
+{
+	int l1;
+	l1 = ++label;
+	emit(f,"\tmov\thl,%d\n", size);
+	if(regs[ix])
+	{
+		pushed+=2;
+		emit(f, "\tpush\tx\n");
+	}
+	if(regs[iy])
+	{
+		pushed+=2;
+		emit(f, "\tpush\ty\n");
+	}
+	load_reg(f, iy, q, POINTER, 0);
+	z->flags |= VARADR;
+	load_reg(f, ix, z, POINTER, 0);
+	z->flags &= ~VARADR;
+	
+	emit(f, "%s%d:\n",labprefix,l1);
+	emit(f, "\tmov\t[x],[y]\n");
+	emit(f, "\tinc\tx\n");
+	emit(f, "\tinc\ty\n");
+	emit(f, "\tdec\thl\n");
+	emit(f, "\tjnzb\t%s%d\n",labprefix,l1);
+	
+	if(regs[iy])
+	{
+		pushed-=2;
+		emit(f, "\tpop\ty\n");
+	}
+	if(regs[ix])
+	{
+		pushed-=2;
+		emit(f, "\tpop\tx\n");
+	}
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  emit(f,"\n");
+  rsavesize=0;
+  if(v->storage_class==EXTERN)
+  {
+    /*
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,";\t.global\t%s%s\n",idprefix,v->identifier);
+	*/
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }
+  else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  if(offset)
+    emit(f,"\tsub\tsp,%ld\n", offset);
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  if(offset)
+    emit(f,"\tadd\tsp,%ld\n", offset);
+  emit(f,ret);
+}
+
+int address_number(char *str)
+{
+	if(strncmp(str, "0x", 2)==0)
+		return strtol(str, 0, 16);
+	else
+		return atoi(str);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+void help(char *str)
+{
+	printf("Parameters:\n");
+	printf("  -help             This help screen \n");
+	printf("  -ram-vars=<ADDR>  Address from which will start ram variables. \n");
+	printf("                        Default value is 0x14E0 \n");
+	printf("  -id=<ID_STR>      Identificatior of the game. Maximum 4 characters long.\n");
+	printf("  -name=<NAME_STR>  Name of the game. Maximum 12 characters. \n");	
+	fflush(stdout);
+	exit(0);
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+   return 0;
+}
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+	int i;
+	/*  Initialize some values which cannot be statically initialized   */
+	/*  because they are stored in the target's arithmetic.             */
+	maxalign=l2zm(1L);
+	char_bit=l2zm(8L);
+	for(i=0;i<=MAX_TYPE;i++)
+	{
+		sizetab[i]=l2zm(msizetab[i]);
+		align[i]=l2zm(malign[i]);
+	}
+	for(i=1;i<=MAXR;i++)
+	{
+		regsize[i]=l2zm(2L);regtype[i]=&ityp;
+	}   
+
+	/*  Initialize the min/max-settings. Note that the types of the     */
+	/*  host system may be different from the target system and you may */
+	/*  only use the smallest maximum values ANSI guarantees if you     */
+	/*  want to be portable.                                            */
+	/*  That's the reason for the subtraction in t_min[INT]. Long could */
+	/*  be unable to represent -2147483648 on the host system.          */
+	t_min[CHAR]=l2zm(-128L);
+	t_min[SHORT]=l2zm(-32768L);
+	t_min[INT]=t_min[SHORT];
+	t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+	t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+	t_min[MAXINT]=t_min(LLONG);
+	t_max[CHAR]=ul2zum(127L);
+	t_max[SHORT]=ul2zum(32767UL);
+	t_max[INT]=t_max[SHORT];
+	t_max[LONG]=ul2zum(2147483647UL);
+	t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+	t_max[MAXINT]=t_max(LLONG);
+	tu_max[CHAR]=ul2zum(255UL);
+	tu_max[SHORT]=ul2zum(65535UL);
+	tu_max[INT]=tu_max[SHORT];
+	tu_max[LONG]=ul2zum(4294967295UL);
+	tu_max[LLONG]=zumkompl(ul2zum(0UL));
+	tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+	start_ram_vars = RAM_VARS_ADDR;
+
+	memset(game_id, 0, sizeof(game_id));
+	strncpy(game_id, GAME_ID, 4);
+
+	memset(game_name, 0, sizeof(game_id));
+	strncpy(game_name, GAME_NAME, 12);
+
+	target_macros=marray;
+
+	for(i=0; i<26; i++)
+		used_interrupt[i] = 0;
+
+	return 1;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+   int c=p->code;
+   if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+      return 1;
+   if((c==DIV||c==MOD)&&!isconst(q2))
+      return 1;
+   return 0;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+   int f=t->flags&NQ;
+   if(ISSCALAR(f)&&((f&NQ)==INT||(f&NQ)==SHORT||f==CHAR))
+      return ix;
+   return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+   if(!ISSCALAR(t)) return 0;
+   return 1;
+}
+
+int shortcut(int c,int t)
+{
+	/* TODO */
+	/* enable those for more optimised code */
+	/*if(c==COMPARE||c==AND||c==OR||c==XOR) return 1;*/
+	return 0;
+}
+
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+{
+   int op=o&NQ,tp=t&NQ;
+   if(op==tp) return 0;
+   if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+   if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+   if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+   return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  /*
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+  */
+  int i;
+  int num_per_line = 16;
+  for(i=0; i<size; ++i)
+  {
+     if(i % num_per_line == 0)
+     emit(f, "\t.db\t");
+   if(i % num_per_line == num_per_line - 1 || i == size - 1)
+       emit(f, "0\n");
+     else
+       emit(f, "0, ");
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if((t&NQ)==CHAR || (t&NQ)==SHORT)
+    emit(f,"\t.db\t");
+  else if((t&NQ)==INT || (t&NQ)==POINTER)
+    emit(f,"\t.dw\t");
+  else
+    emit(f,";\tdc.%s %d\t",dt(t&NQ), t&NQ);
+    
+  if(!p->tree)
+  {
+    /*
+    if(ISFLOAT(t))
+    {
+      // auch wieder nicht sehr schoen und IEEE noetig
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT)
+      {
+        emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }
+    else
+    */
+	 emitval(f,&p->val,t&NU);
+	 if((t&NQ)==CHAR && 0x20 <= p->val.vchar && p->val.vchar <=0x7f)
+		emit(f, "\t; '%c'", (char)p->val.vchar);
+  }
+  else
+  {
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");
+  //newobj=0;
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag = 0;
+  char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  
+  if(v->tattr&ALIGN8)
+  {
+		emit(f, "\t.align\t8\n");
+		/*
+		emit(f, "\t.equ\tvbcc___unaligned_address .\n");
+		emit(f, "\t.equ\tvbcc___unaligned_address2 (vbcc___unaligned_address + 7)\n");
+		emit(f, "\t.equ\tvbcc___unaligned_address3 (vbcc___unaligned_address2 & 7)\n");
+		emit(f, "\t.equ\tvbcc___unaligned_address4 (vbcc___unaligned_address2 - vbcc___unaligned_address3)\n");
+		emit(f, "\t.org\tvbcc___unaligned_address4\n");
+		*/
+  }
+  
+  if(v->tattr&ALIGN64)
+  {
+		emit(f, "\t.align\t64\n");
+		/*
+		emit(f, "\t.equ\tvbcc___unaligned_address .\n");
+		emit(f, "\t.equ\tvbcc___unaligned_address2 (vbcc___unaligned_address + 63)\n");
+		emit(f, "\t.equ\tvbcc___unaligned_address3 (vbcc___unaligned_address2 & 63)\n");
+		emit(f, "\t.equ\tvbcc___unaligned_address4 (vbcc___unaligned_address2 - vbcc___unaligned_address3)\n");
+		emit(f, "\t.org\tvbcc___unaligned_address4\n");
+		*/
+  }
+  
+  if(/*(v->tattr&ROM) ||*/ /*constflag*/ is_const(v->vtyp))
+  {
+	//emit(f, "\n\t; CONST\n");
+	if(!last_was_rom)
+	{
+		emit(f, "\t.equ\tvbcc___saved_rom_shadow .\n");
+		emit(f, "\t.org\tvbcc___saved_rom_shadow - %d\n", ram_rom_distance);
+		emit(f, "\t.equ\tvbcc___saved_ram_addr .\n");
+		emit(f, "\t.org\tvbcc___saved_rom_addr\n");
+		last_was_rom = 1;
+	}
+  }
+  else
+  {
+	//emit(f, "; in ram!!!  %s%ld:  %s%s: \n",labprefix,zm2l(v->offset), idprefix,v->identifier);
+	if(last_was_rom)
+	{
+		emit(f, "\t.equ\tvbcc___saved_rom_addr .\n");
+		if(!ram_vars_initialized)
+		{
+			emit(f, "\t.org\t%d\n", start_ram_vars);
+			emit(f, "\t.equ\tvbcc___saved_ram_addr .\n");
+			ram_vars_initialized = 1;
+		}
+		else
+		{
+			emit(f, "\t.org\tvbcc___saved_ram_addr\n");
+		}
+		last_was_rom = 0;
+	}
+	else
+	{
+		emit(f, "\t.equ\tvbcc___saved_rom_shadow .\n");
+		emit(f, "\t.org\tvbcc___saved_rom_shadow - %d\n", ram_rom_distance);
+		emit(f, "\t.equ\tvbcc___saved_ram_addr .\n");
+	}
+  }
+  
+  if(v->storage_class==STATIC)
+  {
+    if(!ISFUNC(v->vtyp->flags))
+	{
+		/*
+		if(!special_section(f,v)){
+		  if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+		  if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+		  if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+		}
+		if(v->clist||section==SPECIAL){
+		  gen_align(f,falign(v->vtyp));
+		  emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+		}else
+		  emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+		newobj=1;
+		*/
+		emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+	}
+  }
+  if(v->storage_class==EXTERN)
+  {
+    //emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      /*
+      if(!special_section(f,v)){
+        if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+        if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+        if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||section==SPECIAL){
+        gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+      */
+      emit(f,"%s%s:\n",idprefix,v->identifier);
+    }
+  }
+  if(!last_was_rom)
+  {
+	emit(f, "\t.org\tvbcc___saved_ram_addr + %d\n", ram_rom_distance);	
+  }
+}
+
+static int init_dump = 0;
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+    int c, t, t2, i, cmp_type = 0;
+    struct IC *m;
+
+	if(!init_dump)
+	{
+		init_dump = 1;
+		emit_start(f);
+	}
+	
+	if(strcmp(v->identifier,"main")==0)
+	{
+		emit_end(f);
+	}
+		
+    localsize=(zm2l(offset));
+    for(m=p;m;m=m->next)
+    {
+		c=m->code;t=m->typf&NU;
+		/* convert MULT/DIV/MOD with powers of two */
+		if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+		  eval_const(&m->q2.val,t);
+		  i=pof2(vmax);
+		  if(i){
+			if(c==MOD){
+			  vmax=zmsub(vmax,l2zm(1L));
+			  m->code=AND;
+			}else{
+			  vmax=l2zm(i-1);
+			  if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+			}
+			c=m->code;
+			gval.vmax=vmax;
+			eval_const(&gval,MAXINT);
+			if(c==AND){
+			  insert_const(&m->q2.val,t);
+			}else{
+			  insert_const(&m->q2.val,INT);
+			  m->typf2=INT;
+			}
+		  }
+		}
+        //if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+    }
+ 	//emit(f, ";%s\n", v->identifier);
+	
+	if(v->tattr&INTERRUPT)
+	{
+		char *p;
+		
+		for(p = v->identifier; *p; ++p)
+			if(isdigit(*p))
+				break;
+		if(!*p)
+		{
+			fprintf(stderr, "ERROR: Interrupt routine with no interrupt number!\n");
+		}
+		else
+		{
+			int num = atoi(p);
+			if(used_interrupt[num])
+			{
+				fprintf(stderr, "ERROR: Interrupt %d defined twice!\n", num);
+			}
+			else
+			{
+				used_interrupt[num] = 1;
+				emit(f, "%s%d:\n", int_handler_prefix, num);
+				
+				emit(f, "\tpushax\n");
+				ret="\tpopax\n\treti\n";
+			}
+		}
+	}
+	else
+		ret="\tret\n";
+ 
+    function_top(f,v,localsize);
+    pushed=0;
+ 	
+
+    for(;p;p=p->next)
+    {
+		if(debug_prints)
+		{
+			fprintf(f,";;;;");
+			pric2(f,p);
+		}
+		
+		c=p->code;
+		t=p->typf&NU;
+		t2=p->typf2&NU;
+		
+		if(c==ALLOCREG) 
+		{
+			regs[p->q1.reg]=1;
+			continue;
+		}
+		if(c==FREEREG) 
+		{
+			regs[p->q1.reg]=0;
+			continue;
+		}
+		if(c==BRA){
+		  /*
+		  if(t==exit_label)
+			emit(f,ret);
+		  else
+		  */
+			emit(f,"\tjmp\t%s%d\n",labprefix,t);
+		  continue;
+		}
+		if(c>=BEQ&&c<BRA){
+			int tmp_label = ++label;
+			/* FIXME */
+			/* some of the comparissions can be also 16-bit jumps */
+			if(debug_prints)
+				emit(f, "; t: 0x%x (0x%x)  so: ", cmp_type, UNSIGNED);
+			if(cmp_type&UNSIGNED)
+			{
+				if(debug_prints)
+					emit(f, "UNSIGNED\n");
+				if(c < BLE)
+				{
+					emit(f,"\tj%s\t%s%d\n",uccs2[c-BEQ],labprefix,tmp_label);
+					emit(f,"\tjmp\t%s%d\n",labprefix,t);
+				}
+				else
+				{
+					if(c==BLE)
+					{
+						emit(f,"\tjz\t%s%d\n",labprefix,t);
+						emit(f,"\tj%s\t%s%d\n",uccs2[c-BEQ],labprefix,t);
+					}
+					else /* BGT */
+					{
+						emit(f,"\tjz\t%s%d\n",labprefix,tmp_label);
+						emit(f,"\tj%s\t%s%d\n",uccs2[c-BEQ],labprefix,t);
+					}
+				}
+			}
+			else
+			{
+				if(debug_prints)
+					emit(f, "SIGNED\n");
+				emit(f,"\tj%s\t%s%d\n",ccs2[c-BEQ],labprefix,tmp_label);
+				emit(f,"\tjmp\t%s%d\n",labprefix,t);
+			}
+			emit(f,"%s%d:\n",labprefix,tmp_label);
+			continue;
+		}
+		if(c==MOVETOREG){
+		  load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags, 0);
+		  continue;
+		}
+		if(c==MOVEFROMREG){
+		  store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+		  continue;
+		}
+		if(c==CALL){					
+			if((p->q1.flags & (VAR|DREFOBJ)) == VAR &&
+				p->q1.v->fi &&
+				p->q1.v->fi->inline_asm)
+			{
+				emit_inline_asm(f,p->q1.v->fi->inline_asm);
+			}
+			else
+			{
+				emit(f,"\tcall\t");
+				if(p->q1.v->storage_class==STATIC)
+				{
+					emit(f,"%s%ld",labprefix,zm2l(p->q1.v->offset));
+				}
+				else
+				{
+					emit(f,"%s%s",idprefix,p->q1.v->identifier);
+				}
+				emit(f,"\n");
+			}		  
+			if(pushed != 0)
+				emit(f,"\tadd\tsp,%ld\n", pushed);			
+			pushed = 0;
+			continue;
+		}
+		
+		if(c==ADDRESS)
+		{
+			if(isreg(z))
+				zreg=p->z.reg;
+			else
+				zreg=ba;
+			load_address(f,zreg,&p->q1,POINTER);
+			save_result(f,p);
+			continue;
+		}
+			 
+		p=preload(f,p);
+		c=p->code;
+		
+		if(c==SUBPFP) c=SUB;
+		if(c==ADDI2P) c=ADD;
+		if(c==SUBIFP) c=SUB;
+		
+		if(c==CONVERT)
+		{
+			/* FIXME */
+			if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+			load_reg(f,zreg,&p->q1,t, t2);
+			if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ] && (ztyp(p)&NQ&POINTER)!=POINTER)
+			{
+				if(zreg == ba && msizetab[q1typ(p)&NQ] == 1)
+				{
+					if(q1typ(p)&UNSIGNED)
+						emit(f,"\tmov\tb,0\n");
+					else
+						emit(f,"\tex\tba,a\n",dt(q1typ(p)),regnames[zreg]);
+				}
+				else
+					NOT_IMP();
+			}
+			save_result(f,p);
+			continue;
+		}
+		
+		if(c==SETRETURN){
+		  load_reg(f,p->z.reg,&p->q1,t, 0);
+		  continue;
+		}
+		
+		if(c==GETRETURN){
+		  if(p->q1.reg){
+			zreg=p->q1.reg;
+			save_result(f,p);
+		  }else
+			p->z.flags=0;
+		  continue;
+		}
+	 
+		if(c==ASSIGN)
+		{
+			if(debug_prints)
+				emit(f,"; ASSIGN start\n");
+			if(t==0) 
+				ierror(0);
+			if(t==ARRAY)
+			{
+				emit_move_array(f, &p->z, &p->q1, p->q2.val.vmax);
+			}
+			else
+			{
+				load_reg(f,zreg,&p->q1,t, 0);
+				save_result(f,p);
+			}
+			if(debug_prints)
+				emit(f,"; ASSIGN end\n");
+			continue;
+		}
+		
+		if(c==PUSH)
+		{
+			if(t==0) ierror(0);
+			pushed+=zm2l(p->q2.val.vmax);
+			//emit(f,"\tmov\t[sp+%ld],",pushed);
+			emit(f, "\tpush\t");
+			emit_obj(f,&p->q1,t);
+			emit(f,"\n");
+			continue;
+		}
+		
+		if(c==LABEL) 
+		{
+			emit(f,"%s%d:\n",labprefix,t);
+			continue;
+		}
+
+		if(c==KOMPLEMENT)
+		{
+			load_reg(f,ba,&p->q1,t, 0);
+			emit(f,"\tnot\ta\n");
+			emit(f,"\tnot\tb\n");
+			save_result(f,p);
+			continue;
+		}
+		
+		if(c==MINUS)
+		{
+			load_reg(f,ba,&p->q1,t, 0);
+			emit(f,"\tmov\thl,0\n");
+			emit(f,"\tsub\thl,ba\n");
+			emit(f,"\tmov\tba,hl\n");
+			save_result(f,p);
+			continue;
+		}
+		
+		if(c==TEST)
+		{
+			if(q1reg != ba)
+			{
+				emit(f, "\tmov\tba,");
+				emit_obj(f,&p->q1,t);
+				emit(f, "\n");
+			}
+			emit(f,"\tcmp\t%s,0\n", (msizetab[(t&NQ)]==1)?"a":"ba");
+			continue;
+		}
+		
+		if(c==COMPARE)
+		{
+			cmp_type = t;
+			if(q1reg != ba)
+			{
+				emit(f, "\tmov\tba,");
+				emit_obj(f,&p->q1,t);
+				emit(f, "\n");
+			}
+			emit(f,"\tcmp\t%s,", (msizetab[(t&NQ)]==1)?"a":"ba");
+			emit_obj(f,&p->q2,t);
+			emit(f,"\n");
+			continue;
+		}
+    
+		if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD))
+		{
+			load_reg(f, zreg, &p->q1, t, 0);
+			if(c>=OR&&c<=AND)
+			{
+				emit_logical(f, c, &p->q2, t);
+			}
+			else if(c>=LSHIFT&&c<=RSHIFT)
+			{
+				emit_shift(f, c, &p->q2, t);
+			}
+			else if(c==MULT)
+			{
+				load_reg(f, ba, &p->q1, t, 0);
+				load_reg(f, hl, &p->q2, t, 0);
+				emit(f, "\tcall\tvbcc___mul16x16_16\n");
+			}
+			else if(DIV <=c && c <=MOD)
+			{
+				load_reg(f, ba, &p->q1, t, 0);
+				load_reg(f, hl, &p->q2, t, 0);
+				emit(f, "\tcall\tvbcc___div_mod16x16_16\n");
+				if(c==MOD)
+					emit(f, "\tmov\tba, hl\n");
+			}
+			else
+			{
+				if(zreg != ba)
+					emit(f, "\tmov\tba,%s\n", regnames[zreg]);
+				emit(f,"\t%s\t%s,",arithmetics[c-LSHIFT],regnames[ba]);
+				emit_obj(f,&p->q2,t);
+				emit(f,"\n");
+				if(zreg != ba)
+					emit(f, "\tmov\t%s,ba\n", regnames[zreg]);
+			}
+			save_result(f,p);
+			continue;
+		}
+		 
+		fprintf(f,";\tNOT IMPLEMENTED INSTRUCTION >>> %s <<< (code:%d)\n", ename[p->code], p->code);
+		fprintf(f,";;;;");
+		pric2(f,p);
+    }
+
+    function_bottom(f,v,localsize);
+}
+
+void cleanup_cg(FILE *f)
+{
+}
+
+void init_db(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+} 
diff --git a/machines/pm/machine.dt b/machines/pm/machine.dt
new file mode 100755
index 0000000..0926f51
--- /dev/null
+++ b/machines/pm/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S16BUbE S16BULE
+
+
diff --git a/machines/pm/machine.h b/machines/pm/machine.h
new file mode 100755
index 0000000..2b4bec6
--- /dev/null
+++ b/machines/pm/machine.h
@@ -0,0 +1,55 @@
+
+
+#include "dt.h"
+
+
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 2
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 4
+
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 1
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 20000 /* should be enough */
+
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 1
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
diff --git a/machines/ppc/machine.c b/machines/ppc/machine.c
new file mode 100644
index 0000000..e547fc1
--- /dev/null
+++ b/machines/ppc/machine.c
@@ -0,0 +1,4012 @@
+/*  Code generator for a PPC RISC cpu with 32 general purpose,  */
+/*  32 floating point and 8 condition code registers.           */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for PPC V0.7 (c) in 1997-2022 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={STRINGFLAG,STRINGFLAG,0,0,0,0,
+                    0,0,0,0,0,
+                    0,0,0,0,0,0,
+		    0,0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","const-in-data","sd","merge-constants","fsub-zero",
+                           "elf","amiga-align","no-regnames","no-peephole","setccs",
+                           "use-lmw","poweropen","sc","madd","eabi","gas",
+			   "no-align-args","conservative-sr","use-commons",
+                           "baserel32os4","baserel32mos","oldlibcalls"};
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  Tabelle fuer die Groesse der einzelnen Typen                */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[MAXR+1]={"noreg",
+                        "r0","r1","r2","r3","r4","r5","r6","r7",
+                        "r8","r9","r10","r11","r12","r13","r14","r15",
+                        "r16","r17","r18","r19","r20","r21","r22","r23",
+                        "r24","r25","r26","r27","r28","r29","r30","r31",
+                        "f0","f1","f2","f3","f4","f5","f6","f7",
+                        "f8","f9","f10","f11","f12","f13","f14","f15",
+                        "f16","f17","f18","f19","f20","f21","f22","f23",
+                        "f24","f25","f26","f27","f28","f29","f30","f31",
+                        "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7",
+                        "cnt",
+			"r3/r4","r5/r6","r7/r8","r9/r10",
+			"r14/r15","r16/r17","r18/r19","r20/r21",
+			"r22/r23","r24/r25","r26/r27","r28/r29","r30/r31",
+			"lr"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+		          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+		          1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+			  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+			  1,1,0,0,0,1,1,1,1,
+			  1,1,1,1,
+			  0,0,0,0,0,0,0,0,0};
+
+int reg_prio[MAXR+1]={0,0,0,0,19,20,21,22,23,24,25,26,27,28,0,1,2,
+		        3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
+		        0,1,2,3,4,5,6,7,8,9,10,11,12,13,0,0,
+		        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+		        1,1,0,0,0,1,1,1,1,
+		        19,21,23,25,
+		        1,3,5,7,9,11,13,15,17};
+
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__far","__near","__chip","__saveds","__rfi","__saveall",
+		     "__syscall","__nosave","__brel",0};
+#define FAR 1
+#define NEAR 2
+#define CHIP 4
+#define SAVEDS 8
+#define RFI 16
+#define SAVEALL 32
+#define SYSCALL 64
+#define NOSAVE 128
+#define BREL 256
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+#define SMALLDATA (g_flags[3]&USEDFLAG)
+#define POWEROPEN (g_flags[12]&USEDFLAG)
+#define STORMC (g_flags[13]&USEDFLAG)
+#define EABI (g_flags[15]&USEDFLAG)
+#define GAS (g_flags[16]&USEDFLAG)
+#define NOALIGNARGS (g_flags[17]&USEDFLAG)
+#define CONSERVATIVE_SR (g_flags[18]&USEDFLAG)
+#define USE_COMMONS (g_flags[19]&USEDFLAG)
+#define BASERELOS4 (g_flags[20]&USEDFLAG)
+#define BASERELMOS (g_flags[21]&USEDFLAG)
+#define OLDLIBCALLS (g_flags[22]&USEDFLAG)
+
+
+static char *mregnames[MAXR+1];
+
+static char *ret="\tblr\n";
+
+static long malign[MAX_TYPE+1]=  {1,1,2,4,4,8,4,8,8,1,4,1,1,1,4,1};
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+static struct Typ ltyp={LONG},lltyp={LLONG},ldbl={DOUBLE},lchar={CHAR};
+
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+		       "__PPC__",
+		       "__aos4libcall=__attr(\"aos4libcall;\")",
+		       "__linearvarargs=__attr(\"linearvarargs;\")",
+		       "__interrupt=__rfi __saveall",
+		       0};
+
+const int r4=5,r5=6,r6=7,r3r4=74,r5r6=75;
+
+
+static int r0=1;                   /*  special register                    */
+static int r2=3;                   /*  reserved or toc                     */
+static int r3=4;                   /*  return value                        */
+static int sp=2;                   /*  Stackpointer                        */
+static int fp=2;                   /*  Framepointer                        */
+static int vlafp=32;               /*  Framepointer to use with vlas       */
+static int sd=14;                  /*  SmallDataPointer                    */
+static int sd2=3;                  /*  SmallData2 (eabi)                   */
+static int t1=12,t2=13,t3=1;       /*  Temporaries used by code generator  */
+static int f1=45,f2=46,f3=33;      /*  Temporaries used by code generator  */
+static int cr0=65;                 /*  Default condition-code-register     */
+static int ctr=73;                 /*  ctr                                 */
+static int lr=87;                  /*  link register                       */
+static int bp32os4=3;              /*  baserel32 pointer for Amiga OS4     */
+static int bp32mos=14;             /*  baserel32 pointer for MorphOS       */
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define TOC 4
+#define SDATA 5
+#define SDATA2 6
+#define SBSS 7
+#define SPECIAL 8
+
+#if HAVE_OSEK
+/* removed */
+/* removed */
+#endif
+
+static long stack;
+static int stack_valid;
+static long tmpoff; /* offset for additional temporaries, upper end! */
+static int lastlabel,exit_label;
+static int sdp;
+static int q1loaded,q2loaded;
+static int section=-1,newobj,crsave;
+static char *codename="\t.text\n\t.align\t2\n",
+  *dataname="\t.data\n\t.align\t2\n",
+  *bssname="",
+  *rodataname="\t.section\t.rodata\n\t.align\t2\n",
+  *tocname="\t.tocd\n\t.align\t2\n",
+  *sdataname="\t.section\t\".sdata\",\"aw\"\n\t.align\t2\n",
+  *sdata2name="\t.section\t\".sdata2\",\"a\"\n\t.align\t2\n",
+  *sbssname="\t.section\t\".sbss\",\"auw\"\n\t.align\t2\n";
+
+static char *labprefix="l",*idprefix="_",*tocprefix="@_";
+static long frameoffset,pushed,maxpushed,framesize,localoffset,minframe=8;
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+static int all_regs;
+
+struct StatFPtrList {
+  struct StatFPtrList *next;
+  struct Var *vptr;
+};
+static struct StatFPtrList *firstfptr = NULL;
+
+void title(FILE *f)
+{
+  static int done;
+  extern char *inname; /*grmpf*/
+  if(!done&&f){
+    done=1;
+    emit(f,"\t.file\t\"%s\"\n",inname);
+  }
+} 
+
+static long real_offset(struct obj *o)
+{
+  long off;
+  if(zm2l(o->v->offset)>=0){
+     return zm2l(o->v->offset)+frameoffset+zm2l(o->val.vmax);
+  }else{
+    return framesize+minframe-zm2l(o->v->offset)-zm2l(maxalign)+zm2l(o->val.vmax);
+  }
+}
+static long hi(long off)
+{
+  zmax zm=l2zm(off),r=zmrshift(zm,l2zm(16L));
+  if(!zmeqto(zmand(zm,l2zm(32768L)),l2zm(0L))) r=zmadd(r,l2zm(1L));
+  return zm2l(zs2zm(zm2zs(zmand(r,l2zm(65535L)))));
+}
+static long lo(long off)
+{
+  return zm2l(zs2zm(zm2zs(zmand(l2zm(off),l2zm(65535L)))));
+}
+static struct fpconstlist {
+  struct fpconstlist *next;
+  int label,typ;
+  union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(t==LDOUBLE) t=DOUBLE;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+        eval_const(&p->val,t);
+        if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+        if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+#define REG_IND 1
+#define IMM_IND 2
+#define UPDATE  64
+
+static struct obj *cam(int flags,int base,long offset)
+/*  Initializes an addressing-mode structure and returns a pointer to   */
+/*  that object. Will not survive a second call!                        */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+static char *ldts[]={"","bz","ha","wz","wz","wz","fs","fd","fd","","wz"};
+static char *ldtu[]={"","bz","hz","wz","wz","wz","??","??","??","??","??"};
+static char *sdts[]={"","b","h","w","w","w","fs","fd","fd","","w"};
+static char *sdtu[]={"","b","h","w","w","w","??","??","??","??","??"};
+
+#define ldt(t) ((t&UNSIGNED)?ldtu[t&NQ]:ldts[t&NQ])
+#define sdt(t) ((t&UNSIGNED)?sdtu[t&NQ]:sdts[t&NQ])
+
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static int use_sd(int t)
+/*  Shall the object of type t be addressed in small-data-mode?  */
+{
+  int r=0;
+  if(ISFUNC(t)) return 0;
+  if(g_flags[3]&USEDFLAG) 
+    r=sd;
+  else if(STORMC&&(t&NQ)<=POINTER) 
+    r=sd;
+  else if(EABI&&ISSCALAR(t)){
+    if(t&CONST)
+      r=sd2;
+    else
+      r=sd;
+  }
+  return r;
+}
+
+static void load_address(FILE *f,int r,struct obj *o,int typ)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  BSET(regs_modified,r);
+  if(!(o->flags&VAR)) 
+    ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    if(off<=32767){
+      emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[fp],off);
+    }else{
+      if(r==r0){
+	BSET(regs_modified,t2);
+	emit(f,"\taddis\t%s,%s,%ld\n",mregnames[t2],mregnames[fp],hi(off));
+	emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[t2],lo(off));
+      }else{
+	emit(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[fp],hi(off));
+	emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],lo(off));
+      }
+    }
+  }else{
+    if((sdp=use_sd(o->v->vtyp->flags))&&!(o->v->tattr&FAR)
+       &&zmleq(l2zm(0L),o->val.vmax)&&!zmleq(szof(o->v->vtyp),o->val.vmax)){
+      emit(f,"\tla\t%s,",mregnames[r]);
+      emit_obj(f,o,typ);
+      if(GAS)
+	emit(f,"@sda21(0)\n");
+      else
+	emit(f,"(%s)\n",mregnames[sdp]);
+    }else{
+      if(POWEROPEN){
+        zmax offset=o->val.vmax;
+	if(f){
+	  if((o->v->vtyp->flags&NQ)==FUNKT&&o->v->storage_class==STATIC){
+	    /* check if static function pointer was already created in TOC */
+	    struct StatFPtrList **oldsfp=&firstfptr;
+	    struct StatFPtrList *sfp=firstfptr;
+	    while(sfp){
+	      if(sfp->vptr==o->v) break;
+	      oldsfp=&sfp->next;
+	      sfp=sfp->next;
+	    }
+	    if(!sfp){
+	      *oldsfp=sfp=mymalloc(sizeof(struct StatFPtrList));
+	      sfp->next=NULL;
+	      sfp->vptr=o->v;
+	    }
+	  }
+	  emit(f,"\tl%s\t%s,%s",ldt(LONG),mregnames[r],tocprefix);
+	  o->val.vmax=l2zm(0L);emit_obj(f,o,POINTER);o->val.vmax=offset;
+	  emit(f,"(%s)\n",mregnames[r2]);
+	  if(hi(zm2l(offset))) emit(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[r],hi(zm2l(offset)));
+	  if(lo(zm2l(offset))) emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],lo(zm2l(offset)));
+	}
+      }else{
+        if(BASERELOS4){
+          emit(f,"\taddis\t%s,%s,",mregnames[r],mregnames[bp32os4]);
+          emit_obj(f,o,typ);emit(f,"@brel@ha\n");
+          emit(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@brel@l\n");
+        }else if(BASERELMOS){
+          emit(f,"\taddis\t%s,%s,",mregnames[r],mregnames[bp32mos]);
+          emit_obj(f,o,typ);emit(f,"@drel@ha\n");
+          emit(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@drel@l\n");
+        }else{
+          emit(f,"\tlis\t%s,",mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@ha\n");
+          emit(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@l\n");
+        }
+      }
+    }
+  }
+}
+static void load_reg(FILE *f,int r,struct obj *o,int typ,int tmp)
+/*  Generates code to load a memory object into register r. tmp is a    */
+/*  general purpose register which may be used. tmp can be r.           */
+{
+  typ&=NU;
+  BSET(regs_modified,r);
+  if(o->flags&KONST){
+    long l;
+    eval_const(&o->val,typ);
+    if(ISFLOAT(typ)){
+      int lab;
+      if((g_flags[5]&USEDFLAG)&&zldeqto(vldouble,d2zld(0.0))){
+        emit(f,"\tfsub\t%s,%s,%s\n",mregnames[r],mregnames[r],mregnames[r]);
+        return;
+      }
+      lab=addfpconst(o,typ);
+      if(sdp=use_sd(typ)){
+	if(GAS)
+	  emit(f,"\tl%s\t%s,%s%d@sda21(0)\n",ldt(typ),mregnames[r],labprefix,lab);
+	else
+	  emit(f,"\tl%s\t%s,%s%d(%s)\n",ldt(typ),mregnames[r],labprefix,lab,mregnames[sdp]);
+      }else{
+	BSET(regs_modified,tmp);
+        if(POWEROPEN){
+          emit(f,"\tl%s\t%s,%s%s%ld(%s)\n",ldt(LONG),mregnames[tmp],tocprefix,labprefix,(long)lab,mregnames[r2]);
+          emit(f,"\tl%s\t%s,0(%s)\n",ldt(typ),mregnames[r],mregnames[tmp]);
+        }else{
+          emit(f,"\tlis\t%s,%s%d@ha\n",mregnames[tmp],labprefix,lab);
+          emit(f,"\tl%s\t%s,%s%d@l(%s)\n",ldt(typ),mregnames[r],labprefix,lab,mregnames[tmp]);
+        }
+      }
+      return;
+    }
+    if(r==1) ierror(0);
+    l=hi(zm2l(vmax));
+    if(l){
+      emit(f,"\tlis\t%s,%ld\n",mregnames[r],l);
+      l=lo(zm2l(vmax));
+      if(l)
+	emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],l);
+    }else{
+      emit(f,"\tli\t%s,%ld\n",mregnames[r],lo(vmax));
+    }
+    return;
+  }
+  if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+    if(o->flags&VARADR){
+      load_address(f,r,o,POINTER);
+    }else{
+      if((sdp=use_sd(o->v->vtyp->flags))&&!(o->v->tattr&FAR)){
+        emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+        emit_obj(f,o,typ);
+	if(GAS)
+	  emit(f,"@sda21(0)\n");
+	else
+	  emit(f,"(%s)\n",mregnames[sdp]);
+      }else{
+	BSET(regs_modified,tmp);
+        if(POWEROPEN){
+          zmax offset=o->val.vmax;
+          emit(f,"\tl%s\t%s,%s",ldt(LONG),mregnames[tmp],tocprefix);
+          o->val.vmax=l2zm(0L);emit_obj(f,o,POINTER);o->val.vmax=offset;
+          emit(f,"(%s)\n",mregnames[r2]);
+          if(hi(zm2l(offset))) emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[tmp],hi(zm2l(offset)));
+          emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(typ),mregnames[r],lo(zm2l(offset)),mregnames[tmp]);
+        }else{
+          if(BASERELOS4){
+            emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32os4]);
+            emit_obj(f,o,typ);emit(f,"@brel@ha\n");
+            emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+            emit_obj(f,o,typ);emit(f,"@brel@l(%s)\n",mregnames[tmp]);
+          }else if(BASERELMOS){
+            emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32mos]);
+            emit_obj(f,o,typ);emit(f,"@drel@ha\n");
+            emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+            emit_obj(f,o,typ);emit(f,"@drel@l(%s)\n",mregnames[tmp]);
+          }else{
+            emit(f,"\tlis\t%s,",mregnames[tmp]);
+            emit_obj(f,o,typ);emit(f,"@ha\n");
+            emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+            emit_obj(f,o,typ);emit(f,"@l(%s)\n",mregnames[tmp]);
+          }
+        }
+      }
+    }
+  }else{
+    if((o->flags&(DREFOBJ|REG))==REG){
+      if(r!=o->reg)
+        emit(f,"\t%smr\t%s,%s\n",r>=33?"f":"",mregnames[r],mregnames[o->reg]);
+    }else if(!o->am&&(o->flags&(DREFOBJ|REG))==(REG|DREFOBJ)){
+      emit(f,"\tl%s\t%s,0(%s)\n",ldt(typ),mregnames[r],mregnames[o->reg]);
+    }else if(!o->am){
+      long off=real_offset(o);
+      if(off<=32767){
+        emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(typ),mregnames[r],off,mregnames[fp]);
+      }else{
+	BSET(regs_modified,tmp);
+        emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[fp],hi(off));
+        emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(typ),mregnames[r],lo(zm2l(off)),mregnames[tmp]);
+      }
+    }else{
+      emit(f,"\tl%s%s%s\t%s,",ldt(typ),(o->am->flags&UPDATE)?"u":"",(o->am->flags&REG_IND)?"x":"",mregnames[r]);
+      emit_obj(f,o,typ);emit(f,"\n");
+    }
+  }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int typ)
+/*  Generates code to store register r into memory object o.            */
+{
+  int tmp;
+  typ&=NQ;
+  if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+    int tmp=t1;
+    if(tmp==r) tmp=t2;
+    if((sdp=use_sd(o->v->vtyp->flags))&&!(o->v->tattr&FAR)){
+      emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+      emit_obj(f,o,typ);
+      if(GAS)
+	emit(f,"@sda21(0)\n");
+      else
+	emit(f,"(%s)\n",mregnames[sdp]);
+      return;
+    }else{
+      BSET(regs_modified,tmp);
+      if(POWEROPEN){
+        zmax offset=o->val.vmax;
+        emit(f,"\tl%s\t%s,%s",ldt(LONG),mregnames[tmp],tocprefix);
+        o->val.vmax=l2zm(0L);emit_obj(f,o,POINTER);o->val.vmax=offset;
+        emit(f,"(%s)\n",mregnames[r2]);
+        if(hi(zm2l(offset))) emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[tmp],hi(zm2l(offset)));
+        emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(typ),mregnames[r],lo(zm2l(offset)),mregnames[tmp]);
+        return;
+      }else{
+        if(BASERELOS4){
+          emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32os4]);
+          emit_obj(f,o,typ);emit(f,"@brel@ha\n");
+          emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@brel@l(%s)\n",mregnames[tmp]);
+        }else if(BASERELMOS){
+          emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32mos]);
+          emit_obj(f,o,typ);emit(f,"@drel@ha\n");
+          emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@drel@l(%s)\n",mregnames[tmp]);
+        }else{
+          emit(f,"\tlis\t%s,",mregnames[tmp]);
+          emit_obj(f,o,typ);emit(f,"@ha\n");
+          emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+          emit_obj(f,o,typ);emit(f,"@l(%s)\n",mregnames[tmp]);
+        }
+        return;
+      }
+    }
+  }
+  if(!(o->flags&DREFOBJ)&&!o->am){
+    long off=real_offset(o);
+    if(r==t1) tmp=t2; else tmp=t1;
+    if(off<=32767){
+      emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(typ),mregnames[r],off,mregnames[fp]);
+    }else{
+
+      BSET(regs_modified,tmp);
+      emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[fp],hi(off));
+      emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(typ),mregnames[r],lo(off),mregnames[tmp]);
+    }
+  }else{
+    if(!o->am){
+      emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+      emit_obj(f,o,typ);emit(f,"\n");
+    }else{
+      emit(f,"\tst%s%s%s\t%s,",sdt(typ),(o->am->flags&UPDATE)?"u":"",(o->am->flags&REG_IND)?"x":"",mregnames[r]);
+      emit_obj(f,o,typ);emit(f,"\n");
+    }
+  }
+}
+
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+#if 1
+static char *dct[]={"","byte","2byte","4byte","4byte","4byte","4byte","4byte","4byte"};
+#else
+static char *dct[]={"","byte","short","long","long","long","long","long","long"};
+#endif
+static struct IC *do_refs(FILE *,struct IC *);
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *record[]={"","."};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+static char *isimm[]={"","i"};
+
+static struct IC *do_refs(FILE *f,struct IC *p)
+/*  Does some pre-processing like fetching operands from memory to      */
+/*  registers etc.                                                      */
+{
+  int typ,typ1,reg,c=abs(p->code);
+
+  q1loaded=q2loaded=0;
+
+  /* cannot use q1typ, because p->code may have been negated */
+  if(c==CONVERT) 
+    typ=p->typf2;
+  else
+    typ=p->typf;
+
+  if((typ&NQ)==POINTER) typ=UNSIGNED|LONG;
+
+  if((c==SUB||c==SUBIFP)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(typ&NQ)<=LLONG){
+    eval_const(&p->q2.val,typ);
+    if(zmleq(vmax,l2zm(32768L))&&zmleq(l2zm(-32767L),vmax)){
+      union atyps val;
+      if(c==SUB){
+        if(p->code==SUB) p->code=c=ADD; else p->code=c=-ADD;
+      }else{
+        if(p->code==SUBIFP) p->code=c=ADDI2P; else p->code=c=-ADDI2P;
+      }
+      c=abs(c);
+      val.vmax=zmsub(l2zm(0L),vmax);
+      eval_const(&val,MAXINT);
+      insert_const(&p->q2.val,typ);
+      p->typf=typ=(typ&~UNSIGNED);
+    }
+  }
+
+  q1reg=q2reg=zreg=0;
+  if(p->q1.flags&REG) q1reg=p->q1.reg;
+  if(p->q2.flags&REG) q2reg=p->q2.reg;
+  if((p->z.flags&(REG|DREFOBJ))==REG) zreg=p->z.reg;
+
+  if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->q1.val,typ);
+    if(ISFLOAT(typ)) reg=f1; else reg=t1;
+    if(c==ASSIGN&&zreg) reg=zreg;
+    if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+    if(c!=SUB||(typ&NQ)>LONG||!zmleq(vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),vmax)){
+      load_reg(f,reg,&p->q1,typ,t1);
+      q1reg=reg;
+      q1loaded=1;
+    }
+  }else if(c!=ADDRESS){
+    if(ISFLOAT(typ)) reg=f1; else reg=t1;
+    if((c==ASSIGN||(c==CONVERT&&ISINT(p->typf2)))&&zreg>=1&&zreg<=32) reg=zreg;
+    if((c==ASSIGN||(c==CONVERT&&ISFLOAT(p->typf2)))&&zreg>=33&&zreg<=64) reg=zreg;
+    if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+    if(p->q1.am){
+      load_reg(f,reg,&p->q1,typ,t1);
+      q1reg=reg;
+      q1loaded=1;
+    }else{
+      if(p->q1.flags&&!q1reg){
+        if(p->q1.flags&DREFOBJ) {typ1=POINTER;reg=t1;} else typ1=typ;
+        if((typ1&NQ)<=POINTER){
+          int m=p->q1.flags;
+          p->q1.flags&=~DREFOBJ;
+          load_reg(f,reg,&p->q1,typ1,t1);
+          p->q1.flags=m;
+          q1reg=reg;
+	  q1loaded=1;
+        }
+      }
+      if((p->q1.flags&DREFOBJ)&&(typ&NQ)<=POINTER){
+        if(ISFLOAT(typ)) reg=f1; else reg=t1;
+        if((c==ASSIGN||(c==CONVERT&&ISINT(p->typf2)))&&zreg>=1&&zreg<=32) reg=zreg;
+	if((c==ASSIGN||(c==CONVERT&&ISFLOAT(p->typf2)))&&zreg>=33&&zreg<=64) reg=zreg;
+        if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+        if(p->q1.am)
+          load_reg(f,reg,&p->q1,typ,t1);
+        else
+          load_reg(f,reg,cam(IMM_IND,q1reg,0),typ,t1);
+        q1reg=reg;
+	q1loaded=1;
+      }
+    }
+  }
+  /* cannot use q2typ (see above) */
+  typ=p->typf;
+  if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->q2.val,typ);
+    if(ISFLOAT(typ)) reg=f2; else reg=t2;
+    if(ISFLOAT(typ)||c==DIV||c==SUB||c==MOD){
+      load_reg(f,reg,&p->q2,typ,t2);
+      q2reg=reg;
+      q2loaded=1;
+    }else{
+      if((c>=OR&&c<=AND)||(c==COMPARE&&(typ&UNSIGNED))){
+        if(!zumleq(vumax,ul2zum(65535UL))){
+          load_reg(f,reg,&p->q2,typ,t2);
+          q2reg=reg;
+	  q2loaded=1;
+        }
+      }else{
+        if(!zmleq(vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),vmax)){
+          load_reg(f,reg,&p->q2,typ,t2);
+          q2reg=reg;
+	  q2loaded=1;
+        }
+      }
+    }
+  }else{
+    if(p->q2.am){
+      if(ISFLOAT(typ)) reg=f2; else reg=t2;
+      load_reg(f,reg,&p->q2,typ,t2);
+      q2reg=reg;
+      q2loaded=1;
+    }else{
+      if(p->q2.flags&&!q2reg){
+        if((p->q2.flags&DREFOBJ)) typ1=POINTER; else typ1=typ;
+        if(ISFLOAT(typ1)) reg=f2; else reg=t2;
+        if((typ1&NQ)<=POINTER){
+          int m=p->q2.flags;
+          p->q2.flags&=~DREFOBJ;
+          load_reg(f,reg,&p->q2,typ1,t2);
+          p->q2.flags=m;
+          q2reg=reg;
+	  q2loaded=1;
+        }
+      }
+      if((p->q2.flags&DREFOBJ)&&(typ&NQ)<=POINTER){
+        if(ISFLOAT(typ)) reg=f2; else reg=t2;
+        if(p->q2.am)
+          load_reg(f,reg,&p->q2,typ,t2);
+        else
+          load_reg(f,reg,cam(IMM_IND,q2reg,0),typ,t2);
+        q2reg=reg;
+	q2loaded=1;
+      }
+    }
+  }
+  if(p->z.am||(p->z.flags&&!isreg(z))){
+    typ=p->typf;
+    if(c!=ADDRESS&&ISFLOAT(typ)) zreg=f3; else zreg=t3;
+  }
+  if(q1reg){p->q1.flags=REG;p->q1.reg=q1reg;p->q1.am=0;}
+  if(q2reg){p->q2.flags=REG;p->q2.reg=q2reg;p->q2.am=0;}
+  return p;
+}
+static void pr(FILE *f,struct IC *p)
+     /*  Writes the destination register to the real destination if necessary.   */
+{
+  int typ=p->typf;
+  if(p->code==ADDRESS) typ=POINTER;
+  if(p->z.flags){
+    if(zreg>=74&&zreg<=86){printf("c=%d\n",p->code); ierror(0);}
+    if(p->z.am){
+      store_reg(f,zreg,&p->z,typ);
+    }else if(!isreg(z)){
+      if(p->z.flags&DREFOBJ){
+        if(p->z.flags&REG){
+          if(p->z.am)
+            store_reg(f,zreg,&p->z,typ);
+          else
+            store_reg(f,zreg,cam(IMM_IND,p->z.reg,0),typ);
+        }else{
+          int r;
+          if(t1==zreg) r=t2; else r=t1;
+          load_reg(f,r,&p->z,POINTER,r);
+          store_reg(f,zreg,cam(IMM_IND,r,0),typ);
+        }
+      }else{
+        store_reg(f,zreg,&p->z,typ);
+      }
+    }else{
+      if(p->z.reg!=zreg)
+        emit(f,"\t%smr\t%s,%s\n",(zreg>=33&&zreg<=64)?"f":"",mregnames[p->z.reg],mregnames[zreg]);
+    }
+  }
+}
+static int dwarf2_regnumber(int r)
+{
+  if(r==0) ierror(0);
+  if(r<=32)
+    return r-1;
+  else if(r<=64)
+    return r+6;
+  else
+    ierror(0);
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+  struct obj o;
+  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+  o.flags=VAR;
+  o.v=v;
+  o.val.vmax=l2zm(0L);
+  return l2zm(real_offset(&o));
+}
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+  struct obj o;
+  o.flags=REG;
+  o.reg=sp;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+}
+static void emit_obj(FILE *f,struct obj *p,int t)
+/*  Prints an object.                               */
+{
+  if(p->am){
+    if(p->am->flags&REG_IND) emit(f,"%s,%s",mregnames[p->am->offset],mregnames[p->am->base]);
+    if(p->am->flags&IMM_IND) emit(f,"%ld(%s)",p->am->offset,mregnames[p->am->base]);
+    return;
+  }
+  /*  if(p->flags&DREFOBJ) emit(f,"(");*/
+  if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      if(p->flags&REG){
+        emit(f,"%s",mregnames[p->reg]);
+      }else{
+        emit(f,"%ld(%s)",real_offset(p),mregnames[fp]);
+      }
+    }else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if((p->flags&REG)&&!(p->flags&VAR)) emit(f,"%s",mregnames[p->reg]);
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  /*  if(p->flags&DREFOBJ) emit(f,")");*/
+}
+static int exists_freereg(struct IC *p,int reg)
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg. */
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+static size_t lsize;
+static bvtype *once,*twice;
+
+static void peephole(struct IC *p)
+/* Try to use addressing modes */
+{
+  int c,c2,r,cnt,maxlabel,uselr=0;struct IC *p2;struct AddressingMode *am;
+  if(cross_module){
+    lastlabel=0;
+    for(p2=p;p2;p2=p2->next){
+      if(p2->code>=LABEL&&p2->code<=BRA){
+	if(!lastlabel||p2->typf<lastlabel) lastlabel=p2->typf;
+	if(p->typf>maxlabel) maxlabel=p->typf;
+      }
+    }
+  }else{
+    maxlabel=label; /*FIXME*/
+  }
+  /*lsize=((label-lastlabel+1+7)/CHAR_BIT)*CHAR_BIT;*/
+  lsize=BVSIZE(label-lastlabel+1);
+  once=mymalloc(lsize);
+  twice=mymalloc(lsize);
+  memset(once,0,lsize);
+  memset(twice,0,lsize);
+  for(;p;p=p->next){
+    c=p->code;
+    if(c==CALL){
+      if(p->call_list==0){
+	uselr=1;
+      }else{
+	int i;
+	for(i=0;i<p->call_cnt;i++)
+	  if(!p->call_list[i].v->fi||
+	     !p->call_list[i].v->fi->inline_asm||
+	     !(p->call_list[i].v->fi->flags&ALL_REGS)||
+	     BTST(p->call_list[i].v->fi->regs_modified,lr))
+	    uselr=1;
+      }
+    }
+    if((q1typ(p)&NQ)==LLONG&&(c==MULT||c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)) uselr=1;
+    if(c==CONVERT&&(q1typ(p)&NQ)==LLONG&&ISFLOAT(ztyp(p)&NQ)) uselr=1;
+    if(c==CONVERT&&(ztyp(p)&NQ)==LLONG&&ISFLOAT(q1typ(p)&NQ)) uselr=1;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+    /* Test which labels are jumped to more than once. */
+    if((c>=BEQ&&c<=BRA)&&p->typf-lastlabel>=lsize*CHAR_BIT){
+      printf("lsize=%lu p->typf=%d lastlabel=%d\n",lsize,p->typf,lastlabel);
+      ierror(0);
+    }
+    if(c>=BEQ&&c<=BRA){
+      if(BTST(once,p->typf-lastlabel))
+        BSET(twice,p->typf-lastlabel);
+      else
+        BSET(once,p->typf-lastlabel);
+    }
+    /* Try test-opt */
+    if(c==TEST&&!(p->q1.flags&DREFOBJ)){
+      for(p2=p->prev;p2;p2=p2->prev){
+        c2=p2->code;
+        if(c2==NOP||c2==ALLOCREG||c2==FREEREG) continue;
+        if(c2==CALL||(c2>=LABEL&&c2<=BRA)) break;
+        if((p2->z.flags&DREFOBJ)&&(p->q1.flags&(REG|DREFOBJ))!=REG) break;
+        if(p->q1.flags==p2->z.flags&&p->q1.am==p2->z.am){
+          if(!(p->q1.flags&VAR)||(p->q1.v==p2->z.v&&zmeqto(p->q1.val.vmax,p2->z.val.vmax))){
+            if(!(p->q1.flags&REG)||p->q1.reg==p2->z.reg){
+              if(p->z.flags==0||(isreg(z)&&p->z.reg==cr0)){
+                if(p->typf==p2->typf&&(!(p->typf&UNSIGNED)||!multiple_ccs)){
+		  p2->ext.setcc=1;
+                }
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+    /* Try update */
+    if((c==ADDI2P||c==SUBIFP)&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+      if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+        eval_const(&p->q2.val,p->typf);
+        if(c==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+        if(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))){
+          struct obj *o;
+          r=p->q1.reg;cnt=0;o=0;
+          for(p2=p->next;p2;p2=p2->next){
+            c2=p2->code;
+            if(c2==NOP||c2==ALLOCREG||c2==FREEREG) continue;
+            if((c2==CALL/*&&regscratch[r]*/)||(c2>=LABEL&&c2<=BRA)) break;
+            if((p2->q1.flags&(DREFOBJ|REG))==REG&&p2->q1.reg==r) break;
+            if((p2->q2.flags&(DREFOBJ|REG))==REG&&p2->q2.reg==r) break;
+            if((p2->z.flags&(DREFOBJ|REG))==REG&&p2->z.reg==r) break;
+            if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r) cnt|=1;
+            if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r) cnt|=2;
+            if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r) cnt|=4;
+            if((cnt&3)==3) break;
+            if(cnt){
+	      if(cnt&1){
+		if((q1typ(p2)&NQ)==LLONG) break;
+		o=&p2->q1;
+	      }else if(cnt&2){
+		if((q2typ(p2)&NQ)==LLONG) break;
+		o=&p2->q2;
+	      }else{
+		if((ztyp(p2)&NQ)==LLONG) break;
+		o=&p2->z;
+	      }
+              if(p2->code==ASSIGN&&((p2->typf&NQ)>POINTER||!zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ])))
+                break;
+              o->am=am=mymalloc(sizeof(*am));
+              o->am->flags=(IMM_IND|UPDATE);
+              o->am->base=r;
+              o->am->offset=zm2l(vmax);
+              p->code=c=NOP;
+              break;
+            }
+          }
+        }
+      }
+    }
+    /* Try const(reg) */
+#ifndef oldpeep
+    if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))){
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=zm2l(of);
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+#else
+    if((c==ADDI2P||c==SUBIFP)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)){
+      int base;zmax of;
+      p2=p->next;
+      while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+      if(p2) c2=p2->code; else c2=0;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      r=p->z.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      if(c2&&zmleq(l2zm(-32768L),of)&&zmleq(of,l2zm(32767L))&&c2!=CALL&&(c2<LABEL||c2>BRA)
+         &&(c2!=ASSIGN||((p2->typf&NQ)<=POINTER&&zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ])))
+         &&c2!=ADDRESS&&(((p2->z.flags&(DREFOBJ|REG))==REG&&p2->z.reg==r&&p2->q2.flags==0)||exists_freereg(p2->next,r))){
+        if(((p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=r)
+           &&((p2->q2.flags&(REG|DREFOBJ))!=REG||p2->q2.reg!=r)){
+          cnt=0;
+          if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            p2->q1.am=am=mymalloc(sizeof(*am));
+            p2->q1.am->flags=IMM_IND;
+            p2->q1.am->base=base;
+            p2->q1.am->offset=zm2l(of);
+            cnt++;
+          }
+          if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            p2->q2.am=am=mymalloc(sizeof(*am));
+            p2->q2.am->flags=IMM_IND;
+            p2->q2.am->base=base;
+            p2->q2.am->offset=zm2l(of);
+            cnt++;
+          }
+          if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            p2->z.am=am=mymalloc(sizeof(*am));
+            p2->z.am->flags=IMM_IND;
+            p2->z.am->base=base;
+            p2->z.am->offset=zm2l(of);
+            cnt++;
+          }
+          if(isreg(q1)){
+            p->code=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+          }else{
+            p->code=ASSIGN;p->q2.flags=0;
+          }
+          if(cnt==1&&((p2->q1.flags&(DREFOBJ|REG))!=REG||p2->q1.reg!=base)
+             &&((p2->q2.flags&(DREFOBJ|REG))!=REG||p2->q2.reg!=base)
+             &&((p2->z.flags&(DREFOBJ|REG))!=REG||p2->z.reg!=base) ){
+            /* Can we use update? */
+            p2=p2->next;
+            while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+            if(p2){
+              c2=p2->code;
+              if(c2==ADDI2P||c2==SUBIFP){
+                if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==base
+                   &&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==base
+                   &&(p2->q2.flags&(KONST|DREFOBJ))==KONST ){
+                  eval_const(&p2->q2.val,p2->typf);
+                  if(c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+                  if(zmeqto(vmax,of)){
+                    am->flags|=UPDATE;
+                    p2->code=NOP;
+                  }
+                }
+              }
+            }
+          }
+          continue;
+        }
+      }
+    }
+#endif
+    /* Try reg,reg */
+#ifndef oldpeep
+    if(c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=REG_IND;
+              am->base=base;
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+#else
+    if(c==ADDI2P&&isreg(q2)&&isreg(z)&&p->q2.reg!=p->z.reg){
+      int base,idx;
+      p2=p->next;
+      while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+      if(p2) c2=p2->code; else c2=0;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      if(c2&&c2!=CALL&&(c2<LABEL||c2>BRA)
+         &&(c2!=ASSIGN||((p2->typf&NQ)<=POINTER&&zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ])))
+         &&c2!=ADDRESS&&exists_freereg(p2->next,r)){
+        if(((p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=r)
+           &&((p2->q2.flags&(REG|DREFOBJ))!=REG||p2->q2.reg!=r) ){
+          cnt=0;
+          if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            p2->q1.am=am=mymalloc(sizeof(*am));
+            p2->q1.am->flags=REG_IND;
+            p2->q1.am->base=base;
+            p2->q1.am->offset=idx;
+            cnt++;
+          }
+          if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            p2->q2.am=am=mymalloc(sizeof(*am));
+            p2->q2.am->flags=REG_IND;
+            p2->q2.am->base=base;
+            p2->q2.am->offset=idx;
+            cnt++;
+          }
+          if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            p2->z.am=am=mymalloc(sizeof(*am));
+            p2->z.am->flags=REG_IND;
+            p2->z.am->base=base;
+            p2->z.am->offset=idx;
+            cnt++;
+          }
+          if(isreg(q1)){
+            p->code=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+          }else{
+            p->code=ASSIGN;p->q2.flags=0;
+          }
+          if(cnt==1&&((p2->q1.flags&(DREFOBJ|REG))!=REG||p2->q1.reg!=base)
+             &&((p2->q2.flags&(DREFOBJ|REG))!=REG||p2->q2.reg!=base)
+             &&((p2->z.flags&(DREFOBJ|REG))!=REG||p2->z.reg!=base) ){
+            /* Can we use update? */
+            p2=p2->next;
+            while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+            if(p2){
+              c2=p2->code;
+              if(c2==ADDI2P){
+                if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==base
+                   &&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==base
+                   &&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==idx){
+                  am->flags|=UPDATE;
+                  p2->code=NOP;
+                }
+              }
+            }
+          }
+          continue;
+        }
+      }
+    }
+#endif
+  }
+  if(!uselr) function_calls=0;
+}
+
+static void toc_entry(FILE *f,struct Var *v)
+/*  Create a toc-entry.  */
+{
+  if(!use_sd(v->vtyp->flags)||(v->tattr&FAR)){
+    if(v->storage_class==STATIC&&!ISFUNC(v->vtyp->flags)){
+      emit(f,tocname);
+      emit(f,"%s%s%ld:\n",tocprefix,labprefix,zm2l(v->offset));
+      emit(f,"\t.long\t%s%ld\n",labprefix,zm2l(v->offset));
+    }else{
+      if(!ISFUNC(v->vtyp->flags)){
+        emit(f,tocname);
+        emit(f,"%s%s%s:\n",tocprefix,idprefix,v->identifier);
+        emit(f,"\t.long\t%s%s\n",idprefix,v->identifier);
+      }
+      if(v->storage_class==EXTERN)
+        emit(f,"\t.global\t%s%s%s\n",tocprefix,idprefix,v->identifier);
+    }
+    if(f) section=TOC;
+  }
+}
+
+static int savereg(struct Var *v,int i)
+{
+  if(v->tattr&(SYSCALL|NOSAVE)) return 0;
+  if(vlas&&i==fp) return 1;
+  if((i==sd&&(v->tattr&SAVEDS))||(regused[i]&&!regscratch[i]&&!regsa[i])
+     ||((v->tattr&SAVEALL)&&i<=32&&(regscratch[i]||i==t1||i==t2||i==t3)&&((!v->fi)||(!(v->fi->flags&ALL_REGS))||BTST(v->fi->regs_modified,i)) ))
+    return 1;
+  return 0;
+}
+
+static int stmw,stme;
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  Generates function top.                             */
+{
+  int i,preg;long of;
+  if(POWEROPEN) toc_entry(f,v);
+  if(mregnames[1]!=regnames[1]) emit(f,"#vsc elf\n");
+  if(g_flags[0]&USEDFLAG) emit(f,"#vsc cpu %s\n",g_flags_val[0].p);
+  if(g_flags[1]&USEDFLAG) emit(f,"#vsc fpu %s\n",g_flags_val[1].p);
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+  if(!GAS) emit(f,"\t.sdreg\t%s\n",mregnames[sd]);
+  if(!optsize) emit(f,"\t.align\t4\n");
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  frameoffset=minframe+maxpushed;
+  framesize=frameoffset+offset;
+  stme=0;
+  for(i=1;i<=64;i++){
+    if(savereg(v,i)){
+      if(i<=32) framesize+=4; else framesize+=8;
+      if(i<=32&&stme==0) stme=i;
+    }else{
+      if(i<=32) stme=0;
+    }
+  }
+  if(stme==32||!(g_flags[11]&USEDFLAG)) stme=0;
+  for(crsave=0,i=65;i<=72;i++)
+    if((regused[i]&&!regscratch[i]&&!regsa[i])) crsave=1;
+  if(crsave&&!POWEROPEN) framesize+=4;
+  if(framesize==minframe&&((v->tattr&(SYSCALL))||(function_calls==0&&!crsave))) framesize=frameoffset=0;
+  if(EABI)
+    framesize=(framesize+7)/8*8;
+  else
+    framesize=(framesize+15)/16*16;
+  stack=framesize;
+  stack_valid=1;
+  if(v->tattr&SYSCALL){
+    emit(f,"#barrier\n");
+    emit(f,"\tmtspr\t81,0\n");
+    emit(f,"#barrier\n");
+    emit(f,"\tstwu\t%s,-4(%s)\n",mregnames[t1],mregnames[sp]);
+    emit(f,"\tmflr\t%s\n",mregnames[t1]);
+    emit(f,"\tstwu\t%s,-4(%s)\n",mregnames[t1],mregnames[sp]);
+    emit(f,"\tbl\t%s__syscall_init\n",idprefix);
+    /*FIXME: das koennte man evtl. noch sparen */
+    emit(f,"\taddi\t%s,%s,-8\n",mregnames[sp],mregnames[sp]);
+  }else if(v->tattr&NOSAVE){
+    /* nothing */
+  }else if(function_calls||(stack_check&&framesize)){
+    emit(f,"\tmflr\t%s\n",mregnames[t1]);
+    BSET(regs_modified,t1);
+  }
+  if(stack_check&&framesize){
+    BSET(regs_modified,t2);
+    if(framesize<=32767){
+      emit(f,"\tli\t%s,%ld\n",mregnames[t2],framesize);
+    }else{
+      emit(f,"\tlis\t%s,%ld\n",mregnames[t2],hi(framesize));
+      emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[t2],lo(framesize));
+    }     
+    emit(f,"\tbl\t%s__stack_check\n",idprefix);
+    if(!function_calls){
+      emit(f,"\tmtlr\t%s\n",mregnames[t1]);
+      BSET(regs_modified,lr);
+    }
+  }
+  if(function_calls&&!(v->tattr&(SYSCALL|NOSAVE))&&framesize>=32760){
+    if(POWEROPEN)
+      emit(f,"\tst%s\t%s,8(%s)\n",sdt(LONG),mregnames[t1],mregnames[sp]);
+    else
+      emit(f,"\tst%s\t%s,4(%s)\n",sdt(LONG),mregnames[t1],mregnames[sp]);
+  }
+  of=minframe+maxpushed+offset;
+  if(framesize!=0){
+    if(framesize<=32767){
+      emit(f,"\tstwu\t%s,-%ld(%s)\n",mregnames[sp],framesize,mregnames[sp]);
+      preg=sp;
+    }else{
+      BSET(regs_modified,t1);
+      BSET(regs_modified,t2);
+      emit(f,"\tmr\t%s,%s\n",mregnames[t2],mregnames[sp]);
+      emit(f,"\tlis\t%s,%ld\n",mregnames[t1],hi(-framesize));
+      emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],mregnames[t1],lo(-framesize));
+      emit(f,"\tstwux\t%s,%s,%s\n",mregnames[sp],mregnames[sp],mregnames[t1]);
+      preg=t2;of-=framesize;
+    }
+  }
+  if(crsave&&!(v->tattr&NOSAVE)){
+    BSET(regs_modified,t3);
+    if(POWEROPEN){
+      emit(f,"\tmfcr\t%s\n\tst%s\t%s,4(%s)\n",mregnames[t3],sdt(LONG),mregnames[t3],mregnames[preg]);
+    }else{
+      emit(f,"\tmfcr\t%s\n\tst%s\t%s,%ld(%s)\n",mregnames[t3],sdt(LONG),mregnames[t3],of,mregnames[preg]);
+      of+=4;
+    }
+  }
+  for(i=1;i<=64;i++){
+    if(savereg(v,i)){
+      if(i<=32){
+	if(i==stme){
+          emit(f,"\tstmw\t%s,%ld(%s)\n",mregnames[stme],of,mregnames[preg]);
+          of+=(32-stme+1)*4;
+          i=32;
+        }else{
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(LONG),mregnames[i],of,mregnames[preg]);
+          of+=4;
+        }
+      }else{
+        emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[i],of,mregnames[preg]);
+        of+=8;
+      }
+    }
+  }
+  if(function_calls&&!(v->tattr&(SYSCALL|NOSAVE))&&framesize<32760){
+    if(POWEROPEN)
+      emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(LONG),mregnames[t1],framesize+8,mregnames[sp]);
+    else
+      emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(LONG),mregnames[t1],framesize+4,mregnames[sp]);
+  }
+  if((v->tattr&SAVEDS)&&(SMALLDATA||BASERELMOS||POWEROPEN)){
+    if(POWEROPEN){
+      emit(f,"\t.global\t%s__getr2\n",idprefix);
+      if(!function_calls)
+        emit(f,"\tmflr\t%s\n",mregnames[t2]);
+      emit(f,"\tbl\t%s__getr2\n",idprefix);
+      if(!function_calls){
+        emit(f,"\tmtlr\t%s\n",mregnames[t2]);
+	BSET(regs_modified,lr);
+      }
+    }else{
+      if(BASERELMOS){
+        emit(f,"\t.global\t%s__restore_r13\n",idprefix);
+        emit(f,"\tbl\t%s__restore_r13\n",idprefix);
+      }else{
+        emit(f,"\tlis\t%s,%s_SDA_BASE_@ha\n",mregnames[sd],idprefix);
+        emit(f,"\taddi\t%s,%s,%s_SDA_BASE_@l\n",mregnames[sd],mregnames[sd],idprefix);
+      }
+    }
+  }
+  if(v->tattr&BREL){
+    if(BASERELOS4){
+      emit(f,"\t.global\t%s__baserel_get_addr\n",idprefix);
+      emit(f,"\tbl\t%s__baserel_get_addr\n",idprefix);
+    }
+  }
+  if(vlas){
+    emit(f,"\tmr\t%s,%s\n",mregnames[fp],mregnames[sp]);
+    emit(f,"\t.set\t____fo,%ld\n",frameoffset);
+  }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  Generates function bottom.                          */
+{
+  int i,preg;long of;
+  if(v->tattr&SYSCALL){
+    emit(f,"\tb\t%s__dispatch\n",idprefix);
+  }else{
+    of=minframe+maxpushed+offset;
+    if(framesize<=32767){
+      preg=sp;
+    }else{
+      emit(f,"\tlwz\t%s,0(%s)\n",mregnames[t2],mregnames[sp]);
+      preg=t2;of-=framesize;
+    }
+    if(crsave&&!(v->tattr&NOSAVE)){
+      if(POWEROPEN){
+	emit(f,"\tl%s\t%s,8(%s)\n\tmtcr\t%s\n",ldt(LONG),mregnames[t1],mregnames[preg],mregnames[t1]);
+      }else{
+	emit(f,"\tl%s\t%s,%ld(%s)\n\tmtcr\t%s\n",ldt(LONG),mregnames[t1],of,mregnames[preg],mregnames[t1]);
+	of+=4;
+      }
+    }
+    if(function_calls&&!(v->tattr&NOSAVE)&&framesize<32760){
+      BSET(regs_modified,lr);
+      if(POWEROPEN)
+	emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(LONG),mregnames[t1],framesize+8,mregnames[sp]);
+      else
+	emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(LONG),mregnames[t1],framesize+4,mregnames[sp]);
+    }
+    for(i=1;i<=64;i++){
+      if(savereg(v,i)){
+	if(i<=32){
+	  if(i==stme){
+	    emit(f,"\tlmw\t%s,%ld(%s)\n",mregnames[stme],of,mregnames[preg]);
+	    of+=(32-stme+1)*4;
+	    i=32;
+	  }else{
+	    emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(LONG),mregnames[i],of,mregnames[preg]);
+	    of+=4;
+	  }
+	}else{
+	  emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(DOUBLE),mregnames[i],of,mregnames[preg]);
+	  of+=8;
+	}
+      }
+    }
+    if(framesize){
+      if(framesize<=32767)
+	emit(f,"\taddi\t%s,%s,%ld\n",mregnames[sp],mregnames[sp],framesize);
+      else
+	emit(f,"\tmr\t%s,%s\n",mregnames[sp],mregnames[preg]);
+    }
+    if(function_calls&&!(v->tattr&NOSAVE)){
+      if(framesize<32760){
+	emit(f,"\tmtlr\t%s\n",mregnames[t1]);
+      }else{
+	BSET(regs_modified,lr);
+	if(POWEROPEN)
+	  emit(f,"\tl%s\t%s,8(%s)\n\tmtlr\t%s\n",ldt(LONG),mregnames[t1],mregnames[sp],mregnames[t1]);
+	else
+	  emit(f,"\tl%s\t%s,4(%s)\n\tmtlr\t%s\n",ldt(LONG),mregnames[t1],mregnames[sp],mregnames[t1]);
+      }
+    }
+    emit(f,ret);
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+    emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+  }else{
+    emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+  }    
+  if(all_regs&&v->fi) v->fi->flags|=ALL_REGS;
+}
+
+static int balign(struct obj *o)
+/*  Liefert die unteren 2 Bits des Objekts. 1 wenn unklar. */
+{
+  int sc;
+  if(o->flags&DREFOBJ) return 1;
+  if(o->am) ierror(0);
+  if(!(o->flags&VAR)) ierror(0);
+  sc=o->v->storage_class;
+  if(sc==EXTERN||sc==STATIC){
+    /* Alle statischen Daten werden vom cg auf 32bit alignt. */
+    return zm2l(zmand(o->val.vmax,l2zm(3L)));
+  }
+  if(sc==AUTO||sc==REGISTER){
+    zmax of=o->v->offset;
+    if(!zmleq(l2zm(0L),of))
+      of=zmsub(l2zm(0L),zmadd(of,maxalign));
+    return zm2l(zmand(zmadd(of,o->val.vmax),l2zm(3L)));
+  }
+  ierror(0);
+}
+
+/* load hiword of a long long object */
+static void load_hword(FILE *f,int r,struct obj *o,int t,int tmp)
+{
+  struct rpair rp;
+  BSET(regs_modified,r);
+  if(o->flags&KONST){
+    static struct obj cobj;
+    cobj.flags=KONST;
+    eval_const(&o->val,t);
+    vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); 
+    cobj.val.vulong=zum2zul(vumax);
+    load_reg(f,r,&cobj,UNSIGNED|LONG,tmp);
+  }else if(!o->am&&(o->flags&DREFOBJ)){
+    if(!(o->flags&REG)) ierror(0);
+    emit(f,"\tlwz\t%s,0(%s)\n",mregnames[r],mregnames[o->reg]);
+  }else if(!o->am&&(o->flags&REG)){
+    struct rpair rp;
+    if(!reg_pair(o->reg,&rp)) 
+      ierror(0);
+    if(rp.r1!=r)
+      emit(f,"\tmr\t%s,%s\n",mregnames[r],mregnames[rp.r1]);
+  }else{
+    load_reg(f,r,o,UNSIGNED|LONG,tmp);
+  }
+}
+
+/* load loword of a long long object */
+static void load_lword(FILE *f,int r,struct obj *o,int t,int tmp)
+{
+  struct rpair rp;
+  BSET(regs_modified,r);
+  if(o->flags&KONST){
+    static struct obj cobj;
+    cobj.flags=KONST;
+    eval_const(&o->val,t);
+    vumax=zumand(vumax,ul2zum(0xffffffff)); 
+    cobj.val.vulong=zum2zul(vumax);
+    load_reg(f,r,&cobj,UNSIGNED|LONG,tmp);
+  }else if(o->am){
+    if(o->am->flags!=IMM_IND) ierror(0);
+    o->am->offset+=4;
+    load_reg(f,r,o,UNSIGNED|LONG,tmp);
+    o->am->offset-=4;   
+  }else if(o->flags&DREFOBJ){
+    if(!(o->flags&REG)) ierror(0);
+    emit(f,"\tlwz\t%s,4(%s)\n",mregnames[r],mregnames[o->reg]);
+  }else if(o->flags&REG){
+    if(!reg_pair(o->reg,&rp)) ierror(0);
+    if(rp.r2!=r)
+      emit(f,"\tmr\t%s,%s\n",mregnames[r],mregnames[rp.r2]);
+  }else{
+    o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+    load_reg(f,r,o,UNSIGNED|LONG,tmp);
+    o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+  }
+}    
+/* store hiword of a long long object */
+static void store_hword(FILE *f,int r,struct obj *o)
+{
+  struct rpair rp;
+  if(!o->am&&(o->flags&DREFOBJ)){
+    if(!(o->flags&REG)) ierror(0);
+    emit(f,"\tstw\t%s,0(%s)\n",mregnames[r],mregnames[o->reg]);
+  }else if(!o->am&&(o->flags&REG)){
+    if(!reg_pair(o->reg,&rp)) ierror(0);
+    if(rp.r1!=r)
+      emit(f,"\tmr\t%s,%s\n",mregnames[rp.r1],mregnames[r]);
+  }else{
+    store_reg(f,r,o,UNSIGNED|LONG);
+  }
+}
+
+/* store loword of a long long object */
+static void store_lword(FILE *f,int r,struct obj *o)
+{
+  struct rpair rp;
+  if(o->am){
+    if(o->am->flags!=IMM_IND) ierror(0);
+    o->am->offset+=4;
+    store_reg(f,r,o,UNSIGNED|LONG);
+    o->am->offset-=4;
+  }else if(o->flags&DREFOBJ){
+    if(!(o->flags&REG)) ierror(0);
+    emit(f,"\tstw\t%s,4(%s)\n",mregnames[r],mregnames[o->reg]);
+  }else if(o->flags&REG){
+    if(!reg_pair(o->reg,&rp)) ierror(0);
+    if(rp.r2!=r)
+      emit(f,"\tmr\t%s,%s\n",mregnames[rp.r2],mregnames[r]);
+  }else{
+    o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+    store_reg(f,r,o,UNSIGNED|LONG);
+    o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+  }
+}
+/* if object cannot be dereferenced with a single load, load its address
+   in register r (!=r0) and modify the object */
+static void create_loadable(FILE *f,struct obj *o,int r)
+{
+  struct rpair rp;
+  if(o->am) return;
+  if((o->flags&(REG|DREFOBJ))==DREFOBJ){
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,POINTER,r);
+    o->flags|=(REG|DREFOBJ);
+    o->reg=r;
+  }
+  if((o->flags&(VAR|REG))==VAR){
+    if((o->v->storage_class==STATIC||o->v->storage_class==EXTERN)&&(!use_sd(o->v->vtyp->flags)||(o->v->tattr&FAR))){
+      load_address(f,r,o,POINTER);
+      o->reg=r;
+      o->flags=(REG|DREFOBJ);
+    }
+    if((o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&real_offset(o)>32760){
+      load_address(f,r,o,POINTER);
+      o->reg=r;
+      o->flags=(REG|DREFOBJ);
+    }
+  }
+}
+
+static int get_reg()
+{
+  int i;
+  for(i=2;i<=32;i++){
+    if(!regs[i]&&(regscratch[i]||regused[i]))
+      break;
+  }
+  if(i<=32){
+    BSET(regs_modified,i);
+    return i;
+  }
+  return 0;
+}
+
+static int handle_llong(FILE *f,struct IC *p)
+{
+  int c=p->code,t,savemask=0;char *libfuncname;
+  int msp;long mtmpoff;
+
+  t=(ztyp(p)&NU);
+
+  if(c==ADDRESS) return 0;
+
+
+  if(c==GETRETURN){
+    create_loadable(f,&p->z,t1);
+    if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+    store_hword(f,rp.r1,&p->z);
+    store_lword(f,rp.r2,&p->z);
+    p->z.flags=0;
+    return 1;
+  }
+
+  if(c==SETRETURN){
+    create_loadable(f,&p->q1,t1);
+    if(!reg_pair(p->z.reg,&rp)) ierror(0);
+    load_hword(f,rp.r1,&p->q1,q1typ(p),t2);
+    load_lword(f,rp.r2,&p->q1,q1typ(p),t2);
+    p->z.flags=0;
+    return 1;
+  }
+
+  if(c==CONVERT&&(q1typ(p)&NQ)==LLONG&&(ztyp(p)&NQ)==LLONG){
+    p->code=c=ASSIGN;
+    p->q2.val.vmax=sizetab[LLONG];
+  }
+
+  if(c==ASSIGN||c==PUSH){
+    int r;
+    create_loadable(f,&p->q1,t1);
+    if(c==ASSIGN){
+      create_loadable(f,&p->z,t2);
+    }else{
+      pushed=(pushed+3)/4*4;
+      if(align_arguments)
+	pushed=(pushed+7)/8*8;
+    }
+    if(isreg(z)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      load_hword(f,rp.r1,&p->q1,q1typ(p),t1);
+    }else{
+      if(isreg(q1)){
+	if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+	r=rp.r1;
+      }else{
+	if(p->q1.flags&KONST)
+	  r=t1;
+	else
+	  r=t3;
+	load_hword(f,r,&p->q1,q1typ(p),t1);
+      }
+      if(c==ASSIGN){
+	store_hword(f,r,&p->z);
+      }else{
+	emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r],pushed+minframe,mregnames[sp]);
+	pushed+=4;
+      }
+    }
+    if(isreg(z)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      load_lword(f,rp.r2,&p->q1,q1typ(p),t1);
+    }else{
+      if(isreg(q1)){
+	if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+	r=rp.r2;
+      }else{
+	if(p->q1.flags&KONST)
+	  r=t1;
+	else
+	  r=t3;
+	load_lword(f,r,&p->q1,q1typ(p),t1);
+      }
+      if(c==ASSIGN){
+	store_lword(f,r,&p->z);
+      }else{
+	emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r],pushed+minframe,mregnames[sp]);
+	pushed+=4;
+      }    
+    }
+    p->z.flags=0;
+    return 1;
+  }
+
+  if(c==CONVERT&&(t&NQ)<LLONG){
+    if(isreg(q1)){
+      if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+      zreg=rp.r2;
+    }else{
+      int r;
+      if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ)
+        create_loadable(f,&p->q1,t1);
+      if(isreg(z))
+        r=p->z.reg;
+      else
+        r=t1;
+      load_lword(f,r,&p->q1,q1typ(p),t2);
+      zreg=r;
+    }
+    return 1;               
+  }
+  if(c==CONVERT&&(q1typ(p)&NQ)<LLONG){
+    int zl,zh,told=q1typ(p);
+    if(isreg(z)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      zh=rp.r1;
+      zl=rp.r2;
+    }else{
+      zl=t2;
+      zh=t3;
+    }
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ)
+      create_loadable(f,&p->q1,t1);
+    load_reg(f,zl,&p->q1,q1typ(p),t1);
+    if(told&UNSIGNED){
+      if((told&NQ)==CHAR)
+	emit(f,"\tclrlwi\t%s,%s,24\n",mregnames[zl],mregnames[zl]);
+      if((told&NQ)==SHORT)
+	emit(f,"\tclrlwi\t%s,%s,16\n",mregnames[zl],mregnames[zl]);
+      emit(f,"\tli\t%s,0\n",mregnames[zh]);
+    }else{
+      if((told&NQ)==CHAR)
+	emit(f,"\textsb\t%s,%s\n",mregnames[zl],mregnames[zl]);
+      if((told&NQ)==SHORT)
+	emit(f,"\textsh\t%s,%s\n",mregnames[zl],mregnames[zl]);
+      emit(f,"\tsrawi\t%s,%s,31\n",mregnames[zh],mregnames[zl]);
+    }
+    create_loadable(f,&p->z,t1);
+    store_lword(f,zl,&p->z);
+    store_hword(f,zh,&p->z);
+    p->z.flags=0;
+    return 1;
+  }
+
+  if(c==TEST){
+    p->code=c=COMPARE;
+    if(p->typf&UNSIGNED)
+      p->q2.val.vullong=zum2zull(ul2zum(0UL));
+    else
+      p->q2.val.vllong=zm2zll(l2zm(0L));
+    p->q2.flags=KONST;
+  }
+
+  if(c==KOMPLEMENT){
+    p->code=c=XOR;
+    p->q2.flags=KONST;
+    if(p->typf&UNSIGNED)
+      p->q2.val.vullong=tu_max[LLONG];
+    else
+      p->q2.val.vllong=l2zm(-1L);
+  }
+  if(c==MINUS){
+    p->code=c=SUB;
+    p->q2=p->q1;
+    p->q1.flags=KONST;
+    p->q1.am=0;
+    if(p->typf&UNSIGNED)
+      p->q1.val.vullong=ul2zum(0UL);
+    else
+      p->q1.val.vllong=l2zm(0L);
+  }    
+
+  switch_IC(p);
+
+  if(c==COMPARE){
+    int l1,l2,h1,h2,tmp,falselab=++label,c;
+    zumax lo,uhi;zmax shi;
+    char *sh;
+    struct IC *b;
+    if(multiple_ccs)
+      ierror(0); /* still needed? */
+    else
+      p->z.reg=cr0;
+    b=p->next;
+    while(b->code==ALLOCREG||b->code==FREEREG) b=b->next;
+    c=b->code;
+    if(c<BEQ||c>BGT) ierror(0);
+    if(p->typf&UNSIGNED)
+      sh="cmplw";
+    else
+      sh="cmpw";
+    if((c==BNE||c==BEQ)&&(p->q2.flags&KONST)&&p->z.reg==cr0){
+      eval_const(&p->q2.val,q2typ(p));
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+	if(isreg(q1)){
+	  if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+	  emit(f,"\tor.\t%s,%s,%s\n",mregnames[t1],mregnames[rp.r1],mregnames[rp.r2]);
+	}else{
+	  create_loadable(f,&p->q1,t1);
+	  load_lword(f,t3,&p->q1,q1typ(p),t2);
+	  load_hword(f,t1,&p->q1,q1typ(p),t2);
+	  emit(f,"\tor.\t%s,%s,%s\n",mregnames[t3],mregnames[t3],mregnames[t1]);
+	}
+	return 1;
+      }
+    }
+    h1=h2=l1=l2=0;
+    if(isreg(q1)){
+      if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+      h1=rp.r1;
+      l1=rp.r2;
+    }else{
+      create_loadable(f,&p->q1,t1);
+      h1=l1=t3;
+    }
+    if(isreg(q2)){
+      if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+      h2=rp.r1;
+      l2=rp.r2;      
+    }else if(p->q2.flags&KONST){
+      eval_const(&p->q2.val,q2typ(p));
+      lo=zumrshift(zumlshift(vumax,ul2zum(32UL)),ul2zum(32UL));
+      if(zumleq(lo,ul2zum(65535L)))
+	l2=-1; 
+      if(p->typf&UNSIGNED){
+	uhi=zumrshift(vumax,ul2zum(32UL));
+	if(zumleq(uhi,ul2zum(65535L)))
+	  h2=-1; 
+      }else{
+	shi=zmrshift(vmax,l2zm(32L));
+	if(zmleq(shi,l2zm(32767L))&&zmleq(l2zm(-32768L),shi))
+	  h2=-1;
+      }
+    }
+    if(h2==0||l2==0){
+      if(!(p->q1.flags&REG)||p->q1.reg!=t1){
+	create_loadable(f,&p->q2,t1);
+      }else if(tmp=get_reg()){
+	create_loadable(f,&p->q2,tmp);
+      }
+      if(h2==0) h2=t2;
+      if(l2==0) l2=t2;
+    }
+    load_hword(f,h1,&p->q1,q1typ(p),0);
+    if(h2==-1){
+      emit(f,"\t%si\t%s,%s,",sh,mregnames[p->z.reg],mregnames[h1]);
+      if(p->typf&UNSIGNED)
+	emitzum(f,uhi);
+      else
+	emitzm(f,shi);
+      emit(f,"\n");
+    }else{
+      load_hword(f,h2,&p->q2,q2typ(p),t2);
+      emit(f,"\t%s\t%s,%s,%s\n",sh,mregnames[p->z.reg],mregnames[h1],mregnames[h2]);
+    }
+    if(c==BGT||c==BGE){
+      emit(f,"\tbgt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,b->typf);
+      emit(f,"\tblt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,falselab);
+    }else if(c==BLT||c==BLE){
+      emit(f,"\tblt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,b->typf);
+      emit(f,"\tbgt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,falselab);
+    }else if(c!=BNE){
+      emit(f,"\tbne\t%s,%s%d\n",mregnames[p->z.reg],labprefix,falselab);
+    }else{
+      emit(f,"\tbne\t%s,%s%d\n",mregnames[p->z.reg],labprefix,b->typf);
+    }
+
+    load_lword(f,l1,&p->q1,q1typ(p),t1);
+    if(l2==-1){
+      emit(f,"\tcmplwi\t%s,%s,",mregnames[p->z.reg],mregnames[l1]);
+      emitzm(f,lo);
+      emit(f,"\n");
+    }else{
+      load_lword(f,l2,&p->q2,q2typ(p),t2);
+      emit(f,"\tcmplw\t%s,%s,%s\n",mregnames[p->z.reg],mregnames[l1],mregnames[l2]);
+    }   
+    emit(f,"\tb%s\t%s,%s%d\n",ccs[c-BEQ],mregnames[p->z.reg],labprefix,b->typf);
+    emit(f,"%s%d:\n",labprefix,falselab);
+    b->code=NOP;
+	   
+    return 1;
+  }
+
+  if(c==ADD||c==SUB||c==AND||c==OR||c==XOR){
+    /*FIXME: q2==z, q1reg+q2reg=zreg */
+    int zl,zh,l1,l2,h1,h2,tmp;
+    char *sl,*sh;
+    if(c==ADD){
+      sl="addc";
+      sh="adde";
+    }else if(c==SUB){
+      /* there is no subc, therefore we always use reverse order */
+      sl="subfc";
+      sh="subfe";
+    }else if(c==AND){
+      sl=sh="and";
+    }else if(c==OR){
+      sl=sh="or";
+    }else if(c==XOR){
+      sl=sh="xor";
+    }else
+      ierror(0);
+    l1=l2=h1=h2=zl=zh=0;
+    create_loadable(f,&p->q1,t1);
+    if(isreg(q1)){
+      if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+      h1=rp.r1;
+      l1=rp.r2;
+    }else{
+      create_loadable(f,&p->q1,t1);
+      l1=t3;
+      h1=t1;
+    }
+    if(isreg(q2)){
+      if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+      h2=rp.r1;
+      l2=rp.r2;
+    }else if(p->q2.flags&KONST){
+      /* check for immediates */
+      if(c==OR||c==XOR){
+	/* or and xor can always be done using (x)ori and (x)oris */
+	h2=l2=-1;
+      }
+      if(c==ADD){
+	zmax tmp;
+	eval_const(&p->q2.val,q2typ(p));
+	tmp=zmrshift(vmax,l2zm(32L));
+	/* there are addze and addme instructions */
+	if(zmeqto(tmp,l2zm(0L))||zmeqto(tmp,l2zm(-1L)))
+	  h2=-1;	
+	/* addic supports 16bit signed values */
+	tmp=zmrshift(zmlshift(vmax,l2zm(32L)),l2zm(32L));	
+	if(zmleq(tmp,l2zm(32767L))&&zmleq(l2zm(-32768L),tmp))
+	  l2=-1;
+      }
+      if(c==SUB){
+	zmax tmp;
+	eval_const(&p->q2.val,q2typ(p));
+	tmp=zmrshift(vmax,l2zm(32L));
+	/* there are addze and addme instructions */
+	if(zmeqto(tmp,l2zm(0L))||zmeqto(tmp,l2zm(1L)))
+	  h2=-1;	
+	/* addic supports 16bit signed values */
+	tmp=zmrshift(zmlshift(vmax,l2zm(32L)),l2zm(32L));	
+	if(zmleq(tmp,l2zm(32768L))&&zmleq(l2zm(-32767L),tmp))
+	  l2=-1;
+      }	
+    }
+    if(!l2||!h2){
+      if(!(p->q1.flags&REG)||p->q1.reg!=t1){
+	create_loadable(f,&p->q2,t1);
+      }else if(tmp=get_reg()){
+	create_loadable(f,&p->q2,tmp);
+      }
+      if(h2==0) h2=t2;
+      if(l2==0) l2=t2;
+    }
+    if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
+      if(!reg_pair(p->z.reg,&rp)) ierror(0);
+      zh=rp.r1;
+      zl=rp.r2;
+    }else{
+      zl=t3;
+      zh=t1;
+    }
+    if((p->q1.flags&KONST)&&l1==t3){
+      load_lword(f,t2,&p->q1,q1typ(p),0);
+      emit(f,"\tmr\t%s,%s\n",mregnames[t3],mregnames[t2]);
+      BSET(regs_modified,t3);
+    }else
+      load_lword(f,l1,&p->q1,q1typ(p),0);
+    if(l2!=-1){
+      load_lword(f,l2,&p->q2,q2typ(p),t2);
+      emit(f,"\t%s\t%s,%s,%s\n",sl,mregnames[zl],mregnames[l2],mregnames[l1]);
+    }else{
+      eval_const(&p->q2.val,q2typ(p));
+      if(c==ADD||c==SUB){
+	if(c==SUB) vmax=zmsub(l2zm(0L),vmax);
+	vmax=zmrshift(zmlshift(vmax,l2zm(32L)),l2zm(32L));
+	emit(f,"\taddic\t%s,%s,",mregnames[zl],mregnames[l1]);
+	emitzm(f,vmax);
+	emit(f,"\n");
+      }else if(c==OR||c==XOR){
+	zumax tmp;
+	if(zumeqto(zumand(vumax,ul2zum(0xffffffffUL)),ul2zum(0xffffffffUL))){
+	  if(c==XOR)
+	    emit(f,"\tnor\t%s,%s,%s\n",mregnames[zl],mregnames[l1],mregnames[l1]);
+	  else
+	    emit(f,"\tli\t%s,-1\n",mregnames[zl]);
+	}else{
+	  tmp=zumand(vumax,ul2zum(0xffffUL));
+	  if(!zumeqto(tmp,ul2zum(0UL))){
+	    emit(f,"\t%si\t%s,%s,",sl,mregnames[zl],mregnames[l1]);
+	    emitzum(f,tmp);
+	    emit(f,"\n");
+	    l1=zl;
+	  }
+	  tmp=zumand(zumrshift(vumax,ul2zum(16UL)),ul2zum(0xffff));
+	  if(!zumeqto(tmp,ul2zum(0UL))){
+	    emit(f,"\t%sis\t%s,%s,",sl,mregnames[zl],mregnames[l1]);
+	    emitzum(f,tmp);
+	    emit(f,"\n");
+	    l1=zl;
+	  }
+	  if(l1!=zl)
+	    emit(f,"\tmr\t%s,%s\n",mregnames[zl],mregnames[l1]);
+	}
+      }else
+	ierror(0);
+    }
+    if(h2!=-1){
+      load_hword(f,h2,&p->q2,q2typ(p),t2);    
+      load_hword(f,h1,&p->q1,q1typ(p),0);
+      emit(f,"\t%s\t%s,%s,%s\n",sh,mregnames[zh],mregnames[h2],mregnames[h1]);
+    }else{
+      load_hword(f,h1,&p->q1,q1typ(p),0);
+      eval_const(&p->q2.val,q2typ(p));
+      if(c==ADD||c==SUB){
+	if(c==SUB) vmax=zmsub(l2zm(0L),vmax);
+	vmax=zmrshift(vmax,l2zm(32L));
+	if(zmeqto(vmax,l2zm(0L))){
+	  emit(f,"\taddze\t%s,%s\n",mregnames[zh],mregnames[h1]);
+	}else if(zmeqto(vmax,l2zm(-1L))){
+	  emit(f,"\taddme\t%s,%s\n",mregnames[zh],mregnames[h1]);
+	}else
+	  ierror(0);
+      }else if(c==OR||c==XOR){
+	zumax tmp;
+	if(zumeqto(zumand(zumrshift(vumax,ul2zum(32L)),ul2zum(0xffffffffUL)),ul2zum(0xffffffffUL))){
+	  if(c==XOR)
+	    emit(f,"\tnor\t%s,%s,%s\n",mregnames[zh],mregnames[h1],mregnames[h1]);
+	  else
+	    emit(f,"\tli\t%s,-1\n",mregnames[zh]);
+	}else{
+	  tmp=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffUL));
+	  if(!zumeqto(tmp,ul2zum(0UL))){
+	    emit(f,"\t%si\t%s,%s,",sl,mregnames[zh],mregnames[h1]);
+	    emitzum(f,tmp);
+	    emit(f,"\n");
+	    h1=zh;
+	  }
+	  tmp=zumand(zumrshift(vumax,ul2zum(48UL)),ul2zum(0xffff));
+	  if(!zumeqto(tmp,ul2zum(0UL))){
+	    emit(f,"\t%sis\t%s,%s,",sl,mregnames[zh],mregnames[h1]);
+	    emitzum(f,tmp);
+	    emit(f,"\n");
+	    h1=zh;
+	  }	
+	  if(h1!=zh)
+	    emit(f,"\tmr\t%s,%s\n",mregnames[zh],mregnames[h1]);
+	}
+      }
+    }
+    if(p->z.flags){
+      create_loadable(f,&p->z,t2);
+      store_lword(f,zl,&p->z);
+      store_hword(f,zh,&p->z);
+      p->z.flags=0;
+    }
+    return 1;
+  }
+
+  create_loadable(f,&p->q1,t1);
+
+  if(tmpoff>=32768&&(regs[r3]||regs[r4]||regs[r5]||regs[r6])){
+    emit(f,"\taddis\t%s,%s,%ld\n",mregnames[t2],mregnames[sp],hi(tmpoff));
+    if(lo(tmpoff)) emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[t2],lo(tmpoff));
+    msp=t2;
+    mtmpoff=0;
+  }else{
+    msp=sp;
+    mtmpoff=tmpoff;
+  }
+
+  if(regs[r3]){ emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r3],mtmpoff-4,mregnames[msp]);savemask|=1;}
+  if(regs[r4]){ emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r4],mtmpoff-8,mregnames[msp]);savemask|=2;}
+  if(regs[r5]) {emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-12,mregnames[msp]);savemask|=4;}
+  if(regs[r6]) {emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r6],mtmpoff-16,mregnames[msp]);savemask|=8;}
+
+  if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg>=r3&&p->q1.reg<=r6){
+    emit(f,"\tmr\t%s,%s\n",mregnames[t1],mregnames[p->q1.reg]);
+    p->q1.reg=t1;
+  }
+  if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg>=r3&&p->q2.reg<=r6){
+    emit(f,"\tmr\t%s,%s\n",mregnames[t2],mregnames[p->q2.reg]);
+    p->q2.reg=t2;
+  }
+  
+  if((q1typ(p)&NQ)==LLONG){
+    if(p->q1.am&&p->q1.am->base==r3){
+      if(p->q1.am->flags==REG_IND&&p->q1.am->offset==r4) ierror(0);
+      load_lword(f,r4,&p->q1,q1typ(p),0);
+      load_hword(f,r3,&p->q1,q1typ(p),0);
+    }else{
+      if(p->q1.am&&p->q1.am->flags==REG_IND&&p->q1.am->offset==r3) ierror(0);
+      load_hword(f,r3,&p->q1,q1typ(p),0);
+      load_lword(f,r4,&p->q1,q1typ(p),0);
+    }
+  }else{
+    if(!ISFLOAT(q1typ(p))) ierror(0);
+    load_reg(f,f1,&p->q1,q1typ(p),0); 
+  }
+  
+  if(p->q2.flags){
+    create_loadable(f,&p->q2,t2);
+    if((q2typ(p)&NQ)==LLONG){
+      if(isreg(q2)&&p->q2.reg==r3r4){
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-4,mregnames[msp]);
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r6],mtmpoff-8,mregnames[msp]);
+      }else{
+	if(p->q2.am&&p->q2.am->base==r5){
+	  if(p->q2.am->flags==REG_IND&&p->q2.am->offset==r6) ierror(0);
+	  load_lword(f,r6,&p->q2,q2typ(p),0);
+	  load_hword(f,r5,&p->q2,q2typ(p),0);
+	}else{
+	  if(p->q2.am&&p->q2.am->flags==REG_IND&&p->q2.am->offset==r5) ierror(0);
+	  load_hword(f,r5,&p->q2,q2typ(p),0);
+	  load_lword(f,r6,&p->q2,q2typ(p),0);
+	}
+      }
+    }else{
+      if((q2typ(p)&NQ)>=LLONG) ierror(0);
+      if(isreg(q2)&&p->q2.reg==r3){
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-4,mregnames[msp]);
+      }else{
+	load_reg(f,r5,&p->q2,q2typ(p),0);
+      }      
+    }
+  }
+
+  if(c==MULT) libfuncname="__mulint64";
+  else if(c==DIV){
+    if(t&UNSIGNED)
+      libfuncname="__divuint64";
+    else
+      libfuncname="__divsint64";
+  }else if(c==MOD){
+    if(t&UNSIGNED)
+      libfuncname="__moduint64";
+    else
+      libfuncname="__modsint64";
+  }else if(c==CONVERT){
+    static char s[32];
+    if(ISFLOAT(q1typ(p)))
+      sprintf(s,"__flt%dto%cint64",(q1typ(p)&NQ)==FLOAT?32:64,(ztyp(p)&UNSIGNED)?'u':'s');
+    else
+      sprintf(s,"__%cint64toflt%d",(q1typ(p)&UNSIGNED)?'u':'s',(ztyp(p)&NQ)==FLOAT?32:64);
+    libfuncname=s;
+  }else if(c==RSHIFT){
+    if(t&UNSIGNED)
+      libfuncname="__rshuint64";
+    else
+      libfuncname="__rshsint64";
+  }else if(c==LSHIFT)
+    libfuncname="__lshint64";
+  else{
+    printf("c=%d\n",c);
+    ierror(0);
+  }
+  emit(f,"\t.global\t%s%s\n",idprefix,libfuncname);
+  emit(f,"\tbl\t%s%s\n",idprefix,libfuncname);
+  stack_valid=0; /*FIXME*/
+
+  if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+    if((p->z.reg==r3&&(savemask&1))||
+       (p->z.reg==r4&&(savemask&2))||
+       (p->z.reg==r5&&(savemask&4))||
+       (p->z.reg==r6&&(savemask&8))){
+      if(p->z.reg==r3)
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-4,mregnames[msp]);
+      else if(p->z.reg==r4)
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-8,mregnames[msp]);
+      else if(p->z.reg==r5)
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-12,mregnames[msp]);
+      else if(p->z.reg==r6)
+	emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-16,mregnames[msp]);
+      else
+	ierror(0);
+      p->z.reg=t1;
+    }
+  }
+
+  if((p->z.flags&REG)&&p->z.reg==r3)
+    savemask&=~1;
+  if((p->z.flags&REG)&&p->z.reg==r4)
+    savemask&=~2;
+  if((p->z.flags&REG)&&p->z.reg==r5)
+    savemask&=~4;
+  if((p->z.flags&REG)&&p->z.reg==r6)
+    savemask&=~8;
+  if((p->z.flags&REG)&&p->z.reg==r3r4)
+    savemask&=~3;
+  if((p->z.flags&REG)&&p->z.reg==r5r6)
+    savemask&=~12;
+
+
+  if(ISFLOAT(ztyp(p))){
+    zreg=f1;
+  }else{
+    create_loadable(f,&p->z,t1);
+    store_hword(f,r3,&p->z);
+    store_lword(f,r4,&p->z);
+    p->z.flags=0;
+  }
+
+  if(savemask&1)
+    emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r3],mtmpoff-4,mregnames[msp]);
+  if(savemask&2)
+    emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r4],mtmpoff-8,mregnames[msp]);
+  if(savemask&4)
+    emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-12,mregnames[msp]);
+  if(savemask&8)
+    emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r6],mtmpoff-16,mregnames[msp]);
+  
+  return 1;
+}
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  if(POWEROPEN){
+    stackalign=l2zm(4L);
+    align_arguments=0;
+  }else{
+    tocname=sdataname;
+    stackalign=l2zm(4L);
+    if(NOALIGNARGS)
+      align_arguments=0;
+    else
+      align_arguments=1;
+  }
+  char_bit=l2zm(8L);
+  if(g_flags[7]&USEDFLAG){
+    malign[INT]=malign[LONG]=malign[LLONG]=malign[POINTER]=malign[FLOAT]=malign[DOUBLE]=malign[LDOUBLE]=2;
+  }
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i=0;i<=MAXR;i++) mregnames[i]=regnames[i];
+  for(i= 1;i<=32;i++){
+    regsize[i]=l2zm(4L);
+    regtype[i]=&ltyp;
+    if(g_flags[8]&USEDFLAG) mregnames[i]++;
+  }
+  for(i=33;i<=64;i++){
+    regsize[i]=l2zm(8L);
+    regtype[i]=&ldbl;
+    if(g_flags[8]&USEDFLAG) mregnames[i]++;
+  }
+  for(i=65;i<=72;i++){
+    regsize[i]=l2zm(1L);
+    regtype[i]=&lchar;
+    if(g_flags[8]&USEDFLAG) mregnames[i]+=2;
+  }
+  for(i=74;i<=86;i++){
+    regsize[i]=l2zm(8L);
+    regtype[i]=&lltyp;
+  }
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=1;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  if(POWEROPEN){
+    sd=r2;
+  }
+  regsa[t1]=regsa[t2]=regsa[t3]=1;
+  regsa[f1]=regsa[f2]=regsa[f3]=1;
+  regsa[sp]=regsa[fp]=regsa[sd]=regsa[r2]=1;
+  regscratch[t1]=regscratch[t2]=regscratch[t3]=0;
+  regscratch[f1]=regscratch[f2]=regscratch[f3]=0;
+  regscratch[sp]=regscratch[fp]=regscratch[sd]=regscratch[r2]=0;
+
+  if(g_flags[6]&USEDFLAG) {minframe=8;labprefix=".l";idprefix="";}
+  if(POWEROPEN) {minframe=24;labprefix="l";idprefix="_";}
+
+  if(optsize){
+    dataname="\t.data\n";
+    rodataname="\t.section\t.rodata\n";
+    sdataname="\t.section\t\".sdata\",\"aw\"\n";
+    sdata2name="\t.section\t\".sdata2\",\"a\"\n";
+    sbssname="\t.section\t\".sbss\",\"auw\"\n";
+  }
+
+  if(BASERELOS4) bssname="\t.bss\n";
+
+  target_macros=marray;
+
+  declare_builtin("__mulint64",LLONG,LLONG,r3r4,LLONG,r5r6,1,0);
+  declare_builtin("__divsint64",LLONG,LLONG,r3r4,LLONG,r5r6,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r3r4,UNSIGNED|LLONG,r5r6,1,0);
+  declare_builtin("__modsint64",LLONG,LLONG,r3r4,LLONG,r5r6,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r3r4,UNSIGNED|LLONG,r5r6,1,0);
+  declare_builtin("__lshint64",LLONG,LLONG,r3r4,INT,r5,1,0);
+  declare_builtin("__rshsint64",LLONG,LLONG,r3r4,INT,r5,1,0);
+  declare_builtin("__rshuint64",LLONG,UNSIGNED|LLONG,r3r4,INT,r5,1,0);
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+  dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+  dwarf2_print_comp_unit_header(f);
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) return 34; /* f1 */
+    if(ISSTRUCT(t->flags)||ISUNION(t->flags)) return 0;
+    if(zmleq(szof(t),l2zm(4L))) return r3; 
+    if((t->flags&NQ)==LLONG) return 74; /* r3/r4 */
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r<74||r>86)
+    return 0;
+  switch(r){
+  case 74: p->r1=4;p->r2=5;return 1;
+  case 75: p->r1=6;p->r2=7;return 1;
+  case 76: p->r1=8;p->r2=9;return 1;
+  case 77: p->r1=10;p->r2=11;return 1;
+  case 78: p->r1=15;p->r2=16;return 1;
+  case 79: p->r1=17;p->r2=18;return 1;
+  case 80: p->r1=19;p->r2=20;return 1;
+  case 81: p->r1=21;p->r2=22;return 1;
+  case 82: p->r1=23;p->r2=24;return 1;
+  case 83: p->r1=25;p->r2=26;return 1;
+  case 84: p->r1=27;p->r2=28;return 1;
+  case 85: p->r1=29;p->r2=30;return 1;
+  case 86: p->r1=31;p->r2=32;return 1;
+  }
+  ierror(0);
+}
+
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    struct obj *co=&o->v->cobj;
+    int longload;
+    if(o->flags&DREFOBJ)
+      return 4;
+    if(ISFLOAT(p->typf)) return 2;
+    longload=0;
+    if((co->flags&VARADR)&&!use_sd(o->v->vtyp->flags))
+      longload=2;
+    if(co->flags&KONST){
+      eval_const(&co->val,p->typf);
+      if(p->typf&UNSIGNED){
+	if(!zumleq(vumax,ul2zum(65535UL)))
+	  longload=2;
+      }else{
+	if(!zmleq(vmax,l2zm(32767L))||zmleq(vmax,l2zm(-32769L)))
+	  longload=2;
+      }
+    }
+    if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN))
+      return longload+2;
+    else
+      return longload;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+    if(r==0) return 0;
+    t&=NQ;
+    if(t==0){
+        if(r>=65&&r<=72) return 1; else return 0;
+    }
+    if(ISFLOAT(t)&&r>=33&&r<=64) return 1;
+    if(t==POINTER&&r>=1&&r<=32) return 1;
+    if(t>=CHAR&&t<=LONG&&r>=1&&r<=32) return 1;
+    if(t==LLONG&&r>=74&&r<=86) return 1;
+    return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+    int op=o&NQ,tp=t&NQ;
+    if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+      return 0;
+    if(op==DOUBLE&&tp==LDOUBLE) return 0;
+    if(op==LDOUBLE&&tp==DOUBLE) return 0;
+    if(op==tp) return 0;
+    return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  title(f);
+  if(newobj&&section!=TOC&&section!=SBSS&&section!=SPECIAL&&!BASERELOS4)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  title(f);
+  if(!optsize&&(zm2l(align)<4))
+    emit(f,"\t.align\t2\n");
+  else
+    if(zm2l(align)>1)
+      emit(f,"\t.align\t%ld\n",pof2(align)-1);
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  title(f);
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(use_sd(v->vtyp->flags)&&!(v->tattr&FAR)){
+	if(EABI){
+	  if(v->clist&&!constflag&&section!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+	  if(v->clist&&constflag&&section!=SDATA2){emit(f,sdata2name);if(f) section=SDATA2;}
+	  if(!v->clist&&section!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+	}else if (POWEROPEN){
+	  if(section!=TOC){emit(f,tocname);if(f) section=TOC;}
+	}
+        else {
+	  if(v->clist&&section!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+	  if(!v->clist&&section!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+        }
+      }else{
+        if(BASERELOS4){
+          if(v->clist&&section!=DATA){emit(f,dataname); if(f) section=DATA;}
+        }else if(BASERELMOS){
+          if(v->clist&&section!=SDATA){emit(f,sdataname); if(f) section=SDATA;}
+          if(!v->clist&&section!=SBSS){emit(f,sbssname); if(f) section=SBSS;}
+        }else{
+          if(POWEROPEN) toc_entry(f,v);
+          if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+          if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	  if(!USE_COMMONS&&!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+        }
+      }
+    }
+    if(v->clist||section==TOC||section==SBSS||section==SPECIAL){
+      emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+      emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else{
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+      newobj=1;
+    }
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    if(POWEROPEN&&(!use_sd(v->vtyp->flags)||(v->tattr&FAR)))
+      emit(f,"\t.global\t%s%s%s\n",tocprefix,idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(use_sd(v->vtyp->flags)&&!(v->tattr&FAR)){
+	  if(EABI){
+	    if(v->clist&&!constflag&&section!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+	    if(v->clist&&constflag&&section!=SDATA2){emit(f,sdata2name);if(f) section=SDATA2;}
+	    if(!v->clist&&section!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+	  }else if (POWEROPEN){
+	    if(section!=TOC){emit(f,tocname);if(f) section=TOC;}
+	  }
+          else {
+	    if(v->clist&&section!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+	    if(!USE_COMMONS&&!v->clist&&section!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+          }
+	}else{
+          if(BASERELOS4){
+            if(v->clist&&section!=DATA){emit(f,dataname); if(f) section=DATA;}
+          }else if(BASERELMOS){
+            if(v->clist&&section!=SDATA){emit(f,sdataname); if(f) section=SDATA;}
+            if(!USE_COMMONS&&!v->clist&&section!=SBSS){emit(f,sbssname); if(f) section=SBSS;}
+          }else{
+            if(POWEROPEN) toc_entry(f,v);
+            if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+            if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	    if(!USE_COMMONS&&!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+          }
+	}
+      }
+      if(v->clist||section==TOC||section==SBSS||section==SPECIAL){
+        emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+        emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+	gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else{
+        emit(f,"\t.%scomm\t%s%s,",USE_COMMONS?"":"l",idprefix,v->identifier);
+	newobj=1;
+      }
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  title(f);
+  if((t&NQ)==POINTER) t=UNSIGNED|LONG;
+  emit(f,"\t.%s\t",dct[t&NQ]);
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else if((t&NQ)==LLONG){
+      zumax tmp;
+      eval_const(&p->val,t);
+      tmp=vumax;
+      vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); 
+      gval.vulong=zum2zul(vumax);
+      emitval(f,&gval,UNSIGNED|LONG);
+      emit(f,",");
+      vumax=zumand(tmp,ul2zum(0xffffffff)); 
+      gval.vulong=zum2zul(vumax);
+      emitval(f,&gval,UNSIGNED|LONG);
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+static void allocreg(int r)
+{
+  if(reg_pair(r,&rp)){
+    regs[rp.r1]=1;
+    regs[rp.r2]=1;
+  }
+  regs[r]=1;
+}
+
+static void freereg(int r)
+{
+  if(reg_pair(r,&rp)){
+    regs[rp.r1]=0;
+    regs[rp.r2]=0;
+  }
+  regs[r]=0;
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i,addbuf,varargs=0,fixedgpr,fixedfpr,setcc,ccset;
+  char *fpp;int fpf;struct IC *m;
+  long of=(zm2l(offset)+3)/4*4,regbase,vparmos=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  if(vlas) fp=vlafp; else fp=sp;
+  maxpushed=0;addbuf=0;
+  if(v->tattr&RFI)
+    ret="\trfi\n";
+  else
+    ret="\tblr\n";
+  if(!v->fi) v->fi=new_fi();
+  title(f);
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    m->ext.setcc=0;
+    if(c==ALLOCREG){
+      allocreg(m->q1.reg);
+      continue;
+    }
+    if(c==FREEREG){
+      freereg(m->q1.reg);
+      continue;
+    }
+    if(c==COMPARE&&(m->q2.flags&KONST)&&(t&NQ)!=CHAR&&(t&NQ)!=SHORT){
+      eval_const(&m->q2.val,t);
+      if(zmeqto(vmax,l2zm(0L))&&zldeqto(vldouble,d2zld(0.0))){
+        m->q2.flags=0;m->code=c=TEST;
+      }
+    }
+    if((t&NQ)<=LLONG&&(m->q2.flags&KONST)&&(t&NQ)<=LLONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  m->typf2=INT;
+	}
+      }
+    }
+    if(addbuf<16){
+      if((q1typ(m)&NQ)==LLONG&&(c==MULT||c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)) {addbuf=16;function_calls++;}
+      if(c==CONVERT&&(q1typ(m)&NQ)==LLONG&&ISFLOAT(ztyp(m)&NQ)){addbuf=16;function_calls++;}
+      if(c==CONVERT&&(ztyp(m)&NQ)==LLONG&&ISFLOAT(q1typ(m)&NQ)){addbuf=16;function_calls++;}
+      if(addbuf<8){
+	if(c==CONVERT&&ISFLOAT(m->typf2)&&!ISFLOAT(t)) addbuf=8;
+	if(c==CONVERT&&!ISFLOAT(m->typf2)&&ISFLOAT(t)) addbuf=8;
+      }
+    }
+    if(c==CALL&&maxpushed<zm2l(m->q2.val.vmax)) maxpushed=zm2l(m->q2.val.vmax);
+    if(c==CALL&&(m->q1.flags&VAR)&&!strcmp(m->q1.v->identifier,"__va_start")) varargs=1;
+  }
+  once=twice=0;
+  if(!(g_flags[9]&USEDFLAG)) peephole(p);
+  if(varargs){
+    fixedgpr=fixedfpr=0;
+    if(!freturn(v->vtyp->next)) fixedgpr++;
+    for(i=0;i<v->vtyp->exact->count;i++){
+      c=(*v->vtyp->exact->sl)[i].styp->flags&NQ;
+      if(fixedgpr<8&&(c==POINTER||c<=LONG))
+	fixedgpr++;
+      else if(fixedgpr<7&&c==LLONG)
+	fixedgpr=(fixedgpr+3)/2*2;
+      else if(fixedfpr<8&&ISFLOAT(c)) 
+	fixedfpr++;
+      else{
+	
+	vparmos+=zm2l(szof((*v->vtyp->exact->sl)[i].styp));
+	vparmos=(vparmos+zm2l(stackalign)-1)/zm2l(stackalign)*zm2l(stackalign);
+      }
+    }
+    regbase=of;
+    addbuf+=96;
+  }
+  for(c=1;c<=MAXR;c++){
+    if((!regsa[c])&&regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+  of+=addbuf;tmpoff=minframe+maxpushed+of;
+  function_top(f,v,of);
+  all_regs=1;
+  if(varargs){
+    regbase=frameoffset+regbase;
+    fpp="";
+    if(!(g_flags[8]&USEDFLAG)) fpp="r";
+    for(i=fixedgpr;i<8;i++)
+      emit(f,"\tstw\t%s%d,%ld(%s)\n",fpp,i+3,regbase+i*4,mregnames[sp]);
+    if(!(g_flags[8]&USEDFLAG)) fpp="f";
+    for(i=fixedfpr;i<8;i++)
+      emit(f,"\tstfd\t%s%d,%ld(%s)\n",fpp,i+1,regbase+32+i*8,mregnames[sp]);
+  }
+  pushed=0;ccset=0;
+  for(;p;pr(f,p),p=p->next){
+    c=p->code;t=p->typf;
+    setcc=p->ext.setcc;
+    if(debug_info)
+      dwarf2_line_info(f,p);
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG){
+      allocreg(p->q1.reg);
+      continue;
+    }
+    if(c==FREEREG){
+      freereg(p->q1.reg);
+      continue;
+    }
+    if(c==COMPARE&&(p->q2.flags&KONST)&&(t&NQ)!=LLONG){
+      struct case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
+      if(ct&&(ct->num>=JUMP_TABLE_LENGTH||(!isreg(q1)&&ct->num>=JUMP_TABLE_LENGTH/2))){
+	int r,defl,tabl=++label;
+	long l;unsigned long ul;
+	struct IC *np;
+	for(np=p;np!=ct->next_ic;np=np->next){
+	  if(np->code==ALLOCREG) allocreg(np->q1.reg);
+	  if(np->code==FREEREG) freereg(np->q1.reg);
+	}
+	if(ct->next_ic->code==BRA)
+	  defl=ct->next_ic->typf;
+	else
+	  defl=++label;
+	if(!isreg(q1)){
+	  if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+	    p->q1.flags&=~DREFOBJ;
+	    load_reg(f,t1,&p->q1,POINTER,t1);
+	    p->q1.flags|=(REG|DREFOBJ);
+	    p->q1.flags&=~VAR;
+	    p->q1.reg=t1;
+	  }
+	  load_reg(f,t2,&p->q1,p->typf,t1);
+	  r=t2;
+	}else
+	  r=p->q1.reg;
+	if(t&UNSIGNED)
+	  l=-(long)zum2ul(ct->min.vumax);
+	else
+	  l=-zm2l(ct->min.vmax);
+	if(l>=-32767&&l<=32767){
+	  emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[r],l);
+	}else{
+	  emit(f,"\taddis\t%s,%s,%ld\n",mregnames[t2],mregnames[r],hi(l));
+	  if(lo(l))
+	    emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[t2],lo(l));
+	}
+	ul=zum2ul(ct->diff);
+	if(regs[cr0]) ierror(0);
+	if(ul<=65535){
+	  emit(f,"\tcmplwi\t%s,%lu\n",mregnames[t2],ul);
+	}else{
+	  emit(f,"\tlis\t%s,%ld\n",mregnames[t1],hi(ul));
+	  if(lo(ul))
+	    emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],regnames[t1],lo(ul));
+	}
+	emit(f,"\tbgt\t%s,%s%d\n",mregnames[cr0],labprefix,defl);
+	emit(f,"\tslwi\t%s,%s,2\n",mregnames[t2],mregnames[t2]);
+	/*FIXME: small-data */
+	if(POWEROPEN){
+	  emit(f,"\tlwz\t%s,%s%s%d(%s)\n",mregnames[t1],tocprefix,labprefix,tabl,mregnames[r2]);
+	}else{
+	  emit(f,"\tlis\t%s,%s%d@ha\n",mregnames[t1],labprefix,tabl);
+	  emit(f,"\taddi\t%s,%s,%s%d@l\n",mregnames[t1],mregnames[t1],labprefix,tabl);
+	}
+	emit(f,"\tlwzx\t%s,%s,%s\n",mregnames[t2],mregnames[t1],mregnames[t2]);
+	emit(f,"\tmtctr\t%s\n",mregnames[t2]);
+	emit(f,"\tbctr\n");
+	BSET(regs_modified,ctr);
+	if(POWEROPEN){
+	  emit(f,tocname);
+	  emit(f,"%s%s%d:\n",tocprefix,labprefix,tabl);
+	  emit(f,"\t.long\t%s%d\n",labprefix,tabl);
+	}
+	emit(f,rodataname);
+	emit(f,"\t.align\t2\n");
+	emit(f,"%s%d:\n",labprefix,tabl);
+	emit_jump_table(f,ct,"\t.long\t",labprefix,defl);
+	if(!special_section(f,v)) emit(f,codename);
+	if(ct->next_ic->code!=BRA){
+	  emit(f,"%s%d:\n",labprefix,defl);
+	  p=ct->next_ic->prev;
+	}else
+	  p=ct->next_ic;
+	continue;
+      }
+    }
+    if(c==LABEL) {ccset=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      ccset=0;
+      if(t==exit_label&&framesize==0)
+	emit(f,ret);
+      else
+	emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      ccset=0;
+      if(!(p->q1.flags&REG)) p->q1.reg=cr0;
+      if(!(g_flags[9]&USEDFLAG)&&!BTST(twice,p->typf-lastlabel)){
+        struct IC *p2,*p3,*p4;int exit_label;
+        p2=p->next;
+        while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+        if(p2&&p2->code==SETRETURN&&p2->z.reg){p2->code=ASSIGN;p2->z.flags=REG;}
+        if(p2&&p2->code==ASSIGN&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg<=32){
+          p3=p2->next;
+          while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
+          if(p3&&p3->code==BRA){
+            exit_label=p3->typf;
+            p3=p3->next;
+            while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
+            if(p3&&p3->code==LABEL&&p3->typf==p->typf){
+              p3=p3->next;
+              while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
+              if(p3&&p3->code==SETRETURN&&p3->z.reg){p3->code=ASSIGN;p3->z.flags=REG;}
+              if(p3&&p3->code==ASSIGN&&(p3->z.flags&(REG|DREFOBJ))==REG&&p3->z.reg==p2->z.reg){
+                p4=p3->next;
+                while(p4&&(p4->code==FREEREG||p4->code==ALLOCREG)) p4=p4->next;
+                if(p4&&p4->code==LABEL&&p4->typf==exit_label){
+                  int bit=(p->q1.reg-cr0)*4;
+                  if((p2->q1.flags&KONST)&&(p3->q1.flags&KONST)){
+                    eval_const(&p2->q1.val,p2->typf);
+                    if(zmeqto(vmax,l2zm(0L))){
+                      eval_const(&p3->q1.val,p3->typf);
+                      if(zmeqto(vmax,l2zm(1L))||zmeqto(vmax,l2zm(-1L))){
+                        if(c==BLE){emit(f,"\tcror\t%d,%d,%d\n",bit,bit,bit+2);}
+                        if(c==BGE){bit++;emit(f,"\tcror\t%d,%d,%d\n",bit,bit,bit+1);}
+                        if(c==BNE){bit+=2;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+                        if(c==BGT) bit++;
+                        if(c==BEQ) bit+=2;
+                        emit(f,"\tmfcr\t%s\n",mregnames[t1]);
+                        emit(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[p2->z.reg],mregnames[t1],bit+1,31,31);
+                        if(zmeqto(vmax,l2zm(-1L))) emit(f,"\tneg\t%s,%s\n",mregnames[p2->z.reg],mregnames[p2->z.reg]);
+                        if(BTST(twice,p4->typf-lastlabel)) emit(f,"%s%d:\n",labprefix,p4->typf);
+                        p=p4;continue;
+                      }
+                    }else{
+                      eval_const(&p3->q1.val,p3->typf);
+                      if(zmeqto(vmax,l2zm(0L))){
+                        eval_const(&p2->q1.val,p2->typf);
+                        if(zmeqto(vmax,l2zm(1L))||zmeqto(vmax,l2zm(-1L))){
+                          if(c==BLE){emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit+2);}
+                          if(c==BGE){bit++;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit+1);}
+                          if(c==BNE){bit+=2;}
+                          if(c==BGT){bit++;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+                          if(c==BEQ){bit+=2;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+                          if(c==BLT){emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+                          emit(f,"\tmfcr\t%s\n",mregnames[t1]);
+                          emit(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[p2->z.reg],mregnames[t1],bit+1,31,31);
+                          if(zmeqto(vmax,l2zm(-1L))) emit(f,"\tneg\t%s,%s\n",mregnames[p2->z.reg],mregnames[p2->z.reg]);
+                          if(BTST(twice,p4->typf-lastlabel)) emit(f,"%s%d:\n",labprefix,p4->typf);
+                          p=p4;continue;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      if(t==exit_label&&framesize==0&&!strcmp(ret,"\tblr\n"))
+	emit(f,"\tb%slr\t%s\n",ccs[c-BEQ],mregnames[p->q1.reg]);
+      else
+	emit(f,"\tb%s\t%s,%s%d\n",ccs[c-BEQ],mregnames[p->q1.reg],labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      if(p->z.reg<=32){
+        load_reg(f,p->z.reg,&p->q1,INT,t1);
+      }else if(p->z.reg>=33&&p->z.reg<=64){
+        load_reg(f,p->z.reg,&p->q1,DOUBLE,t1);
+      }else if(reg_pair(p->z.reg,&rp)){
+	create_loadable(f,&p->q1,t1);
+	load_hword(f,rp.r1,&p->q1,LLONG,t2);
+	load_lword(f,rp.r2,&p->q1,LLONG,t2);
+      }else
+	ierror(0);
+      p->z.flags=0;
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      if(p->q1.reg<=32){
+        store_reg(f,p->q1.reg,&p->z,INT);
+      }else if(p->q1.reg>=33&&p->q1.reg<=64){
+        store_reg(f,p->q1.reg,&p->z,DOUBLE);
+      }else if(reg_pair(p->q1.reg,&rp)){
+	create_loadable(f,&p->z,t1);
+	store_hword(f,rp.r1,&p->z);
+	store_lword(f,rp.r2,&p->z);
+      }else
+	ierror(0);
+      p->z.flags=0;
+      continue;
+    }
+    if((p->q1.flags&&(q1typ(p)&NQ)==LLONG)||(p->q2.flags&&(q2typ(p)&NQ)==LLONG)||(p->z.flags&&(ztyp(p)&NQ)==LLONG))
+      if(handle_llong(f,p))
+	continue;
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      unsigned long size,l;
+      int a1,a2,b;char *ld,*st;
+      size=zm2l(p->q2.val.vmax);
+      a1=balign(&p->q1);
+      if(c==ASSIGN) a2=balign(&p->z); else a2=0;
+      b=1;ld=ldt(CHAR);st=sdt(CHAR);
+      if(p->q1.flags&VAR){
+	if(p->q1.flags&DREFOBJ){
+	  if(p->q1.v->vtyp->next&&zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp->next))&&(a1&1)){
+	    a1=zm2l(falign(p->q1.v->vtyp->next))&3;
+	    a2&=a1;
+	  }
+	}else{
+	  if(zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp))&&(a1&1)){
+	    a1=zm2l(falign(p->q1.v->vtyp))&3;
+	    a2&=a1;
+	  }
+	}
+      }
+      if(p->z.flags&VAR){
+	if(p->z.flags&DREFOBJ){
+	  if(p->z.v->vtyp->next&&zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp->next))&&(a2&1)){
+	    a2=zm2l(falign(p->z.v->vtyp->next))&3;
+	    a1&=a2;
+	  }
+	}else{
+	  if(zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp))&&(a2&1)){
+	    a2=zm2l(falign(p->z.v->vtyp))&3;
+	    a1&=a2;
+	  }
+	}
+      } 
+      if(a1>=0&&a2>=0){
+        if(a1==0&&a2==0){
+          b=4;ld=ldt(INT);st=sdt(INT);
+        }else if((a1&1)==0&&(a2&1)==0){
+          b=2;ld=ldt(SHORT);st=sdt(SHORT);
+        }
+      }
+      if(p->q1.flags&DREFOBJ){
+        if(p->q1.am){
+          if(p->q1.am->flags&REG_IND){
+	    emit(f,"\tadd\t%s,%s,%s\n",mregnames[t1],mregnames[p->q1.am->offset],mregnames[p->q1.am->base]);
+	    emit(f,"\taddi\t%s,%s,%d\n",mregnames[t1],mregnames[t1],-b);
+	  }
+          if(p->q1.am->flags&IMM_IND)
+	    emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],mregnames[p->q1.am->base],p->q1.am->offset-b);
+        }else{
+          p->q1.flags&=~DREFOBJ;
+	  if(isreg(q1)){
+	    emit(f,"\taddi\t%s,%s,%d\n",mregnames[t1],mregnames[p->q1.reg],-b);
+	  }else{
+	    load_reg(f,t1,&p->q1,POINTER,t1);
+	    emit(f,"\taddi\t%s,%s,%d\n",mregnames[t1],mregnames[t1],-b);
+	  }    
+          p->q1.flags|=DREFOBJ;
+        }
+      }else{
+	p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm((long)b));
+        load_address(f,t1,&p->q1,POINTER);
+	p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm((long)b));
+      }
+      if(p->z.flags&DREFOBJ){
+        if(p->z.am){
+          if(p->z.am->flags&REG_IND){
+	    emit(f,"\tadd\t%s,%s,%s\n",mregnames[t2],mregnames[p->z.am->offset],mregnames[p->z.am->base]);
+	    emit(f,"\taddi\t%s,%s,%d\n",mregnames[t2],mregnames[t2],-b);
+	  }
+          if(p->z.am->flags&IMM_IND) 
+	    emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[p->z.am->base],p->z.am->offset-b);
+        }else{
+          p->z.flags&=~DREFOBJ;
+	  if(isreg(z)){
+	    emit(f,"\taddi\t%s,%s,%d\n",mregnames[t2],mregnames[p->z.reg],-b);
+	  }else{
+	    load_reg(f,t2,&p->z,POINTER,t2);
+	    emit(f,"\taddi\t%s,%s,%d\n",mregnames[t2],mregnames[t2],-b);
+	  }
+          p->z.flags|=DREFOBJ;
+        }
+      }else{
+        if(c==PUSH){
+          pushed=(pushed+3)/4*4;
+	  if(align_arguments&&p->ityp){
+	    long al=falign(p->ityp);
+	    pushed=(pushed+al-1)/al*al;
+	  }
+          emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[sp],pushed+minframe-b);
+          pushed+=size;
+	  size=zm2l(p->z.val.vmax);
+        }else{
+	  p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)b));
+          load_address(f,t2,&p->z,POINTER);
+	  p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)b));
+        }
+      }
+      BSET(regs_modified,t1);
+      BSET(regs_modified,t2);
+      BSET(regs_modified,t3);
+      if(optspeed)
+	l=size/(8*b);
+      else
+	l=size/b;
+      if(l>1){
+        if(hi(l)){
+	  emit(f,"\tlis\t%s,%lu\n",mregnames[t3],(l>>16)&65535);
+	  emit(f,"\tori\t%s,%s,%lu\n",mregnames[t3],mregnames[t3],l&65535);
+	}else{
+	  emit(f,"\tli\t%s,%ld\n",mregnames[t3],lo(l));
+	}
+        emit(f,"\tmtctr\t%s\n",mregnames[t3]);
+	BSET(regs_modified,ctr);
+        emit(f,"%s%d:\n",labprefix,++label);
+      }
+      if(l>0){
+        for(i=b;optspeed&&i<=7*b;i+=b){
+          emit(f,"\tl%s\t%s,%d(%s)\n",ld,mregnames[t3],i,mregnames[t1]);
+          emit(f,"\tst%s\t%s,%d(%s)\n",st,mregnames[t3],i,mregnames[t2]);
+        }
+        emit(f,"\tl%su\t%s,%d(%s)\n",ld,mregnames[t3],i,mregnames[t1]);
+        emit(f,"\tst%su\t%s,%d(%s)\n",st,mregnames[t3],i,mregnames[t2]);
+	
+      }
+      if(l>1){
+        emit(f,"\tbdnz\t%s%d\n",labprefix,label);
+      }
+      if(optspeed)
+	size=size%(8*b);
+      else
+	size=size%b;
+      for(i=0;i<size/b;i++){
+        emit(f,"\tl%su\t%s,%d(%s)\n",ld,mregnames[t3],b,mregnames[t1]);
+        emit(f,"\tst%su\t%s,%d(%s)\n",st,mregnames[t3],b,mregnames[t2]);
+      }
+      size=size%b;i=b;
+      if(size&2){
+        emit(f,"\tl%su\t%s,%d(%s)\n",ldt(SHORT),mregnames[t3],b,mregnames[t1]);
+        emit(f,"\tst%su\t%s,%d(%s)\n",sdt(SHORT),mregnames[t3],b,mregnames[t2]);
+        i=2;
+      }
+      if(size&1){
+        emit(f,"\tl%su\t%s,%d(%s)\n",ldt(CHAR),mregnames[t3],i,mregnames[t1]);
+        emit(f,"\tst%su\t%s,%d(%s)\n",sdt(CHAR),mregnames[t3],i,mregnames[t2]);
+      }
+      p->z.flags=0;
+      continue;
+    }
+    if(c==TEST&&ISFLOAT(t)){
+      p->code=c=COMPARE;
+      p->q2.flags=KONST;
+      p->q2.val.vldouble=d2zld(0.0);
+      if((t&NQ)==DOUBLE) p->q2.val.vdouble=zld2zd(p->q2.val.vldouble);
+      if((t&NQ)==FLOAT) p->q2.val.vfloat=zld2zf(p->q2.val.vldouble);
+    }
+    p=do_refs(f,p);
+    c=p->code;
+    setcc=p->ext.setcc;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      int to;
+      static struct obj o;char *ip;
+      long moff;int offreg;
+      to=p->typf2;
+      if(ISFLOAT(to)){
+        if(ISFLOAT(t)){
+          zreg=q1reg;
+          continue;
+        }
+        if(tmpoff>32767){
+          moff=0;offreg=t1;
+          emit(f,"\taddis\t%s,%s,%ld\n",mregnames[offreg],mregnames[sp],hi(tmpoff));
+          emit(f,"\taddi\t%s,%s,%ld\n",mregnames[offreg],mregnames[offreg],lo(tmpoff));
+        }else{
+          moff=tmpoff;
+          offreg=sp;
+        }
+        if((t&NU)==(UNSIGNED|INT)||(t&NU)==(UNSIGNED|LONG)){
+          o.flags=KONST;
+          ip=(char *)&o.val.vdouble;
+          ip[0]=0x41;
+          ip[1]=0xe0;
+          ip[2]=0x00;
+          ip[3]=0x00;
+          ip[4]=0x00;
+          ip[5]=0x00;
+          ip[6]=0x00;
+          ip[7]=0x00;
+          load_reg(f,f2,&o,DOUBLE,t2);
+          emit(f,"\tfcmpu\t%s,%s,%s\n",mregnames[cr0],mregnames[q1reg],mregnames[f2]);
+          emit(f,"\tcror\t3,2,1\n");
+          emit(f,"\tbso\t%s,%s%d\n",mregnames[cr0],labprefix,++label);
+          emit(f,"\tfctiwz\t%s,%s\n",mregnames[f2],mregnames[q1reg]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[f2],moff-8,mregnames[offreg]);
+          emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(t&NQ),mregnames[zreg],moff-zm2l(sizetab[t&NQ]),mregnames[offreg]);
+          emit(f,"\tb\t%s%d\n",labprefix,++label);
+          emit(f,"%s%d:\n",labprefix,label-1);
+          emit(f,"\tfsub\t%s,%s,%s\n",mregnames[f2],mregnames[q1reg],mregnames[f2]);
+          emit(f,"\tfctiwz\t%s,%s\n",mregnames[f2],mregnames[f2]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[f2],moff-8,mregnames[offreg]);
+          emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(INT),mregnames[zreg],moff-zm2l(sizetab[t&NQ]),mregnames[offreg]);
+          emit(f,"\txoris\t%s,%s,32768\n",mregnames[zreg],mregnames[zreg]);
+          emit(f,"%s%d:\n",labprefix,label);
+	  BSET(regs_modified,f2);
+	  BSET(regs_modified,zreg);
+	  BSET(regs_modified,q1reg);
+        }else{
+          emit(f,"\tfctiwz\t%s,%s\n",mregnames[f3],mregnames[q1reg]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[f3],moff-8,mregnames[offreg]);
+          emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(t&NQ),mregnames[zreg],moff-zm2l(sizetab[t&NQ]),mregnames[offreg]);
+	  BSET(regs_modified,f3);
+	  BSET(regs_modified,zreg);
+	  BSET(regs_modified,q1reg);
+        }
+        if(t==CHAR) emit(f,"\textsb\t%s,%s\n",mregnames[zreg],mregnames[zreg]);
+        continue;
+      }
+      if(ISFLOAT(t)){
+        if(tmpoff>32767){
+          moff=0;offreg=t1;
+	  if(q1reg==t1){
+	    emit(f,"\tmr\t%s,%s\n",mregnames[t3],mregnames[q1reg]);
+	    q1reg=t3;
+	    BSET(regs_modified,t3);
+	  }
+          emit(f,"\taddis\t%s,%s,%ld\n",mregnames[offreg],mregnames[sp],hi(tmpoff));
+          emit(f,"\taddi\t%s,%s,%ld\n",mregnames[offreg],mregnames[offreg],lo(tmpoff));
+        }else{
+          moff=tmpoff;
+          offreg=sp;
+        }
+        o.flags=KONST;
+        ip=(char *)&o.val.vdouble;
+        ip[0]=0x43;
+        ip[1]=0x30;
+        ip[2]=0x00;
+        ip[3]=0x00;
+        ip[4]=0x80;
+        ip[5]=0x00;
+        ip[6]=0x00;
+        ip[7]=0x00;
+        if((to&NU)==(UNSIGNED|INT)||(to&NU)==(UNSIGNED|LONG)){
+          ip[4]=0x00;
+          load_reg(f,f2,&o,DOUBLE,t2);
+          emit(f,"\tlis\t%s,17200\n",mregnames[t2]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[q1reg],moff-4,mregnames[offreg]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[t2],moff-8,mregnames[offreg]);
+          emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(DOUBLE),mregnames[zreg],moff-8,mregnames[offreg]);
+          emit(f,"\tfsub\t%s,%s,%s\n",mregnames[zreg],mregnames[zreg],mregnames[f2]);
+        }else{
+          emit(f,"\tlis\t%s,17200\n",mregnames[t2]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[t2],moff-8,mregnames[offreg]);
+          emit(f,"\txoris\t%s,%s,32768\n",mregnames[t2],mregnames[q1reg]);
+          emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[t2],moff-4,mregnames[offreg]);
+          emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(DOUBLE),mregnames[zreg],moff-8,mregnames[offreg]);
+          load_reg(f,f2,&o,DOUBLE,t2);
+          emit(f,"\tfsub\t%s,%s,%s\n",mregnames[zreg],mregnames[zreg],mregnames[f2]);
+        }
+        continue;
+      }
+      if((t&NQ)>=(to&NQ)){
+	if((to&NU)==CHAR){
+	  emit(f,"\textsb%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+	  ccset|=setcc;
+	}else if((to&NU)==SHORT&&!q1loaded){
+	  emit(f,"\textsh%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+	  ccset|=setcc;
+	}else if((to&NU)==(UNSIGNED|CHAR)&&!q1loaded){
+	  emit(f,"\tclrlwi%s\t%s,%s,24\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+	  ccset|=setcc;
+	}else if((to&NU)==(UNSIGNED|SHORT)&&!q1loaded){
+	  emit(f,"\tclrlwi%s\t%s,%s,16\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+	  ccset|=setcc;
+	}else{
+	  if(setcc){
+	    emit(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
+	    ccset=1;
+	  }else{
+	    zreg=q1reg;
+	  }
+	}
+	continue;
+      }else{
+	zreg=q1reg;
+        continue;
+      }
+    }
+    if(c==KOMPLEMENT){
+      emit(f,"\tnor%s\t%s,%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg],mregnames[q1reg]);
+      ccset|=setcc;
+      continue;
+    }
+    if(ISFLOAT(t)) {fpp="f";fpf=1;} else {fpp="";fpf=0;}
+    if(c==SETRETURN){
+      if(p->z.reg){
+	if((t&NU)==CHAR)
+	  emit(f,"\textsb\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if(!q1loaded&&(t&NU)==SHORT)
+	  emit(f,"\textsh\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if(!q1loaded&&(t&NU)==(UNSIGNED|CHAR))
+	  emit(f,"\tclrlwi\t%s,%s,24\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if(!q1loaded&&(t&NU)==(UNSIGNED|SHORT))
+	  emit(f,"\tclrlwi\t%s,%s,16\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if(p->z.reg!=q1reg)
+	  emit(f,"\t%smr\t%s,%s\n",fpp,mregnames[p->z.reg],mregnames[q1reg]);
+	BSET(regs_modified,p->z.reg);
+      }else
+        ierror(0);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg)
+        zreg=p->q1.reg;
+      else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      ccset=0;
+      if(stack_valid){
+	int i;
+	if(p->call_cnt<=0){
+	  err_ic=p;error(320);
+	  stack_valid=0;
+	  v->fi->flags|=(WARNED_STACK|WARNED_REGS);
+	}
+	for(i=0;i<p->call_cnt;i++){
+	  if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+	    if(framesize+zum2ul(p->call_list[i].v->fi->stack1)>stack)
+	      stack=framesize+zum2ul(p->call_list[i].v->fi->stack1);
+	  }else{
+	    err_ic=p;
+	    if(!p->call_list[i].v->fi) p->call_list[i].v->fi=new_fi();
+	    if(!(p->call_list[i].v->fi->flags&WARNED_STACK)){
+	      error(317,p->call_list[i].v->identifier);
+	      p->call_list[i].v->fi->flags|=WARNED_STACK;
+	    }
+	    v->fi->flags|=WARNED_STACK;
+	    stack_valid=0;
+	  }
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+	}
+      }
+      if(!calc_regs(p,f!=0)&&v->fi) all_regs=0;
+#if HAVE_OSEK
+/* removed */
+/* removed */
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+        if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+          if(!strcmp("__va_start",p->q1.v->identifier)){
+            emit(f,"\taddi\t%s,%s,%lu\n",mregnames[r3],mregnames[sp],framesize+minframe+zm2l(va_offset(v))/*+vparmos*/);
+            BSET(regs_modified,r3);continue;
+          }
+          if(!strcmp("__va_regbase",p->q1.v->identifier)){
+            emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r3],mregnames[sp],regbase);
+            BSET(regs_modified,r3);continue;continue;
+          }
+          if(!strcmp("__va_fixedgpr",p->q1.v->identifier)){
+            emit(f,"\tli\t%s,%d\n",mregnames[r3],fixedgpr);
+            BSET(regs_modified,r3);continue;continue;
+          }
+          if(!strcmp("__va_fixedfpr",p->q1.v->identifier)){
+            emit(f,"\tli\t%s,%d\n",mregnames[r3],fixedfpr);
+            BSET(regs_modified,r3);continue;continue;
+          }
+        }
+        if(g_flags[10]&USEDFLAG) emit(f,"\tcreqv\t6,6,6\n");
+	/* poweropen-hack! look if some fp-args have been passed on the stack */
+	if(POWEROPEN&&!zmeqto(p->q2.val.vmax,l2zm(0L))){
+	  int r=45/*f12*/,off=24;
+	  for(i=0;r<47&&i<p->arg_cnt;i++){
+	    if(p->arg_list[i]->code==PUSH){
+	      int typ=p->arg_list[i]->typf;
+	      if(ISFLOAT(typ)){
+		emit(f,"\tl%s\t%s,%d(%s)\n",ldt(typ&NQ),mregnames[r],off,mregnames[sp]);
+		r++;
+	      }
+	    }
+	    off+=(zm2l(p->arg_list[i]->q2.val.vmax)+3)/4*4;
+	  }
+	}
+	if(q1reg){
+          emit(f,"\tmtlr\t%s\n",mregnames[q1reg]);
+          emit(f,"\tblrl\n");
+        }else{
+          emit(f,"\tbl\t");emit_obj(f,&p->q1,t);
+          emit(f,"\n");
+        }
+	BSET(regs_modified,lr);
+      }
+      pushed-=zm2l(p->q2.val.vmax);
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(q1reg||c==PUSH){
+        if(c==PUSH){
+	  pushed=(pushed+3)/4*4;
+	  if(align_arguments&&malign[p->typf&NQ]==8)
+	    pushed=(pushed+7)/8*8;
+          if(q1reg)
+            emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(t&NQ),mregnames[q1reg],pushed+minframe,mregnames[sp]);
+          pushed+=zm2l(p->q2.val.vmax);
+          continue;
+        }
+        if(c==ASSIGN){
+          if(setcc&&!fpf&&sizetab[t&NQ]==sizetab[INT]){
+            emit(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
+            ccset=1;
+          }else{
+            zreg=q1reg;
+          }
+        }
+        continue;
+      }
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      continue;
+    }
+    if(c==MINUS){
+      emit(f,"\t%sneg%s\t%s,%s\n",fpp,record[setcc&&!fpf],mregnames[zreg],mregnames[q1reg]);
+      if(setcc&&!fpf) ccset=1;
+      continue;
+    }
+    if(c==TEST){
+      if(!(p->z.flags&REG))
+        p->z.reg=cr0;
+      if(!multiple_ccs&&(t&UNSIGNED)){
+        struct IC *p2=p->next;
+        while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+        if(!p2) continue;
+        if(p2->code==BGT) p2->code=BNE;
+        else if(p2->code==BGE) p2->code=BRA;
+        else if(p2->code==BLT) p2->code=NOP;
+        else if(p2->code==BLE) p2->code=BEQ;
+      }
+      if(ccset&&p->z.reg==cr0) continue;
+      if(ISFLOAT(t)){
+        ierror(0);
+      }else{
+	if((t&NU)==CHAR)
+	  emit(f,"\textsb.\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if((t&NU)==SHORT)
+	  emit(f,"\textsh.\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if((t&NU)==(UNSIGNED|CHAR))
+	  emit(f,"\tandi.\t%s,%s,255\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else if((t&NU)==(UNSIGNED|SHORT))
+	  emit(f,"\tandi.\t%s,%s,65535\n",mregnames[p->z.reg],mregnames[q1reg]);
+	else
+	  emit(f,"\tcmp%swi\t%s,%s,0\n",(t&UNSIGNED)?"l":"",mregnames[p->z.reg],mregnames[q1reg]);
+      }
+      if(p->z.reg==cr0) ccset=0;
+      continue;
+    }
+    if(c==COMPARE){
+      if(!(p->z.flags&REG))
+        p->z.reg=cr0;
+      if(ISFLOAT(t))
+        emit(f,"\tfcmpu\t%s,%s,",mregnames[p->z.reg],mregnames[q1reg]);
+      else
+        emit(f,"\tcmp%sw%s\t%s,%s,",((t&UNSIGNED)||((t&NQ)==POINTER))?"l":"",isimm[q2reg==0],mregnames[p->z.reg],mregnames[q1reg]);
+      emit_obj(f,&p->q2,t);emit(f,"\n");
+      if(p->z.reg==cr0) ccset=0;
+      continue;
+    }
+    BSET(regs_modified,zreg);
+    if(c==AND&&q2reg==0){
+      ccset=setcc;
+      emit(f,"\tandi.\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
+      emit_obj(f,&p->q2,t|UNSIGNED);emit(f,"\n");
+      continue;
+    }
+    if(c>=OR&&c<=AND){
+      emit(f,"\t%s%s%s\t%s,%s,",logicals[c-OR],isimm[q2reg==0],record[setcc&&q2reg],mregnames[zreg],mregnames[q1reg]);
+      emit_obj(f,&p->q2,t|UNSIGNED);emit(f,"\n");
+      if(setcc&&q2reg) ccset=1;
+      continue;
+    }
+    if(c==SUB&&(p->q1.flags&KONST)){
+      emit(f,"\tsubfic\t%s,%s,",mregnames[zreg],mregnames[q2reg]);
+      emit_obj(f,&p->q1,t&NQ);emit(f,"\n");
+      continue;
+    }
+    if(c>=LSHIFT&&c<=MOD){
+      if(c==RSHIFT&&((t&NQ)<=SHORT)){
+	/* special treatment for short shifts used in bitfields with
+	   sub-int type; will not handle the general case (which, however,
+	   should never occur) */
+	int width,shift;
+	width=sizetab[t&NQ]*8;
+	if(!(p->q2.flags&KONST)) ierror(0);
+	eval_const(&p->q2.val,p->typf2&NU);
+	shift=zm2l(vmax);
+	if(shift<0||shift>=width) ierror(0);
+	if(shift==0) continue;
+	if(!(t&UNSIGNED)){
+	  emit(f,"\texts%c\t%s,%s\n",width==8?'b':'h',mregnames[zreg],mregnames[q1reg]);
+	  q1reg=zreg;
+	}
+	emit(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[zreg],mregnames[q1reg],32-shift,32-width+((t&UNSIGNED)?shift:0),31);
+	continue;
+      }
+      if(c==RSHIFT&&!(t&UNSIGNED)){
+        emit(f,"\tsraw%s%s\t%s,%s,",isimm[q2reg==0],record[setcc],mregnames[zreg],mregnames[q1reg]);
+        emit_obj(f,&p->q2,q2typ(p));
+	/* fix for illegal shift values (undefined behaviour) */
+	if(!isreg(q2))
+	  emit(f,"&31");
+	emit(f,"\n");
+        ccset|=setcc;
+        continue;
+      }
+      if(c==MOD){
+        i=0;
+        if(zreg==q1reg||zreg==q2reg){
+          if(t1!=q1reg&&t1!=q2reg) i=t1;
+          if(t2!=q1reg&&t2!=q2reg) i=t2;
+        }else i=zreg;
+        if(i==0||i==q1reg||i==q2reg) ierror(0);
+        emit(f,"\tdivw%s\t%s,%s,%s\n",(t&UNSIGNED)?"u":"",mregnames[i],mregnames[q1reg],mregnames[q2reg]);
+        emit(f,"\tmullw\t%s,%s,%s\n",mregnames[i],mregnames[i],mregnames[q2reg]);
+        emit(f,"\tsubf%s\t%s,%s,%s\n",record[setcc],mregnames[zreg],mregnames[i],mregnames[q1reg]);
+        ccset|=setcc;
+        continue;
+      }
+      if(c==DIV&&(t&UNSIGNED)){
+        emit(f,"\tdivwu%s%s\t%s,%s,",isimm[q2reg==0],record[setcc&&q2reg],mregnames[zreg],mregnames[q1reg]);
+        if(setcc&&q2reg) ccset=1;
+      }else if(c==MULT&&ISFLOAT(t)){
+	if(isreg(z)&&(g_flags[14]&USEDFLAG)){
+	  struct IC *np=p->next,*add;int madd;
+	  while(np&&(np->code==FREEREG||np->code==ALLOCREG)) np=np->next;
+	  if(np&&(np->code==ADD||np->code==SUB)&&(np->q1.flags&(REG|DREFOBJ))==REG&&(np->q1.reg==p->z.reg||(np->code==ADD&&np->q2.reg==p->z.reg))&&(np->q2.flags&(REG|DREFOBJ))==REG&&np->q1.reg!=np->q2.reg){
+	    add=np;
+	    madd=0;
+	    if((np->z.flags&(REG|DREFOBJ))==REG&&np->z.reg==p->z.reg) madd=1;
+	    np=np->next;
+	    while(np&&(np->code==FREEREG||np->code==ALLOCREG)){
+	      if(np->code==FREEREG&&np->q1.reg==p->z.reg) madd=1;
+	      np=np->next;
+	    }
+	    if(madd){
+	      if((add->z.flags&(REG|DREFOBJ))==REG) zreg=add->z.reg;
+	      if(add->code==ADD){
+		if(add->q1.reg==p->z.reg) madd=add->q2.reg; else madd=add->q1.reg;
+		emit(f,"\tfmadd%s\t%s,%s,%s,%s\n",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg],mregnames[q2reg],mregnames[madd]);
+	      }else
+		emit(f,"\tfmsub%s\t%s,%s,%s,%s\n",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg],mregnames[q2reg],mregnames[add->q2.reg]);
+	      add->code=NOP;
+	      p->z=add->z;
+	      add->z.am=0;
+	      continue;
+	    }
+	  }
+	}
+	emit(f,"\tfmul%s\t%s,%s,",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg]);
+      }else if(c==DIV&&ISFLOAT(t)){
+        emit(f,"\tfdiv%s\t%s,%s,",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg]);
+      }else if(c==MULT&&q2reg==0){
+        emit(f,"\tmulli\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
+      }else if(c==ADD&&setcc&&!q2reg){
+        emit(f,"\taddic.\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
+        ccset=1;
+      }else{
+        emit(f,"\t%s%s%s%s%s\t%s,%s,",fpp,arithmetics[c-LSHIFT],(t&NQ)==FLOAT?"s":"",isimm[q2reg==0],record[setcc&&q2reg&&!fpf],mregnames[zreg],mregnames[q1reg]);
+        if(setcc&&q2reg&&!fpf) ccset=1;
+      }
+      emit_obj(f,&p->q2,q2typ(p)&NQ);
+      /* fix for illegal shift values (undefined behaviour) */
+      if((c==LSHIFT||c==RSHIFT)&&q2reg==0) emit(f,"&31");
+      emit(f,"\n");
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  if(!cross_module)  lastlabel=label;  /*FIXME*/
+  free(once);free(twice);
+  function_bottom(f,v,of);
+#if HAVE_OSEK
+/* removed */
+#endif
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    if(v->fi->flags&ALL_STACK){
+      if(v->fi->stack1!=stack&&!(v->tattr&SAVEALL))
+	if(f) error(319,"",stack,v->fi->stack1);
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+#endif
+    }else{
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=stack;
+    }
+  }
+  emit(f,"# stacksize=%lu%s\n",(unsigned long)stack,stack_valid?"":"+??");
+  if(stack_valid) emit(f,"\t.set\t%s__stack_%s,%lu\n",idprefix,v->identifier,(unsigned long)stack);
+  if(debug_info){
+    emit(f,"%s%d:\n",labprefix,++label);
+    dwarf2_function(f,v,label);
+    if(f) section=-1;
+  }
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *ft)
+{
+#if HAVE_AOS4
+  extern int aos4_attr(struct Typ *,char *);
+#endif
+  int f;
+  if(!m) ierror(0);
+  if(!t) ierror(0);
+  if(vararg&&POWEROPEN) return 0;
+#ifdef HAVE_AOS4
+  if(vararg&&ft&&aos4_attr(ft,"linearvarargs")) return 0;
+#endif
+  f=t->flags&NQ;
+  if(f<=LONG||f==POINTER){
+    if(m->gregs>=8) return 0;
+    if(POWEROPEN){
+      if(!STORMC) m->fregs++;
+      return -(r3+m->gregs++);
+    }else{
+      return r3+m->gregs++;
+    }
+  }
+  if(f==LLONG){
+    int r;
+    if(m->gregs>=7) return 0;
+    m->gregs=(m->gregs+3)/2*2;
+    if(m->gregs==2) r=74;
+    else if(m->gregs==4) r=75;
+    else if(m->gregs==6) r=76;
+    else if(m->gregs==8) r=77;
+    else ierror(0);
+    if(POWEROPEN) 
+      return -r;
+    else
+      return r;
+  }
+  if(ISFLOAT(f)){
+    if(POWEROPEN){
+      if(m->fregs>=11) return 0; /* hack! we pretend fp-arg 12/13 is passed on the stack */
+      if(!STORMC){
+        if(f!=FLOAT) m->gregs+=2; else m->gregs++;
+      }
+      return -(34+m->fregs++);
+    }else{
+      if(m->fregs>=8) return 0;
+      return 34+m->fregs++;
+    }
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+  if(!strncmp("amiga-align",s,11)){
+    align[INT]=align[LONG]=align[LLONG]=align[POINTER]=align[FLOAT]=align[DOUBLE]=align[LDOUBLE]=l2zm(2L);
+    return 1;
+  }else if(!strncmp("natural-align",s,13)){
+    align[INT]=align[LONG]=align[POINTER]=align[FLOAT]=l2zm(4L);
+    align[LLONG]=align[DOUBLE]=align[LDOUBLE]=l2zm(8L);
+    return 1;
+  }else if(!strncmp("default-align",s,13)){
+    if(g_flags[7]&USEDFLAG){
+      align[INT]=align[LONG]=align[LLONG]=align[POINTER]=align[FLOAT]=align[DOUBLE]=align[LDOUBLE]=l2zm(2L);
+    }else{
+      align[INT]=align[LONG]=align[POINTER]=align[FLOAT]=l2zm(4L);
+      align[LLONG]=align[DOUBLE]=align[LDOUBLE]=l2zm(8L);
+    }
+    return 1;
+  }
+  return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+  struct StatFPtrList *tfp,*fp=firstfptr;
+
+  title(f);
+
+  if(fp){
+    emit(f,tocname);
+    if(f) section=TOC;
+  }
+  while(tfp=fp){
+    emit(f,"%s%s%ld:\n\t.long\t%s%ld\n",
+	 tocprefix,labprefix,zm2l(tfp->vptr->offset),
+	 labprefix,zm2l(tfp->vptr->offset));
+    fp=fp->next;
+    free(tfp);
+  }
+  if(f&&stack_check)
+    emit(f,"\t.global\t%s__stack_check\n",idprefix);
+  while(p=firstfpc){
+    if(f){
+      if(POWEROPEN&&!use_sd(p->typ)){
+        emit(f,tocname);
+        emit(f,"%s%s%ld:\n",tocprefix,labprefix,zm2l(p->label));
+        emit(f,"\t.long\t%s%ld\n",labprefix,zm2l(p->label));
+        if(f) section=TOC;
+      }
+      if(use_sd(p->typ)){
+	if(EABI){
+	  if(section!=SDATA2){emit(f,sdata2name);if(f) section=SDATA2;}
+	}else{
+	  if(section!=TOC){emit(f,tocname);if(f) section=TOC;}
+	}
+      }else{
+        if(section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      }
+      if((p->typ&NQ)==DOUBLE)
+        emit(f,"\t.align\t3\n");
+      else
+        emit(f,"\t.align\t2\n");
+      emit(f,"%s%d:\n\t.long\t",labprefix,p->label);
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((p->typ&NQ)==DOUBLE){
+        emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+}
+void cleanup_db(FILE *f)
+{
+  dwarf2_cleanup(f);
+  if(f) section=-1;
+}
+/* mark instructions which can (probably) be implemented with faster
+   machine-code than the IC migh suggest, e.g. an addition which can
+   be merged with a load bz use of target addressing-modes;
+   the optimizer should hesitate to modifz such instructions if it's not
+   a definite win */
+
+static int is_single_eff_ic(struct IC *p)
+{
+  struct Var *v;
+  if(p->code!=ADDI2P&&p->code!=SUBIFP)
+    return 0;
+  if(!(p->q2.flags&KONST)){
+    if(CONSERVATIVE_SR){
+      if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+	return 0;
+      if(p->q2.v->storage_class==STATIC||p->q2.v->storage_class==EXTERN)
+	return 0;
+    }else
+      return 0;
+  }
+  if((p->q1.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)
+    return 0;
+  if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+    return 0;
+  if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+    return 0;
+  v=p->z.v;
+  for(p=p->next;p;p=p->next){
+    int c=p->code;
+    if(c==LABEL||(c>=BEQ&&c<=BRA))
+      return 0;
+    if((p->q1.flags&VAR)&&p->q1.v==v){
+      if(p->q1.flags&DREFOBJ)
+	return 1;
+      else
+	return 0;
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==v){
+      if(p->q2.flags&DREFOBJ)
+	return 1;
+      else
+	return 0;
+    }
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->z.flags&DREFOBJ)
+	return 1;
+      else
+	return 0;
+    }
+  }
+}
+void mark_eff_ics(void)
+{
+  struct IC *p;
+  for(p=first_ic;p;p=p->next){
+    if(is_single_eff_ic(p))
+      p->flags|=EFF_IC;
+    else
+      p->flags&=~EFF_IC;
+  }
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[32];
+  char *ret=0;
+
+  if(OLDLIBCALLS) return 0;
+
+  if((t&NQ)==LLONG){
+    ret=fname;
+    if(c==MULT)
+      sprintf(fname,"__mulint64");
+    else if(c==DIV)
+      sprintf(fname,"__div%cint64",(t&UNSIGNED)?'u':'s');
+    else if(c==MOD)
+      sprintf(fname,"__mod%cint64",(t&UNSIGNED)?'u':'s');
+    else if(c==RSHIFT)
+      sprintf(fname,"__rsh%cint64",(t&UNSIGNED)?'u':'s');
+    else if(c==LSHIFT)
+      sprintf(fname,"__lshint64");
+    else
+      ret=0;
+  }
+  return ret;
+}
+
+
+
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
diff --git a/machines/ppc/machine.dt b/machines/ppc/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/ppc/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/ppc/machine.h b/machines/ppc/machine.h
new file mode 100755
index 0000000..f02654c
--- /dev/null
+++ b/machines/ppc/machine.h
@@ -0,0 +1,137 @@
+/*  Example of a code-generator for a PowerPC                       */
+
+#include "dt.h"
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 87
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 30
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  This specifies the largest integer type that can be added to a  */
+/*  pointer.                                                        */
+#define MAXADDI2P LONG
+
+#define HAVE_INT_SIZET 1
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 256
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH 1
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+    unsigned long fregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we have a mark_eff_ics function */
+#define HAVE_TARGET_EFF_IC 1
+
+/* we have register-pairs */
+#define HAVE_REGPAIRS 1
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 12
+
+/* This type will be added to every IC. Can be used by the cg.      */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+  int setcc;
+};
+
+/* OSEK support */
+#define HAVE_OSEK 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* support for variable-length arrays */
+#define ALLOCVLA_REG 4
+#if 0
+#define ALLOCVLA_INLINEASM "\tlwz\t0,0(1)\n"\
+                           "\taddi\t3,3,7\n"\
+                           "\tsrwi\t3,3,3\n"\
+                           "\tslwi\t3,3,3\n"\
+                           "\tneg\t11,3\n"\
+                           "\tsub\t3,1,3\n"\
+                           "\tsubi\t11,11,8\n"\
+                           "\tstwux\t0,1,11"
+#endif
+#define ALLOCVLA_INLINEASM "\tlwz\t0,0(1)\n"\
+                           "\tneg\t3,3\n"\
+                           "\tsrwi\t3,3,3\n"\
+                           "\tslwi\t3,3,3\n"\
+                           "\tstwux\t0,1,3\n"\
+                           "\taddi\t3,1,____fo"
+#define FREEVLA_REG 6
+#define FREEVLA_INLINEASM "\tlwz\t0,0(1)\n"\
+                          "\tmr\t1,5\n"\
+                          "\tstw\t0,0(1)"
+#define OLDSPVLA_INLINEASM "\tmr\t3,1"
+#define FPVLA_REG 32
diff --git a/machines/ppc/schedule.c b/machines/ppc/schedule.c
new file mode 100755
index 0000000..e7172d3
--- /dev/null
+++ b/machines/ppc/schedule.c
@@ -0,0 +1,1158 @@
+/*
+ * vscppc
+ *
+ * vbcc PowerPC scheduler
+ * (C)1998-2001 by Frank Wille <frank@phoenix.owl.de>
+ *
+ * vscppc is freeware and part of the portable and retargetable ANSI C
+ * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
+ * vscppc may be freely redistributed as long as no modifications are
+ * made and nothing is charged for it. Non-commercial usage is allowed
+ * without any restrictions.
+ * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
+ * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
+ *
+ * History:
+ * V0.5   14-Feb-01
+ *        FSCPR is no longer marked as used/modified, which allows the
+ *        scheduler to rearrange all FPU instructions. As a consequence, the
+ *        only instruction reading FPSCR, mffs, has to be marked as barrier.
+ * V0.4   01-Dec-99
+ *        603e PID7 seems to have a latency of 20 instead 37 for
+ *        the "div" instruction (source: Michal Bartczak).
+ * V0.3b  30-Jul-98
+ *        crxxx instructions used/modified wrong CCRs.
+ * V0.3a  21-Jul-98
+ *        "la" instruction was not recognized.
+ * V0.3   20-Jul-98
+ *        Target-specific options via sched_option() removed. Options
+ *        are passed in the assembler source, e.g. "#vsc elf".
+ *        Differentiation between 603 and 604 (selected by "#vsc cpu").
+ *        Now, scheduling takes place with regard to the real PowerPC
+ *        architecture.
+ * V0.2   12-Jul-98
+
+ *        Option "-elf" lets the scheduler accept ELF/SVR4 sources,
+ *        which only use numbers instead of full register names.
+ *        Target-specific options require a modification in the
+ *        portable scheduler part vsc.c.
+ * V0.1   10-Jul-98
+ *        vscppc seems to be stable, after some tests.
+ *        However, it still needs a lot of fine tuning (my PowerPC
+ *        docs are at home).
+ *        A differentiation between the PPC CPUs (603e, 604e) is missing.
+ * V0.0   09-Jul-98
+ *        File created.
+ *
+ */
+
+#include "vsc.h"
+
+char tg_copyright[]="PowerPC scheduler V0.5 (c) in 1998-2001 by Frank Wille";
+
+static int elf=0,cpu=604;
+
+
+
+int sched_init(void)
+{
+  return (1);
+}
+
+
+void sched_cleanup(void)
+{
+}
+
+
+static void sched_option(char *s)
+{
+  if (!strncmp(s,"elf",3)) {
+    elf = 1;
+  }
+  else if (!strncmp(s,"cpu ",4)) {
+    if (!strncmp(s+4,"603",3))
+      cpu = 603;
+    else if (!strncmp(s+4,"604",3))
+      cpu = 604;
+  }
+}
+
+
+static char *strest(char *s,int n)
+/* returns ptr to the last n characters of string s */
+{
+  return (s + strlen(s) - n);
+}
+
+
+static int setlab(struct sinfo *p,char *lab)
+/* check for a valid local label */
+{
+  int i;
+
+  if (sscanf(lab,elf?".l%d":"l%d",&i) == 1) {
+    p->label = i;
+    return (1);
+  }
+  return (0);
+}
+
+
+static int lsreg(char *s)
+/* checks the operand for load/store addressing mode and returns */
+/* the base register on success, -1 otherwise */
+{
+  char *p = (s+strlen(s))-1;
+  int q;
+
+  while (p>s && *p!='(')
+    --p;
+  if (sscanf(p,elf?"(%d)":"(r%d)",&q) == 1)
+    return (q);
+  return (-1);
+}
+
+
+int sched_info(struct sinfo *p)
+{
+  char buf[16],oper[40],c;
+  int q1,q2,q3,z,i,x,n;
+
+  /* check for vscppc specific options in the source */
+  if (!strncmp(p->txt,"#vsc ",5)) {
+    sched_option(p->txt+5);
+    p->flags = BARRIER;
+    return (1);
+  }
+
+  if (!strncmp(p->txt,"#barrier",8)) {
+    /* an artificial barrier, used e.g. for inline-code */
+    p->flags = BARRIER;
+    return (1);
+  }
+
+  if (sscanf(p->txt," .%15s %39s",buf,oper) >= 1) {
+    /* assembler directive or macro */
+    p->flags = BARRIER;
+    return (1);
+  }
+
+  if (sscanf(p->txt,elf?".l%d:":"l%d:",&i) == 1) {
+    /* a local label */
+    p->label = i;
+    p->flags = LABEL;
+    return (1);
+  }
+
+  if (sscanf(p->txt," mffs%15s %39s",buf,oper) >= 1) {
+    /* mffs reads FPSCR and therefore has to be treated as a barrier, */
+    /* because FPSCR is never marked as used by the scheduler */
+    p->flags = BARRIER;
+    return (1);
+  }
+
+  if ((n = sscanf(p->txt," b%15s %39s",buf,oper)) >= 1) {
+    /* branch instruction */
+    p->latency = 1;
+    BSET(p->pipes,BPU);
+
+    if (n == 1) {
+      /* branch unconditional: b label */
+      if (setlab(p,buf)) {
+        p->flags = UNCOND_BRANCH;
+        return (1);
+      }
+    }
+    else {
+      char *a = strest(buf,3);
+
+      /* reject branch instructions ending with */
+      /* "lr", "ctr", "a" or "l", but accept "bnl" */
+      if ((strncmp(a+1,"lr",2) && strncmp(a,"ctr",3) &&
+           *(a+2)!='l' && *(a+2)!='a') ||
+          !strcmp(buf,"nl")) {
+
+        if (*buf == 'd') {
+          /* bdz... or bdnz... */
+          a = oper;
+          if (strcmp(buf,"dz") && strcmp(buf,"dnz")) {
+            while (*a && *a!=',')
+              a++;
+            if (*a == ',')
+              a++;
+            else
+              a = 0;
+          }
+          if (a) {
+            if (setlab(p,a)) {
+              p->flags = COND_BRANCH;
+              BSET(p->modifies,CTR);
+              /* @@@ unable to determine the used CCRs - set all to used */
+              for (x=CCR; x<(CCR+8); x++)
+                BSET(p->uses,x);
+              return (1);
+            }
+          }
+        }
+
+        else if (*buf == 'c') {
+          if (sscanf(oper,"%d,%d,%s",&q1,&q2,buf) == 3) {
+            /* conditional branch: bc m,n,label */
+            if (setlab(p,buf)) {
+              p->flags = COND_BRANCH;
+              BSET(p->uses,CCR+(q2>>2));
+              return (1);
+            }
+          }
+        }
+
+        else {
+          /* normal conditional branch: b<cond> [crN,]label */
+          a = buf;
+          if (sscanf(oper,elf?"%d,%s":"cr%d,%s",&i,buf) != 2) {
+            i = 0;
+            a = oper;
+          }
+          if (setlab(p,a)) {
+            p->flags = COND_BRANCH;
+            BSET(p->uses,CCR+i);
+            return (1);
+          }
+        }
+      }
+    }
+
+    p->flags = BARRIER;
+    return (1);
+  }
+
+
+  if (cpu == 603) {
+    /* scheduling for the PowerPC 603 */
+
+    if ((!elf && sscanf(p->txt," %15s %c%d,%39s",buf,&c,&z,oper) == 4) ||
+        (elf && sscanf(p->txt," %15s %d,%39s",buf,&z,oper) == 3)) {
+      if (elf) {
+        if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+          c = 'f';
+        else
+          c = 'r';
+      }
+      if ((q1 = lsreg(oper))>=0 && (c=='r'||c=='f')) {
+        /* load/store instruction ...,d(rQ1) */
+
+        if (!strcmp(buf,"la")) {
+          /* la rZ,d(rQ1) is the same as: addi rZ,rQ1,d */
+          p->latency = 1;
+          BSET(p->pipes,IU);
+          BSET(p->pipes,SRU);  /* addi may also execute in SRU */
+          BSET(p->uses,GPR+q1);
+          BSET(p->modifies,GPR+z);
+          return (1);
+        }
+
+        BSET(p->pipes,LSU);
+        if (*(strest(buf,1)) == 'u')  /* update instruction? */
+          BSET(p->modifies,GPR+q1);
+        else
+          BSET(p->uses,GPR+q1);
+
+        if (c == 'r') {
+          /* integer load/store */
+
+          if (!strncmp(strest(buf,2),"mw",2)) {
+            /* load/store multiple word rz,i(rq1) */
+
+            if (*buf == 'l') {
+              p->latency = 2+(32-z);
+              for (x=z; x<32; x++)
+                BSET(p->modifies,GPR+x);
+              BSET(p->uses,MEM);
+            }
+            else {
+              p->latency = 1+(32-z);
+              for (x=z; x<32; x++)
+                BSET(p->uses,GPR+x);
+              BSET(p->modifies,MEM);
+            }
+          }
+          else {
+            /* load/store integer rz,i(rq1) */
+
+            p->latency = 3;
+            if(*buf == 'l') {
+              BSET(p->modifies,GPR+z);
+              BSET(p->uses,MEM);
+            }
+            else{
+              BSET(p->uses,GPR+z);
+              BSET(p->modifies,MEM);
+            }
+          }
+        }
+
+        else {
+          /* load/store float fz,d(rQ1) */
+
+          p->latency = 3;
+          if(*buf == 'l') {
+            BSET(p->modifies,FPR+z);
+            BSET(p->uses,MEM);
+          }
+          else{
+            BSET(p->uses,FPR+z);
+            BSET(p->modifies,MEM);
+          }
+        }
+
+        return (1);
+      }
+    }
+
+    if ((!elf && sscanf(p->txt," %15s %c%d,r%d,r%d",buf,&c,&z,&q1,&q2) == 5) ||
+        (elf && sscanf(p->txt," %15s %d,%d,%d",buf,&z,&q1,&q2) == 4)) {
+      if (*buf=='l' || (buf[0]=='s' && buf[1]=='t')) {
+        if (elf) {
+          if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+            c = 'f';
+          else
+            c = 'r';
+        }
+
+        BSET(p->pipes,LSU);
+        BSET(p->uses,GPR+q2);
+        if (!strncmp(strest(buf,2),"ux",2))  /* update instruction? */
+          BSET(p->modifies,GPR+q1);
+        else
+          BSET(p->uses,GPR+q1);
+
+        if (c == 'r') {
+          /* integer load/store */
+
+          if (!strncmp(buf,"lsw",3) || !strncmp(buf,"stsw",4)) {
+            /* load/store string word rz,rq1,rq2/imm */
+            p->flags = BARRIER;  /* too complex... ;) */
+            return (1);
+          }
+          else {
+            /* load/store integer indexed rz,rq1,rq2 */
+
+            p->latency = 3;
+            if(*buf == 'l') {
+              BSET(p->modifies,GPR+z);
+              BSET(p->uses,MEM);
+            }
+            else{
+              if (!strcmp(buf,"stwcx."))
+                p->latency = 8;
+              BSET(p->uses,GPR+z);
+              BSET(p->modifies,MEM);
+            }
+            return (1);
+          }
+        }
+
+        else if (c == 'f') {
+          /* load/store float indexed fz,rq1,rq2 */
+          p->latency = 3;
+          if(*buf == 'l') {
+            BSET(p->modifies,FPR+z);
+            BSET(p->uses,MEM);
+          }
+          else{
+            BSET(p->uses,FPR+z);
+            BSET(p->modifies,MEM);
+          }
+          return (1);
+        }
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " fcm%15s %d,%d,%d" : " fcm%15s cr%d,f%d,f%d",
+               buf,&z,&q1,&q2) == 4) {
+      /* floating point compare CR0 */
+      p->latency = 3;
+      BSET(p->pipes,FPU);
+      BSET(p->modifies,CCR+z);
+      /*BSET(p->modifies,FPSCR);*/
+      BSET(p->uses,FPR+q1);
+      BSET(p->uses,FPR+q2);
+      return (1);
+    }
+    if (sscanf(p->txt,elf ? " fcm%15s %d,%d" : " fcm%15s f%d,f%d",
+               buf,&q1,&q2) == 3) {
+      /* floating point compare */
+      p->latency = 3;
+      BSET(p->pipes,FPU);
+      BSET(p->modifies,CCR);
+      /*BSET(p->modifies,FPSCR);*/
+      BSET(p->uses,FPR+q1);
+      BSET(p->uses,FPR+q2);
+      return (1);
+    }
+
+    if ((n = sscanf(p->txt,elf ? " f%15s %d,%d,%d,%d" :
+                    " f%15s f%d,f%d,f%d,f%d",buf,&z,&q1,&q2,&q3))>=3) {
+      /* floating point operation with 2, 3 or 4 operands */
+
+#if 0
+      if (strncmp(buf,"abs",3) &&
+          strncmp(buf,"mr",2) &&
+          strncmp(buf,"nabs",4) &&
+          strncmp(buf,"neg",3) &&
+          strncmp(buf,"sel",3))
+        BSET(p->modifies,FPSCR);  /* only some instr. don't alter FPSCR */
+#endif
+
+      if (!strncmp(buf,"divs",4) ||
+          !strncmp(buf,"res",3))
+        p->latency = 18;
+      else if (!strncmp(buf,"div",3))
+        p->latency = 33;
+      else if (!strncmp(buf,"mul",3) ||
+               !strncmp(buf,"madd",4) ||
+               !strncmp(buf,"msub",4) ||
+               !strncmp(buf,"nmadd",5) ||
+               !strncmp(buf,"nmsub",5))
+        p->latency = 4;
+      else
+        p->latency = 3;
+
+      if (*(strest(buf,1)) == '.')
+        BSET(p->modifies,CCR+1);
+      BSET(p->pipes,FPU);
+      BSET(p->uses,FPR+q1);
+      if (n >= 4) {
+        BSET(p->uses,FPR+q2);
+        if (n == 5)
+          BSET(p->uses,FPR+q3);
+      }
+      BSET(p->modifies,FPR+z);
+      return (1);
+    }
+
+    if (sscanf(p->txt,elf ? " cm%15s %d,%d,%d" : " cm%15s cr%d,r%d,r%d",
+        buf,&z,&q1,&q2) == 4) {
+      /* integer compare instruction */
+      p->latency = 1;
+      BSET(p->pipes,IU);
+      BSET(p->pipes,SRU);
+      BSET(p->modifies,CCR+z);
+      BSET(p->uses,GPR+q1);
+      if (*(strest(buf,1)) != 'i')
+        BSET(p->uses,GPR+q2);
+      return (1);
+    }
+    if (sscanf(p->txt,elf ? " cm%15s %d,%d" : " cm%15s r%d,r%d",
+        buf,&q1,&q2) == 3) {
+      /* integer compare instruction CR0 */
+      p->latency = 1;
+      BSET(p->pipes,IU);
+      BSET(p->pipes,SRU);
+      BSET(p->modifies,CCR);
+      BSET(p->uses,GPR+q1);
+      if (*(strest(buf,1)) != 'i')
+        BSET(p->uses,GPR+q2);
+      return (1);
+    }
+
+    if (!elf) {
+      if (sscanf(p->txt," cm%15s cr%d,r%d,%d",buf,&z,&q1,&i) == 4) {
+        /* immediate integer compare instruction */
+        p->latency = 1;
+        BSET(p->pipes,IU);
+        BSET(p->pipes,SRU);
+        BSET(p->modifies,CCR+z);
+        BSET(p->uses,GPR+q1);
+        return (1);
+      }
+      if (sscanf(p->txt," cm%15s r%d,%d",buf,&q1,&i) == 3) {
+        /* immediate integer compare instruction CR0 */
+        p->latency = 1;
+        BSET(p->pipes,IU);
+        BSET(p->pipes,SRU);
+        BSET(p->modifies,CCR+z);
+        BSET(p->uses,GPR+q1);
+        return (1);
+      }
+    }
+
+    if ((n = sscanf(p->txt," cr%15s %d,%d,%d",buf,&z,&q1,&q2)) >= 2) {
+      /* condition code register operation (vbcc uses this version) */
+      p->latency = 1;
+      BSET(p->pipes,SRU);
+      BSET(p->modifies,CCR+(z>>4));
+      if (n >= 3) {
+        BSET(p->uses,CCR+(q1>>4));
+        if (n == 4)
+          BSET(p->uses,CCR+(q2>>4));
+      }
+      return (1);
+    }
+
+    if (sscanf(p->txt,elf ? " rlw%15s %d,%d,%d,%d,%d" :
+               " rlw%15s r%d,r%d,%d,%d,%d",buf,&z,&q1,&i,&n,&x) == 6) {
+      /* rotate left: rlwimi, rlwinm, rlwnm r1,r2,x,y,z */
+      p->latency = 1;
+      BSET(p->pipes,IU);
+      if (*(strest(buf,1)) == '.')
+        BSET(p->modifies,CCR);
+      BSET(p->uses,GPR+q1);
+      BSET(p->modifies,GPR+z);
+      return (1);
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,%d,%c" : " %15s r%d,r%d,%c",
+        buf,&z,&q1,&c) == 4) {
+      /* op r1,r2,imm */
+      if (!strncmp(buf,"addi",4) ||
+          !strncmp(buf,"andi",4) ||
+          !strncmp(buf,"mulli",5) ||
+          !strncmp(buf,"ori",3) ||
+          !strncmp(buf,"slwi",4) ||
+          !strncmp(buf,"srwi",4) ||
+          !strncmp(buf,"srawi",5) ||
+          !strncmp(buf,"subi",4) ||
+          !strncmp(buf,"xori",4)) {
+        char *a = strest(buf,1);
+
+        if (*buf == 'm')  /* mulli */
+          p->latency = 3;
+        else
+          p->latency = 1;
+        BSET(p->pipes,IU);
+        if (!strncmp(buf,"add",3) && *(buf+4)!='c')
+          BSET(p->pipes,SRU);  /* addi/addis may also execute in SRU */
+        if (*a == '.') {
+          BSET(p->modifies,CCR);
+          --a;
+        }
+        if (*a == 'c')
+          BSET(p->modifies,XER);
+        BSET(p->uses,GPR+q1);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,0,%d" : " %15s r%d,0,r%d",
+        buf,&z,&q2) == 3) {
+      /* op r1,0,r3 */
+      if (!strncmp(buf,"add",3) ||
+          !strncmp(buf,"sub",3)) {
+        p->latency = 1;
+        BSET(p->pipes,IU);
+        if (*(strest(buf,1)) == '.')
+          BSET(p->modifies,CCR);
+        else
+          BSET(p->pipes,SRU);  /* add/addo may also execute in SRU */
+        BSET(p->uses,GPR+q2);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,%d,%d" : " %15s r%d,r%d,r%d",
+        buf,&z,&q1,&q2) == 4) {
+      /* op r1,r2,r3 */
+      if (!strncmp(buf,"add",3) ||
+          !strncmp(buf,"and",3) ||
+          !strncmp(buf,"div",3) ||
+          !strncmp(buf,"eqv",3) ||
+          !strncmp(buf,"mul",3) ||
+          !strncmp(buf,"nand",4) ||
+          !strncmp(buf,"nor",3) ||
+          !strncmp(buf,"or",2) ||
+          !strncmp(buf,"sl",2) ||
+          !strncmp(buf,"sr",2) ||
+          !strncmp(buf,"sub",3) ||
+          !strncmp(buf,"xor",3)) {
+        char *a = strest(buf,1);
+
+        if (!strncmp(buf,"mul",3)) {
+          if (*(buf+5) == 'u')
+            p->latency = 6;  /* mulhwu needs 6 cycles */
+          else
+            p->latency = 5;
+          if (*(buf+3) == 'l')
+            BSET(p->modifies,XER);
+        }
+        else if (!strncmp(buf,"div",3)) {
+/*          p->latency = 37;*/
+          p->latency = 20;  /* 603e has 20 since PID7 */
+          BSET(p->modifies,XER);
+        }
+        else
+          p->latency = 1;
+        BSET(p->pipes,IU);
+        if (!strcmp(buf,"add") || !strcmp(buf,"addo"))
+          BSET(p->pipes,SRU);  /* add/addo may also execute in SRU */
+
+        if (*a == '.') {
+          BSET(p->modifies,CCR);
+          --a;
+        }
+        if (*a == 'o') {
+          BSET(p->modifies,XER);
+          --a;
+        }
+        if (*a == 'c') {
+          BSET(p->modifies,XER);
+          --a;
+        }
+        if (*a == 'e')
+          BSET(p->uses,XER);
+        BSET(p->uses,GPR+q1);
+        BSET(p->uses,GPR+q2);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " l%15s %d,%c" : " l%15s r%d,%c",
+        buf,&z,&c) == 3) {
+      if (*buf == 'i') {
+        /* li, lis -> addi, addis */
+        p->latency = 1;
+        BSET(p->pipes,IU);
+        BSET(p->pipes,SRU);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,%d" : " %15s r%d,r%d",
+        buf,&z,&q1) == 3) {
+      /* op r1,r2 */
+      if (!strncmp(buf,"add",3) ||
+          !strncmp(buf,"exts",4) ||
+          !strncmp(buf,"mr",2) ||
+          !strncmp(buf,"neg",3) ||
+          !strncmp(buf,"sub",3)) {
+        char *a = strest(buf,1);
+
+        p->latency = 1;
+        if (*buf=='a' || *buf=='s')
+          BSET(p->uses,XER);  /* addme/addze/subfme/subfze/... */
+        BSET(p->pipes,IU);
+        if (*a == '.') {
+          BSET(p->modifies,CCR);
+          --a;
+        }
+        if (*a == 'o') {
+          BSET(p->modifies,XER);
+        }
+        BSET(p->uses,GPR+q1);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf?" m%15s %d":" m%15s r%d",buf,&z) == 2) {
+      /* mtxxx, mfxxx: move from/to special registers */
+      int reg=0;
+  
+      if (!strcmp(&buf[1],"xer"))
+        reg = XER;
+      else if (!strcmp(&buf[1],"ctr"))
+        reg = CTR;
+      else if (!strcmp(&buf[1],"lr"))
+        reg = LR;
+      else if (!strncmp(&buf[1],"fs",2))
+        reg = FPSCR;
+      if (reg) {
+        if (reg == FPSCR) {
+          p->latency = 3;
+          BSET(p->pipes,FPU);
+          /*if (*buf == 'f') {
+            BSET(p->uses,reg);
+            BSET(p->modifies,z);
+          }
+          else {*/
+            BSET(p->uses,z);
+            BSET(p->modifies,reg);
+          /*}*/
+        }
+        else {
+          BSET(p->pipes,SRU);
+          if (*buf == 'f') {
+            p->latency = 1;
+            BSET(p->uses,reg);
+            BSET(p->modifies,z);
+          }
+          else {
+            p->latency = 2;
+            BSET(p->uses,z);
+            BSET(p->modifies,reg);
+          }
+        }
+        return (1);
+      }
+    }
+  }
+
+
+  else if (cpu == 604) {
+    /* scheduling for the PowerPC 604 */
+
+    if ((!elf && sscanf(p->txt," %15s %c%d,%39s",buf,&c,&z,oper) == 4) ||
+        (elf && sscanf(p->txt," %15s %d,%39s",buf,&z,oper) == 3)) {
+      if (elf) {
+        if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+          c = 'f';
+        else
+          c = 'r';
+      }
+      if ((q1 = lsreg(oper))>=0 && (c=='r'||c=='f')) {
+        /* load/store instruction ...,d(rQ1) */
+
+        if (!strcmp(buf,"la")) {
+          /* la rZ,d(rQ1) is the same as: addi rZ,rQ1,d */
+          p->latency = 1;
+          BSET(p->pipes,SCIU1);
+          BSET(p->pipes,SCIU2);
+          BSET(p->uses,GPR+q1);
+          BSET(p->modifies,GPR+z);
+          return (1);
+        }
+
+        BSET(p->pipes,LSU);
+        if (*(strest(buf,1)) == 'u')  /* update instruction? */
+          BSET(p->modifies,GPR+q1);
+        else
+          BSET(p->uses,GPR+q1);
+
+        if (c == 'r') {
+          /* integer load/store */
+
+          if (!strncmp(strest(buf,2),"mw",2)) {
+            /* load/store multiple word rz,i(rq1) */
+
+            p->latency = 2+(32-z);
+            if (*buf == 'l') {
+              for (x=z; x<32; x++)
+                BSET(p->modifies,GPR+x);
+              BSET(p->uses,MEM);
+            }
+            else {
+              for (x=z; x<32; x++)
+                BSET(p->uses,GPR+x);
+              BSET(p->modifies,MEM);
+            }
+          }
+          else {
+            /* load/store integer rz,i(rq1) */
+
+            if(*buf == 'l') {
+              p->latency = 2;
+              BSET(p->modifies,GPR+z);
+              BSET(p->uses,MEM);
+            }
+            else{
+              p->latency = 3;
+              BSET(p->uses,GPR+z);
+              BSET(p->modifies,MEM);
+            }
+          }
+        }
+
+        else {
+          /* load/store float fz,d(rQ1) */
+
+          p->latency = 3;
+          if(*buf == 'l') {
+            BSET(p->modifies,FPR+z);
+            BSET(p->uses,MEM);
+          }
+          else{
+            BSET(p->uses,FPR+z);
+            BSET(p->modifies,MEM);
+          }
+        }
+
+        return (1);
+      }
+    }
+
+    if ((!elf && sscanf(p->txt," %15s %c%d,r%d,r%d",buf,&c,&z,&q1,&q2) == 5) ||
+        (elf && sscanf(p->txt," %15s %d,%d,%d",buf,&z,&q1,&q2) == 4)) {
+      if (*buf=='l' || (buf[0]=='s' && buf[1]=='t')) {
+        if (elf) {
+          if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+            c = 'f';
+          else
+            c = 'r';
+        }
+
+        BSET(p->pipes,LSU);
+        BSET(p->uses,GPR+q2);
+        if (!strncmp(strest(buf,2),"ux",2))  /* update instruction? */
+          BSET(p->modifies,GPR+q1);
+        else
+          BSET(p->uses,GPR+q1);
+
+        if (c == 'r') {
+          /* integer load/store */
+
+          if (!strncmp(buf,"lsw",3) || !strncmp(buf,"stsw",4)) {
+            /* load/store string word rz,rq1,rq2/imm */
+            p->flags = BARRIER;  /* too complex... ;) */
+            return (1);
+          }
+          else {
+            /* load/store integer indexed rz,rq1,rq2 */
+
+            if(*buf == 'l') {
+              p->latency = 2;
+              BSET(p->modifies,GPR+z);
+              BSET(p->uses,MEM);
+            }
+            else{
+              p->latency = 3;
+              BSET(p->uses,GPR+z);
+              BSET(p->modifies,MEM);
+            }
+            return (1);
+          }
+        }
+
+        else if (c == 'f') {
+          /* load/store float indexed fz,rq1,rq2 */
+          p->latency = 3;
+          if(*buf == 'l') {
+            BSET(p->modifies,FPR+z);
+            BSET(p->uses,MEM);
+          }
+          else{
+            BSET(p->uses,FPR+z);
+            BSET(p->modifies,MEM);
+          }
+          return (1);
+        }
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " fcm%15s %d,%d,%d" : " fcm%15s cr%d,f%d,f%d",
+               buf,&z,&q1,&q2) == 4) {
+      /* floating point compare CR0 */
+      p->latency = 3;
+      BSET(p->pipes,FPU);
+      BSET(p->modifies,CCR+z);
+      /*BSET(p->modifies,FPSCR);*/
+      BSET(p->uses,FPR+q1);
+      BSET(p->uses,FPR+q2);
+      return (1);
+    }
+    if (sscanf(p->txt,elf ? " fcm%15s %d,%d" : " fcm%15s f%d,f%d",
+               buf,&q1,&q2) == 3) {
+      /* floating point compare */
+      p->latency = 3;
+      BSET(p->pipes,FPU);
+      BSET(p->modifies,CCR);
+      /*BSET(p->modifies,FPSCR);*/
+      BSET(p->uses,FPR+q1);
+      BSET(p->uses,FPR+q2);
+      return (1);
+    }
+
+    if ((n = sscanf(p->txt,elf ? " f%15s %d,%d,%d,%d" :
+                    " f%15s f%d,f%d,f%d,f%d",buf,&z,&q1,&q2,&q3))>=3) {
+      /* floating point operation with 2, 3 or 4 operands */
+
+#if 0
+      if (strncmp(buf,"abs",3) &&
+          strncmp(buf,"mr",2) &&
+          strncmp(buf,"nabs",4) &&
+          strncmp(buf,"neg",3) &&
+          strncmp(buf,"sel",3))
+        BSET(p->modifies,FPSCR);  /* only some instr. don't alter FPSCR */
+#endif
+
+      if (!strncmp(buf,"divs",4) ||
+          !strncmp(buf,"res",3))
+        p->latency = 18;
+      else if (!strncmp(buf,"div",3))
+        p->latency = 32;
+      else
+        p->latency = 3;
+
+      if (*(strest(buf,1)) == '.')
+        BSET(p->modifies,CCR+1);
+      BSET(p->pipes,FPU);
+      BSET(p->uses,FPR+q1);
+      if (n >= 4) {
+        BSET(p->uses,FPR+q2);
+        if (n == 5)
+          BSET(p->uses,FPR+q3);
+      }
+      BSET(p->modifies,FPR+z);
+      return (1);
+    }
+
+    if (sscanf(p->txt,elf ? " cm%15s %d,%d,%d" : " cm%15s cr%d,r%d,r%d",
+        buf,&z,&q1,&q2) == 4) {
+      /* integer compare instruction */
+      p->latency = 1;
+      BSET(p->pipes,SCIU1);
+      BSET(p->pipes,SCIU2);
+      BSET(p->modifies,CCR+z);
+      BSET(p->uses,GPR+q1);
+      if (*(strest(buf,1)) != 'i')
+        BSET(p->uses,GPR+q2);
+      return (1);
+    }
+    if (sscanf(p->txt,elf ? " cm%15s %d,%d" : " cm%15s r%d,r%d",
+        buf,&q1,&q2) == 3) {
+      /* integer compare instruction CR0 */
+      p->latency = 1;
+      BSET(p->pipes,SCIU1);
+      BSET(p->pipes,SCIU2);
+      BSET(p->modifies,CCR);
+      BSET(p->uses,GPR+q1);
+      if (*(strest(buf,1)) != 'i')
+        BSET(p->uses,GPR+q2);
+      return (1);
+    }
+
+    if (!elf) {
+      if (sscanf(p->txt," cm%15s cr%d,r%d,%d",buf,&z,&q1,&i) == 4) {
+        /* immediate integer compare instruction */
+        p->latency = 1;
+        BSET(p->pipes,SCIU1);
+        BSET(p->pipes,SCIU2);
+        BSET(p->modifies,CCR+z);
+        BSET(p->uses,GPR+q1);
+        return (1);
+      }
+      if (sscanf(p->txt," cm%15s r%d,%d",buf,&q1,&i) == 3) {
+        /* immediate integer compare instruction CR0 */
+        p->latency = 1;
+        BSET(p->pipes,SCIU1);
+        BSET(p->pipes,SCIU2);
+        BSET(p->modifies,CCR+z);
+        BSET(p->uses,GPR+q1);
+
+        return (1);
+      }
+    }
+
+    if ((n = sscanf(p->txt," cr%15s %d,%d,%d",buf,&z,&q1,&q2)) >= 2) {
+      /* condition code register operation (vbcc uses this version) */
+      p->latency = 1;
+      BSET(p->pipes,CRU);
+      BSET(p->modifies,CCR+(z>>4));
+      if (n >= 3) {
+        BSET(p->uses,CCR+(q1>>4));
+        if (n == 4)
+          BSET(p->uses,CCR+(q2>>4));
+      }
+      return (1);
+    }
+
+    if (sscanf(p->txt,elf ? " rlw%15s %d,%d,%d,%d,%d" :
+               " rlw%15s r%d,r%d,%d,%d,%d",buf,&z,&q1,&i,&n,&x) == 6) {
+      /* rotate left: rlwimi, rlwinm, rlwnm r1,r2,x,y,z */
+      p->latency = 1;
+      BSET(p->pipes,SCIU1);
+      BSET(p->pipes,SCIU2);
+      if (*(strest(buf,1)) == '.')
+        BSET(p->modifies,CCR);
+      BSET(p->uses,GPR+q1);
+      BSET(p->modifies,GPR+z);
+      return (1);
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,%d,%c" : " %15s r%d,r%d,%c",
+        buf,&z,&q1,&c) == 4) {
+      /* op r1,r2,imm */
+      if (!strncmp(buf,"addi",4) ||
+          !strncmp(buf,"andi",4) ||
+          !strncmp(buf,"mulli",5) ||
+          !strncmp(buf,"ori",3) ||
+          !strncmp(buf,"slwi",4) ||
+          !strncmp(buf,"srwi",4) ||
+          !strncmp(buf,"srawi",5) ||
+          !strncmp(buf,"subi",4) ||
+          !strncmp(buf,"xori",4)) {
+        char *a = strest(buf,1);
+
+        if (*buf == 'm') { /* mulli */
+          p->latency = 3;
+          BSET(p->pipes,MCIU);
+        }
+        else {
+          p->latency = 1;
+          BSET(p->pipes,SCIU1);
+          BSET(p->pipes,SCIU2);
+        }
+        if (*a == '.') {
+          BSET(p->modifies,CCR);
+          --a;
+        }
+        if (*a == 'c')
+          BSET(p->modifies,XER);
+        BSET(p->uses,GPR+q1);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,0,%d" : " %15s r%d,0,r%d",
+        buf,&z,&q2) == 3) {
+      /* op r1,0,r3 */
+      if (!strncmp(buf,"add",3) ||
+          !strncmp(buf,"sub",3)) {
+        p->latency = 1;
+        BSET(p->pipes,SCIU1);
+        BSET(p->pipes,SCIU2);
+        if (*(strest(buf,1)) == '.')
+          BSET(p->modifies,CCR);
+        else
+          BSET(p->pipes,SRU);  /* add/addo may also execute in SRU */
+        BSET(p->uses,GPR+q2);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,%d,%d" : " %15s r%d,r%d,r%d",
+        buf,&z,&q1,&q2) == 4) {
+      /* op r1,r2,r3 */
+      if (!strncmp(buf,"add",3) ||
+          !strncmp(buf,"and",3) ||
+          !strncmp(buf,"div",3) ||
+          !strncmp(buf,"eqv",3) ||
+          !strncmp(buf,"mul",3) ||
+          !strncmp(buf,"nand",4) ||
+          !strncmp(buf,"nor",3) ||
+          !strncmp(buf,"or",2) ||
+          !strncmp(buf,"sl",2) ||
+          !strncmp(buf,"sr",2) ||
+          !strncmp(buf,"sub",3) ||
+          !strncmp(buf,"xor",3)) {
+        char *a = strest(buf,1);
+
+        if (!strncmp(buf,"mul",3)) {
+          p->latency = 4;
+          BSET(p->pipes,MCIU);
+          if (*(buf+3) == 'l')
+            BSET(p->modifies,XER);
+        }
+        else if (!strncmp(buf,"div",3)) {
+          p->latency = 20;
+          BSET(p->pipes,MCIU);
+          BSET(p->modifies,XER);
+        }
+        else {
+          p->latency = 1;
+          BSET(p->pipes,SCIU1);
+          BSET(p->pipes,SCIU2);
+        }
+        if (*a == '.') {
+          BSET(p->modifies,CCR);
+          --a;
+        }
+        if (*a == 'o') {
+          BSET(p->modifies,XER);
+          --a;
+        }
+        if (*a == 'c') {
+          BSET(p->modifies,XER);
+          --a;
+        }
+        if (*a == 'e')
+          BSET(p->uses,XER);
+        BSET(p->uses,GPR+q1);
+        BSET(p->uses,GPR+q2);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " l%15s %d,%c" : " l%15s r%d,%c",
+        buf,&z,&c) == 3) {
+      if (*buf == 'i') {
+        /* li, lis -> addi, addis */
+        p->latency = 1;
+        BSET(p->pipes,SCIU1);
+        BSET(p->pipes,SCIU2);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf ? " %15s %d,%d" : " %15s r%d,r%d",
+        buf,&z,&q1) == 3) {
+      /* op r1,r2 */
+      if (!strncmp(buf,"add",3) ||
+          !strncmp(buf,"exts",4) ||
+          !strncmp(buf,"mr",2) ||
+          !strncmp(buf,"neg",3) ||
+          !strncmp(buf,"sub",3)) {
+        char *a = strest(buf,1);
+
+        p->latency = 1;
+        BSET(p->pipes,SCIU1);
+        BSET(p->pipes,SCIU2);
+        if (*buf=='a' || *buf=='s')
+          BSET(p->uses,XER);  /* addme/addze/subfme/subfze/... */
+        if (*a == '.') {
+          BSET(p->modifies,CCR);
+          --a;
+        }
+        if (*a == 'o') {
+          BSET(p->modifies,XER);
+        }
+        BSET(p->uses,GPR+q1);
+        BSET(p->modifies,GPR+z);
+        return (1);
+      }
+    }
+
+    if (sscanf(p->txt,elf?" m%15s %d":" m%15s r%d",buf,&z) == 2) {
+      /* mtxxx, mfxxx: move from/to special registers */
+      int reg=0;
+  
+      if (!strcmp(&buf[1],"xer"))
+        reg = XER;
+      else if (!strcmp(&buf[1],"ctr"))
+        reg = CTR;
+      else if (!strcmp(&buf[1],"lr"))
+        reg = LR;
+      else if (!strncmp(&buf[1],"fs",2))
+        reg = FPSCR;
+      if (reg) {
+        if (reg == FPSCR) {
+          p->latency = 3;
+          BSET(p->pipes,FPU);
+          /*if (*buf == 'f') {
+            BSET(p->uses,reg);
+            BSET(p->modifies,z);
+          }
+          else {*/
+            BSET(p->uses,z);
+            BSET(p->modifies,reg);
+          /*}*/
+        }
+        else {
+          BSET(p->pipes,MCIU);
+          if (*buf == 'f') {
+            p->latency = 3;
+            BSET(p->uses,reg);
+            BSET(p->modifies,z);
+          }
+          else {
+            p->latency = 1;
+            BSET(p->uses,z);
+            BSET(p->modifies,reg);
+          }
+        }
+        return (1);
+      }
+    }
+  }
+
+  p->flags = BARRIER;
+  return (1);
+}
diff --git a/machines/ppc/schedule.h b/machines/ppc/schedule.h
new file mode 100755
index 0000000..9d6fba8
--- /dev/null
+++ b/machines/ppc/schedule.h
@@ -0,0 +1,53 @@
+/*
+ * vscppc
+ *
+ * vbcc PowerPC scheduler
+ * (C)1998 by Frank Wille <frank@phoenix.owl.de>
+ *
+ * vscppc is freeware and part of the portable and retargetable ANSI C
+ * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
+ * vscppc may be freely redistributed as long as no modifications are
+ * made and nothing is charged for it. Non-commercial usage is allowed
+ * without any restrictions.
+ * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
+ * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
+ *
+ * History:
+ * V0.3   20-Jul-98
+ *        Differentiation between 603 and 604. Now, scheduling takes
+ *        place with regard to the real PowerPC architecture.
+ * V0.1   10-Jul-98
+ *        vscppc seems to be stable enough, after some tests.
+ *        However, it still needs a lot of fine tuning.
+ *        A differentiation between the PPC CPUs (603e, 604e) is missing.
+ * V0.0   09-Jul-98
+ *        File created.
+ *
+ */
+
+#define PIPES 7   /* the max. number of pipes, as required by the 604 */
+
+/* Pipe Names 603 */
+#define BPU 0     /* Branch Prediction Unit */
+#define SRU 1     /* Special Reg. Unit */
+#define IU 2      /* Integer Unit */
+#define FPU 5     /* Floating Point Unit */
+#define LSU 6     /* Load Store Unit */
+
+/* Pipe Names 604 */
+#define CRU 1     /* Condition Register Unit */
+#define SCIU1 2   /* Single Cycle Integer Unit #1 */
+#define SCIU2 3   /* Single Cycle Integer Unit #2 */
+#define MCIU 4    /* Multiple Cycle Integer Unit */
+
+
+#define REGS 76   /* 32 GPR, 32 FPR, 8 CCR, LR, CTR, XER, FPSCR */
+
+/* REG-offsets */
+#define GPR 0
+#define FPR 32
+#define CCR 64
+#define XER 72
+#define CTR 73
+#define LR 74
+#define FPSCR 75
diff --git a/machines/qnice/machine.c b/machines/qnice/machine.c
new file mode 100755
index 0000000..b919925
--- /dev/null
+++ b/machines/qnice/machine.c
@@ -0,0 +1,2412 @@
+/*  Code generator for qnice cpu.               */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for qnice V0.1 (c) in 2016 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,0,0,0,
+                    0,0,0,0,
+                    0,VALFLAG};
+char *g_flags_name[MAXGF]={"cpu","int32","no-delayed-popping","const-in-data",
+                           "merge-constants","no-peephole","mtiny","mlarge",
+                           "mhuge","rw-threshold","soft-mul"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+		 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+		 "array","struct","union","enum","function"};
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[]={"noreg","R0","R1","R2","R3","R4","R5","R6","R7",
+		  "R8","R9","R10","R11","R12","R13","R14","R15",
+		  "R0/R1","R2/R3","R4/R5","R6/R7",
+		  "R8/R9","R11/R12"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1};
+
+int reg_prio[MAXR+1]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__rbank","__norbank",0};
+#define INTERRUPT 1
+#define RBANK 2
+#define NORBANK 4
+
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,1,1,2,4,2,4,4,0,1,2,2,0,0,0,1,0,1,1};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define INT32 (g_flags[1]&USEDFLAG)
+#define NOPEEP  (g_flags[5]&USEDFLAG)
+#define TINY  1 /*(g_flags[6]&USEDFLAG)*/
+#define LARGE 0 /*(g_flags[7]&USEDFLAG)*/
+#define HUGE  0 /*(g_flags[8]&USEDFLAG)*/
+#define SOFTMUL  (g_flags[10]&USEDFLAG)
+
+
+#define NDATA 0
+#define NBSS 1
+#define NCDATA 2
+#define FDATA 3
+#define FBSS 4
+#define FCDATA 5
+#define HDATA 6
+#define HBSS 7
+#define HCDATA 8
+#define CODE 9
+#define SPECIAL 10
+#define BITS 11
+
+static int section=-1,newobj,scnt;
+static char *codename="\t.text\n",
+  *ndataname="\t.data\n",
+  *fdataname="\t.data\n",
+  *hdataname="\t.data\n",
+  *nbssname="\t.bss\n",
+  *fbssname="\t.bss\n",
+  *hbssname="\t.bss\n",
+  *ncdataname="\t.text\n",
+  *fcdataname="\t.text\n",
+  *hcdataname="\t.text\n";
+
+#define POST_INC 1
+#define PRE_DEC  2
+
+extern int static_cse, dref_cse;
+
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static const int sp=14,sr=15,pc=16,t1=12,t2=13,MTMP1=22;
+static const int r8=9,r9=10,r8r9=21;
+static int tmp1,tmp2,tmp3,tmp4,t2_used;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+static int scratchreg(int,struct IC *);
+static struct Var nvar,fvar;
+static int load_const;
+static struct IC *icp;
+
+static char *marray[]={0,
+                       "__far=__attr(\"far\")",
+		       "__near=__attr(\"near\")",
+		       "__huge=__attr(\"huge\")",
+                       "__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+		       "__interrupt(x)=__interrupt __vattr(\"ivec(\"__str(x)\")\")",
+		       "__QNICE__",
+		       "__SIZE_T_INT=1",
+		       "__str(x)=#x",
+		       0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static long loff,stack,stackoffset,notpopped,dontpop,maxpushed;
+
+static char *ccs[]={"z","!z","v","!v","??","??"};
+static char *ccu[]={"z","!z","n","!n","??","??"};
+
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"shl","shr","add","sub"};
+
+static char *dct[]={"",".bit",".short",".short",".short",".short",".short",".short",".short",".short",
+		    "(void)",".short",".long",".long"};
+static int pushedsize,pushorder=2;
+static char *idprefix="_",*labprefix="l";
+static int exit_label,have_frame,stackchecklabel,stack_valid;
+static char *ret,*call,*jump;
+static int frame_used;
+static int rwthreshold;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==CHAR||(t&NQ)==NPOINTER)
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+
+static int ISFAR(struct Var *v)
+{
+  struct Typ *vt;
+  if(v==&nvar) return 0;
+  if(v==&fvar) return 1;
+  vt=v->vtyp;
+  while(ISARRAY(vt->flags)) vt=vt->next;
+  if(vt->attr&&strstr(STR_NEAR,vt->attr))
+    return 0;
+  if(HUGE||LARGE)
+    return 1;
+  if(vt->attr&&(strstr(STR_FAR,vt->attr)||strstr(STR_HUGE,vt->attr)))
+    return 1;
+  return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec,*e;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static struct fpconstlist {
+    struct fpconstlist *next;
+    int label,typ;
+    union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+	eval_const(&p->val,t);
+	if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+	if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+	if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+static void callee_push(long push)
+{
+  if(push-stackoffset>stack)
+    stack=push-stackoffset;
+}
+static void push(long push)
+{
+  stackoffset-=push;
+  if(stackoffset<maxpushed) 
+    maxpushed=stackoffset;
+  if(-maxpushed>stack) stack=-maxpushed;
+}
+static void pop(long pop)
+{
+  stackoffset+=pop;
+}
+int pointer_type(struct Typ *p)
+{
+  struct Typ *merk=p;
+  if(!p) ierror(0);
+  while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+  if(p->attr){
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+  }
+  if((merk->flags&NQ)==FUNKT){
+    if(TINY)
+      return NPOINTER;
+    else
+      return HPOINTER;
+  }
+  if(LARGE)
+    return FPOINTER;
+  else if(HUGE)
+    return HPOINTER;
+  else
+    return NPOINTER;
+}
+
+/* return non-zero if IC is implemented by a function call */
+static int islibcall(struct IC *p)
+{
+  /* TODO: check if necessary */
+  return 0;
+}
+
+static long voff(struct obj *p)
+{
+  if(p->v->offset<0)
+    return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+pushedsize;
+  return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
+}
+static int alignment(struct obj *o)
+{
+  if(o->flags&DREFOBJ) return 1;
+  if(!(o->flags&VAR)) ierror(0);
+  if(ISSTATIC(o->v)) return zm2l(o->val.vmax)&1;
+  return voff(o)&1;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/*  output an operand                      */
+{
+  if(p->am){
+    if(p->am->flags==POST_INC){
+      emit(f,"@%s++",regnames[p->am->base]);
+      return;
+    }else if(p->am->flags==PRE_DEC){
+      emit(f,"@--%s",regnames[p->am->base]);
+      return;
+    }else{
+      ierror(0);
+    }
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"@");
+  /*if(p->flags&VARADR) ierror(0);*/
+  if((p->flags&(VAR|REG))==VAR){
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      if(voff(p))
+	emit(f,"@%s+#%ld",regnames[sp],voff(p));
+      else emit(f,"@%s",regnames[sp]);
+    }else{
+      if(p->v->storage_class==STATIC){
+	emit(f,"#%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+	emit(f,"#%s%s",idprefix,p->v->identifier);
+      }
+      if(!zmeqto(l2zm(0L),p->val.vmax))
+	emit(f,"+%ld",(long)zm2l(p->val.vmax)*2);
+    }
+  }
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }
+  /* sometimes we just or a REG into a KONST */
+  if((p->flags&(KONST|REG))==KONST){
+    if(ISFLOAT(t)){
+      ierror(0);
+      emit(f,"#%s%d",labprefix,addfpconst(p,t));
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }
+}
+
+static void emit_lword(FILE *f,struct obj *p,int t,char *def)
+/*  output low-word of an operand */
+{
+  if((p->flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->val,t);
+    if(ISFLOAT(t)){
+      unsigned char *ip=(unsigned char *)&vfloat;
+      emit(f,"0x%02x%02x",ip[1],ip[0]);
+    }else{
+      long v;
+      v=zm2l(vmax);
+      emit(f,"%ld",v&0xffff);
+    }
+    return;
+  }
+  if((p->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(p->reg,&rp))
+      ierror(0);
+    emit(f,"%s",regnames[rp.r1]);
+    return;
+  }
+  if((p->flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+    emit(f,def,regnames[p->reg]);
+    return;
+  }
+  ierror(0);
+}
+
+static void emit_hword(FILE *f,struct obj *p,int t,char *def)
+/*  output high-word of an operand */
+{
+  if((p->flags&(KONST|DREFOBJ))==KONST){
+    eval_const(&p->val,t);
+    if(ISFLOAT(t)){
+      unsigned char *ip=(unsigned char *)&vfloat;
+      emit(f,"0x%02x%02x",ip[3],ip[2]);
+    }else{
+      long v;
+      v=zm2l(vmax);
+      emit(f,"%ld",(v>>16)&0xffff);
+    }
+    return;
+  }
+  if((p->flags&(REG|DREFOBJ))==REG){
+    if(!reg_pair(p->reg,&rp))
+      ierror(0);
+    emit(f,"%s",regnames[rp.r2]);
+    return;
+  }
+  if((p->flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+    emit(f,def,regnames[p->reg]);
+    return;
+  }
+  ierror(0);
+}
+
+static void cleanup_lword(FILE *f,struct obj *p)
+/* cleanup increased address pointers of emit_hlword */
+{
+  if((p->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&!scratchreg(p->reg,icp))
+    emit(f,"\tsub\t2,%s\n",regnames[p->reg]);
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+}
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionskopf                       */
+{
+  int i,rcnt;char *tmp;
+
+  have_frame=0;stack_valid=1;
+  pushedsize=0;
+
+  if(!special_section(f,v)&&section!=CODE){
+    emit(f,codename);
+  }
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier); 
+  }else{
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));  
+  }
+  if(stack_check){
+    stackchecklabel=++label;
+    BSET(regs_modified,t1);
+    emit(f,"\tmov\t%s,#%s%d\n",regnames[t1],labprefix,stackchecklabel);
+    emit(f,"\t%s\t%s__stack_check\n",call,idprefix);/*FIXME:usrstack*/
+  }
+  for(rcnt=0,i=1;i<=16;i++){
+    if(regused[i]&&!regscratch[i]&&!regsa[i])
+      rcnt++;
+  }
+  if(v->tattr&NORBANK) rcnt=0;
+  if(rcnt>((v->tattr&RBANK)?0:rwthreshold)){
+    /*emit(f,"\tadd\t256,%s\n",regnames[sr]);*/
+    emit(f,"\tincrb\n");
+    have_frame=3;
+  }else{
+    for(i=1;i<=16;i++){
+      if(regused[i]&&!regscratch[i]&&!regsa[i]){
+	emit(f,"\tmove\t%s,@--%s\n",regnames[i],regnames[sp]);
+	push(1);
+	have_frame=1;pushedsize+=1;
+      }
+    }
+  }
+  if(offset){
+    emit(f,"\tsub\t%ld,%s\n",offset,regnames[sp]);
+    if(!have_frame) 
+      have_frame|=1;
+  }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionsende                       */
+{
+  int i;
+  if(offset) emit(f,"\tadd\t%ld,%s\n",offset,regnames[sp]);
+  if(have_frame==3){
+    /*emit(f,"\tsub\t256,%s\n",regnames[sr]);*/
+    emit(f,"\tdecrb\n");
+  }else{
+    for(i=16;i>0;i--){
+      if(regused[i]&&!regscratch[i]&&!regsa[i]){
+	emit(f,"\tmove\t@%s++,%s\n",regnames[sp],regnames[i]);
+	pop(1);
+      }
+    }
+  }
+  if(v->tattr&INTERRUPT){
+    emit(f,"\trti\n");
+  }else{
+    if(ret) emit(f,"\t%s\n",ret);
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+    emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+  }else{
+    emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+  }
+  if(stack_check)
+    emit(f,"%s%d\tequ\t%ld\n",labprefix,stackchecklabel,offset+pushedsize-maxpushed);
+  if(stack_valid){
+    long ustack=stack+offset+pushedsize;
+    if(!v->fi) v->fi=new_fi();
+    if(v->fi->flags&ALL_STACK){
+      if(v->fi->stack1!=stack)
+        if(f) error(319,"stack",ustack,v->fi->stack1);
+    }else{
+      v->fi->flags|=ALL_STACK;
+      v->fi->stack1=stack;
+    }
+    emit(f,"\t.equ\t%s__ustack_%s,%ld\n",idprefix,v->identifier,zm2l(v->fi->stack1));
+  }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+    return 1;
+  if((o1->flags&(KONST|VAR|DREFOBJ|REG|VARADR))==(o2->flags&(KONST|VAR|DREFOBJ|REG|VARADR))&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+static void clear_ext_ic(struct ext_ic *p)
+{
+  p->flags=0;
+  p->r=0;
+  p->offset=0;
+}
+
+static void peephole(struct IC *p)
+{
+  int c,c2,r,t;struct IC *p2;
+  struct AddressingMode *am;
+  frame_used=0;
+  for(;p;p=p->next){
+    c=p->code;
+    if(!frame_used){
+      if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+      if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+      if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+    }
+    /* letztes Label merken */
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* [Rx+] in q1 */
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q1.reg; t=q1typ(p);
+      if((!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(zmeqto(vmax,l2zm(1L))&&ISHWORD(t)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q1.am=mymalloc(sizeof(*am));
+	      p->q1.am->flags=POST_INC;
+	      p->q1.am->base=r;
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* [Rx+] in q2 */
+    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q2.reg; t=q2typ(p);
+      if((!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+	  if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(zmeqto(vmax,l2zm(1L))&&ISHWORD(t)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q2.am=mymalloc(sizeof(*am));
+	      p->q2.am->flags=POST_INC;
+	      p->q2.am->base=r;
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* [Rx+] in z */
+    /* currently we do it only if q2 is empty; could be more clever */
+    if(!p->z.am&&!p->q2.flags&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->z.reg; t=ztyp(p);
+      if((!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+	  if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(zmeqto(vmax,l2zm(1L))&&ISHWORD(t)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->z.am=mymalloc(sizeof(*am));
+	      p->z.am->flags=POST_INC;
+	      p->z.am->base=r;
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* --@Rx */
+    if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=16&&isconst(q2)){
+      long sz;
+      r=p->q1.reg;
+      eval_const(&p->q2.val,q2typ(p));
+      sz=zm2l(vmax);
+      if(sz==1){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)&&(c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
+	    t=(q1typ(p2)&NQ);
+	    if((ISINT(t)||ISPOINTER(t))&&ISHWORD(t)&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+	      p2->q1.am=am=mymalloc(sizeof(*am));
+	      p2->q1.val.vmax=l2zm(0L);
+	      am->base=r;
+	      am->flags=PRE_DEC;
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)){
+	    t=(q2typ(p2)&NQ);
+	    if((ISINT(t)||ISPOINTER(t))&&ISHWORD(t)&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+	      p2->q2.am=am=mymalloc(sizeof(*am));
+	      p2->q2.val.vmax=l2zm(0L);
+	      am->base=r;
+	      am->flags=PRE_DEC;
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      break;
+	    }
+	  }
+	  /* currently we do it only if q2 is empty; perhaps be more clever in the future */
+	  if(!p2->z.am&&!p2->q2.flags&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)){
+	    t=(ztyp(p2)&NQ);
+	    if((ISINT(t)||ISPOINTER(t))&&ISHWORD(t)&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+	      p2->z.am=am=mymalloc(sizeof(*am));
+	      p2->z.val.vmax=l2zm(0L);
+	      am->base=r;
+	      am->flags=PRE_DEC;
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      break;
+	    }
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
+	}
+      }
+    }
+  }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/*  Initializes an addressing-mode structure and returns a pointer to   */
+/*  that object. Will not survive a second call!                        */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  return &obj;
+}
+
+
+/* load an operand if necessary, use register r if needed */
+static void load_op(FILE *f,struct obj *o,int t,int r)
+{
+  if(o->am)
+    return;
+
+  if(o->flags&(REG|VARADR))
+    return;
+
+  if(o->flags&KONST){
+    if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+      int l=addfpconst(o,t);
+      emit(f,"\tmove\t%s%d,%s\n",labprefix,l,regnames[r]);
+      o->reg=r;
+      o->flags=REG|DREFOBJ;
+    }else if(load_const||(o->flags&DREFOBJ)){
+      emit(f,"\tmove\t");
+      emit_obj(f,o,t);
+      emit(f,",%s\n",regnames[r]);
+      o->flags|=REG;
+      o->flags&=~KONST;
+    }else
+      return;
+  }else{
+    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+      if(ISHWORD(t)&&voff(o)==0){
+	if(o->flags&DREFOBJ){
+	  emit(f,"\tmove\t@%s,%s\n",regnames[sp],regnames[r]);
+	  o->reg=r;
+	  o->flags|=REG|DREFOBJ;
+	  BSET(regs_modified,r);
+	  return;
+	}else
+	  r=sp;
+      }else{
+	emit(f,"\tmove\t%s,%s\n",regnames[sp],regnames[r]);
+	if(voff(o))
+	  emit(f,"\tadd\t%ld,%s\n",voff(o),regnames[r]);
+      }
+      
+    }else{
+      emit(f,"\tmove\t");
+      emit_obj(f,o,t);
+      emit(f,",%s\n",regnames[r]);
+    }
+    
+    
+    if(o->flags&DREFOBJ){
+      emit(f,"\tmove\t@%s,%s\n",regnames[r],regnames[r]);
+    }
+    
+    o->flags|=REG|DREFOBJ;
+  }
+
+  BSET(regs_modified,r);
+  o->reg=r;
+}
+
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/*  Generates code to move object q (or register qr) into object z (or  */
+/*  register zr). One must be a register and DREFOBJ only allowed with  */
+/*  registers.                                                          */
+{
+  if(q&&z&&compare_objects(q,z))
+    return;
+
+  if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+  if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+
+  if(qr&&qr==zr)
+    return;
+
+
+  if(ISLWORD(t)){
+    if(!qr) load_op(f,q,t,t1);
+    if(!zr) load_op(f,z,t,t2);
+    
+    emit(f,"\tmove\t");
+    if(qr&&reg_pair(qr,&rp))
+      emit(f,"%s",regnames[rp.r1]);
+    else
+      emit_lword(f,q,t,"@%s++");
+    emit(f,",");
+    if(zr&&reg_pair(zr,&rp))
+      emit(f,"%s",regnames[rp.r1]);
+    else
+      emit_lword(f,z,t,"@%s++");
+    emit(f,"\n");
+    emit(f,"\tmove\t");
+    if(qr&&reg_pair(qr,&rp))
+      emit(f,"%s",regnames[rp.r2]);
+    else
+      emit_hword(f,q,t,"@%s++");
+    emit(f,",");
+    if(zr&&reg_pair(zr,&rp))
+      emit(f,"%s",regnames[rp.r2]);
+    else
+      emit_hword(f,z,t,"@%s++");
+    emit(f,"\n");
+    if(!qr) cleanup_lword(f,q);
+    if(!zr) cleanup_lword(f,z);
+    return;
+  }
+
+
+  emit(f,"\tmove\t");
+  if(qr) emit(f,"%s",regnames[qr]); else emit_obj(f,q,t);
+  emit(f,",");
+  if(zr) emit(f,"%s",regnames[zr]); else emit_obj(f,z,t);
+  emit(f,"\n");
+}
+
+static int get_reg(FILE *f,struct IC *p)
+{
+  int i;
+  for(i=1;i<=16;i++){
+    if(!regs[i]&&(regscratch[i]||regused[i])&&!regsa[i]){
+      BSET(regs_modified,i);
+      return i;
+    }
+  }
+  return 0;
+}
+
+
+
+static void save_result(FILE *f,int r,struct IC *p,int t)
+/*  Saves result in register r to object o. May use tp or ti. */ 
+{
+  ierror(0);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+  int c;
+  if(r==t1||r==t2)
+    return 1;
+  while(1){
+    p=p->next;
+    if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+    if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+    if((p->q1.flags&REG)&&p->q1.reg==r) return 0;
+    if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
+    if((p->z.flags&REG)&&p->z.reg==r) return 0;
+  }
+}
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+int emit_peephole(void)
+{
+  int entries,i,r1,r2,r3,r4;long x,y,z;
+  char *asmline[EMIT_BUF_DEPTH];
+  char s1[16],s2[16];
+
+  if(NOPEEP)
+    return 0;
+
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+ 
+  if(entries>=1){
+    if(sscanf(asmline[0],"\tmove\t0,R%d",&r1)==1){
+      sprintf(asmline[0],"\txor\tR%d,R%d\n",r1,r1);
+      return 1;
+    }
+  }
+
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+    if(sscanf(asmline[0],"\t%15s\t%ld,R%d",s1,&x,&r1)==3&&sscanf(asmline[1],"\t%15s\t%ld,R%d",s2,&y,&r2)==3&&r1==r2&&!strcmp(s1,s2)&&(!strcmp(s1,"add")||!strcmp(s1,"sub")||!strcmp(s1,"shl")||!strcmp(s1,"shr"))){
+      sprintf(asmline[1],"\t%s\t%ld,R%d\n",s1,x+y,r1);
+      remove_asm();
+      return 1;
+    }
+    if(sscanf(asmline[0],"\t%15s\t%ld,@R%d",s1,&x,&r1)==3&&sscanf(asmline[1],"\t%15s\t%ld,@R%d",s2,&y,&r2)==3&&r1==r2&&!strcmp(s1,s2)&&(!strcmp(s1,"add")||!strcmp(s1,"sub")||!strcmp(s1,"shl")||!strcmp(s1,"shr"))){
+      sprintf(asmline[1],"\t%s\t%ld,@R%d\n",s1,x+y,r1);
+      remove_asm();
+      return 1;
+    }
+    if(sscanf(asmline[0],"\tmove\tR%d,R%d",&r1,&r2)==2&&sscanf(asmline[1],"\tmove\tR%d,R%d",&r3,&r4)==2&&r1==r4&&r2==r3){
+      remove_asm();
+      return 1;
+    }
+    if(sscanf(asmline[0],"\tshl\t1,R%d",&r1)==1&&!strstr(asmline[0],"shr")){
+      sprintf(asmline[0],"\tadd\tR%d,R%d\n",r1,r1);
+      return 1;
+    }
+  } 
+
+  return 0;
+}
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(1L);
+  stackalign=l2zm(1L);
+  char_bit=l2zm(16L);
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i=1;i<=MAXR;i++){
+    if(i<=16){
+      regsize[i]=l2zm(1L);regtype[i]=&ityp;
+    }else{
+      regsize[i]=l2zm(2L);regtype[i]=&ltyp;
+    }
+  }	
+  
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-32768L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=t_min[SHORT];
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(32767UL);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=t_max[SHORT];
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(65535UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=tu_max[SHORT];
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  regsa[sp]=regsa[sr]=regsa[pc]=regsa[t1]=regsa[t2]=regsa[MTMP1]=1;
+  regscratch[sp]=regscratch[sr]=regscratch[pc]=regscratch[t1]=regscratch[t2]=0;
+  target_macros=marray;
+  if(TINY) marray[0]="__TINY__";
+  else if(LARGE) marray[0]="__LARGE__";
+  else if(HUGE) marray[0]="__HUGE__";
+  else marray[0]="__MEDIUM__";
+
+  /*static_cse=0;*/
+  dref_cse=0;
+
+  if(g_flags[9]&USEDFLAG)
+    rwthreshold=g_flags_val[9].l;
+  else{
+    if(optspeed)
+      rwthreshold=1;
+    else
+      rwthreshold=2;
+  }
+
+  /* TODO: set argument registers */
+  declare_builtin("__mulint32",LONG,LONG,r8r9,LONG,0,1,0);
+  declare_builtin("__divint32",LONG,LONG,r8r9,LONG,0,1,0);
+  declare_builtin("__divuint32",LONG,LONG,r8r9,LONG,0,1,0);
+  declare_builtin("__modint32",LONG,LONG,r8r9,LONG,0,1,0);
+  declare_builtin("__moduint32",LONG,LONG,r8r9,LONG,0,1,0);
+  declare_builtin("__lslint32",LONG,LONG,r8r9,INT,11,1,0);
+  declare_builtin("__lsrint32",LONG,LONG,r8r9,INT,11,1,0);
+  declare_builtin("__lsruint32",LONG,LONG,r8r9,INT,11,1,0);
+
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__sint32toflt32",FLOAT,LONG,r8r9,0,0,1,0);
+  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,r8r9,0,0,1,0);
+  declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
+  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint32",LONG,FLOAT,r8r9,0,0,1,0);
+  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,r8r9,0,0,1,0);
+  declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__sint16toflt32",FLOAT,INT,r8,0,0,1,0);
+  declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,r8,0,0,1,0);
+  declare_builtin("__sint16toflt64",DOUBLE,INT,r9,0,0,1,0);
+  declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,r9,0,0,1,0);
+  declare_builtin("__flt32tosint16",INT,FLOAT,r8r9,0,0,1,0);
+  declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,r8r9,0,0,1,0);
+  declare_builtin("__flt64tosint16",INT,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,0,0,0,1,0);
+
+
+
+
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,r8r9,0,0,1,0);
+  declare_builtin("__cmpsflt32",INT,FLOAT,r8r9,FLOAT,0,1,0);
+
+  declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__negflt64",DOUBLE,DOUBLE,0,0,0,1,0);
+  declare_builtin("__cmpsflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+  return 1;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+  int f=t->flags&NQ;
+  if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+    return 0;
+  if(ISSCALAR(f)){
+    if(f==LONG||f==FPOINTER||f==HPOINTER||f==FLOAT)
+      return r8r9;
+    else
+      return r8;
+  }
+  return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  t&=NQ;
+  if(r==0) return(0);
+  if((t<LONG||t==NPOINTER)&&r<=16) return 1;
+  if(t==LONG||t==FLOAT||t==FPOINTER||t==HPOINTER){
+    if(r>16) return 1;
+  }
+  return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r<=16) return 0;
+  if(p){
+    switch(r){
+    case 17: p->r1=1;p->r2=2;break;
+    case 18: p->r1=3;p->r2=4;break;
+    case 19: p->r1=5;p->r2=6;break;
+    case 20: p->r1=7;p->r2=8;break;
+    case 21: p->r1=9;p->r2=10;break;
+    case 22: p->r1=t1;p->r2=t2;break;
+	
+    default: ierror(0);
+    }
+  }
+  return 1;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if((o->flags&DREFOBJ)){
+    if(o->flags&VKONST) return 1;
+    if(r<=4&&p->q2.flags&&o!=&p->z)
+      return 6;
+    else
+      return 4;
+  }else if(o->flags&VKONST){
+    struct obj *co=&o->v->cobj;
+    if((p->code==ASSIGN&&(p->z.flags&DREFOBJ))||p->code==PUSH)
+      return 4;
+    if(co->flags&VARADR)
+      return 4;
+    if(o==&p->q1)
+      eval_const(&co->val,q1typ(p));
+    else
+      eval_const(&co->val,q2typ(p));
+    /*FIXME*/
+    return 0;
+  }else if(c==GETRETURN&&p->q1.reg==r){
+    return 4;
+  }else if(c==SETRETURN&&p->z.reg==r){
+    return 4;
+  }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&&regok(r,CHAR,0)){
+    return 3;
+  }
+  return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  In this generic 32bit RISC cpu pointers and 32bit   */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if(op==tp) return 0;
+  if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+  if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+  if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  long l=zm2l(size)*2;
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",l);
+  else
+    emit(f,"\t.space\t%ld\n",l);
+  newobj=0; 
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+}
+static void new_section(FILE *f,int nsec)
+{
+  if(!f||section==nsec) return;
+  section=nsec;
+  if(nsec==HDATA){
+    emit(f,hdataname);
+  }else if(nsec==FDATA){
+    emit(f,fdataname);
+  }else if(nsec==NDATA){
+    emit(f,ndataname);
+  }else if(nsec==HCDATA){
+    emit(f,hcdataname);
+  }else if(nsec==FCDATA){
+    emit(f,fcdataname);
+  }else if(nsec==NCDATA){
+    emit(f,ncdataname);
+  }else if(nsec==HBSS){
+    emit(f,hbssname);
+  }else if(nsec==FBSS){
+    emit(f,fbssname);
+  }else if(nsec==NBSS){
+    emit(f,nbssname);
+  }
+}
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  char *attr;struct Typ *tv;
+  tv=v->vtyp;
+  while(tv->flags==ARRAY) tv=tv->next;
+  attr=tv->attr;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp))*2);
+    if(!special_section(f,v)){
+      if((v->vtyp->flags&NQ)==BIT){
+	new_section(f,BITS);
+      }else{
+	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HDATA);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FDATA);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NDATA);
+	  else{
+	    if(HUGE)
+	      new_section(f,HDATA);
+	    else if(LARGE)
+	      new_section(f,FDATA);
+	    else
+	      new_section(f,NDATA);
+	  }
+	}
+	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HCDATA);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FCDATA);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NCDATA);
+	  else{
+	    if(HUGE)
+	      new_section(f,HCDATA);
+	    else if(LARGE)
+	      new_section(f,FCDATA);
+	    else
+	      new_section(f,NCDATA);
+	  }
+	}
+	if(!v->clist){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HBSS);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FBSS);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NBSS);
+	  else{
+	    if(HUGE)
+	      new_section(f,HBSS);
+	    else if(LARGE)
+	      new_section(f,FBSS);
+	    else
+	      new_section(f,NBSS);
+	  }
+	}
+      }
+    }
+    gen_align(f,falign(v->vtyp));
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  }
+
+  if(v->storage_class==EXTERN){
+    if(v->flags&(DEFINED|TENTATIVE)){
+      emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp))*2);
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HDATA);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FDATA);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NDATA);
+	  else{
+	    if(HUGE)
+	      new_section(f,HDATA);
+	    else if(LARGE)
+	      new_section(f,FDATA);
+	    else
+	      new_section(f,NDATA);
+	  }
+	}
+	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HCDATA);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FCDATA);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NCDATA);
+	  else{
+	    if(HUGE)
+	      new_section(f,HCDATA);
+	    else if(LARGE)
+	      new_section(f,FCDATA);
+	    else
+	      new_section(f,NCDATA);
+	  }
+	}
+	if(!v->clist){
+	  if(attr&&strstr(attr,STR_HUGE))
+	    new_section(f,HBSS);
+	  else if(attr&&strstr(attr,STR_FAR))
+	    new_section(f,FBSS);
+	  else if(attr&&strstr(attr,STR_NEAR))
+	    new_section(f,NBSS);
+	  else{
+	    if(HUGE)
+	      new_section(f,HBSS);
+	    else if(LARGE)
+	      new_section(f,FBSS);
+	    else
+	      new_section(f,NBSS);
+	  }
+	}
+      }
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%s:\n",idprefix,v->identifier);
+    }else if(strcmp(v->identifier,"__va_start")){
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if(ISPOINTER(t)){
+    if(p->tree)
+      emit(f,"\t%s\t",dct[t&NQ]); 
+    if(ISLWORD(t))
+      t=UNSIGNED|LONG;
+    else
+      t=UNSIGNED|SHORT;
+    if(!p->tree)
+      emit(f,"\t%s\t",dct[t&NQ]);
+  }else{
+    emit(f,"\t%s\t",dct[t&NQ]);
+  }
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+      if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+      }
+    }else{
+      if(ISLWORD(t)){
+	long l;
+	eval_const(&p->val,t);
+	l=zm2l(zmand(p->val.vmax,l2zm(65535L)));
+	emit(f,"%ld",l);
+	l=zm2l(zmand(zmrshift(p->val.vmax,l2zm(16L)),l2zm(65535L)));
+	emit(f,",%ld",l);
+      }else
+	emitval(f,&p->val,(t&NU)|UNSIGNED);
+    }
+  }else{
+    int m=p->tree->o.flags;
+    p->tree->o.flags&=~VARADR;
+    emit_obj(f,&p->tree->o,t&NU);
+    p->tree->o.flags=m;
+  }
+  emit(f,"\n");
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+  int c,t,lastcomp=0,cmpzero=0,elab=0,reg,short_add,bit_reverse,need_return=0;
+  struct obj *bit_obj;char *bit_reg;
+  static int idone;
+  struct obj o,*cc=0;int cc_t;
+  struct IC *p2;
+  if(TINY){
+    call="asub";
+    jump="abra";
+  }else{
+    call="asub";
+    jump="abra";
+  }
+  if(v->tattr&INTERRUPT){
+    ret="rti";
+    need_return=1;
+  }else
+    ret="move\t@R13++,R15";
+
+  if(DEBUG&1) printf("gen_code()\n");
+  if(!v->fi) v->fi=new_fi();
+  v->fi->flags|=ALL_REGS;
+
+  for(p2=p;p2;p2=p2->next) clear_ext_ic(&p2->ext);
+  if(!(g_flags[5]&USEDFLAG)){
+    peephole(p);
+    if(!frame_used) offset=l2zm(0L);
+  }
+  for(c=1;c<=15;c++) regs[c]=regsa[c];
+  regs[16]=0;
+  for(c=1;c<=MAXR;c++){
+    if(regscratch[c]&&(regsa[c]||regused[c])){
+      BSET(regs_modified,c);
+    }
+  }
+  loff=zm2l(offset);
+  function_top(f,v,loff);
+  stackoffset=notpopped=dontpop=maxpushed=0;
+  stack=0;
+  for(;p;pr(f,p),p=p->next){
+    c=p->code;t=p->typf;
+    t2_used=0; short_add=0;
+    icp=p;
+    if(c==NOP) continue;
+    if(c==ALLOCREG){
+      regs[p->q1.reg]=1;
+      if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=1;
+      BSET(regs_modified,p->q1.reg);
+      continue;
+    }
+    if(c==FREEREG){
+      regs[p->q1.reg]=0;
+      if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=0;
+      continue;
+    }
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+	emit(f,"\tadd\t%ld,%s\n",notpopped,regnames[sp]);
+	pop(notpopped);notpopped=0;cc=0;
+      }
+    }
+    if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(p->typf==exit_label&&!have_frame){
+	emit(f,"\t%s\n",ret);
+      }else{
+	if(t==exit_label) need_return=1;
+	emit(f,"\trbra\t%s%d,1\n",labprefix,t);
+      }
+      cc=0;continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      char *s=0;
+      cc=0;
+      if(cmpzero){
+	cmpzero=0;
+	if(lastcomp&UNSIGNED){
+	  if(c==BLT) continue;
+	  if(c==BGE) s="1";
+	  if(c==BLE) s="z";
+	  if(c==BGT) s="!z";
+	}else{
+	  if(c==BLT) s="n";
+	  if(c==BGE) s="!n";
+	  if(c==BLE) ierror(0);
+	  if(c==BGT) ierror(0);
+	}
+      }
+      if(!s){
+	if(lastcomp&UNSIGNED) s=ccu[c-BEQ]; else s=ccs[c-BEQ];
+      }
+      if(t==exit_label&&!have_frame){
+	emit(f,"\tabra\t@%s++,%s\n",regnames[sp],s);
+      }else{
+	emit(f,"\trbra\t%s%d,%s\n",labprefix,t,s);
+	if(t==exit_label) need_return=1;
+      }
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_op(f,&p->q1,SHORT,t1);
+      if(p->z.reg<=16){
+	move(f,&p->q1,0,0,p->z.reg,SHORT);
+	cc=&p->q1;cc_t=SHORT;
+      }else{
+	move(f,&p->q1,0,0,p->z.reg,LONG);
+	cc=0;
+      }
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      load_op(f,&p->z,SHORT,t2);
+      if(p->q1.reg<=16){
+	move(f,0,p->q1.reg,&p->z,0,SHORT);
+	cc=&p->z;cc_t=SHORT;
+      }else{
+	move(f,0,p->q1.reg,&p->z,0,LONG);
+	cc=0;
+      }
+      continue;
+    }
+    
+    if(c==TEST){
+      /* TODO: optimize in COMPARE? */
+      lastcomp=t;
+      if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+	continue;
+      }
+
+      p->code=c=COMPARE;
+      gval.vmax=l2zm(0L);
+      p->q2.flags=KONST;
+      eval_const(&gval,MAXINT);
+      insert_const(&p->q2.val,t);
+    } 
+    /* switch operands so that we have matching branch */
+    if(c==COMPARE){
+      p2=p->next;
+      while(p2&&p2->code==FREEREG) p2=p2->next;
+      if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+      if(p2->code==BGT){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+	p2->code=BLT;
+      }else if(p2->code==BLE){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+	p2->code=BGE;
+      }
+    }
+
+    if(c==COMPARE&&isconst(q2)){
+      eval_const(&p->q2.val,t);
+      if(ISNULL()){
+	if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+	  p2=p->next;
+	  while(p2&&p2->code==FREEREG) p2=p2->next;
+	  if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+	  if((t&UNSIGNED)||p2->code==BNE||p2->code==BEQ||p2->code==BLT||p2->code==BGE){
+	    lastcomp=t;
+	    cmpzero=1;
+	    continue;
+	  }
+	}
+      }
+    }
+
+    if(c==SUBPFP){
+      p->code=c=SUB;
+      if((p->typf2&NQ)==NPOINTER) p->typf=t=INT;
+      else if((p->typf2&NQ)==HPOINTER) p->typf=t=LONG;
+      else ierror(0);
+      if((p->typf2&NQ)==NPOINTER){
+	cc=&p->z;cc_t=NPOINTER;
+      }else{
+	cc=0;
+      }
+    }
+
+    if(c==ADDI2P||c==SUBIFP){
+      /*if(c==ADDI2P) p->code=c=ADD; else p->code=c=SUB;*/
+      if((p->typf2&NQ)!=HPOINTER){
+	p->typf=t=(UNSIGNED|SHORT);
+	short_add=2;
+	if(isreg(q2)&&reg_pair(p->q2.reg,&rp)){
+	  /*FIXME:warning*/
+	  p->q2.reg=rp.r1;
+	}
+      }else if(ISHWORD(t)){
+	p->typf=t=(UNSIGNED|LONG);
+	short_add=1;
+      }
+      if((p->typf2&NQ)==NPOINTER){
+	cc=&p->z;cc_t=NPOINTER;
+      }else{
+	cc=0;
+      }      
+    }
+
+    if(c==CONVERT&&!must_convert(p->typf,p->typf2,0)){
+      p->code=c=ASSIGN;
+      p->q2.val.vmax=sizetab[p->typf&NQ];
+    }
+
+    if(c==CONVERT){
+      int to=p->typf2&NU;
+      if(to==INT||to==CHAR) to=SHORT;
+      if(to==(UNSIGNED|INT)||to==(UNSIGNED|CHAR)||to==NPOINTER) to=(UNSIGNED|SHORT);
+      if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+      if((t&NU)==INT||(t&NU)==CHAR) t=SHORT;
+      if((t&NU)==(UNSIGNED|INT)||(t&NU)==(UNSIGNED|CHAR)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+      if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+      if((to&NQ)==LONG){
+	if((t&NQ)!=SHORT) ierror(0);
+	load_op(f,&p->q1,to,t1);
+	load_op(f,&p->z,t,t2);
+	if(isreg(q1)){
+	  if(!reg_pair(p->q1.reg,&rp))
+	    ierror(0);
+	  move(f,0,rp.r1,&p->z,0,t);
+	}else
+	  move(f,&p->q1,0,&p->z,0,t);
+	cc=&p->z;cc_t=t;
+	continue;
+      }else if((t&NQ)==LONG){
+	if((to&NQ)!=SHORT) ierror(0);
+	load_op(f,&p->q1,to,t1);
+	load_op(f,&p->z,t,t2);
+	if(isreg(z)){
+	  if(!reg_pair(p->z.reg,&rp))
+	    ierror(0);
+	  emit(f,"\txor\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+	  move(f,&p->q1,0,0,rp.r1,to);
+	  if(!(to&UNSIGNED)){
+	    emit(f,"\trbra\t%s%d,!n\n",labprefix,++label);
+	    emit(f,"\tsub\t1,%s\n",regnames[rp.r2]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }
+	}else{
+	  if(to&UNSIGNED){
+	    emit(f,"\tmove\t");
+	    emit_obj(f,&p->q1,to);
+	    emit(f,",@%s++\n",regnames[p->z.reg]);
+	    emit(f,"\tmove\t0,@%s\n",regnames[p->z.reg]);
+	  }else{
+	    if(isreg(q1)){
+	      reg=p->q1.reg;
+	    }else{
+	      reg=t1;
+	      move(f,&p->q1,0,0,t1,to);
+	    }
+	    emit(f,"\tmove\t%s,@%s++\n",regnames[reg],regnames[p->z.reg]);
+	    emit(f,"\tmove\t0,@%s\n",regnames[p->z.reg]);
+	    emit(f,"\tmove\t%s,%s\n",regnames[reg],regnames[reg]);
+	    emit(f,"\trbra\t%s%d,!n\n",labprefix,++label);
+	    emit(f,"\tsub\t1,@%s\n",regnames[p->z.reg]);
+	    emit(f,"%s%d:\n",labprefix,label);
+	  }
+	  if(!scratchreg(p->z.reg,p))
+	    emit(f,"\tsub\t1,%s\n",regnames[p->z.reg]);
+	}
+	cc=0;
+	continue;
+      }else
+	ierror(0);
+    }
+    if(c==MINUS){
+      p->code=c=SUB;
+      p->q2=p->q1;
+      gval.vmax=l2zm(0L);
+      eval_const(&gval,t);
+      insert_const(&p->q1.val,t);
+      p->q1.flags=KONST;
+    }
+    if(c==KOMPLEMENT){
+      load_op(f,&p->q1,t,t1);
+      load_op(f,&p->z,t,t2);
+      if(ISLWORD(t)){
+	emit(f,"\tnot\t");
+	emit_lword(f,&p->q1,t,"@%s++");
+	emit(f,",");
+	emit_lword(f,&p->z,t,"@%s++");
+	emit(f,"\n");
+	emit(f,"\tnot\t");
+	emit_hword(f,&p->q1,t,"@%s++");
+	emit(f,",");
+	emit_hword(f,&p->z,t,"@%s++");
+	emit(f,"\n");
+	cleanup_lword(f,&p->q1);
+	cleanup_lword(f,&p->z);
+	cc=0;
+      }else{
+	emit(f,"\tnot\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	cc=&p->z;cc_t=t;
+      }
+      continue;
+    }
+    if(c==SETRETURN){
+      if(p->z.reg){
+	if(reg_pair(p->z.reg,&rp))
+	  load_op(f,&p->q1,t,t1);
+	else
+	  load_op(f,&p->q1,t,p->z.reg);
+	move(f,&p->q1,0,0,p->z.reg,t);
+	BSET(regs_modified,p->z.reg);
+      }
+      cc=0; /* probably not needed */
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+	if((!isreg(z)||p->z.reg!=p->q1.reg)&&!ISLWORD(t)){ cc=&p->z;cc_t=t;}
+	load_op(f,&p->z,t,t2);
+	move(f,0,p->q1.reg,&p->z,0,t);
+      }
+      continue;
+    }
+    if(c==CALL){
+      int reg,jmp=0;long cstack=0;
+      cc=0;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	long va_off=loff-stackoffset+pushedsize+zm2l(va_offset(v))+1;
+	emit(f,"\tmove\t%s,%s\n",regnames[sp],regnames[r8]);
+	if(va_off)
+	  emit(f,"\tadd\t%ld,%s\n",va_off,regnames[r8]);
+	BSET(regs_modified,r8);
+	if(LARGE||HUGE){
+	  emit(f,"\tmove\t0,%s\n",regnames[r9]);
+	  BSET(regs_modified,r9);
+	}
+	continue;
+      }
+      if(stack_valid){
+        int i;
+        if(p->call_cnt<=0){
+          err_ic=p;if(f) error(320);
+          stack_valid=0;
+        }
+        for(i=0;stack_valid&&i<p->call_cnt;i++){
+          if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+	    if(p->call_list[i].v->fi->stack1>cstack) cstack=p->call_list[i].v->fi->stack1;
+          }else{
+            err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+            stack_valid=0;
+          }
+        }
+      }
+      if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	callee_push(cstack);
+      }else{
+	if(stackoffset==0&&!have_frame&&!(v->tattr&INTERRUPT)){
+	  struct IC *p2;
+	  jmp=1;
+	  for(p2=p->next;p2;p2=p2->next){
+	    if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL&&p2->code!=NOP&&
+	       (p2->code!=GETRETURN||(p2->z.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)&&
+	       (p2->code!=SETRETURN||(p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)){
+	      jmp=0;break;
+	    }
+	  }
+	}
+	if(p->q1.flags&DREFOBJ){
+	  int clabel=++label;
+	  if(ISLWORD(p->q1.dtyp)){
+	    ierror(0);
+	  }
+	  p->q1.flags&=~DREFOBJ;
+	  load_op(f,&p->q1,t,t1);
+	  if(!ISLWORD(p->q1.dtyp)){
+	    emit(f,"\t%s\t",jmp?jump:"asub");
+	    emit_obj(f,&p->q1,p->q1.dtyp);
+	    emit(f,",1\n");
+	    push(1);
+	    callee_push(cstack);
+	    pop(1);
+	  }else{
+	    ierror(0);
+	  }
+	}else{
+	  if(jmp){
+	    emit(f,"\t%s\t",jump);
+	    callee_push(cstack);
+	  }else{
+	    emit(f,"\t%s\t",call);
+	    if(TINY)
+	      push(1);
+	    else
+	      push(2);
+	    callee_push(cstack);
+	    if(TINY)
+	      pop(1);
+	    else
+	      pop(2);
+	  }
+	  emit_obj(f,&p->q1,t);
+	  emit(f,",1\n");
+	}
+      }
+      if(jmp&&!need_return) ret="";
+      if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+	notpopped+=zm2l(p->q2.val.vmax);
+	dontpop-=zm2l(p->q2.val.vmax);
+	if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+	  /*  Entfernen der Parameter verzoegern  */
+	}else{
+	  emit(f,"\tadd\t%ld,%s\n",zm2l(p->q2.val.vmax),regnames[sp]);
+	  pop(zm2l(p->q2.val.vmax));
+	  notpopped-=zm2l(p->q2.val.vmax);cc=0;
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+
+      if(c==ASSIGN||c==PUSH){
+	long sz=zm2l(p->q2.val.vmax);
+	int qreg,zreg,creg,i;
+	if(sz==1){
+	  load_op(f,&p->q1,t,t1);
+	  if(c==ASSIGN){
+	    load_op(f,&p->z,t,t2);
+	    move(f,&p->q1,0,&p->z,0,t);
+	    cc=&p->z;cc_t=t;
+	  }else{
+	    emit(f,"\tmove\t");
+	    emit_obj(f,&p->q1,t);
+	    emit(f,",@--%s\n",regnames[sp]);
+	    push(zm2l(p->z.val.vmax));	
+	    cc=&p->q1;cc_t=t;
+	  }    
+	  continue;
+	}else if(ISLWORD(t)&&(isreg(q1)||isreg(z)||(p->q1.flags&(KONST|DREFOBJ))==KONST)){
+	  if(c==ASSIGN){
+	    move(f,&p->q1,0,&p->z,0,t);
+	  }else{
+	    load_op(f,&p->q1,t,t1);
+	    
+	    if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ))
+	      emit(f,"\tadd\t2,%s\n",regnames[p->q1.reg]);
+	    
+	    emit(f,"\tmove\t");
+	    emit_hword(f,&p->q1,t,"@--%s");
+	    emit(f,",@--%s\n",regnames[sp]);
+	    emit(f,"\tmove\t");
+	    emit_lword(f,&p->q1,t,"@--%s");
+	    emit(f,",@--%s\n",regnames[sp]);
+	    push(2);
+	  }	  
+	  cc=0;
+	  continue;
+	}else{
+	  static char cpstr[64];
+	  cc=0;
+	  load_op(f,&p->q1,t,t1);
+	  if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&scratchreg(p->q1.reg,p)){
+	    qreg=p->q1.reg;
+	  }else{
+	    if(!(p->q1.flags&REG))
+	      ierror(0);
+	    qreg=t1;
+	    move(f,0,p->q1.reg,0,qreg,INT);
+	  }
+	  if(c==ASSIGN){
+	    load_op(f,&p->z,t,t2);
+	    if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&scratchreg(p->z.reg,p)){
+	      zreg=p->z.reg;
+	    }else{
+	      if(!(p->z.flags&REG))
+		ierror(0);
+	      if(qreg==t1) zreg=t2; else zreg=t1;
+	      move(f,0,p->z.reg,0,zreg,INT);
+	    }
+	    sprintf(cpstr,"\tmove\t@%s++,@%s++\n",regnames[qreg],regnames[zreg]);
+	  }else{
+	    zreg=sp;
+	    emit(f,"\tadd\t%ld,%s\n",sz,regnames[qreg]);
+	    sprintf(cpstr,"\tmove\t@--%s,@--%s\n",regnames[qreg],regnames[zreg]);
+	    push(zm2l(p->q2.val.vmax));
+	  }
+	  if(sz<=9){
+	    for(i=0;i<sz;i++)
+	      emit(f,cpstr);
+	  }else{
+	    int cntpushed=0;
+	    if(zreg!=t2)
+	      creg=t2;
+	    else{
+	      creg=get_reg(f,p);
+	      if(c==PUSH) ierror(0);
+	      creg=r8;
+	      emit(f,"\tmove\t%s,@--%s\n",regnames[creg],regnames[sp]);
+	      cntpushed=1;
+	    }
+	    emit(f,"\tmove\t%ld,%s\n",sz/4,regnames[creg]);
+	    emit(f,"%s%d:\n",labprefix,++label);
+	    emit(f,cpstr);
+	    emit(f,cpstr);
+	    emit(f,cpstr);
+	    emit(f,cpstr);
+	    emit(f,"\tsub\t1,%s\n",regnames[creg]);
+	    emit(f,"\trbra\t%s%d,!z\n",labprefix,label);
+	    for(i=0;i<sz%4;i++)
+	      emit(f,cpstr);
+	    if(cntpushed)
+	      emit(f,"\tmove\t@%s++,%s\n",regnames[sp],regnames[creg]);
+	  }
+	  continue;
+	}
+
+      }
+      ierror(0);
+    }
+    if(c==ADDRESS){
+      reg=0;
+      if(0/*reg_pair(reg,&rp)*/){
+	ierror(0);
+	emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[sp]);
+	emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+	if(voff(&p->q1))
+	  emit(f,"\tadd\t%s,#%ld\n",regnames[rp.r1],voff(&p->q1)&0xffff);
+      }else{
+	if(isreg(z))
+	  reg=p->z.reg;
+	else{
+	  load_op(f,&p->z,t,t2);
+	}
+	if(voff(&p->q1)){
+	  if(!reg) reg=t1;
+	  emit(f,"\tmove\t%s,%s\n",regnames[sp],regnames[reg]);
+	  emit(f,"\tadd\t%ld,%s\n",voff(&p->q1),regnames[reg]);
+	}else
+	  reg=sp;
+	move(f,0,reg,&p->z,0,ztyp(p));
+      }
+      cc=&p->z;cc_t=ztyp(p);
+      continue;
+    }
+
+    if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==COMPARE||c==ADDI2P||c==SUBIFP){
+      char *s;
+
+      if(c==MULT||c==DIV||c==MOD){
+	int code;
+	load_op(f,&p->q1,t,t1);
+	emit(f,"\tmove\t%ld,%s\n",(long)0xff1b,regnames[t2]);
+	emit(f,"\tmove\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,",@%s++\n",regnames[t2]);
+	load_op(f,&p->q2,t,t1);
+	emit(f,"\tmove\t");
+	emit_obj(f,&p->q2,t);
+	emit(f,",@%s++\n",regnames[t2]);
+	emit(f,"\tmove\t%ld,%s\n",(long)0xff1f,regnames[t1]);
+	if(c==MULT) code=0; else code=2;
+	if(!(t&UNSIGNED)) code++;
+	emit(f,"\tmove\t%d,@%s\n",code,regnames[t1]);
+	if(c==MOD)
+	  emit(f,"\tmove\t%ld,%s\n",(long)0xff1e,regnames[t2]);
+	load_op(f,&p->z,t,t1);
+	emit(f,"\tmove\t@%s,",regnames[t2]);
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	cc=&p->z;cc_t=t;
+	continue;
+      }
+
+      if(c==LSHIFT&&isconst(q2)&&isreg(q1)){
+	eval_const(&p->q2.val,INT);
+	if(zmeqto(vmax,l2zm(1L))){
+	  p->code=c=ADD;
+	  p->q2=p->q1;
+	}
+      }
+
+      if(compare_objects(&p->q2,&p->z)){
+	if(!compare_objects(&p->q1,&p->z)){
+	  if(c==LSHIFT||c==RSHIFT){
+	    reg=get_reg(f,p);
+	    if(reg){
+	      move(f,&p->q2,0,0,reg,q2typ(p));
+	      p->q2.flags=REG;
+	      p->q2.reg=reg;
+	    }else{
+	      emit(f,"\tmove\t");
+	      emit_obj(f,&p->q2,q2typ(p));
+	      emit(f,",@--%s\n",regnames[sp]);
+	      p->q2.flags=REG|DREFOBJ;
+	      p->q2.reg=sp;
+	      p->q2.am=mymalloc(sizeof(*p->q2.am));
+	      p->q2.am->flags=POST_INC;
+	      p->q2.am->base=sp;
+	    }
+	  }else if(c==SUB||c==SUBPFP||c==SUBIFP){
+	    /* TODO: check pointer sizes subifp/subpfp */
+	    if(ISLWORD(t)){
+	      if(isreg(z)){
+		if(!reg_pair(p->z.reg,&rp)) ierror(0);
+		emit(f,"\tnot\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+		emit(f,"\tnot\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+		emit(f,"\tadd\t1,%s\n",regnames[rp.r1]);
+		emit(f,"\taddc\t0,%s\n",regnames[rp.r2]);
+		p->q2=p->q1;
+		p->q1=p->z;
+		p->code=c=ADD;
+	      }else
+		ierror(0);
+	    }else{
+	      load_op(f,&p->z,t,t1);
+	      emit(f,"\tnot\t");
+	      emit_obj(f,&p->z,t);
+	      emit(f,",");
+	      emit_obj(f,&p->z,t);
+	      emit(f,"\n");
+	      emit(f,"\tadd\t1,");
+	      emit_obj(f,&p->z,t);
+	      emit(f,"\n");
+	      load_op(f,&p->q1,t,t2);
+	      emit(f,"\tadd\t");
+	      emit_obj(f,&p->q1,t);
+	      emit(f,",");
+	      emit_obj(f,&p->z,t);
+	      emit(f,"\n");
+	      cc=&p->z;cc_t=t;
+	      continue;
+	    }
+	  }else{
+	    struct obj m;
+	    m=p->q1;p->q1=p->q2;p->q2=m;
+	  }
+	}
+      }
+
+      if(c>=OR&&c<=AND){
+	s=logicals[c-OR];
+      }else{
+	if(c==ADDI2P)
+	  s=arithmetics[ADD-LSHIFT];
+	else if(c==SUBIFP)
+	  s=arithmetics[SUB-LSHIFT];
+	else
+	  s=arithmetics[c-LSHIFT];
+      }
+
+      if(c==COMPARE){
+	lastcomp=t;
+	load_op(f,&p->q1,t,t1);
+	load_op(f,&p->q2,t,t2);
+
+	if(ISLWORD(t)){
+	  if((p->q1.flags&DREFOBJ)&&p->q1.reg!=t1){
+	    emit(f,"\tmove\t%s,%s\n",regnames[p->q1.reg],regnames[t1]);
+	    p->q1.reg=t1;
+	  }
+	  if((p->q2.flags&DREFOBJ)&&p->q2.reg!=t2){
+	    emit(f,"\tmove\t%s,%s\n",regnames[p->q2.reg],regnames[t2]);
+	    p->q2.reg=t2;
+	  }
+	  p2=p->next;
+	  while(p2&&p2->code==FREEREG) p2=p2->next;
+	  if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+	  c=p2->code;
+	  if(c==BEQ||c==BNE){
+	    emit(f,"\tcmp\t",s);
+	    emit_lword(f,&p->q1,t,"@%s++");
+	    emit(f,",");
+	    emit_lword(f,&p->q2,t,"@%s++");
+	    emit(f,"\n");
+	    if(c==BEQ)
+	      emit(f,"\trbra\t%s%d,!z\n",labprefix,elab=++label);
+	    else 
+	      emit(f,"\trbra\t%s%d,!z\n",labprefix,p2->typf);
+	    emit(f,"\tcmp\t",s);
+	    emit_hword(f,&p->q1,t,"@%s++");
+	    emit(f,",");
+	    emit_hword(f,&p->q2,t,"@%s++");
+	    emit(f,"\n");
+	    emit(f,"\trbra\t%s%d,%s\n",labprefix,p2->typf,ccs[c-BEQ]);
+	  }else{
+	    elab=++label;
+	    if(p->q1.flags&DREFOBJ) emit(f,"\tadd\t1,%s\n",regnames[p->q1.reg]);
+	    if(p->q2.flags&DREFOBJ) emit(f,"\tadd\t1,%s\n",regnames[p->q2.reg]);
+	    emit(f,"\tcmp\t",s);
+	    emit_hword(f,&p->q2,t,"@%s");
+	    emit(f,",");
+	    emit_hword(f,&p->q1,t,"@%s");
+	    emit(f,"\n");
+	    emit(f,"\trbra\t%s%d,%s\n",labprefix,c==BLT?p2->typf:elab,(t&UNSIGNED)?ccu[BLT-BEQ]:ccs[BLT-BEQ]);
+	    /* unfortunately flags are overwritten... */
+	    emit(f,"\tcmp\t",s);
+	    emit_hword(f,&p->q2,t,"@%s");
+	    emit(f,",");
+	    emit_hword(f,&p->q1,t,"@%s");
+	    emit(f,"\n");
+	    emit(f,"\trbra\t%s%d,!z\n",labprefix,c==BLT?elab:p2->typf);
+	    if(p->q1.flags&DREFOBJ) emit(f,"\tsub\t1,%s\n",regnames[p->q1.reg]);
+	    if(p->q2.flags&DREFOBJ) emit(f,"\tsub\t1,%s\n",regnames[p->q2.reg]);
+	    emit(f,"\tcmp\t",s);
+	    emit_lword(f,&p->q2,t,"@%s");
+	    emit(f,",");
+	    emit_lword(f,&p->q1,t,"@%s");
+	    emit(f,"\n");
+	    emit(f,"\trbra\t%s%d,%s\n",labprefix,p2->typf,ccu[c-BEQ]);
+	  }
+	  cc=0;
+#if 0
+	  /* last branch done in branch IC */
+	  lastcomp=UNSIGNED|INT;
+#else
+	  if(c!=BNE)
+	    emit(f,"%s%d:\n",labprefix,elab);
+	  p2->code=NOP;
+#endif
+	  continue;
+	}else{
+	  emit(f,"\tcmp\t",s);
+	  emit_obj(f,&p->q2,t);
+	  emit(f,",");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+	cc=0;
+	continue;
+      }
+
+
+      if(!compare_objects(&p->q1,&p->z)){
+	load_op(f,&p->q1,t,t1);
+	load_op(f,&p->z,t,t2);
+	if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&isreg(z)&&p->q2.reg==p->z.reg){
+	  move(f,0,p->q2.reg,0,t2,NPOINTER);
+	  p->q2.reg=t2;
+	}
+	move(f,&p->q1,0,&p->z,0,t);
+	/* cleanup postinc if necessary (not done by cleanup_lword */
+	if(p->z.reg==t2&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISLWORD(t))
+	  emit(f,"\tsub\t2,%s\n",regnames[t2]);
+      }else
+	load_op(f,&p->z,t,t2);
+      load_op(f,&p->q2,t,t1);
+
+      if(ISLWORD(t)){
+
+	emit(f,"\t%s\t",s);
+	emit_lword(f,&p->q2,t,"@%s++");
+	emit(f,",");
+	emit_lword(f,&p->z,t,"@%s++");
+	emit(f,"\n");
+	emit(f,"\t%s%s\t",s,!strcmp(s,"add")||!strcmp(s,"sub")?"c":"");
+	emit_hword(f,&p->q2,t,"@%s++");
+	emit(f,",");
+	emit_hword(f,&p->z,t,"@%s++");
+	emit(f,"\n");
+	cleanup_lword(f,&p->q2);
+	cleanup_lword(f,&p->z);
+	cc=0;
+
+      }else{
+
+	/* TODO: try to eliminate */
+	if(c==LSHIFT){
+	  emit(f,"\tcmp\t%s,%s\n",regnames[sp],regnames[sp]);
+	}else if(c==RSHIFT){
+	  if(t&UNSIGNED){
+	    emit(f,"\tor\t%s,%s\n",regnames[sp],regnames[sp]);
+	  }else{
+	    emit(f,"\tshl\t1,");
+	    emit_obj(f,&p->z,t);
+	    emit(f,"\n");
+	    emit(f,"\tshr\t1,");
+	    emit_obj(f,&p->z,t);
+	    emit(f,"\n");
+	  }
+	}
+	emit(f,"\t%s\t",s);
+	emit_obj(f,&p->q2,t);
+	emit(f,",");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	cc=&p->z;cc_t=t;
+
+      }
+      if(ISLWORD(t)) cc=0;
+
+      continue;
+    }
+    ierror(0);
+  }
+  if(notpopped){
+    emit(f,"\tadd\t%ld,%s\n",notpopped,regnames[sp]);
+    pop(notpopped);notpopped=0;
+  }
+  function_bottom(f,v,loff);
+}
+
+int shortcut(int c,int t)
+{
+  if(c==COMPARE||c==AND||c==OR||c==XOR) return 1;
+  if(c==ADD||c==SUB) return 1;
+  return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+  if(f&&stack_check){
+    emit(f,"\t.global\t%s__stack_check\n",idprefix);
+  }
+  while(p=firstfpc){
+    if(f){
+      new_section(f,NDATA);
+      emit(f,"%s%d:\n\t%s\t",labprefix,p->label,dct[SHORT]);
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+      if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+  int f=t->flags&NQ;
+  if(!ISSCALAR(f)) return 0;
+  if(p->gpr>2||mode) return 0;
+  if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+    return 0;
+  else if(f==LONG||f==FLOAT||f==FPOINTER||f==HPOINTER){
+    if(p->gpr==0) {p->gpr=2;return r8r9;}
+    return 0;
+  }else
+    return r8+p->gpr++;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+/*  *p = (union atyps) 0 ; /* rfi: clear unused bits */
+  t&=NU;
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}  
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==NPOINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==NPOINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==BIT){fprintf(f,"B");vmax=zc2zm(p->vchar);fprintf(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){fprintf(f,"UB");vumax=zuc2zum(p->vuchar);fprintf(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vumax,ul2zum(0UL)));}
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+	if(strstr(attr,STR_NEAR))
+	  p->flags=((p->flags&~NU)|NPOINTER);
+	if(strstr(attr,STR_FAR))
+	  p->flags=((p->flags&~NU)|FPOINTER);
+	if(strstr(attr,STR_HUGE))
+	  p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+      p->flags=((p->flags&~NU)|BIT);
+    p=p->next;
+  }
+}
+
+void init_db(FILE *f)
+{
+}
+
+void cleanup_db(FILE *f)
+{
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0,*tt;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*16);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*16,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*16);
+        ret=fname;
+      }
+      if((t&NQ)==LLONG||(t2&NQ)==LLONG){
+	sprintf(fname,"__%cint%ldto%cint%ld",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*16,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*16);
+        ret=fname;
+      }
+    }
+    if(ISINT(t)&&ISLWORD(t)){
+      if(c==MINUS||c==KOMPLEMENT||c==ADD||c==SUB||c==OR||c==AND||c==XOR)
+	return 0;
+    }
+    if((t&NQ)==LONG||(t&NQ)==LLONG||ISFLOAT(t)||(SOFTMUL&&(c==MULT||c==DIV||c==MOD))){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+	if(c!=DIV&&c!=MOD&&c!=RSHIFT&&c!=COMPARE)
+	  t&=~UNSIGNED;
+	sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*16);
+	ret=fname;
+      }
+    }
+  }
+
+
+  return ret;
+}
diff --git a/machines/qnice/machine.dt b/machines/qnice/machine.dt
new file mode 100755
index 0000000..fa60647
--- /dev/null
+++ b/machines/qnice/machine.dt
@@ -0,0 +1,16 @@
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/qnice/machine.h b/machines/qnice/machine.h
new file mode 100755
index 0000000..b9795a3
--- /dev/null
+++ b/machines/qnice/machine.h
@@ -0,0 +1,185 @@
+/*  Example of a code-generator for qnice cpu.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them:      */
+/* - #define HAVE_EXT_TYPES
+   - #undef all standard types
+   - #define all standard types plus new types
+   - write eval_const and insert_const
+   - write typedefs for zmax and zumax
+   - write typname[]
+   - write conv_typ()
+   - optionally #define ISPOINTER, ISARITH, ISINT etc.
+   - optionally #define HAVE_TGT_PRINTVAL and write printval
+   - optionally #define POINTER_TYPE
+   - optionally #define HAVE_TGT_FALIGN and write falign
+   - optionally #define HAVE_TGT_SZOF and write szof
+   - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+#define BOOL 19
+
+#define MAXINT 20
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+struct AddressingMode{
+    int flags;
+    int base;
+};
+
+/* This type will be added to every IC. Can be used by the cg.      */
+#define HAVE_EXT_IC 0
+struct ext_ic {
+  int flags;
+  int r;
+  long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 22
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P CHAR
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+  int gpr;
+};
+
+/*  We use unsigned int as size_t rather than unsigned long which   */
+/*  is the default setting.                                         */
+#define HAVE_INT_SIZET 1
+
+/*  We have register pairs.                                         */
+#define HAVE_REGPAIRS 1
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+#define HAVE_WANTBNE 1
+
+#define HAVE_POF2OPT 1
diff --git a/machines/qnice/sysdef.h b/machines/qnice/sysdef.h
new file mode 100644
index 0000000..bdc733e
--- /dev/null
+++ b/machines/qnice/sysdef.h
@@ -0,0 +1,461 @@
+//;
+//;  sysdef.asm: This file contains definitions to simplify assembler programming
+//;              and for accessing the various hardware registers via MMIO
+//;
+//
+//***************************************************************************************
+//*  Assembler macros which make life much easier:
+//***************************************************************************************
+//
+
+
+//
+//  Some register short names:
+//
+
+//
+//***************************************************************************************
+//*  IO-page addresses: Default: 8 registers per block
+//***************************************************************************************
+//
+#define IO_AREA_START  	0xFF00
+//
+//---------------------------------------------------------------------------------------
+//  Block FF00: FUNDAMENTAL IO
+//---------------------------------------------------------------------------------------
+//
+//  Switch-register:
+//
+#define IO_SWITCH_REG  	0xFF00 // 16 binary keys
+//
+//  Registers for TIL-display:
+//
+#define IO_TIL_DISPLAY 	0xFF01 // Address of TIL-display
+#define IO_TIL_MASK    	0xFF02 // Mask register of TIL display
+//
+//  USB-keyboard-registers:
+//
+#define IO_KBD_STATE   	0xFF04 // Status register of USB keyboard
+//    Bit  0 (read only):      New ASCII character avaiable for reading
+//                             (bits 7 downto 0 of Read register)
+//    Bit  1 (read only):      New special key available for reading
+//                             (bits 15 downto 8 of Read register)
+//    Bits 2..4 (read/write):  Locales: 000 = US English keyboard layout,
+//                             001 = German layout, others: reserved for more locales
+//    Bits 5..7 (read only):   Modifiers: 5 = shift, 6 = alt, 7 = ctrl
+//                             Only valid, when bits 0 and/or 1 are '1'
+//
+#define IO_KBD_DATA    	0xFF05 // Data register of USB keyboard
+//    Contains the ASCII character in bits 7 downto 0  or the special key code
+//    in 15 downto 8. The "or" is meant exclusive, i.e. it cannot happen that
+//    one transmission contains an ASCII character PLUS a special character.
+//
+//---------------------------------------------------------------------------------------
+//  Block FF08: SYSTEM COUNTERS
+//---------------------------------------------------------------------------------------
+//
+//  CYCLE-COUNT-registers       
+//
+#define IO_CYC_LO      	0xFF08     // low word of 48-bit counter
+#define IO_CYC_MID     	0xFF09     // middle word of 48-bit counter
+#define IO_CYC_HI      	0xFF0A     // high word of 48-bit counter
+#define IO_CYC_STATE   	0xFF0B     // status register
+//    Bit  0 (write only):     Reset counter to zero and start counting, i.e.
+//                             bit 1 is automatically set to 1 when resetting
+//    Bit  1 (read/write):     Start/stop counter
+//
+//  INSTRUCTION-COUNT-registers       
+//
+#define IO_INS_LO      	0xFF0C     // low word of 48-bit counter
+#define IO_INS_MID     	0xFF0D     // middle word of 48-bit counter
+#define IO_INS_HI      	0xFF0E     // high word of 48-bit counter
+#define IO_INS_STATE   	0xFF0F     // status register
+//    Bit  0 (write only):     Reset counter to zero and start counting, i.e.
+//                             bit 1 is automatically set to 1 when resetting
+//    Bit  1 (read/write):     Start/stop counter
+//
+//---------------------------------------------------------------------------------------
+//  Block FF10: UART
+//---------------------------------------------------------------------------------------
+//
+//  QNICE-FPGA supports: IO_UART_SRA, IO_UART_RHRA and IO_UART_THRA 
+//  The other registers are mentioned for completeness to map real hardware (16550)
+//
+#define IO_UART_BASE_ADDRESS   	0xFF10
+#define IO_UART_MR1A   	0xFF10 // n/a
+#define IO_UART_MR1B   	0xFF10 // n/a
+#define IO_UART_SRA    	0xFF11 // Status register (relative to base address)
+#define IO_UART_RHRA   	0xFF12 // Receiving register (relative to base address)
+#define IO_UART_THRA   	0xFF13 // Transmitting register (relative to base address)
+//
+//---------------------------------------------------------------------------------------
+//  Block FF18: EAE
+//---------------------------------------------------------------------------------------
+//
+//  EAE (Extended Arithmetic Element) registers:
+//
+#define IO_EAE_OPERAND_0   	0xFF18
+#define IO_EAE_OPERAND_1   	0xFF19
+#define IO_EAE_RESULT_LO   	0xFF1A
+#define IO_EAE_RESULT_HI   	0xFF1B
+#define IO_EAE_CSR         	0xFF1C // Command and Status Register
+//
+//  EAE-Opcodes (CSR):   0x0000  MULU  32-bit result in LO HI
+//                       0x0001  MULS  32-bit result in LO HI
+//                       0x0002  DIVU  result in LO, modulo in HI
+//                       0x0003  DIVS  result in LO, modulo in HI
+//  Bit 15 of CSR is the busy bit. If it is set, the EAE is still busy crunching numbers.
+//
+//---------------------------------------------------------------------------------------
+//  Block FF20: SD CARD
+//---------------------------------------------------------------------------------------
+//
+//  SD CARD INTERFACE registers
+//
+#define IO_SD_BASE_ADDRESS 	0xFF20
+#define IO_SD_ADDR_LO  	0xFF20 // low word of 32bit linear SD card block address
+#define IO_SD_ADDR_HI  	0xFF21 // high word of 32bit linear SD card block address
+#define IO_SD_DATA_POS 	0xFF22 // "Cursor" to navigate the 512-byte data buffer
+#define IO_SD_DATA     	0xFF23 // read/write 1 byte from/to the 512-byte data buffer
+#define IO_SD_ERROR    	0xFF24 // error code of last operation (read only)
+#define IO_SD_CSR      	0xFF25 // Command and Status Register (write to execute command)
+//
+//  SD-Opcodes (CSR):    0x0000  Reset SD card
+//                       0x0001  Read 512 bytes from the linear block address
+//                       0x0002  Write 512 bytes to the linear block address
+//  Bits 0 .. 2 are write-only (reading always returns 0)
+//  Bits 13 .. 12 return the card type: 00 = no card / unknown card
+//                                      01 = SD V1
+//                                      10 = SD V2
+//                                      11 = SDHC                       
+//  Bit 14 of the CSR is the error bit: 1, if the last operation failed. In such
+//                                      a case, the error code is in IO_SD_ERROR and
+//                                      you need to reset the controller to go on
+//  Bit 15 of the CSR is the busy bit: 1, if current operation is still running
+//
+//---------------------------------------------------------------------------------------
+//  Block FF28: TIMER 0 and 1
+//---------------------------------------------------------------------------------------
+//
+//  Interrupt timer: There are two timers capable of generating interrupts.
+//                   Each timer is controlled by three 16 bit registers:
+//
+//  IO_TIMER_x_PRE: The 100 kHz timer clock is divided by the value stored in
+//                  this device register. 100 (which corresponds to 0x0064 in
+//                  the prescaler register) yields a 1 millisecond pulse which
+//                  in turn is fed to the actual counter.
+//  IO_TIMER_x_CNT: When the number of output pulses from the prescaler circuit 
+//                  equals the number stored in this register, an interrupt will
+//                  be generated (if the interrupt address is 0x0000, the
+//                  interrupt will be suppressed).
+//  IO_TIMER_x_INT: This register contains the address of the desired interrupt 
+//                  service routine.
+//
+#define IO_TIMER_BASE_ADDRESS  	0xFF28
+#define IO_TIMER_0_PRE 	0xFF28
+#define IO_TIMER_0_CNT 	0xFF29
+#define IO_TIMER_0_INT 	0xFF2A
+#define IO_TIMER_1_PRE 	0xFF2B
+#define IO_TIMER_1_CNT 	0xFF2C
+#define IO_TIMER_1_INT 	0xFF2D
+//
+//---------------------------------------------------------------------------------------
+//  Block FF30: VGA (double block, 16 registers)
+//---------------------------------------------------------------------------------------
+//
+#define VGA_STATE          	0xFF30 // VGA status register
+    // Bits 11-10: Hardware scrolling / offset enable: Bit #10 enables the use
+    //             of the offset register #4 (display offset) and bit #11
+    //             enables the use of register #5 (read/write offset).
+    // Bit      9: Busy: VGA is currently busy, e.g. clearing the screen,
+    //             printing, etc. While busy, commands will be ignored, but
+    //             they can still be written into the registers, though
+    // Bit      8: Set bit to clear screen. Read bit to find out, if clear
+    //             screen is still active
+    // Bit      7: VGA enable (1 = on; 0: no VGA signal is generated)
+    // Bit      6: Hardware cursor enable
+    // Bit      5: Hardware cursor blink enable
+    // Bit      4: Hardware cursor mode: 1 - small
+    //                                   0 - large
+    // Bits   2-0: Output color for the whole screen, bits (2, 1, 0) = RGB
+#define VGA_CR_X           	0xFF31 // VGA cursor X position
+#define VGA_CR_Y           	0xFF32 // VGA cursor Y position
+#define VGA_CHAR           	0xFF33 // write: VGA character to be displayed
+                                // read: character "under" the cursor
+#define VGA_OFFS_DISPLAY   	0xFF34 // Offset in bytes that is used when displaying
+                                // the video RAM. Scrolling forward one line
+                                // means adding 0x50 to this register.
+                                // Only works, if bit #10 in VGA_STATE is set.
+#define VGA_OFFS_RW        	0xFF35 // Offset in bytes that is used, when you read
+                                // or write to the video RAM using VGA_CHAR.
+                                // Works independently from VGA_OFFS_DISPLAY.
+                                // Active, when bit #11 in VGA_STATE is set.
+#define VGA_HDMI_H_MIN     	0xFF36 // HDMI Data Enable: X: minimum valid column
+#define VGA_HDMI_H_MAX     	0xFF37 // HDMI Data Enable: X: maximum valid column
+#define VGA_HDMI_V_MAX     	0xFF38 // HDMI Data Enable: Y: maximum row (line)                                
+//
+//---------------------------------------------------------------------------------------
+//  Block FFF0: MEGA65 (double block, 16 registers)
+//---------------------------------------------------------------------------------------
+//
+//  HyperRAM
+//
+#define IO_M65HRAM_LO      	0xFFF0 // Low word of address  (15 downto 0)
+#define IO_M65HRAM_HI      	0xFFF1 // High word of address (26 downto 16)
+#define IO_M65HRAM_DATA8   	0xFFF2 // HyperRAM native 8-bit data in/out
+#define IO_M65HRAM_DATA16  	0xFFF3 // HyperRAM 16-bit data in/out
+
+//
+//***************************************************************************************
+//* Constant definitions
+//***************************************************************************************
+//
+
+// ========== VGA ==========
+
+#define VGA_MAX_X              	79                      // Max. X-coordinate in decimal!
+#define VGA_MAX_Y              	39                      // Max. Y-coordinate in decimal!
+#define VGA_MAX_CHARS          	3200                    // 80 * 40 chars
+#define VGA_CHARS_PER_LINE     	80  
+
+#define VGA_EN_HW_CURSOR       	0x0040                  // Show hardware cursor
+#define VGA_EN_HW_SCRL         	0x0C00                  // Hardware scrolling enable
+#define VGA_CLR_SCRN           	0x0100                  // Clear screen
+#define VGA_BUSY               	0x0200                  // VGA is currently performing a task
+
+#define VGA_COLOR_RED          	0x0004
+#define VGA_COLOR_GREEN        	0x0002
+#define VGA_COLOR_BLUE         	0x0001
+#define VGA_COLOR_WHITE        	0x0007
+
+// ========== CYCLE COUNTER ==========
+
+#define CYC_RESET              	0x0001                  // Reset cycle counter
+#define CYC_RUN                	0x0002                  // Start/stop counter
+
+// ========== CYCLE COUNTER ==========
+
+#define INS_RESET              	0x0001                  // Reset instruction counter
+#define INS_RUN                	0x0002                  // Start/stop counter
+
+// ========== EAE ==========
+
+#define EAE_MULU               	0x0000                  // Unsigned 16 bit multiplication
+#define EAE_MULS               	0x0001                  // Signed 16 bit multiplication
+#define EAE_DIVU               	0x0002                  // Unsigned 16 bit division with remainder
+#define EAE_DIVS               	0x0003                  // Signed 16 bit division with remainder
+#define EAE_BUSY               	0x8000                  // Busy flag (1 = operation still running)
+
+// ========== SD CARD ==========
+
+#define SD_CMD_RESET           	0x0000                  // Reset SD card
+#define SD_CMD_READ            	0x0001                  // Read 512 bytes from SD to internal buffer
+#define SD_CMD_WRITE           	0x0002                  // Write 512 bytes from int. buf. to SD
+#define SD_BIT_ERROR           	0x4000                  // Error flag: 1, if last operation failed
+#define SD_BIT_BUSY            	0x8000                  // Busy flag: 1, if current op. is still running
+#define SD_TIMEOUT_MID         	0x0479                  // equals ~75.000.000 cycles, i.e. 1.5sec @ 50 MHz
+
+#define SD_ERR_MASK            	0x00FF                  // AND mask for errors: HI byte = state machine info, so mask it for error checks 
+#define SD_ERR_R1_ERROR        	0x0001                  // SD Card R1 error (R1 bit 6-0)
+#define SD_ERR_CRC_OR_TIMEOUT  	0x0002                  // Read CRC error or Write Timeout error
+#define SD_ERR_RESPONSE_TOKEN  	0x0003                  // Data Response Token error (Token bit 3)
+#define SD_ERR_ERROR_TOKEN     	0x0004                  // Data Error Token error (Token bit 3-0)
+#define SD_ERR_WRITE_PROTECT   	0x0005                  // SD Card Write Protect switch
+#define SD_ERR_CARD_UNUSABLE   	0x0006                  // Unusable SD card
+#define SD_ERR_NO_CARD         	0x0007                  // No SD card (no response from CMD0)
+#define SD_ERR_READ_TIMEOUT    	0x0008                  // Timeout while trying to receive the read start token "FE"
+#define SD_ERR_TIMEOUT         	0xEEFF                  // General timeout
+
+#define SD_CT_SD_V1            	0x0001                  // Card type: SD Version 1
+#define SD_CT_SD_V2            	0x0002                  // Card type: SD Version 2
+#define SD_CT_SDHC             	0x0003                  // Card type: SDHC (or SDXC)
+
+// ========== FAT32 =============
+
+// FAT32 ERROR CODES
+
+#define FAT32_ERR_MBR          	0xEE10                  // no or illegal Master Boot Record (MBR) found
+#define FAT32_ERR_PARTITION_NO 	0xEE11                  // the partition number needs to be in the range 1 .. 4
+#define FAT32_ERR_PARTTBL      	0xEE12                  // no or illegal partition table entry found (e.g. no FAT32 partition)
+#define FAT32_ERR_NOTIMPL      	0xEE13                  // functionality is not implemented
+#define FAT32_ERR_SIZE         	0xEE14                  // partition size or volume size too large (see doc/constraints.txt)
+#define FAT32_ERR_NOFAT32      	0xEE15                  // illegal volume id (either not 512 bytes per sector, or not 2 FATs or wrong magic)
+#define FAT32_ERR_ILLEGAL_SIC  	0xEE16                  // trying to read/write a sector within a cluster that is out of range
+#define FAT32_ERR_ILLEGAL_CLUS 	0xEE17                  // trying to access an illegal cluster number
+#define FAT32_ERR_CORRUPT_DH   	0xEE18                  // corrupt directory handle (e.g. because current to-be-read offs > sector size)
+#define FAT32_ERR_DIRNOTFOUND  	0xEE19                  // directory not found (illegal path name passed to change directory command)
+#define FAT32_ERR_FILENOTFOUND 	0xEE20                  // file not found
+#define FAT23_ERR_SEEKTOOLARGE 	0xEE21                  // seek position > file size
+
+// FAT32 STATUS CODES
+
+#define FAT32_EOF              	0xEEEE                  // end of file reached
+
+// LAYOUT OF THE MOUNT DATA STRUCTURE (DEVICE HANDLE)
+
+#define FAT32_DEV_RESET        	0x0000                  // pointer to device reset function
+#define FAT32_DEV_BLOCK_READ   	0x0001                  // pointer to 512-byte block read function
+#define FAT32_DEV_BLOCK_WRITE  	0x0002                  // pointer to 512-byte block write function
+#define FAT32_DEV_BYTE_READ    	0x0003                  // pointer to 1-byte read function (within block buffer)
+#define FAT32_DEV_BYTE_WRITE   	0x0004                  // pointer to 1-byte write function (within block buffer)
+#define FAT32_DEV_PARTITION    	0x0005                  // number of partition to be mounted
+#define FAT32_DEV_FS_LO        	0x0006                  // file system start address (LBA): low word
+#define FAT32_DEV_FS_HI        	0x0007                  // file system start address (LBA): high word
+#define FAT32_DEV_FAT_LO       	0x0008                  // fat start address (LBA): low word
+#define FAT32_DEV_FAT_HI       	0x0009                  // fat start address (LBA): high word
+#define FAT32_DEV_CLUSTER_LO   	0x000A                  // cluster start address (LBA): low word
+#define FAT32_DEV_CLUSTER_HI   	0x000B                  // cluster start address (LBA): high word
+#define FAT32_DEV_SECT_PER_CLUS	0x000C                  // sectors per cluster
+#define FAT32_DEV_RD_1STCLUS_LO	0x000D                  // root directory first cluster: low word
+#define FAT32_DEV_RD_1STCLUS_HI	0x000E                  // root directory first cluster: high word
+#define FAT32_DEV_AD_1STCLUS_LO	0x000F                  // currently active directory first cluster: low word
+#define FAT32_DEV_AD_1STCLUS_HI	0x0010                  // currently active directory first cluster: high word
+#define FAT32_DEV_BUFFERED_FDH 	0x0011                  // FDH which is responsible for the current 512 byte hardware buffer filling
+
+#define FAT32_DEV_STRUCT_SIZE  	0x0012                  // size (words) of the mount data structure (device handle)
+
+// LAYOUT OF THE FILE HANDLE AND DIRECTORY HANDLE (FDH)
+
+#define FAT32_FDH_DEVICE       	0x0000                  // pointer to the device handle
+#define FAT32_FDH_CLUSTER_LO   	0x0001                  // current cluster (low word)
+#define FAT32_FDH_CLUSTER_HI   	0x0002                  // current cluster (high word)
+#define FAT32_FDH_SECTOR       	0x0003                  // current sector
+#define FAT32_FDH_INDEX        	0x0004                  // current byte index within current sector
+#define FAT32_FDH_SIZE_LO      	0x0005                  // only in case FDH is a file: low word of file size, otherwise undefined
+#define FAT32_FDH_SIZE_HI      	0x0006                  // only in case FDH is a file: high word of file size, otherwise undefined
+#define FAT32_FDH_READ_LO      	0x0007                  // only in case FDH is a file: low word of already read amount of bytes
+#define FAT32_FDH_READ_HI      	0x0008                  // only in case FDH is a file: high word of already read amount of bytes
+
+#define FAT32_FDH_STRUCT_SIZE  	0x0009                  // size of the directory handle structure
+
+// FILE ATTRIBUTES
+
+#define FAT32_FA_READ_ONLY     	0x0001                  // read only file
+#define FAT32_FA_HIDDEN        	0x0002                  // hidden file
+#define FAT32_FA_SYSTEM        	0x0004                  // system file
+#define FAT32_FA_VOLUME_ID     	0x0008                  // volume id (name of the volume)
+#define FAT32_FA_DIR           	0x0010                  // directory
+#define FAT32_FA_ARCHIVE       	0x0020                  // archive flag
+
+#define FAT32_FA_DEFAULT       	0x0035                  // browse for non hidden files and directories but not for the volume id
+#define FAT32_FA_ALL           	0x0037                  // browse for all files, but not for the volume id
+
+// LAYOUT OF THE DIRECTORY ENTRY STRUCTURE
+
+#define FAT32_DE_NAME          	0x0000                  // volume, file or directory name, zero terminated (max 256 characters)
+#define FAT32_DE_ATTRIB        	0x0101                  // file attributes (read-only, hidden, system, volume id, directory, archive)
+#define FAT32_DE_SIZE_LO       	0x0102                  // file size: low word
+#define FAT32_DE_SIZE_HI       	0x0103                  // file size: high word
+#define FAT32_DE_YEAR          	0x0104                  // last file write: year   (valid range 1980 .. 2107)
+#define FAT32_DE_MONTH         	0x0105                  // last file write: month
+#define FAT32_DE_DAY           	0x0106                  // last file write: day
+#define FAT32_DE_HOUR          	0x0107                  // last file write: hour
+#define FAT32_DE_MINUTE        	0x0108                  // last file write: minute
+#define FAT32_DE_SECOND        	0x0109                  // last file write: second (in 2 second steps, valid range 0 .. 58)
+#define FAT32_DE_CLUS_LO       	0x010A                  // start cluster: low word
+#define FAT32_DE_CLUS_HI       	0x010B                  // start cluster: high word
+
+#define FAT32_DE_STRUCT_SIZE   	0x010C                  // size (words) of the directory entry data structure of the
+
+// DISPLAY FLAGS FOR FILE ENTRY PRETTY PRINTER
+
+#define FAT32_PRINT_SHOW_DIR   	0x0001                  // show "<DIR>" indicator
+#define FAT32_PRINT_SHOW_ATTRIB	0x0002                  // show attributes as "HRSA"
+#define FAT32_PRINT_SHOW_SIZE  	0x0004                  // show file size
+#define FAT32_PRINT_SHOW_DATE  	0x0008                  // show file date as YYYY-MM-DD
+#define FAT32_PRINT_SHOW_TIME  	0x0010                  // show file time as HH:MM
+
+#define FAT32_PRINT_DEFAULT    	0x001D                  // print <DIR> indicator, size, date and time (no attributes)
+#define FAT32_PRINT_ALL        	0x001F                  // print all details
+
+// ========== KEYBOARD ==========
+
+// STATUS REGISTER
+
+#define KBD_NEW_ASCII          	0x0001                  // new ascii character available
+#define KBD_NEW_SPECIAL        	0x0002                  // new special key available
+#define KBD_NEW_ANY            	0x0003                  // any new key available 
+
+#define KBD_ASCII              	0x00FF                  // mask the special keys
+#define KBD_SPECIAL            	0xFF00                  // mask the ascii keys
+
+#define KBD_LOCALE             	0x001C                  // bit mask for checking locales
+#define KBD_LOCALE_US          	0x0000                  // default: US keyboard layout
+#define KBD_LOCALE_DE          	0x0004                  // DE: German keyboard layout
+
+#define KBD_MODIFIERS          	0x00E0                  // bit mask for checking modifiers
+#define KBD_SHIFT              	0x0020                  // modifier "SHIFT" pressed
+#define KBD_ALT                	0x0040                  // modifier "ALT" pressed
+#define KBD_CTRL               	0x0080                  // modifier "CTRL" pressed
+
+// READ REGISTER: COMMON ASCII CODES
+
+#define KBD_SPACE              	0x0020
+#define KBD_ENTER              	0x000D
+#define KBD_ESC                	0x001B
+#define KBD_TAB                	0x0009
+#define KBD_BACKSPACE          	0x0008
+
+// READ REGISTER: SPECIAL KEYS
+
+#define KBD_F1                 	0x0100
+#define KBD_F2                 	0x0200
+#define KBD_F3                 	0x0300
+#define KBD_F4                 	0x0400
+#define KBD_F5                 	0x0500
+#define KBD_F6                 	0x0600
+#define KBD_F7                 	0x0700
+#define KBD_F8                 	0x0800
+#define KBD_F9                 	0x0900
+#define KBD_F10                	0x0A00
+#define KBD_F11                	0x0B00
+#define KBD_F12                	0x0C00
+
+#define KBD_CUR_UP             	0x1000
+#define KBD_CUR_DOWN           	0x1100
+#define KBD_CUR_LEFT           	0x1200
+#define KBD_CUR_RIGHT          	0x1300
+#define KBD_PG_UP              	0x1400
+#define KBD_PG_DOWN            	0x1500
+#define KBD_HOME               	0x1600
+#define KBD_END                	0x1700
+#define KBD_INS                	0x1800
+#define KBD_DEL                	0x1900
+
+// READ REGISTER: CTRL + character is also mapped to an ASCII code
+
+#define KBD_CTRL_A             	0x0001 
+#define KBD_CTRL_B             	0x0002 
+#define KBD_CTRL_C             	0x0003 
+#define KBD_CTRL_D             	0x0004 
+#define KBD_CTRL_E             	0x0005 
+#define KBD_CTRL_F             	0x0006 
+#define KBD_CTRL_G             	0x0007 
+#define KBD_CTRL_H             	0x0008 
+#define KBD_CTRL_I             	0x0009 
+#define KBD_CTRL_J             	0x000A 
+#define KBD_CTRL_K             	0x000B 
+#define KBD_CTRL_L             	0x000C 
+#define KBD_CTRL_M             	0x000D 
+#define KBD_CTRL_N             	0x000E 
+#define KBD_CTRL_O             	0x000F 
+#define KBD_CTRL_P             	0x0010 
+#define KBD_CTRL_Q             	0x0011 
+#define KBD_CTRL_R             	0x0012 
+#define KBD_CTRL_S             	0x0013 
+#define KBD_CTRL_T             	0x0014 
+#define KBD_CTRL_U             	0x0015 
+#define KBD_CTRL_V             	0x0016 
+#define KBD_CTRL_W             	0x0017 
+#define KBD_CTRL_X             	0x0018 
+#define KBD_CTRL_Y             	0x0019 
+#define KBD_CTRL_Z             	0x001A 
+
+//
+//  Useful ASCII constants:
+//
+#define CHR_BELL       	0x0007 // ASCII-BELL character
+#define CHR_TAB        	0x0009 // ASCII-TAB character
+#define CHR_SPACE      	0x0020 // ASCII-Space
+#define CHR_CR         	0x000d // Carriage return
+#define CHR_LF         	0x000a // Line feed
diff --git a/machines/rf12/machine.c b/machines/rf12/machine.c
new file mode 100755
index 0000000..40c6bc9
--- /dev/null
+++ b/machines/rf12/machine.c
@@ -0,0 +1,3808 @@
+/*  Code generator for Motorola 68hc12 microcontrollers.               */
+
+/*TODO:
+  regs_modified bei struct-copy
+  savings verfeinern
+  4-Byte Copy
+  [static] testen
+  peephole-Pass um ALLOCREGs zu entfernen
+  ACC_IND (Achtung?)
+  struct-copy Problemfälle
+  banked
+  bit
+  long long, float, double, long double
+
+*/
+
+#include "supp.h"
+#include "vbc.h" /* nicht schoen, aber ... */
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for 6809/6803/68hc12 V0.2 (c) in 2000-2022 by Volker Barthelmann";
+
+/*  Commandline-flags the code-generator accepts                */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+                    0,0,0,0,
+		    0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+                           "merge-constants","no-peephole","mem-cse","acc-glob",
+			   "pcrel","drel","no-char-addi2p","nodx","nou"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+		 "float","double","long double","void",
+                 "near-pointer","far-pointer","huge-pointer",
+		 "array","struct","union","enum","function"};
+
+int bitsperbyte = 8;
+int bytemask = 0xff;
+int dbl_bytemask = 0xffff;
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT of the target machine.                             */
+zmax char_bit;
+
+/*  Sizes of all elementary types in bytes.                     */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers.                                     */
+char *regnames[]={"noreg","d","x","y","sp","u","d/x"};
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1]={0,1,1,0,1,0};
+
+int reg_prio[MAXR+1]={0,0,1,1,0,0};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt","__dpage","__far",0};
+#define INTERRUPT 1
+#define DPAGE     2
+#define FAR				4
+
+int MINADDI2P=CHAR;
+
+/****************************************/
+/*  Some private data and functions.    */
+/****************************************/
+
+static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,4,4,4,4,0,2,4,4,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static int section=-1,newobj,scnt,pushed_acc;
+static char *codename="\t.text\n",
+            *dataname="\t.data\n",
+            *bssname="\t.section\t.bss\n",
+            *rodataname="\t.section\t.rodata\n";
+
+#define IMM_IND  1
+#define VAR_IND  2
+#define POST_INC 3
+#define POST_DEC 4
+#define PRE_INC  5
+#define PRE_DEC  6
+#define ACC_IND  7
+#define KONSTINC 8
+
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static int acc=1,ix=2,iy=3,sp=4,iu=5,dx=6;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+		       "__HC12__",
+		       "__SIZE_T_INT=1",
+		       "__direct=__vattr(\"section(\\\"dpage\\\")\")",
+		       0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static long loff,roff,stackoffset,notpopped,dontpop,maxpushed,stack;
+
+static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
+static char *ccs[]={"eq","ne","lt","ge","le","gt"};
+static char *uccs[]={"eq","ne","lo","hs","ls","hi"};
+static char *logicals[]={"ora","eor","and"};
+static char *dct[]={"",".bit",".byte",".2byte",".2byte",".4byte",".8byte",".4byte",".8byte",".8byte",
+		    "(void)",".2byte",".34byte",".34byte"};
+static char *idprefix="",*labprefix=".l";
+static int exit_label,have_frame;
+static char *ret;
+static int stackchecklabel;
+static int frame_used,stack_valid;
+static int CPU=6812;
+static int pcrel,drel;
+static int skip_rel;
+static char *jsrinst="jsr";
+static char *jmpinst="jmp";
+static int nodx,nou;
+int switchsubs;
+
+static int cc_t;
+static struct obj *cc;
+
+static struct obj mobj;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+#define STR_BADDR "baddr"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
+#define ISCHWORD(t) ((t&NQ)==CHAR||ISHWORD(t))
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
+/*FIXME*/
+#define ISFAR(v) ((v)->vtyp->attr&&(strstr(STR_FAR,(v)->vtyp->attr)||strstr(STR_HUGE,(v)->vtyp->attr)))
+
+#define ISACC(x) ((x)==acc)
+#define ISX(x) ((x)==ix)
+#define ISY(x) ((x)==iy)
+#define ISU(x) ((x)==iu)
+#define ISIDX(x) (ISX(x)||ISY(x)||(ISU(x)&&CPU!=6812))
+#define ISRACC(x) (isreg(x)&&ISACC(p->x.reg))
+#define ISRX(x) (isreg(x)&&ISX(p->x.reg))
+#define ISRY(x) (isreg(x)&&ISY(p->x.reg))
+#define ISRU(x) (isreg(x)&&ISU(p->x.reg))
+#define ISRIDX(x) (isreg(x)&&ISIDX(p->x.reg))
+
+#define CPUOPT ((g_flags[0]&USEDFLAG)?g_flags_val[0].l:6812)
+
+#define SPUSH(x) (CPU==6812?"\tpsh" x "\n":"\tpshs\t" x "\n")
+#define SPUSHD   (CPU==6812?"\tpshd\n":"\tpshs\tb,a\n")
+#define SPULL(x) (CPU==6812?"\tpul" x "\n":"\tpuls\t" x "\n")
+#define SPULLD   (CPU==6812?"\tpuld\n":"\tpuls\ta,b\n")
+#define SCMP(x)  (CPU==6812?"\tcp" x "\t":"\tcmp" x "\t")
+#define SEX      (CPU==6812?"\tsex\tb,d\n":"\tsex\n")
+
+#define SGN16(x) (zm2l(zi2zm(zm2zi(l2zm((long)(x))))))
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2, ALLOWSFX = 4};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+static int check_sfx(char *s)
+{
+  if(!*s) return 0;
+  s+=strlen(s)-1;
+  if(*s=='+'||*s=='-') return 1;
+  if(*s!='s'&&*s!='x'&&*s!='y'&&*s!='u') return 0;
+  s--;
+  if(*s!=',') return 0;
+  s--;
+  if(*s=='+'||*s=='-') return 1;
+  return 0;
+}
+
+static int setszflag(char *op,char r)
+{
+  static char *zb[]={"adcb","addb","andb","aslb","asrb","clrb","comb","decb","eorb","incb",
+		"ldab","ldb","lslb","lsrb","negb","orb","orab","rolb","rorb","sbcb",
+		"stb","stab","subb","tstb"};
+  static char *zd[]={"addd","ldd","sex","std","subd"};
+
+  int i;
+
+  if(r=='b'){
+    for(i=0;i<sizeof(zb)/sizeof(*zb);i++)
+      if(!strcmp(op,zb[i]))
+	return 1;
+  }
+  if(r=='d'){
+    for(i=0;i<sizeof(zd)/sizeof(*zd);i++)
+      if(!strcmp(op,zd[i]))
+	return 1;
+  }
+  if(r=='x'&&(!strcmp(op,"leax")||!strcmp(op,"ldx"))) return 1;
+  if(r=='y'&&(!strcmp(op,"leay")||!strcmp(op,"ldy"))) return 1;
+  if(CPU==6812){
+    if(r=='x'&&(!strcmp(op,"dex")||!strcmp(op,"inx"))) return 1;
+    if(r=='y'&&(!strcmp(op,"dey")||!strcmp(op,"iny"))) return 1;
+  }
+  return 0;
+}
+
+int emit_peephole(void)
+{
+  int entries,i,j,v1,v2;
+  char *asmline[EMIT_BUF_DEPTH];
+  char buf1[1024],buf2[1024];
+  char op1[8],op2[8];
+
+
+  /* TODO: adapt better */
+  static struct peeps elim[]={
+    "lda","sta",0,NEEDSAME,
+    "ldb","stb",0,NEEDSAME,
+    "ldaa","staa",0,NEEDSAME,
+    "ldab","stab",0,NEEDSAME,
+    "ldd","std",0,NEEDSAME,
+    "ldx","stx",0,NEEDSAME,
+    "ldy","sty",0,NEEDSAME,
+    "ldu","stu",0,NEEDSAME,
+    "sta","sta",0,NEEDSAME,
+    "stb","stb",0,NEEDSAME,
+    "staa","staa",0,NEEDSAME,
+    "stab","stab",0,NEEDSAME,
+    "std","std",0,NEEDSAME,
+    "stx","stx",0,NEEDSAME,
+    "sty","sty",0,NEEDSAME,
+    "stu","stu",0,NEEDSAME,
+    "sta","lda",0,NEEDSAME,
+    "stb","ldb",0,NEEDSAME,
+    "staa","ldaa",0,NEEDSAME,
+    "stab","ldab",0,NEEDSAME,
+    "std","ldd",0,NEEDSAME,
+    "stx","ldx",0,NEEDSAME,
+    "sty","ldy",0,NEEDSAME,
+    "stu","ldu",0,NEEDSAME,
+#if 0
+    "lda","lda",0,REMOVE1ST,
+    "ldaa","ldaa",0,REMOVE1ST,
+    "ldab","ldab",0,REMOVE1ST,
+    "ldb","ldb",0,REMOVE1ST,
+    "ldd","ldd",0,REMOVE1ST,
+    "ldx","ldx",0,REMOVE1ST,
+    "ldy","ldy",0,REMOVE1ST,
+    "ldu","ldu",0,REMOVE1ST,
+    "lda","pla",0,REMOVE1ST,
+    "lda","txa",0,REMOVE1ST,
+    "lda","tya",0,REMOVE1ST,
+    "ldx","tax",0,REMOVE1ST,
+    "ldy","tay",0,REMOVE1ST,
+    "tay","ldy",0,REMOVE1ST,
+    "tax","ldx",0,REMOVE1ST,
+    "txa","lda",0,REMOVE1ST,
+    "tya","lda",0,REMOVE1ST,
+#endif
+  };
+
+
+  i=emit_l;
+  if(emit_f==0)
+    entries=i-emit_f+1;
+  else
+    entries=EMIT_BUF_DEPTH;
+  asmline[0]=emit_buffer[i];
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpb")&&!strcmp(buf1,"#0"))
+    strcpy(asmline[0],"\ttstb\n");
+  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpd")&&!strcmp(buf1,"#0"))
+    strcpy(asmline[0],"\tsubd\t#0\n");
+
+  if(entries>=2){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[1]=emit_buffer[i];
+
+    for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+      if(elim[j].flags&NEEDSAME){
+	if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+	   sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+	   !strcmp(buf1,buf2)){
+	  if(!check_sfx(buf1)&&!check_sfx(buf2)){
+	    if(elim[j].r){
+	      strcpy(asmline[0],elim[j].r);
+	    }else{
+	      if(elim[j].flags&REMOVE1ST)
+		strcpy(asmline[1],asmline[0]);
+	      remove_asm();
+	    }
+	    return 1;
+	  }
+	}
+      }else{
+	*buf1=0;*buf2=0;
+	if(sscanf(asmline[1]," %6s %999s",op1,buf1)>=1&&
+	   sscanf(asmline[0]," %6s %999s",op2,buf2)>=1&&
+	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+	  if((elim[j].flags&ALLOWSFX)||(!check_sfx(buf1)&&!check_sfx(buf2))){
+	    if(elim[j].flags&REMOVE1ST)
+	      strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+      }
+    }
+
+    if(!strcmp(asmline[0],"\trts\n")&&sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"puls")){
+      sprintf(asmline[1]+strlen(asmline[1])-1,",pc\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tstb\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-1,s\n")){
+      strcpy(asmline[1],"\tpshs\tb\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tstd\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-2,s\n")){
+      strcpy(asmline[1],"\tpshs\tb,a\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tldb\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb\n")){
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tldd\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb,a\n")){
+      remove_asm();
+      return 1;
+    }
+
+    if(!strcmp(asmline[0],"\tpshs\tb,a\n")&&!strcmp(asmline[1],"\tpuls\ta,b\n")){
+      strcpy(asmline[1],"\tldd\t0,s\n");
+      remove_asm();
+      return 1;
+    }
+
+    if(sscanf(asmline[1]," ldd %999s",op1)>=1&&sscanf(asmline[0]," ldd %999s",op2)>=1){
+      if(!((op2[0]=='a'||op2[0]=='b'||op2[0]=='d')&&op2[1]==',')){
+	strcpy(asmline[1],asmline[0]);
+	remove_asm();
+	return 1;
+      }
+    }
+
+    if(!strcmp(asmline[0],"\ttfr\tx,d\n")&&!strcmp(asmline[1],"\ttfr\td,x\n")){
+      remove_asm();
+      return 1;
+    }
+    if(!strcmp(asmline[0],"\ttfr\ty,d\n")&&!strcmp(asmline[1],"\ttfr\td,y\n")){
+      remove_asm();
+      return 1;
+    }
+    if(!strcmp(asmline[0],"\tstd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+      remove_asm();
+      return 1;
+    }
+    if(!strcmp(asmline[0],"\tldd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+      remove_asm();
+      return 1;
+    }
+
+    if(sscanf(asmline[0]," leas %d,s",&v1)==1&&sscanf(asmline[1]," leas %d,s",&v2)==1){
+      sprintf(asmline[1],"\tleas\t%ld,s\n",SGN16(v1+v2));
+      remove_asm();
+      return 1;
+    }
+
+    if(CPU!=6812&&sscanf(asmline[0]," tfr %c,%c",buf1,buf2)==2){
+      if((*buf1=='x'||*buf1=='y'||*buf1=='u'||*buf1=='s')&&
+	 (*buf2=='x'||*buf2=='y'||*buf2=='u'||*buf2=='s')){
+	sprintf(asmline[0],"\tlea%c\t,%c\n",*buf2,*buf1);
+      }
+    }
+    if(CPU==6812&&(!strcmp(asmline[1],"\tdex\n")||!strcmp(asmline[1],"\tdey\n")||!strcmp(asmline[1],"\tsubd\t#1\n"))&&
+       (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+      char r=asmline[1][3];
+      if(r=='b') r='d';
+      strcpy(asmline[1],"\td");
+      strncpy(asmline[1]+2,asmline[0]+1,4);
+      asmline[1][6]=r;asmline[1][7]=',';
+      strcpy(asmline[1]+8,asmline[0]+5);
+      remove_asm();
+      return 1;
+    }
+    if(CPU==6812&&(!strcmp(asmline[1],"\tinx\n")||!strcmp(asmline[1],"\tiny\n")||!strcmp(asmline[1],"\taddd\t#1\n"))&&
+       (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+      char r=asmline[1][3];
+      strcpy(asmline[1],"\ti");
+      strncpy(asmline[1]+2,asmline[0]+1,4);
+      asmline[1][6]=r;asmline[1][7]=',';
+      strcpy(asmline[1]+8,asmline[0]+5);
+      remove_asm();
+      return 1;
+    }
+  }
+  if(entries>=3){
+    i--;
+    if(i<0) i=EMIT_BUF_DEPTH-1;
+    asmline[2]=emit_buffer[i];
+    if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+	if(!strcmp(asmline[1],"\ttstb\n")||!strcmp(asmline[1],"\tcpb\t#0\n")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'b')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   (!strcmp(op2,"subd")||!strcmp(op2,"cpd"))&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'d')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,(CPU==6812)?"cpx":"cmpx")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'x')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+	   !strcmp(op2,(CPU==6812)?"cpy":"cmpy")&&!strcmp(buf2,"#0")){
+	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+	     setszflag(op2,'y')){
+	    strcpy(asmline[1],asmline[0]);
+	    remove_asm();
+	    return 1;
+	  }
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(v->tattr&DPAGE){
+    emit(f,"\t.section\t.dpage\n");
+  }else{
+    if(!v->vattr) return 0;
+    sec=strstr(v->vattr,"section(");
+    if(!sec) return 0;
+    sec+=strlen("section(");
+    emit(f,"\t.section\t");
+    while(*sec&&*sec!=')') emit_char(f,*sec++);
+    emit(f,"\n");
+  }
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static struct fpconstlist {
+    struct fpconstlist *next;
+    int label,typ;
+    union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+  struct fpconstlist *p=firstfpc;
+  t&=NQ;
+  if(g_flags[4]&USEDFLAG){
+    for(p=firstfpc;p;p=p->next){
+      if(t==p->typ){
+	eval_const(&p->val,t);
+	if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+	if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+	if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+      }
+    }
+  }
+  p=mymalloc(sizeof(struct fpconstlist));
+  p->next=firstfpc;
+  p->label=++label;
+  p->typ=t;
+  p->val=o->val;
+  firstfpc=p;
+  return p->label;
+}
+
+int pointer_type(struct Typ *p)
+{
+  if(!p) ierror(0);
+  while((p->flags&NQ)==ARRAY) p=p->next;
+  if((p->flags&NQ)==FUNKT) {
+  	if(p->attr)
+    	if(strstr(p->attr,STR_FAR)) return FPOINTER;
+  	if (p->flags&FAR)
+  		return FPOINTER;
+  	return NPOINTER; /*FIXME: banked*/
+  }
+  if(p->attr){
+    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+    if(strstr(p->attr,STR_FAR)) return FPOINTER;
+    if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+  }
+  /*FIXME*/
+  return NPOINTER;
+}
+static long voff(struct obj *p)
+{
+  if(zm2l(p->v->offset)<0) 
+    return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+1;
+  else
+    return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/*  Gibt Objekt auf Bildschirm aus                      */
+{
+  if(p->am){
+    int flags=p->am->flags;
+    if(flags==ACC_IND){
+      emit(f,"%s,%s",regnames[acc],regnames[p->am->base]);
+      return;
+    }
+    if(flags==KONSTINC){
+      eval_const(&p->val,p->am->base);
+      if((t&NQ)==CHAR){
+	vumax=zumrshift(vumax,bitsperbyte*3-bitsperbyte*p->am->offset);
+	vumax=zumand(vumax,ul2zum(tu_max[CHAR]));
+      }else{
+	vumax=zumrshift(vumax,bitsperbyte*2-bitsperbyte*p->am->offset);
+	vumax=zumand(vumax,ul2zum(tu_max[SHORT]));
+      }
+      emit(f,"#%lu",zum2ul(vumax));
+      return;
+    }
+    if(flags<POST_INC||flags>PRE_DEC||CPU==6812)
+      emit(f,"%ld",p->am->offset&tu_max[SHORT]);
+    if(p->am->v){
+      if(p->am->v->storage_class==STATIC)
+	emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
+      else
+	emit(f,"+(%s%s)",idprefix,p->am->v->identifier);
+    }
+    emit(f,",");
+    if(flags==PRE_INC){
+      emit(f,"+");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+    }else if(flags==PRE_DEC){
+      emit(f,"-");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+    }
+    emit(f,"%s",regnames[p->am->base]);
+    if(flags==POST_INC){
+      emit(f,"+");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+    }else if(flags==POST_DEC){
+      emit(f,"-");
+      if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+    }
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&VARADR) emit(f,"#");
+  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"0,");
+  if((p->flags&(DREFOBJ|REG))==DREFOBJ) emit(f,"[");
+  if((p->flags&(VAR|REG))==VAR){
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+      emit(f,"%ld,%s",voff(p),regnames[sp]);
+    }else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){
+	emit(f,"%ld",zm2l(zi2zm(zm2zi(p->val.vmax))));
+	emit(f,"+");
+      }
+      if(p->v->storage_class==STATIC){
+	emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+	emit(f,"(%s%s)",idprefix,p->v->identifier);
+      }
+      if(pcrel&&!(p->flags&VARADR)&&ISFUNC(p->v->vtyp->flags))
+	emit(f,",pc");
+      if(drel&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)){
+	if(CPU==6812) ierror(0);
+	emit(f,",%s",regnames[iu]);
+      }
+    }
+  }
+  if(p->flags&REG){
+    if(ISACC(p->reg)&&(t&NQ)==CHAR)
+      emit(f,"b");
+    else
+      emit(f,"%s",regnames[p->reg]);
+  }
+  if(p->flags&KONST){
+    if(ISFLOAT(t)){
+      emit(f,"%s%d",labprefix,addfpconst(p,t));
+    }else{
+      emit(f,"#");emitval(f,&p->val,t&NU);
+    }
+  }
+  if((p->flags&(DREFOBJ|REG))==DREFOBJ){
+    if(p->v->storage_class==EXTERN||p->v->storage_class==STATIC){
+      if(is_const(p->v->vtyp)){
+	if(!pcrel&&CPU==6812) emit(f,",pc");
+      }else{
+	if(!drel&&CPU==6812) emit(f,",pc");
+      }
+    }
+    emit(f,"]");
+  }
+}
+
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+  /*FIXME: needs a location list and correct register translation */
+  struct obj o;
+  o.flags=REG;
+  o.reg=sp;
+  o.val.vmax=l2zm(0L);
+  o.v=0;
+  dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+  /*FIXME: always returns D as accumulator, even if byte size */
+  static int dwarf_regs[MAXR+1]={-1,3,7,8,15};
+  return dwarf_regs[r];
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+  /*FIXME*/
+  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+  if(!zmleq(l2zm(0L),v->offset))
+    return l2zm((long)(loff-zm2l(v->offset)));
+  else
+    return v->offset;
+} 
+
+/* test operand for mov instruction */
+static int mov_op(struct obj *o)
+{
+  long off;
+  if(CPU!=6812) return 0;
+  if(o->am){
+    int f=o->am->flags;
+    if(f==POST_INC||f==PRE_INC||f==POST_DEC||f==PRE_DEC||f==ACC_IND)
+      return 1;
+    if(f==IMM_IND){
+      if(o->am->v) return 0;
+      off=o->am->offset;
+      if(off>=-256&&off<=255)
+	return 1;
+      else
+	return 0;
+    }
+    ierror(0);
+  }
+  if(o->flags&(KONST|VARADR)) return 1;
+  if((o->flags&(REG|DREFOBJ))==(REG|DREFOBJ)) return 1;
+  if((o->flags&(VAR|REG|DREFOBJ))==VAR){
+    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN)
+      return 1;
+    off=voff(o);
+    if(off>=-256&&off<=255)
+      return 1;
+    else
+      return 0;
+  }
+  return 0;
+}
+
+/* add an offset to an object describing a memory address */
+static void inc_addr(struct obj *o,long val,int t)
+{
+  if(o->am){
+    int f=o->am->flags;
+    if(f==IMM_IND||f==KONSTINC)
+      o->am->offset+=val;
+    else if(f==POST_INC||f==POST_DEC||f==PRE_INC||f==PRE_DEC){
+      struct AddressingMode *old=o->am;
+      o->am=mymalloc(sizeof(*o->am));
+      o->am->flags=IMM_IND;
+      o->am->base=old->base;
+      o->am->v=0;
+      if(f==POST_DEC) o->am->offset=old->offset-val;
+      else if(f==POST_INC) o->am->offset=-old->offset+val;
+      else if(f==PRE_DEC) o->am->offset=val;
+      else o->am->offset=-val;
+    }else
+      ierror(0);
+  }else if(o->flags&DREFOBJ){
+    struct AddressingMode *am;
+    o->am=am=mymalloc(sizeof(*am));
+    am->flags=IMM_IND;
+    if(!o->reg) ierror(0);
+    am->base=o->reg;
+    am->offset=zm2l(val);
+    am->v=0;
+  }else if(o->flags&KONST){
+    struct AddressingMode *am;
+    if(o->am) ierror(0);
+    o->am=am=mymalloc(sizeof(*am));
+    am->flags=KONSTINC;
+    am->offset=zm2l(val);
+    am->base=t;
+  }else{
+    o->val.vmax=zmadd(o->val.vmax,val);
+  }
+}
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+  if(l-stackoffset>stack)
+    stack=l-stackoffset;
+}
+static void push(long l)
+{
+  stackoffset-=l;
+  if(stackoffset<maxpushed) maxpushed=stackoffset;
+  if(-maxpushed>stack) stack=-maxpushed;
+}
+static void pop(long l)
+{
+  stackoffset+=l;
+}
+static void gen_pop(FILE *f,long l)
+{
+  if(l==0) return;
+  if(l==1&&CPU==6812){
+    emit(f,"\tins\n");
+#if 0 /* might clobber return register */
+  }else if(l==2&&!regs[acc]){
+    emit(f,SPULLD);
+    BSET(regs_modified,acc);
+  }else if(l==2&&!regs[ix]){
+    emit(f,SPULL("x"));
+    BSET(regs_modified,ix);
+  }else if(l==2&&!regs[iy]){
+    emit(f,SPULL("y"));
+    BSET(regs_modified,iy);
+#endif
+  }else{
+    emit(f,"\tleas\t%u,%s\n",SGN16(l),regnames[sp]);
+  }
+  pop(l);
+}
+static void pr(FILE *f,struct IC *p)
+{
+  int r;
+  if(pushed_acc){
+    emit(f,SPULLD);
+    pop(2);
+    pushed_acc=0;
+  }
+  for(r=MAXR;r>=1;r--){
+    if(regs[r]&8){
+      emit(f,"\t%s%s\n",CPU==6812?"pul":"puls\t",regnames[r]);
+      pop(2);
+    }
+    regs[r]&=~12;
+  }
+}
+static void function_top(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionskopf                       */
+{
+  int i;
+  emit(f,"# offset=%ld\n",offset);
+  have_frame=0;stack_valid=1;stack=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else{
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  }
+  roff=0;
+  for(i=MAXR;i>0;i--){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      have_frame=1;
+      loff+=2;
+      roff+=2;
+      if(i==iy) emit(f,SPUSH("y"));
+      else if(i==iu){
+	if(CPU!=6812&&regused[iy]){
+	  emit(f,"\tpshs\tu,y\n");
+	  loff+=2;roff+=2;i=iy;
+	}else
+	  emit(f,SPUSH("u"));
+      }else
+	ierror(0);
+    }
+  }
+  if(stack_check){
+    stackchecklabel=++label;
+    emit(f,"\tldy\t#%s%d\n",labprefix,stackchecklabel);
+    /* FIXME: banked */
+    emit(f,"\t%s\t%s__stack_check\n",jsrinst,idprefix);
+  }
+  if(offset){
+    if(CPU==6812&&offset==1)
+      emit(f,SPUSH("b"));
+    else if(CPU==6812&&offset==2)
+      emit(f,SPUSHD);
+    else
+      emit(f,"\tleas\t%ld,%s\n",SGN16(-offset),regnames[sp]);
+    have_frame=1;
+  }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/*  erzeugt Funktionsende                       */
+{
+  int i;
+  offset-=roff;
+  if(offset){
+    if(offset==1&&CPU==6812)
+      emit(f,"\tins\n");
+    else if(offset==2&&CPU==6812&&!zmeqto(szof(v->vtyp->next),l2zm(4L)))
+      emit(f,SPULL("x"));
+    else if(offset==2&&CPU==6812&&regused[iy])
+      emit(f,SPULL("y"));
+    else
+      emit(f,"\tleas\t%ld,%s\n",SGN16(offset),regnames[sp]);
+  }
+  for(i=1;i<=MAXR;i++){
+    if(regused[i]&&!regscratch[i]&&!regsa[i]){
+      have_frame=1;
+      if(i==iy){
+	if(CPU!=6812&&regused[iu]&&!regscratch[iu]&&!regsa[iu]){
+	  emit(f,"\tpuls\tu,y\n");
+	  i=iu;
+	}else
+	  emit(f,SPULL("y"));
+      }else if(i==iu) emit(f,SPULL("u"));
+      else
+	ierror(0);
+    }
+  }
+  if(ret) emit(f,"\t%s\n",ret);
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+    emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+  }else{
+    emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+  }
+  if(stack_check)
+    emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stackchecklabel,offset-maxpushed);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=l2zm(stack+offset);
+    emit(f,"# stacksize=%ld\n",stack+offset);
+    emit(f,"\t.equ\t%s__stack_%s,%ld\n",idprefix,v->identifier,stack+offset);
+  }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+  if(o1->flags==o2->flags&&o1->am==o2->am){
+    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+      if(!(o1->flags&REG)||o1->reg==o2->reg){
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/*FIXME*/
+static void clear_ext_ic(struct ext_ic *p)
+{
+  p->flags=0;
+  p->r=0;
+  p->offset=0;
+}
+static long pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+static void peephole(struct IC *p)
+{
+  int c,c2,r,t;struct IC *p2;
+  struct AddressingMode *am;
+  zmax incmin,incmax;
+  if(CPU==6812){
+    incmin=l2zm(-8L);
+    incmax=l2zm(8L);
+  }else{
+    incmin=l2zm(-2L);
+    incmax=l2zm(2L);
+  }
+  frame_used=0;
+  for(;p;p=p->next){
+    c=p->code;
+    if(!frame_used){
+      if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+      if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+      if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+    }
+    /* letztes Label merken */
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+#if 0
+    /* and x,#const;bne/beq, FIXME */
+    if(c==AND&&isconst(q2)&&isreg(z)){
+      long bit;
+      eval_const(&p->q2.val,p->typf);
+      if(bit=pof2(vumax)){
+	struct IC *cmp=0;int fr=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==TEST){
+	    if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+	      cmp=p2;continue;
+	    }
+	  }
+	  if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf);
+	    if(ISNULL()){
+	      cmp=p2;continue;
+	    }
+	    break;
+	  }
+	  if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
+	  if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
+	    p->ext.flags=EXT_IC_BTST;
+	    p2->ext.flags=EXT_IC_BTST;
+	    p2->ext.offset=bit-1;
+	    cmp->code=NOP;
+	    cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
+	    break;
+	  }
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==p->z.reg)||((p2->q2.flags&REG)&&p2->q2.reg==p->z.reg)||((p2->z.flags&REG)&&p2->z.reg==p->z.reg)) break;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	}
+      }
+    }
+#endif
+    /* Try d,idx */
+    if(c==ADDI2P&&ISRACC(q2)&&ISRIDX(z)&&(ISRIDX(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||!ISCHWORD(q1typ(p2))) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	    break; /*TODO: check what is possible */
+            if(o||!ISCHWORD(q2typ(p2))) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	    break; /*TODO: check what is possible */
+            if(o||!ISCHWORD(ztyp(p2))) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=ACC_IND;
+              am->base=base;
+	      if(idx!=acc) ierror(0);
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+	  continue;
+	}
+	/* better no instructions between, accu used too much */
+	if(c2!=FREEREG&&c2!=ALLOCREG&&!o) break;
+      }
+    }
+    /* POST_INC/DEC in q1 */
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q1.reg; t=q1typ(p);
+      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q1.am=mymalloc(sizeof(*am));
+	      p->q1.am->base=r;
+	      p->q1.am->v=0;
+	      if(zmleq(vmax,l2zm(0L))){
+		p->q1.am->flags=POST_DEC;
+		p->q1.am->offset=-zm2l(vmax);
+	      }else{
+		p->q1.am->flags=POST_INC;
+		p->q1.am->offset=zm2l(vmax);
+	      }
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* POST_INC/DEC in q2 */
+    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->q2.reg; t=q2typ(p);
+      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->q2.am=mymalloc(sizeof(*am));
+	      p->q2.am->base=r;
+	      p->q2.am->v=0;
+	      if(zmleq(vmax,l2zm(0L))){
+		p->q2.am->flags=POST_DEC;
+		p->q2.am->offset=-zm2l(vmax);
+	      }else{
+		p->q2.am->flags=POST_INC;
+		p->q2.am->offset=zm2l(vmax);
+	      }
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+    /* POST_INC/DEC in z */
+    if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+      r=p->z.reg; t=ztyp(p);
+      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)){
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	    eval_const(&p2->q2.val,p2->typf2);
+	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+	      p2->code=NOP;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      p->z.am=mymalloc(sizeof(*am));
+	      p->z.am->base=r;
+	      p->z.am->v=0;
+	      if(zmleq(vmax,l2zm(0L))){
+		p->z.am->flags=POST_DEC;
+		p->z.am->offset=-zm2l(vmax);
+	      }else{
+		p->z.am->flags=POST_INC;
+		p->z.am->offset=zm2l(vmax);
+	      }
+	    }else break;
+	  }
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
+	}
+      }
+    }
+
+    /* R,#c */
+    if((c==ADDI2P||c==SUBIFP)&&ISHWORD(p->typf)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(!drel&&(p->q1.flags&VARADR)))){
+      int base;zmax of;struct obj *o;struct Var *v;
+      if(p->q1.flags&VARADR){
+	v=p->q1.v;
+	of=p->q1.val.vmax;
+	r=p->z.reg;
+	if(isreg(q2)&&ISIDX(p->q2.reg))
+	  base=p->q2.reg;
+	else
+	  base=r;
+      }else{
+	eval_const(&p->q2.val,p->typf);
+	if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+	v=0;
+	r=p->z.reg;
+	if(isreg(q1)&&ISIDX(p->q1.reg)) base=p->q1.reg; else base=r;
+      }
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+	c2=p2->code;
+	if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	    if(o||!ISHWORD(q1typ(p2))) break;
+	    o=&p2->q1;
+	  }
+	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	    if(o||!ISHWORD(q2typ(p2))) break;
+	    o=&p2->q2;
+	  }
+	  if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	    if(o||!ISHWORD(ztyp(p2))) break;
+	    o=&p2->z;
+	  }
+	}
+	if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	  int m;
+	  if(c2==FREEREG) 
+	    m=p2->q1.reg;
+	  else
+	    m=p2->z.reg;
+	  if(m==r){
+	    if(o){
+	      o->am=am=mymalloc(sizeof(*am));
+	      am->flags=IMM_IND;
+	      am->base=base;
+	      am->offset=zm2l(of);
+	      am->v=v;
+	      if(!v){
+		if(isreg(q1)&&ISIDX(p->q1.reg)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }else{
+		if(isreg(q2)&&ISIDX(p->q2.reg)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
+		  p->q2.val.vmax=sizetab[p->typf&NQ];
+		}
+	      }
+	    }
+	    break;
+	  }
+	  if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
+	  continue;
+	}
+      }
+    }      
+  }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/*  Initializes an addressing-mode structure and returns a pointer to   */
+/*  that object. Will not survive a second call!                        */
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  am.v=v;
+  return &obj;
+}
+
+static void get_acc(FILE *f,struct IC *p)
+{
+  if(regs[acc]){
+    if(p->q2.am)
+      if(p->q2.am->flags==ACC_IND) ierror(0);
+    else
+      if((p->q2.flags&REG)&&ISACC(p->q2.reg)) ierror(0);
+    if(p->z.am)
+      if(p->z.am->flags==ACC_IND) ierror(0);
+    else
+      if((p->z.flags&REG)&&ISACC(p->z.reg)) ierror(0);
+    if(regs[acc]){
+      emit(f,SPUSHD);
+      push(2);
+      pushed_acc=1;
+    }
+  }
+}
+static int get_idx(FILE *f,IC *p)
+{
+  int r;
+  for(r=1;r<=MAXR;r++){
+    if(ISIDX(r)){
+      if(!regs[r]){
+	regs[r]|=4;
+	return r;
+      }
+    }
+  }
+  for(r=1;r<=MAXR;r++){
+    if(ISIDX(r)){
+      if((!(p->q1.flags&REG)||p->q1.reg!=r)&&
+	 (!(p->q2.flags&REG)||p->q2.reg!=r)&&
+	 (!(p->z.flags&REG)||p->z.reg!=r)){
+	emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[r]);
+	regs[r]|=8;
+	push(2);
+	return r;
+      }
+    }
+  }
+  ierror(0);
+}
+static int get_reg(FILE *f,struct IC *p,int t)
+{
+  int reg;
+  if(!regs[acc])
+    reg=acc;
+  else if(ISHWORD(t)&&!regs[ix])
+    reg=ix;
+#if 0
+  else if(ISHWORD(t)&&!regs[iy])
+    reg=iy;
+#endif
+  else{
+    get_acc(f,p);
+    reg=acc;
+  }
+  BSET(regs_modified,reg);
+  return reg;
+}
+static void load_reg(FILE *f,int r,struct obj *o,int t)
+{
+  if(!o->am){
+    if((o->flags&(REG|DREFOBJ))==REG){
+      if(o->reg==r) return;
+      emit(f,"\ttfr\t%s,%s\n",regnames[o->reg],regnames[r]);
+      return;
+    }
+    if(r==acc&&(o->flags&(KONST|DREFOBJ))==KONST){
+      eval_const(&o->val,t);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+	if(CPU!=6812&&!optsize)
+	  emit(f,"\tldd\t#0\n");
+	else
+	  emit(f,"\tclra\n\tclrb\n"); 
+	cc=o;cc_t=t;
+	return;
+      }
+    }
+  }
+  if(o->flags&VARADR){
+    char *base=0;
+    if(pcrel&&ISFUNC(o->v->vtyp->flags))
+      base="pc";
+    if(drel&&!ISFUNC(o->v->vtyp->flags))
+      base=regnames[iu];
+    if(base&&!skip_rel){
+      if(ISACC(r))
+	emit(f,"\ttfr\t%s,d\n",base);
+      if(ISIDX(r))
+	emit(f,"\tlea%s\t",regnames[r]);
+      else{
+	if(*base=='p') emit(f,"%s%d:\n",labprefix,++label);
+	emit(f,"\taddd\t#");
+      }
+      emitzm(f,o->val.vmax);
+      emit(f,"+");
+      if(o->v->storage_class==EXTERN)
+	emit(f,"%s%s",idprefix,o->v->identifier);
+      else
+	emit(f,"%s%ld",labprefix,zm2l(o->v->offset));
+      if(ISIDX(r))
+	emit(f,",%s",base);
+      else if(*base=='p')
+	emit(f,"-%s%d",labprefix,label);
+      emit(f,"\n");
+      cc=o;cc_t=t;
+      return;
+    }
+    skip_rel=0;
+  }
+  emit(f,"\tld%s\t",(r==acc&&(t&NQ)==CHAR)?(CPU==6812?"ab":"b"):regnames[r]);
+  emit_obj(f,o,t);emit(f,"\n");
+  cc=o;cc_t=t;
+}
+static void store_reg(FILE *f,int r,struct obj *o,int t)
+{
+  if((o->flags&(REG|DREFOBJ))==REG){
+    if(o->reg==r) return;
+    emit(f,"\ttfr\t%s,%s\n",regnames[r],regnames[o->reg]);
+  }else{
+    if(r==acc&&(t&NQ)==CHAR)
+      emit(f,"\tst%s\t",(CPU==6812)?"ab":"b");
+    else
+      emit(f,"\tst%s\t",regnames[r]);
+    emit_obj(f,o,t);emit(f,"\n");
+    cc=o;cc_t=t;
+  }
+}
+static void load_addr(FILE *f,int r,struct obj *o)
+{
+  if(o->am){
+    if(o->am->flags==IMM_IND){
+      if(o->am->base==r&&o->am->offset==0&&!o->am->v) return;
+      if(ISIDX(r)){
+	emit(f,"\tlea%s\t",regnames[r]);
+	emit_obj(f,o,0);
+	emit(f,"\n");
+      }else{
+	if(r!=acc) ierror(0);
+	emit(f,"\ttfr\t%s,%s\n",regnames[o->am->base],regnames[r]);
+	emit(f,"\taddd\t#%ld\n",o->am->offset);
+	if(o->am->v){
+	  if(o->am->v->storage_class==STATIC)
+	    emit(f,"+%s%ld",labprefix,zm2l(o->am->v->offset));
+	  else
+	    emit(f,"+%s%s",idprefix,o->am->v->identifier);
+	}
+	emit(f,"\n");
+	cc=0;
+      }
+      return;
+    }
+    ierror(0);
+  }
+  if(o->flags&DREFOBJ){
+    o->flags&=~DREFOBJ;
+    load_reg(f,r,o,o->dtyp);
+    o->flags|=DREFOBJ;
+    return;
+  }
+  if((o->flags&(VAR|VARADR))==VAR){
+    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
+      o->flags|=VARADR;
+      load_reg(f,r,o,POINTER_TYPE(o->v->vtyp));
+      o->flags&=~VARADR;
+      return;
+    }
+    if(voff(o)==0){
+      emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+      return;
+    }
+    if(ISIDX(r)){
+      emit(f,"\tlea%s\t",regnames[r]);
+      emit_obj(f,o,0);
+      emit(f,"\n");
+    }else{
+      if(r!=acc) ierror(0);
+      emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+      emit(f,"\taddd\t#%ld\n",voff(o));
+      cc=0;
+    }
+    return;
+  }
+  ierror(0);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+  int c;
+  while(1){
+    p=p->next;
+    if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+    if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+    if((p->q1.flags&REG)&&p->q1.reg==r) return 0;
+    if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
+    if((p->z.flags&REG)&&p->z.reg==r) return 0;
+  }
+}
+
+/****************************************/
+/*  End of private fata and functions.  */
+/****************************************/
+
+
+int init_cg(void)
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+{
+  int i;
+
+  CPU=CPUOPT;
+
+	if (CPU==680912) {
+		bitsperbyte = 12;
+		bytemask = 0xfff;
+		dbl_bytemask = 0xffffff;
+	}
+	
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(1L);
+  char_bit=l2zm((long)bitsperbyte);
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+  for(i=1;i<=iu;i++){
+    regsize[i]=l2zm(2L);regtype[i]=&ityp;
+  }	
+  regsize[dx]=l2zm(4L);regtype[i]=&ltyp;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  if (CPU==680912) {
+	  t_min[CHAR]=l2zm(-2048L);
+	  t_min[SHORT]=l2zm(-8388608L);
+	  t_min[INT]=t_min[SHORT];
+	  t_min[LONG]=zmsub(l2zm(0x800000000000LL),l2zm(1L));
+	  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+	  t_min[MAXINT]=t_min(LLONG);
+	  t_max[CHAR]=ul2zum(2047L);
+	  t_max[SHORT]=ul2zum(8388607UL);
+	  t_max[INT]=t_max[SHORT];
+	  t_max[LONG]=ul2zum(0x7fffffffffffULL);
+	  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+	  t_max[MAXINT]=t_max(LLONG);
+	  tu_max[CHAR]=ul2zum(4095UL);
+	  tu_max[SHORT]=ul2zum(16777215UL);
+	  tu_max[INT]=tu_max[SHORT];
+	  tu_max[LONG]=ul2zum(0xffffffffffffULL);
+	  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+	  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+	}
+	else {
+	  t_min[CHAR]=l2zm(-128L);
+	  t_min[SHORT]=l2zm(-32768L);
+	  t_min[INT]=t_min[SHORT];
+	  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+	  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+	  t_min[MAXINT]=t_min(LLONG);
+	  t_max[CHAR]=ul2zum(127L);
+	  t_max[SHORT]=ul2zum(32767UL);
+	  t_max[INT]=t_max[SHORT];
+	  t_max[LONG]=ul2zum(2147483647UL);
+	  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+	  t_max[MAXINT]=t_max(LLONG);
+	  tu_max[CHAR]=ul2zum(255UL);
+	  tu_max[SHORT]=ul2zum(65535UL);
+	  tu_max[INT]=tu_max[SHORT];
+	  tu_max[LONG]=ul2zum(4294967295UL);
+	  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+	  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+	}
+
+  if(g_flags[9]&USEDFLAG) drel=1;
+  if(g_flags[10]&USEDFLAG) MINADDI2P=SHORT;
+  if(g_flags[11]&USEDFLAG) nodx=1;
+  if(g_flags[12]&USEDFLAG) nou=1;
+
+  if(CPU==6812) switchsubs=1;
+
+  /*  Reserve a few registers for use by the code-generator.      */
+  regsa[sp]=REGSA_NEVER;
+  regscratch[sp]=0;
+
+  if(CPU==6812||drel||nou){
+    regsa[iu]=REGSA_NEVER;
+    regscratch[iu]=0;
+  }
+
+  if(CPU!=6812){
+    regnames[sp]="s";
+    logicals[0]="or";
+  }
+
+  if(!(g_flags[6]&USEDFLAG)){
+    extern int static_cse,dref_cse;
+    static_cse=0;
+    dref_cse=0;
+  }
+
+  if(!(g_flags[7]&USEDFLAG)){
+    regsa[acc]=REGSA_TEMPS;
+    regsa[dx]=REGSA_TEMPS;
+  }
+
+  if(g_flags[8]&USEDFLAG){
+    pcrel=1;
+    jsrinst="lbsr";
+    jmpinst="lbra";
+    rodataname="\t.data\n";
+  }
+
+  if(CPU==6809)
+    marray[1]="__6809__";
+  if(CPU==6309)
+    marray[1]="__6309__";
+  if(CPU==680912)
+    marray[1]="__680912__";
+  target_macros=marray;
+
+
+  declare_builtin("__mulint16",INT,INT,acc,INT,0,1,0);
+  declare_builtin("__divint16",INT,INT,ix,INT,acc,1,0);
+  declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+  declare_builtin("__modint16",INT,INT,ix,INT,acc,1,0);
+  declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+
+
+  /* TODO: set argument registers */
+  declare_builtin("__mulint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__addint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__subint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__andint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__orint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__eorint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__negint32",LONG,LONG,0,0,0,1,0);
+  declare_builtin("__lslint32",LONG,LONG,0,INT,0,1,0);
+
+  declare_builtin("__divint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+  declare_builtin("__modint32",LONG,LONG,0,LONG,0,1,0);
+  declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+  declare_builtin("__lsrsint32",LONG,LONG,0,INT,0,1,0);
+  declare_builtin("__lsruint32",UNSIGNED|LONG,UNSIGNED|LONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint32",INT,LONG,0,LONG,0,1,0);
+  declare_builtin("__cmpuint32",INT,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+  declare_builtin("__sint32toflt32",FLOAT,LONG,0,0,0,1,0);
+  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
+  declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
+  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint32",LONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+
+
+
+  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+  declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+  declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+  declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);
+
+  declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+  declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+
+  return 1;
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+{
+  int f=t->flags&NQ;
+  if(ISSCALAR(f)){
+    if(ISHWORD(f)||f==CHAR)
+      return acc;
+    else if(ISLWORD(f))
+      return dx;
+  }
+  return 0;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(!ISSCALAR(t)) return 0;
+  if(r==dx){
+    if(ISLWORD(t)&&(optflags&2)&&!nodx) return 1;
+    return 0;
+  }
+  if(mode==-1){
+    if(ISHWORD(t)) return 1;
+    if((t&NQ)==CHAR&&ISACC(r)) return 1;
+  }else{
+    if(ISIDX(r)){
+      if(ISPOINTER(t)&&ISHWORD(t))
+	return 1;
+    }
+    if(ISACC(r)){
+      if((t&NQ)==CHAR)
+	return 1;
+      if(ISINT(t)&&ISHWORD(t))
+	return 1;
+    }
+  }
+  return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r==dx){
+    p->r1=acc;
+    p->r2=ix;
+    return 1;
+  }
+  return 0;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  /*FIXME*/
+  int c=p->code;
+  if(r==dx){
+    if(c==GETRETURN||c==SETRETURN||c==PUSH||c==ASSIGN) return 8;
+    return INT_MIN;
+  }
+  if(o->flags&VKONST){
+    struct obj *co=&o->v->cobj;
+    if(o->flags&DREFOBJ)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
+      return 2;
+    }
+    return 0;
+  }
+  if((o->flags&DREFOBJ)){
+    if(!ISIDX(r)) return INT_MIN;
+    if(p->q2.flags&&o!=&p->z)
+      return 6;
+    else
+      return 6;
+  }else if(c==GETRETURN&&p->q1.reg==r){
+    return 4;
+  }else if(c==SETRETURN&&p->z.reg==r){
+    return 4;
+  }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&&regok(r,CHAR,0)){
+    return 3;
+  }
+  if(o==&p->z&&r==acc){
+    if(c==SUB||c==SUBIFP||c==SUBPFP||c==AND||c==OR||c==XOR)
+      return 6;
+    if((c==ADD||c==ADDI2P)&&!(p->q1.flags&(KONST|VKONST))&&!(p->q2.flags&(KONST|VKONST)))
+      return 4;
+    if(c==MULT) return 5;
+    if(c==ASSIGN&&(p->q1.flags&KONST)){
+      eval_const(&p->q1.val,p->typf);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL)))
+	return 3;
+    }
+  }
+#if 1
+  if((o==&p->q2/*||o==&p->z*/)&&!(o->flags&DREFOBJ)&&!ISACC(o->reg)&&(c==MULT||c==DIV||c==MOD))
+    return INT_MIN;
+#endif
+  if(c==COMPARE||c==TEST){
+    if(r==ix) return 3;
+    if(r==iy) return 2;
+    if(r==iu) return 1;
+  }
+  return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+  static char fname[16];
+  char *ret=0;
+
+  if(c==COMPARE){
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(t==LDOUBLE) t=DOUBLE;
+    if(t2==LDOUBLE) t2=DOUBLE;
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==LLONG||ISFLOAT(t)){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+	if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%suint64",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+	}else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+	  sprintf(fname,"__%suint32",ename[c]);
+	  ret=fname;
+	}else if((t&NQ)==LONG){
+          sprintf(fname,"__%sint32",ename[c]);
+          ret=fname;
+        }else{
+	  sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+	}
+      }
+    }
+    if((c==MULT&&(CPU==6809||(t&NQ)==LONG))||c==DIV||c==MOD){
+      sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }
+
+  return ret;
+}
+
+
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+{
+  int op=o&NQ,tp=t&NQ;
+  if(op==tp) return 0;
+  if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+  if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+  if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;  
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  /* nothing to do */
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(v->tattr&DPAGE)
+      emit(f,"\t.direct\t%s%ld\n",labprefix,zm2l(v->offset));
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){
+	emit(f,dataname);if(f) section=DATA;
+      }
+      if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=RODATA){
+	emit(f,rodataname);if(f) section=RODATA;
+      }
+      if(!v->clist&&section!=BSS){
+	emit(f,bssname);if(f) section=BSS;
+      }
+    }
+    emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+    emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+    if(v->clist||section==SPECIAL)
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1; 
+  }
+  if(v->storage_class==EXTERN){
+    if(v->flags&(DEFINED|TENTATIVE)){
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+      if(v->tattr&DPAGE)
+	emit(f,"\t.direct\t%s%s\n",idprefix,v->identifier);
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){
+	  emit(f,dataname);if(f) section=DATA;
+	}
+	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=RODATA){
+	  emit(f,rodataname);if(f) section=RODATA;
+	}
+	if(!v->clist&&section!=BSS){
+	  emit(f,bssname);if(f) section=BSS;
+	}
+      }
+      emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+      emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+      if(v->clist||section==SPECIAL)
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      else
+        emit(f,"\t.global\t%s%s\n\t.lcomm\t%s%s,",idprefix,v->identifier,idprefix,v->identifier);
+      newobj=1;   
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\t%s\t",dct[t&NQ]);
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+      if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+      }
+    }else{
+      emitval(f,&p->val,(t&NU)|UNSIGNED);
+    }
+  }else{
+    int m=p->tree->o.flags,md=drel,mp=pcrel;
+    p->tree->o.flags&=~VARADR;
+    drel=0;pcrel=0;
+    emit_obj(f,&p->tree->o,t&NU);
+    p->tree->o.flags=m;
+    drel=md;pcrel=mp;
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+static void preload(FILE *f,IC *p)
+{
+  int t,r;
+
+  if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+     ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+     ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+    emit(f,"; volatile barrier\n");
+
+  t=q1typ(p);
+  if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+    r=get_idx(f,p);
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,r,&p->q1,INT);
+    p->q1.flags|=(REG|DREFOBJ);
+    p->q1.reg=r;
+  }
+  t=q2typ(p);
+  if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+    r=get_idx(f,p);
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,r,&p->q2,INT);
+    p->q2.flags|=(REG|DREFOBJ);
+    p->q2.reg=r;
+  }else if(isreg(z)&&(((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg)||(p->q2.am&&p->q2.am->base==p->z.reg))){
+    r=get_idx(f,p);
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,r,&p->q2,INT);
+    p->q2.flags|=(REG|DREFOBJ);
+    p->q2.reg=r;
+  }
+  t=ztyp(p);
+  if(!p->z.am&&(p->z.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+    r=get_idx(f,p);
+    p->z .flags&=~DREFOBJ;
+    load_reg(f,r,&p->z ,INT);
+    p->z .flags|=(REG|DREFOBJ);
+    p->z .reg=r;
+  }
+}
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+void gen_code(FILE *f,struct IC *fp,struct Var *v,zmax offset)
+{
+  int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
+  struct obj *bit_obj;char *bit_reg;
+  static int idone;
+  struct obj o;
+  IC *p,*p2;
+  if(v->tattr&INTERRUPT)
+    ret="rti";
+  else if (v->tattr&FAR)
+  	ret="rtf";
+  else
+    ret="rts"; /*FIXME: banked */
+  if(DEBUG&1) printf("gen_code()\n");
+  for(p=fp;p;p=p->next) clear_ext_ic(&p->ext);
+  emit(f,"#off1=%ld\n",zm2l(offset));
+  if(!(g_flags[5]&USEDFLAG)){
+    peephole(fp);
+    if(!frame_used) offset=l2zm(0L);
+  }
+  for(c=1;c<=MAXR;c++) regs[c]=(regsa[c]==REGSA_NEVER)?1:0;
+  for(c=1;c<=MAXR;c++){
+    if(regscratch[c]&&(regsa[c]||regused[c])){
+      BSET(regs_modified,c);
+    }
+  }
+  t=0;
+  for(p=fp;p;p=p->next){
+    c=p->code;
+    if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1;}
+    if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0;}
+    if((c==LSHIFT||c==RSHIFT)&&(p->typf&NQ)>=LONG) regused[iy]=1;
+    if(c==PUSH&&(p->q1.flags&(REG|DREFOBJ))!=REG){
+      if(zmeqto(p->q2.val.vmax,Z1)){
+	if(regs[acc]) t=(t>2)?t:2;
+      }else if(zmeqto(p->q2.val.vmax,l2zm(2L))){
+	if(regs[acc]&&regs[ix]&&regs[iy]&&(CPU==6812||regs[iu])) t=(t>2)?t:2;
+      }else if(zmeqto(p->q2.val.vmax,l2zm(4L))){
+	if(regs[acc]) t=(t>2)?t:2;
+      }else{
+	/* TODO: finer check */
+	if(drel||!regsa[iu])
+	  t=(t>8)?t:8;
+	else
+	  t=(t>6)?t:6;
+      }
+    }
+  }
+  emit(f,"#toff=%d\n",t);
+  loff=zm2l(offset)+t;
+  function_top(f,v,loff);
+  stackoffset=notpopped=dontpop=maxpushed=0;
+  for(p=fp;p;pr(f,p),p=p->next){
+    c=p->code;t=p->typf;
+    if(debug_info)
+      dwarf2_line_info(f,p); 
+    short_add=0;
+    if(c==NOP) continue;
+    if(c==ALLOCREG){
+      regs[p->q1.reg]=1;
+      if(p->q1.reg==dx) regs[acc]=regs[ix]=1;
+      continue;
+    }
+    if(c==FREEREG){
+      regs[p->q1.reg]=0;
+      if(p->q1.reg==dx) regs[acc]=regs[ix]=0;
+      continue;
+    }
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+	gen_pop(f,notpopped);
+	notpopped=0;
+      }
+    }
+    if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
+    if(c==BRA){
+      if(p->typf==exit_label&&!have_frame){
+	emit(f,"\t%s\n",ret);
+      }else{
+	if(t==exit_label) need_return=1;
+	emit(f,"\tbra\t%s%d\n",labprefix,t);
+      }
+      cc=0;continue;
+    }
+    if(c>=BEQ&&c<BRA){      
+      if((lastcomp&UNSIGNED)||ISPOINTER(lastcomp))
+        emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,t);
+      else
+        emit(f,"\tb%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,SHORT);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->q1.reg,&p->z,SHORT);
+      continue;
+    }
+    
+    /*if(ISFLOAT(t)) {pric2(stdout,p);ierror(0);}*/
+
+    if((t&NQ)==BIT){
+      ierror(0);
+    }
+
+    if(c==CONVERT&&ISLWORD(t)&&ISLWORD(p->typf2)){
+      p->code=c=ASSIGN;
+      p->q2.val.vmax=l2zm(4L);
+    }
+
+    if((p->q2.flags&REG)&&ISACC(p->q2.reg)&&(c==ADD||c==MULT||c==AND||c==OR||c==XOR)){
+      obj o=p->q1;
+      p->q1=p->q2;
+      p->q2=o;
+    }
+
+    if(c==TEST){
+      lastcomp=t;
+      p->code=c=COMPARE;
+      gval.vmax=l2zm(0L);
+      p->q2.flags=KONST;
+      eval_const(&gval,MAXINT);
+      insert_const(&p->q2.val,t);
+    }
+
+    if(c==SUBPFP){
+      p->code=c=SUB;
+      p->typf=t=(UNSIGNED|INT);
+    }
+
+
+
+    if((c==ASSIGN||c==PUSH)&&zmeqto(p->q2.val.vmax,l2zm(4L)))
+      p->typf=t=LONG;
+
+    preload(f,p);
+
+    if(c==ADDI2P||c==SUBIFP){
+      if((p->typf2&NQ)!=HPOINTER){
+	if(p->q2.flags&KONST){
+	  eval_const(&p->q2.val,p->typf);
+	  insert_const(&p->q2.val,p->typf2);
+	  p->typf=t=(UNSIGNED|SHORT);
+	}else{
+	  if(ISLWORD(t)) inc_addr(&p->q2,2,t);
+	  if((t&NQ)==CHAR) short_add=t;
+	  p->typf=t=(UNSIGNED|SHORT);
+	}
+      }else if(ISHWORD(t)){
+	if((t&NQ)==LLONG) 
+	  inc_addr(&p->q2,4,t);
+	else if((t&NQ)!=LONG) 
+	  short_add=t;
+	p->typf=t=(UNSIGNED|LONG);
+      }
+      p->code=c=(c==ADDI2P)?ADD:SUB;
+    }
+
+    if(c==COMPARE&&ISLWORD(t)){
+      IC *branch=p->next;
+      int r;
+      while(branch&&branch->code==FREEREG) branch=branch->next;
+      if(!branch) ierror(0);
+      c=branch->code;
+      if(c<BEQ||c>BGT) ierror(0);
+      if(!regs[ix])
+	r=ix;
+      else
+	r=get_reg(f,p,INT);
+      
+      if(c==BEQ||c==BNE){
+	inc_addr(&p->q1,0,t);
+	inc_addr(&p->q2,0,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	if(pushed_acc) emit(f,SPULLD);
+	emit(f,"\tbne\t%s%d\n",labprefix,c==BEQ?++label:branch->typf);
+	if(pushed_acc) emit(f,SPUSHD);
+	inc_addr(&p->q1,2,t);
+	inc_addr(&p->q2,2,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	pr(f,p);
+	if(c==BEQ){
+	  emit(f,"\tbeq\t%s%d\n",labprefix,branch->typf);
+	  emit(f,"%s%d:\n",labprefix,label);
+	}else
+	  emit(f,"\tbne\t%s%d\n",labprefix,branch->typf);
+      }else{
+	inc_addr(&p->q1,0,t);
+	inc_addr(&p->q2,0,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	label++;
+	if(pushed_acc) emit(f,SPULLD);
+	if(t&UNSIGNED){
+	  if(c==BLT||c==BGT)
+	    emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lo":"hi",labprefix,branch->typf);
+	  else
+	    emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lo":"hi",labprefix,label);
+	}else{
+	  if(c==BLT||c==BGT)
+	    emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lt":"gt",labprefix,branch->typf);
+	  else
+	    emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lt":"gt",labprefix,label);
+	}
+	emit(f,"\tbne\t%s%d\n",labprefix,(c==BLT||c==BGT)?label:branch->typf);
+	if(pushed_acc) emit(f,SPUSHD);
+	inc_addr(&p->q1,2,t);
+	inc_addr(&p->q2,2,t);
+	load_reg(f,r,&p->q1,INT);
+	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+	pr(f,p);
+	emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,branch->typf);
+	emit(f,"%s%d:\n",labprefix,label);
+      }
+      branch->code=NOP;
+      continue;
+    }
+
+    if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
+      int cnt=-1000,i,r=0;
+      int px=0,py=0,pa=0;
+      if(isconst(q2)){
+	eval_const(&p->q2.val,p->typf2);
+	cnt=(int)zm2l(vmax);
+	if(cnt==1&&compare_objects(&p->q1,&p->z)){
+	  if(c==LSHIFT)
+	    emit(f,"\tlsl\t");
+	  else
+	    emit(f,"\t%s\t",(t&UNSIGNED)?"lsr":"asr");
+	  inc_addr(&p->z,c==LSHIFT?3:0,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	  continue;
+	}
+      }
+      inc_addr(&p->q1,2,t);
+      inc_addr(&p->z,2,t);
+
+      if(ISRACC(q2)||(regs[acc]&&!scratchreg(acc,p))){
+	emit(f,SPUSHD);
+	push(2);
+	pa=1;
+      }
+
+      if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+	if(regs[ix]&&!scratchreg(ix,p)) {px=1;emit(f,SPUSH("x"));push(2);}
+	if(regs[iy]&&!scratchreg(iy,p)) {py=1;emit(f,SPUSH("y"));push(2);}
+      }
+
+      if(!compare_objects(&p->q1,&p->z)){
+	load_reg(f,acc,&p->q1,INT);
+	store_reg(f,acc,&p->z,INT);
+      }
+      inc_addr(&p->q1,-2,t);
+      inc_addr(&p->z,-2,t);
+      load_reg(f,acc,&p->q1,INT);
+      if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+	if((p->q2.flags&REG)&&p->q2.reg==ix){
+	  if((p->z.flags&REG)&&p->z.reg==iy) ierror(0);
+	}else
+	  load_addr(f,ix,&p->z);
+	if(ISRACC(q2)){
+	  if(scratchreg(acc,p)&&(px+py==0)){
+	    emit(f,SPULL("y"));
+	    pop(2);pa=0;
+	  }else
+	    emit(f,"\tldy\t%d,%s\n",(px+py)*2,regnames[sp]);
+	}else
+	  load_reg(f,iy,&p->q2,p->typf2); /*TODO: types!=INT?? */
+	if((p->q2.flags&REG)&&p->q2.reg==ix)
+	  load_addr(f,ix,&p->z);
+	if(c==LSHIFT)
+	  emit(f,"\t%s\t%s__lsll\n",jsrinst,idprefix);
+	else
+	  emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,(t&UNSIGNED)?"lsrl":"asrl");
+	if(py) {emit(f,SPULL("y"));pop(2);}
+	if(px) {emit(f,SPULL("x"));pop(2);}
+      }else{
+	inc_addr(&p->z,c==LSHIFT?3:2,t);
+	for(i=0;i<cnt;i++){
+	  if(c==LSHIFT){
+	    emit(f,"\tlsl\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,-1,t);
+	    emit(f,"\trol\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,1,t);
+	    emit(f,"\trolb\n");
+	    emit(f,"\trola\n");
+	  }else{
+	    emit(f,"\t%s\n",(t&UNSIGNED)?"lsra":"asra");
+	    emit(f,"\trorb\n");
+	    emit(f,"\tror\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,1,t);
+	    emit(f,"\tror\t");
+	    emit_obj(f,&p->z,CHAR);
+	    emit(f,"\n");
+	    inc_addr(&p->z,-1,t);
+	  }
+	}
+	inc_addr(&p->z,c==LSHIFT?-3:-2,t);
+	store_reg(f,acc,&p->z,INT);
+      }
+      if(pa) {emit(f,SPULLD);pop(2);}
+      continue;
+    }
+
+    if(ISLWORD(t)&&c!=GETRETURN&&c!=SETRETURN&&c!=COMPARE&&c!=CONVERT&&c!=ADDRESS){
+      if(c==PUSH&&isreg(q1)&&p->q1.reg==dx){
+	if(CPU==6812){
+	  emit(f,"\tpshd\n");
+	  emit(f,"\tpshx\n");
+	}else{
+	  //emit(f,"\tpshs\ta,b,x\n");
+	  emit(f,"\tpshs\tb,a\n");
+	  emit(f,"\tpshs\tx\n");
+	}
+	push(4);
+	continue;
+      }
+      if(c==ASSIGN&&isreg(q1)&&p->q1.reg==dx){
+	inc_addr(&p->z,2,t);
+	store_reg(f,ix,&p->z,INT);
+	inc_addr(&p->z,-2,t);
+	store_reg(f,acc,&p->z,INT);
+	continue;
+      }
+      if(c==ASSIGN&&isreg(z)&&p->z.reg==dx){
+	inc_addr(&p->q1,2,t);
+	load_reg(f,ix,&p->q1,INT);
+	inc_addr(&p->q1,-2,t);
+	load_reg(f,acc,&p->q1,INT);
+	continue;
+      }
+      if(c==PUSH){
+	if(regs[acc]) emit(f,"\tstd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+      }else
+	get_acc(f,p);
+      /*TODO: acc in IC, constants */
+      inc_addr(&p->q1,2,t);
+      if(c==MINUS){
+	if(CPU!=6812&&!optsize)
+	  emit(f,"\tldd\t#0\n");
+	else
+	  emit(f,"\tclra\n\tclrb\n");
+      }else
+	load_reg(f,acc,&p->q1,INT);
+      if(c==ADD||c==SUB){
+	inc_addr(&p->q2,2,t);
+	emit(f,"\t%s\t",c==ADD?"addd":"subd");
+	emit_obj(f,&p->q2,INT);
+	emit(f,"\n");
+      }else if(c==ASSIGN||c==PUSH){
+      }else if(c==MINUS){
+	emit(f,"\tsubd\t");
+	emit_obj(f,&p->q1,INT);
+	emit(f,"\n");
+      }else if(c==KOMPLEMENT){
+	emit(f,"\tcoma\n");
+	emit(f,"\tcomb\n");
+      }else{
+	if(c==AND)
+	  emit(f,"\tandb\t");
+	else if(c==OR)
+	  emit(f,"\tor%sb\t",CPU==6812?"a":"");
+	else if(c==XOR)
+	  emit(f,"\teorb\t");
+	inc_addr(&p->q2,3,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+	if(c==AND)
+	  emit(f,"\tanda\t");
+	else if(c==OR)
+	  emit(f,"\tor%sa\t",CPU==6812?"a":"");
+	else if(c==XOR)
+	  emit(f,"\teora\t");
+	inc_addr(&p->q2,-1,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+      }
+      if(c==PUSH){
+	if(CPU==6812)
+	  emit(f,"\tpshd\n");
+	else
+	  emit(f,"\tpshs\tb,a\n");
+	push(2);dontpop+=2;
+      }else{
+	inc_addr(&p->z,2,t);
+	store_reg(f,acc,&p->z,INT);
+      }
+      inc_addr(&p->q1,-2,t);
+      if(c==MINUS)
+	emit(f,"\tldd\t#0\n");
+      else
+	load_reg(f,acc,&p->q1,INT);
+      if(c==ADD)
+	emit(f,"\tadcb\t");
+      else if(c==SUB)
+	emit(f,"\tsbcb\t");
+      else if(c==AND)
+	emit(f,"\tandb\t");
+      else if(c==OR)
+	emit(f,"\tor%sb\t",CPU==6812?"a":"");
+      else if(c==XOR)
+	emit(f,"\teorb\t");
+      else if(c==KOMPLEMENT)
+	emit(f,"\tcomb\n");
+      else if(c==MINUS){
+	inc_addr(&p->q1,1,t);
+	emit(f,"\tsbcb\t");
+	emit_obj(f,&p->q1,CHAR);
+	emit(f,"\n");
+      }
+      if(p->q2.flags){
+	inc_addr(&p->q2,-1,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+      }
+      if(c==ADD)
+	emit(f,"\tadca\t");
+      else if(c==SUB)
+	emit(f,"\tsbca\t");
+      else if(c==AND)
+	emit(f,"\tanda\t");
+      else if(c==OR)
+	emit(f,"\tor%sa\t",CPU==6812?"a":"");
+      else if(c==XOR)
+	emit(f,"\teora\t");
+      else if(c==KOMPLEMENT)
+	emit(f,"\tcoma\n");
+      else if(c==MINUS){
+	inc_addr(&p->q1,-1,t);
+	emit(f,"\tsbca\t");
+	emit_obj(f,&p->q1,CHAR);
+	emit(f,"\n");
+      }
+      if(p->q2.flags){
+	inc_addr(&p->q2,-1,t);
+	emit_obj(f,&p->q2,CHAR);
+	emit(f,"\n");
+      }
+      if(c==PUSH){
+	if(CPU==6812)
+	  emit(f,"\tpshd\n");
+	else
+	  emit(f,"\tpshs\tb,a\n");
+	push(2);dontpop+=2;
+	if(regs[acc]) emit(f,"\tldd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+      }else{
+	inc_addr(&p->z,-2,t);
+	store_reg(f,acc,&p->z,INT);
+      }
+      continue;
+    }
+
+ 
+    if(c==COMPARE){
+      int vadr;
+      if(drel&&(p->q1.flags&VARADR)&&!ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+      else if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+      else if(pcrel&&(p->q1.flags&VARADR)&&ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+      else if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+      else vadr=0;
+      if(vadr!=1&&(vadr==2||isconst(q1)||ISRACC(q2))){
+	struct IC *p2;
+	o=p->q1;p->q1=p->q2;p->q2=o;
+	p2=p->next;
+	while(p2&&p2->code==FREEREG) p2=p2->next;
+	if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+	if(p2->code==BLT) p2->code=BGT;
+	else if(p2->code==BGT) p2->code=BLT;
+	else if(p2->code==BLE) p2->code=BGE;
+	else if(p2->code==BGE) p2->code=BLE;
+      }
+      /* case with two relative addresses */
+      if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+      if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+    }
+#if 0
+    /* TODO: fix cc */
+    if(c==COMPARE&&isconst(q2)){
+      eval_const(&p->q2.val,t);
+      if(ISNULL()){
+	if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+	  lastcomp=t;continue;
+	}
+      }
+    }
+#endif
+
+    if(!short_add)
+      switch_IC(p);
+
+    if(c==CONVERT){
+      int to=p->typf2&NU;
+      if(to==INT) to=SHORT;
+      if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
+      if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+      if((t&NU)==INT) t=SHORT;
+      if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+      if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+      /*if((t&NQ)>=LONG||(to&NQ)>=LONG) ierror(0);*/
+      if((to&NQ)<=LONG&&(t&NQ)<=LONG){
+	if((to&NQ)<(t&NQ)){
+	  if(ISLWORD(t)){
+	    get_acc(f,p);
+	    load_reg(f,acc,&p->q1,to);
+	    if((to&NU)==CHAR)
+	      emit(f,SEX);
+	    else if((to&NU)==(UNSIGNED|CHAR))
+	      emit(f,"\tclra\n");
+	    inc_addr(&p->z,2,t);
+	    store_reg(f,acc,&p->z,INT);
+	    inc_addr(&p->z,-2,t);
+	    if(to&UNSIGNED){
+	      emit(f,"\tclra\n\tclrb\n");
+	    }else{
+	      if(CPU==6812)
+		emit(f,"\texg\ta,b\n");
+	      else
+		emit(f,"\ttfr\ta,b\n");
+	      emit(f,SEX);
+	      emit(f,"\ttfr\ta,b\n");
+	    }
+	    store_reg(f,acc,&p->z,INT);
+	    continue;
+	  }
+	  /*emit(f,"#conv RACC=%d, regs=%d scratch=%d\n",(int)ISRACC(z),regs[acc],scratchreg(acc,p));*/
+	  if(!ISRACC(z))
+	    get_acc(f,p);
+	  load_reg(f,acc,&p->q1,to);
+	  if(to&UNSIGNED)
+	    emit(f,"\tclra\n");
+	  else
+	    emit(f,SEX);
+	  store_reg(f,acc,&p->z,t);
+	  cc=&p->z;cc_t=t;
+	  continue;
+	}else if((to&NQ)>(t&NQ)){
+	  if(!ISRACC(z)&&!ISRACC(q1))
+	    get_acc(f,p);
+	  if(ISLWORD(to))
+	    inc_addr(&p->q1,2,to);
+	  load_reg(f,acc,&p->q1,to);
+	  store_reg(f,acc,&p->z,t);
+	  continue;
+	}else{
+	  c=ASSIGN;
+	  p->q2.val.vmax=sizetab[t&NQ];
+	}
+      }
+    }
+    if(c==KOMPLEMENT){
+      cc=0;
+      if(compare_objects(&p->q1,&p->z)&&!isreg(q1)&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&(!p->q1.am||p->q1.am->flags!=ACC_IND)){
+	emit(f,"\tcom\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	if(ISHWORD(t)){
+	  mobj=p->z;
+	  inc_addr(&mobj,1,t);
+	  emit(f,"\tcom\t");
+	  emit_obj(f,&mobj,INT);
+	  emit(f,"\n");
+	}
+	continue;
+      }
+      if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	get_acc(f,p);
+      load_reg(f,acc,&p->q1,t);
+      emit(f,"\tcoma\n\tcomb\n");
+      store_reg(f,acc,&p->z,t);
+      continue;
+    }
+    if(c==MINUS){
+      if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	get_acc(f,p);
+      if(isreg(q1)){
+	load_reg(f,acc,&p->q1,t);
+	emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+      }else{
+	if(CPU!=6812&&!optsize)
+	  emit(f,"\tldd\t#0\n");
+	else
+	  emit(f,"\tclra\n\tclrb\n");
+	emit(f,"\tsubd\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      cc=&p->z;cc_t=t;
+      store_reg(f,acc,&p->z,t);
+      continue;
+    }
+    if(c==SETRETURN){
+      if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+      if(p->z.reg){
+	if(ISLWORD(t)){
+	  inc_addr(&p->q1,0,t);
+	  load_reg(f,ix,&p->q1,INT);
+	  BSET(regs_modified,ix);
+	  inc_addr(&p->q1,2,t);
+	}
+	load_reg(f,acc,&p->q1,t);
+	BSET(regs_modified,acc);
+
+      }
+      continue;
+    }
+    if(c==GETRETURN){
+      if(isreg(z)&&p->z.reg==p->q1.reg) continue;
+      if(p->q1.reg){
+	if(ISLWORD(t)){
+	  store_reg(f,ix,&p->z,INT);
+	  BSET(regs_modified,ix);
+	  inc_addr(&p->z,2,t);
+	}
+	store_reg(f,acc,&p->z,(t&NQ)==CHAR?t:INT);
+      }
+      continue;
+    }
+    if(c==CALL){
+      int reg,jmp=0;
+      cc=0;
+      if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	long of=va_offset(v)+loff+2;
+	emit(f,"\ttfr\t%s,d\n",regnames[sp]);
+	if(of) emit(f,"\taddd\t#%ld\n",of);
+	continue;
+      }
+      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+	emit_inline_asm(f,p->q1.v->fi->inline_asm);
+	jmp=1;
+      }else{
+	if(stackoffset==0&&!have_frame&&!strcmp(ret,"rts")){
+	  struct IC *p2;
+	  jmp=1;
+	  for(p2=p->next;p2;p2=p2->next){
+	    if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL){
+	      jmp=0;break;
+	    }
+	  }
+	}
+	if(p->q1.flags&DREFOBJ){
+	  /*FIXME: test this*/
+	  if(jmp)
+	    emit(f,"\tjmp\t");
+	  else
+	    emit(f,"\tjsr\t");
+	  if (p->q1.v->tattr&FAR)
+	  	emit(f,"\tfar\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}else{
+	  if(jmp){
+	    emit(f,"\t%s\t",jmpinst); /*emit(f,"\tbra\t");*/
+	    /*if(!need_return) ret=0;*/ /*TODO: works with optimizer? */
+	  }else{
+	    emit(f,"\t%s\t",jsrinst); /*emit(f,"\tbsr\t");*/
+	  }
+	  if (p->q1.v->tattr&FAR)
+	  	emit(f,"\tfar\t");
+	  if(pcrel){
+	    pcrel=0;
+	    emit_obj(f,&p->q1,t);
+	    pcrel=1;
+	  }else
+	    emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	}
+      }
+      if(stack_valid){
+        int i;
+        if(p->call_cnt<=0){
+          err_ic=p;if(f) error(320);
+          stack_valid=0;
+        }
+        for(i=0;stack_valid&&i<p->call_cnt;i++){
+          if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+	    /*FIXME: size of return addr depends on mode */
+	    if(!jmp) push(2);
+	    callee_push(zm2l(p->call_list[i].v->fi->stack1));
+	    if(!jmp) pop(2);
+          }else{
+            err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+            stack_valid=0;
+          }
+        }
+      }
+      if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+	notpopped+=zm2l(p->q2.val.vmax);
+	dontpop-=zm2l(p->q2.val.vmax);
+	if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+	  /*  Entfernen der Parameter verzoegern  */
+	}else{
+	  gen_pop(f,zm2l(p->q2.val.vmax));
+	  notpopped-=zm2l(p->q2.val.vmax);
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+      if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+	unsigned long size;int qr=0,zr=0,cr=0,px=0,py=0,pu=0,pd=0,lq=0,lz=0;
+	size=zm2l(p->q2.val.vmax);
+	if(c==ASSIGN){
+	  if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->z.reg)){
+	    zr=p->z.reg;lz=1;
+	  }
+	}
+	if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->q1.reg)&&p->q1.reg!=zr){
+	  qr=p->q1.reg;lq=1;
+	}
+	if(!qr){
+	  if(zr==ix) qr=iy;
+	  else if(zr==iy||zr==iu) qr=ix;
+	  else{qr=ix;zr=iy;}
+	}else if(!zr){
+	  if(qr==ix) zr=iy; else zr=ix;
+	}
+	if(CPU!=6812){
+	  if(qr!=iu&&zr!=iu) cr=iu;
+	  if(qr!=ix&&zr!=ix) cr=ix;
+	  if(qr!=iy&&zr!=iy) cr=iy;
+	  if(!cr) ierror(0);
+	}
+	if(c==PUSH){
+	  emit(f,"\tleas\t%ld,%s\n",SGN16(-size),regnames[sp]);
+	  push(size);
+	}
+	if(CPU!=6812&&(drel||!regused[iu]||(regs[iu]&&!scratchreg(iu,p)))){
+	  if(c==PUSH)
+	    emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPUSH("u"));
+	    push(2);
+	  }
+	  pu=1;
+	}
+	if(!regused[iy]||(regs[iy]&&!scratchreg(iy,p))){
+	  if(c==PUSH)
+	    emit(f,"\tsty\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPUSH("y"));
+	    push(2);
+	  }
+	  py=1;
+	}
+	if(regs[ix]&&!scratchreg(ix,p)){
+	  if(c==PUSH)
+	    emit(f,"\tstx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPUSH("x"));
+	    push(2);
+	  }
+	  px=1;
+	}
+	if(!lq) load_addr(f,qr,&p->q1);
+	if(c==PUSH)
+	  emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[zr]);
+	else
+	  if(!lz) load_addr(f,zr,&p->z);
+	if(size<=6||(size<=16&&!optsize)){
+	  if(CPU!=6812){
+	    if(!scratchreg(acc,p)){
+	      if(c==PUSH)
+		emit(f,"\tstd\t%ld,%s\n",loff-roff-6-stackoffset,regnames[sp]);
+	      else{
+		emit(f,SPUSHD);
+		push(2);
+	      }
+	      pd=2;
+	    }
+	  }
+	  while(size>2){
+	    if(CPU==6812)
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	    else
+	      emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+	    size-=2;
+	  }
+	  if(CPU==6812)
+	    emit(f,"\tmov%c\t0,%s,0,%s\n",size==2?'w':'b',regnames[qr],regnames[zr]);
+	  else
+	    emit(f,"\tld%c\t,%s\n\tst%c\t,%s\n",size==2?'d':'b',regnames[qr],size==2?'d':'b',regnames[zr]);
+	}else{
+	  int l=++label,cnt=(int)(optsize?size:size/8);
+	  if(regs[acc]&&!scratchreg(acc,p)){
+	    if(c==PUSH)
+	      emit(f,"\tst%c\t%ld,%s\n",(CPU!=6812&&cnt<=bytemask)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+	    else{
+	      if(CPU!=6812&&cnt<=bytemask){
+		emit(f,SPUSH("b"));
+		push(1);
+	      }else{
+		emit(f,SPUSHD);
+		push(2);
+	      }
+	    }
+	    pd=(CPU!=6812&&cnt<=bytemask)?1:2;
+	  }
+	  if(CPU!=6812&&cnt<=bytemask)
+	    emit(f,"\tldb\t#%lu\n",cnt);
+	  else
+	    emit(f,"\tldd\t#%lu\n",cnt);
+	  cc=0;
+#if 0
+	  if(CPU!=6812&&((!regsa[iu]&&regs[iu])||drel)){
+	    if(c==PUSH){
+	      emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); 
+	    }else{
+	      emit(f,SPUSH("u"));push(2);
+	    }
+	  }
+#endif
+	  emit(f,"%s%d:\n",labprefix,l);
+	  if(CPU==6812){
+	    if(optsize){
+	      emit(f,"\tmovb\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	    }else{
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	      size=size&7;
+	    }
+	    emit(f,"\tdbne\td,%s%d\n",labprefix,l);
+	  }else{
+	    if(optsize){
+	      emit(f,"\tld%s\t,%s+\n\tst%s\t,%s+\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      size&=1;
+	    }else{
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+	      size&=7;
+	    }
+	    if(cnt<=bytemask)
+	      emit(f,"\tdecb\n");
+	    else
+	      emit(f,"\tsubd\t#1\n");
+	    emit(f,"\tbne\t%s%d\n",labprefix,l);
+	  }
+#if 0
+	  if(CPU!=6812&&((!regsa[iu]&&regs[iu])||drel)){
+	    if(c==PUSH){
+	      emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+	    }else{
+	      emit(f,SPULL("u"));pop(2);
+	    }
+	  }
+#endif
+	  while(size>=2){
+	    if(CPU==6812)
+	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+	    else
+	      emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+	    size-=2;
+	  }
+	  if(size){
+	    if(CPU==6812)
+	      emit(f,"\tmovb\t0,%s,0,%s\n",regnames[qr],regnames[zr]);
+	    else
+	      emit(f,"\tldb\t,%s\n\tstb\t,%s\n",regnames[qr],regnames[zr]);
+	  }
+	}
+	if(pd){
+	  if(c==PUSH) 
+	    emit(f,"\tld%c\t%ld,%s\n",(pd==1)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+	  else{
+	    if(pd==1){
+	      emit(f,SPULL("b"));
+	      pop(1);
+	    }else{
+	      emit(f,SPULLD);
+	      pop(2);
+	    }
+	  }
+	}
+	if(px){
+	  if(c==PUSH) 
+	    emit(f,"\tldx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPULL("x"));
+	    pop(2);
+	  }
+	}
+	if(py){
+	  if(c==PUSH) 
+	    emit(f,"\tldy\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPULL("y"));
+	    pop(2);
+	  }
+	}
+	if(pu){
+	  if(c==PUSH) 
+	    emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+	  else{
+	    emit(f,SPULL("u"));
+	    pop(2);
+	  }
+	}
+	continue;
+      }
+      if(!ISSCALAR(t)) t=zmeqto(p->q2.val.vmax,l2zm(1L))?CHAR:INT;
+      if((t&NQ)==CHAR&&!zmeqto(p->q2.val.vmax,l2zm(1L))) t=INT;	
+      if(mov_op(&p->q1)&&(c==PUSH||mov_op(&p->z))){
+	emit(f,"\tmov%c\t",ISHWORD(t)?'w':'b');
+	emit_obj(f,&p->q1,t);
+	if(c==ASSIGN){
+	  emit(f,",");
+	  emit_obj(f,&p->z,t);
+	  emit(f,"\n");
+	}else{
+	  emit(f,",%d,-%s\n",ISHWORD(t)?2:1,regnames[sp]);
+	  push(ISHWORD(t)?2:1);
+	}
+	continue;
+      }
+      if(((regs[acc]&&regs[ix])||(t&NQ)==CHAR)&&(p->q1.flags&KONST)&&!isreg(z)){
+	eval_const(&p->q1.val,t);
+	if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&((p->z.flags&(REG|DREFOBJ))!=DREFOBJ||(t&NQ)==CHAR)&&(!p->z.am||p->z.am->flags!=ACC_IND||(t&NQ)==CHAR)){
+	  emit(f,"\tclr\t");
+	  if(c==ASSIGN){
+	    emit_obj(f,&p->z,t);emit(f,"\n");
+	  }else{
+	    emit(f,CPU==6812?"1,-sp\n":",-s\n");
+	    push(1);
+	  }
+	  if(!ISHWORD(t)) continue;
+	  emit(f,"\tclr\t");
+	  if(c==ASSIGN){
+	    mobj=p->z;
+	    inc_addr(&mobj,1,t);
+	    emit_obj(f,&mobj,t);emit(f,"\n");
+	  }else{
+	    emit(f,CPU==6812?"1,-sp\n":",-s\n");
+	    push(1);
+	  }
+	  continue;
+	}
+
+      }
+      if(c==PUSH){
+	int st=0;
+	if(isreg(q1)){
+	  reg=p->q1.reg;
+	}else{
+	  if((t&NQ)==CHAR||!regs[acc]||scratchreg(acc,p)) reg=acc;
+	  else if(!regs[ix]||scratchreg(ix,p)) reg=ix;
+	  else if(regused[iy]&&(!regs[iy]||scratchreg(iy,p))) reg=iy;
+	  else if(regused[iu]&&!drel&&CPU!=6812&&(!regs[iu]||scratchreg(iu,p))) reg=iu;
+	  else reg=acc;
+	  if(regs[reg]&&!scratchreg(reg,p)){
+	    st=1;
+	    emit(f,"\tst%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+	  }
+	  load_reg(f,reg,&p->q1,t);
+	}
+	if((t&NQ)==CHAR)
+	  emit(f,SPUSH("b"));
+	else if(reg==ix)
+	  emit(f,SPUSH("x"));
+	else if(reg==iy)
+	  emit(f,SPUSH("y"));
+	else if(reg==iu)
+	  emit(f,SPUSH("u"));
+	else
+	  emit(f,SPUSHD);
+	push(zm2l(p->q2.val.vmax));
+	if(st)
+	  emit(f,"\tld%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+	continue;
+      }
+      if(c==ASSIGN){
+	if(isreg(q1)&&isreg(z)){
+	  if(p->q1.reg!=p->z.reg)
+	    emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]);
+	}else if(isreg(q1)){
+	  store_reg(f,p->q1.reg,&p->z,t);
+	}else if(isreg(z)){
+	  load_reg(f,p->z.reg,&p->q1,t);
+	}else{
+	  reg=get_reg(f,p,t);
+	  load_reg(f,reg,&p->q1,t);
+	  store_reg(f,reg,&p->z,t);
+	}
+	continue;
+      }
+      ierror(0);
+    }
+    if(c==ADDRESS){
+      int px=0;
+      if(isreg(z)){
+	reg=p->z.reg;
+      }else if(!regs[ix]){
+	reg=ix;
+      }else if(!regs[iy]){
+	reg=iy;
+      }else{
+	/*FIXME: test if x used in q1 */
+	px=1;
+	emit(f,SPUSH("x"));
+	reg=ix;
+	push(2);
+      }
+      load_addr(f,reg,&p->q1);
+      if(!(p->z.flags&REG)||p->z.reg!=reg)
+	store_reg(f,reg,&p->z,p->typf2);
+      if(px){
+	emit(f,SPULL("x"));
+	pop(2);
+      }
+      continue;
+    }
+
+    if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
+      long ln;
+      eval_const(&p->q2.val,t);
+      if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	if((ln=pof2(vumax))&&ln<5){
+	  if(c==MOD){
+	    vmax=zmsub(vmax,l2zm(1L));
+	    c=p->code=c=AND;
+	  }else{
+	    vmax=l2zm(ln-1);
+	    if(c==DIV) p->code=c=RSHIFT; else p->code=c=LSHIFT;
+	  }
+	  c=p->code;
+	  gval.vmax=vmax;
+	  eval_const(&gval,MAXINT);
+	  if(c==AND){
+	    insert_const(&p->q2.val,t);
+	  }else{
+	    insert_const(&p->q2.val,t);
+	    p->typf2=INT;
+	  }
+	}
+      }
+    }
+    if(c==MOD||c==DIV){
+      ierror(0);
+      continue;
+    }
+
+
+    if((c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(p->q1.flags&(REG|DREFOBJ))!=REG&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&!p->q1.am&&!p->z.am&&compare_objects(&p->q1,&p->z)){
+      eval_const(&p->q2.val,t);
+      if(c==SUB) vmax=zmsub(Z0,vmax);
+      if((t&NQ)==CHAR&&zmeqto(vmax,Z1)){
+	emit(f,"\tinc\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	continue;
+      }else if((t&NQ)==CHAR&&zmeqto(vmax,l2zm(-1L))){
+	emit(f,"\tdec\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	continue;
+      }else if(((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(1L))){
+	inc_addr(&p->z,1,t);
+	emit(f,"\tinc\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	inc_addr(&p->z,-1,t);
+	emit(f,"\tinc\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	continue;
+      }else if(regs[acc]&&((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(-1L))){
+	inc_addr(&p->z,1,t);
+	emit(f,"\ttst\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"\tbne\t%s%d\n",labprefix,++label);
+	inc_addr(&p->z,-1,t);
+	emit(f,"\tdec\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	emit(f,"%s%d:\n",labprefix,label);
+	inc_addr(&p->z,1,t);
+	emit(f,"\tdec\t");
+	emit_obj(f,&p->z,t);
+	emit(f,"\n");
+	continue;
+      }
+    }
+
+    if((c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP||c==SUBPFP||(c>=OR&&c<=AND)||c==COMPARE){
+      char *s;
+      /*FIXME: nicht immer besser*/
+      if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
+	eval_const(&p->q2.val,t);
+	if(zm2l(vmax)==1){
+	  p->code=c=ADD;
+	  p->q2=p->q1;
+	}
+      }
+      if((c==ADD||c==ADDI2P||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&!isreg(q1)&&!short_add){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+      }
+      if((c==ADD||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&p->q2.reg==acc&&!short_add){
+	o=p->q1;p->q1=p->q2;p->q2=o;
+      }
+      if(c==MULT||c==MOD){
+	if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	  get_acc(f,p);
+	reg=acc;
+	/*FIXME: y bzw. x-Register*/
+      }else if(c==LSHIFT||c==RSHIFT||c==AND||c==OR||c==XOR){
+	if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
+	  get_acc(f,p);
+	reg=acc;
+      }else if(c==DIV){
+	reg=ix;
+	ierror(0);
+      }else if(isreg(z)){
+	reg=p->z.reg;
+      }else if(isreg(q1)&&(c==COMPARE||scratchreg(p->q1.reg,p))){
+	reg=p->q1.reg;
+      }else{
+	if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==COMPARE){
+	  if(ISRACC(q2))
+	    reg=acc;
+	  else
+	    reg=get_reg(f,p,t);
+	}else{
+	  get_acc(f,p);
+	  reg=acc;
+	}
+      }
+      if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
+	int opdone=0;
+	if(isreg(q1)){
+	  if(ISIDX(reg)&&ISIDX(p->q1.reg)&&isconst(q2)){
+	    eval_const(&p->q2.val,short_add?short_add:q2typ(p));
+	    if(CPU==6812&&p->q1.reg==reg&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
+	      emit(f,"\t%s%s\n",c==SUB?"de":"in",regnames[reg]);
+	      /*FIXME: condition-codes for bne/beq could be used */
+	    }else{
+	      emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],c==SUB?SGN16(-zm2l(vmax)):SGN16(zm2l(vmax)),regnames[p->q1.reg]);
+	    }
+	    opdone=1;
+	  }else	if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISIDX(p->q1.reg)&&ISRACC(q2)){
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NQ)==CHAR||(short_add&NQ)==CHAR)?"b":"d",regnames[p->q1.reg]);
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISACC(p->q1.reg)&&ISRIDX(q2)){
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[p->q2.reg]);
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&!short_add){
+	    load_reg(f,reg,&p->q2,t);
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&(short_add&NU)==(UNSIGNED|CHAR)&&scratchreg(acc,p)){
+	    emit(f,"\taddb\t");
+	    emit_obj(f,&p->q2,short_add);
+	    emit(f,"\n");
+	    emit(f,"\tadca\t#0\n");
+	    emit(f,"\ttfr\td,y\n");
+	    opdone=1;
+	  }else if((c==ADD||c==ADDI2P)&&ISACC(p->q1.reg)&&ISRACC(z)&&isreg(q2)&&ISIDX(p->q2.reg)){
+	    if(!scratchreg(p->q2.reg,p)) emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+	    emit(f,"\tlea%s\t%s,%s\n",regnames[p->q2.reg],regnames[acc],regnames[p->q2.reg]);
+	    emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+	    opdone=1;
+	  }else	if(p->q1.reg!=reg){
+	    if(c==ADD||c==ADDI2P||!ISRACC(q2))
+	      emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[reg]);
+	  }
+	}else if(short_add&&c==SUB&&reg==acc&&!(short_add&UNSIGNED)){
+	  load_reg(f,reg,&p->q2,short_add);
+	  emit(f,"\tclra\n");
+	  emit(f,"\tnegb\n");
+	  emit(f,"\tsbca\t#0\n");
+	  emit(f,"\taddd\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	  store_reg(f,reg,&p->z,ztyp(p));
+	  continue;
+	}else if(short_add&&c==ADD&&reg==acc){
+	  load_reg(f,reg,&p->q2,short_add);
+	  if(short_add&UNSIGNED)
+	    emit(f,"\tclra\n");
+	  else
+	    emit(f,SEX);
+	  emit(f,"\taddd\t");
+	  emit_obj(f,&p->q1,t);
+	  emit(f,"\n");
+	  store_reg(f,reg,&p->z,ztyp(p));
+	  continue;
+	}else{
+	  if(!ISRACC(q2))
+	    load_reg(f,reg,&p->q1,q1typ(p));
+	}
+	if(!opdone){
+	  if(reg==acc){
+	    if(ISRACC(q2)){
+	      if(!ISRACC(z)) get_acc(f,p);
+	      if(c==ADD||c==ADDI2P){
+		if(short_add){
+		  if(short_add&UNSIGNED)
+		    emit(f,"\tclra\n");
+		  else
+		    emit(f,SEX);
+		  emit(f,"\taddd\t");
+		  emit_obj(f,&p->q1,t);
+		  emit(f,"\n");
+		}else{
+		  if(CPU==6812)
+		    emit(f,"\tasld\n"); /* only cases with q1=q2=acc should remain */
+		  else{
+		    emit(f,"\taslb\n");
+		    if((t&NQ)!=CHAR)
+		      emit(f,"\trola\n");
+		  }
+		}
+	      }else{
+		if(short_add){
+		  if(short_add&UNSIGNED)
+		    emit(f,"\tld%sa\t#255\n",(CPU==6812)?"a":"");
+		  else{
+		    emit(f,SEX);
+		    emit(f,"\tnega\n");
+		  }
+		  emit(f,"\tnegb\n\tsbca\t#0\n");
+		}else if((t&NQ)!=CHAR){
+		  emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+		}else{
+		  emit(f,"\tnegb\n");
+		}
+		
+		if(ISRIDX(q1)){
+		  emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[p->q1.reg]);
+		  emit(f,"\taddd\t%s\n",CPU==6812?"1,s+":",s++");
+		}else{
+		  emit(f,"\taddd\t");
+		  emit_obj(f,&p->q1,t);
+		  emit(f,"\n");
+		}
+	      }
+	    }else{
+	      if(ISRIDX(q2)){
+		if(CPU==6812)
+		  emit(f,"\tpsh%s\n",regnames[p->q2.reg]);
+		else
+		  emit(f,"\tpshs\t%s\n",regnames[p->q2.reg]);
+		push(2);pop(2);
+		if(CPU==6812)
+		  emit(f,"\t%sd\t2,%s+\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+		else
+		  emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+	      }else{
+		emit(f,"\t%s%s\t",(c==ADD||c==ADDI2P)?"add":"sub",(short_add||(t&NQ)==CHAR)?"b":"d");
+		emit_obj(f,&p->q2,short_add?short_add:t);emit(f,"\n");
+		if(short_add){
+		  if(short_add&UNSIGNED)
+		    emit(f,"\t%s\t#0\n",c==ADD?"adca":"sbca");
+		  else
+		    ierror(0);
+		}
+		if(drel&&(p->q2.flags&VARADR)){
+		  if(CPU==6812) ierror(0);
+		  emit(f,"\tpshs\t%s\n",regnames[iu]);push(2);
+		  emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+		  pop(2);
+		}
+	      }
+	    }
+	    cc=&p->z;cc_t=t;
+	  }else{
+	    if(isconst(q2)){
+	      long l;
+	      eval_const(&p->q2.val,short_add?short_add:t);
+	      l=zm2l(vmax);
+	      if(c==SUB) l=-l;
+	      /*FIXME: condition-codes for bne/beq could be used */
+	      if(l==1&&reg==ix&&CPU==6812){
+		emit(f,"\tinx\n");
+	      }else if(l==1&&reg==iy&&CPU==6812){
+		emit(f,"\tiny\n");
+	      }else if(l==-1&&reg==ix&&CPU==6812){
+		emit(f,"\tdex\n");
+	      }else if(l==-1&&reg==iy&&CPU==6812){
+		emit(f,"\tdey\n");
+	      }else{
+		emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],SGN16(l),regnames[reg]);
+	      }
+	    }else{
+	      if(c!=ADD&&c!=ADDI2P){
+		if(!ISRACC(q2)){
+		  if(!scratchreg(acc,p))
+		    get_acc(f,p);
+		  load_reg(f,acc,&p->q2,t);
+		  if((t&NQ)!=CHAR){
+		    emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+		  }else{
+		    emit(f,"\tnegb\n");
+		  }
+		  /*load_reg(f,reg,&p->q1,t);*/
+		}else{
+		  get_acc(f,p);
+		  load_reg(f,reg,&p->q1,t);
+		  if((t&NQ)==CHAR)
+		    emit(f,"\tnegb\n");
+		  else
+		    emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+		}  
+	      }else if(!ISRACC(q2)){
+		get_acc(f,p);
+		if(short_add){
+		  load_reg(f,acc,&p->q2,short_add);
+		  if(short_add&UNSIGNED){
+		    if(reg==ix){
+		      emit(f,"\tabx\n");
+		      store_reg(f,reg,&p->z,ztyp(p));
+		      continue;
+		    }else{
+		      emit(f,"\tclra\n");
+		    }
+		  }else
+		    t=CHAR;
+		}else
+		  load_reg(f,acc,&p->q2,t);
+	      }else{
+		load_reg(f,reg,&p->q1,t);
+		if(short_add&UNSIGNED)
+		  emit(f,"\tclra\n");
+		emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NU)==CHAR||(short_add&NU)==CHAR)?"b":"d",regnames[reg]);
+		store_reg(f,reg,&p->z,ztyp(p));
+		continue;
+	      }
+	      emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+	    }
+	  }
+	}
+	store_reg(f,reg,&p->z,ztyp(p));
+	continue;
+      }
+      if(c!=LSHIFT&&c!=RSHIFT)
+	load_reg(f,reg,&p->q1,t);
+      if(c==MULT){
+	if(CPU==6812){
+	  int py=0;
+	  if(reg!=acc) ierror(reg);
+	  if(!ISRY(q2)&&regs[iy]){
+	    emit(f,"\tpshy\n");
+	    push(2);
+	    py=1;
+	  }
+	  load_reg(f,iy,&p->q2,t);
+	  emit(f,"\temul\n");
+	  if(py){
+	    emit(f,SPULL("y"));
+	    pop(2);
+	  }
+	  store_reg(f,acc,&p->z,t);
+	  continue;
+	}else
+	  ierror(0);
+      }
+      if(c==LSHIFT||c==RSHIFT){
+	if(isconst(q2)){
+	  int l,oldl;
+	  load_reg(f,acc,&p->q1,t);
+	  eval_const(&p->q2.val,t);
+	  oldl=l=zm2l(vmax);
+	  if(l>=24){
+	    if(CPU!=6812&&!optsize)
+	      emit(f,"\tldd\t#0\n");
+	    else
+	      emit(f,"\tclra\n\tclrb\n");
+	    l=0;
+	  }
+	  if(l>=8){
+	    if(c==LSHIFT)
+	      emit(f,"\t%s\n\tclrb\n",(CPU==6812)?"tba":"tfr\tb,a");
+	    else{
+	      if(t&UNSIGNED)
+		emit(f,"\ttfr\ta,b\n\tclra\n");
+	      else{
+		emit(f,"\ttfr\ta,b\n");
+		emit(f,SEX);
+	      }
+	    }
+	    l-=8;
+	  }
+	  while(l--){
+	    if(c==RSHIFT){
+	      if(t&UNSIGNED){
+		if((t&NQ)==CHAR)
+		  emit(f,"\tlsrb\n");
+		else
+		  emit(f,CPU==6809?"\tlsra\n\trorb\n":"\tlsrd\n");
+	      }else{
+		if(oldl>12||(t&NQ)==CHAR)
+		  emit(f,"\tasrb\n");
+		else
+		  emit(f,"\tasra\n\trorb\n");
+	      }
+	    }else{
+	      if((t&NQ)==CHAR)
+		emit(f,"\taslb\n");
+	      else
+		emit(f,CPU==6809?"\taslb\n\trola\n":"\tasld\n");
+	    }
+	  }
+	}else{
+	  int px;char *s;
+	  if(regs[ix]&&!scratchreg(ix,p)&&(!isreg(z)||p->z.reg!=ix)){
+	    emit(f,SPUSH("x"));
+	    push(2);px=1;
+	  }else
+	    px=0;
+	  if((p->typf2&NQ)==CHAR){
+	    load_reg(f,acc,&p->q2,p->typf2);
+	    emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX);
+	    emit(f,"\ttfr\td,x\n");
+	  }else
+	    load_reg(f,ix,&p->q2,t);
+	  load_reg(f,acc,&p->q1,p->typf);
+	  if((t&NQ)==CHAR)
+	    emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX);
+	  if(c==LSHIFT) s="lsl";
+	  else if(t&UNSIGNED) s="lsr";
+	  else s="asr";
+	  emit(f,"\t.global\t%s__%s\n",idprefix,s);
+	  emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,s);
+	  if(px){
+	    emit(f,SPULL("x"));
+	    /*emit(f,"\tpul%s\n",regnames[ix]);*/
+	    pop(2);
+	  }
+	}
+	cc=0;
+	store_reg(f,acc,&p->z,t);
+	continue;
+      }
+      if(c>=OR&&c<=AND){
+	s=logicals[c-OR];
+	if(p->q2.am&&p->q2.am->flags==ACC_IND){
+	  mobj=p->q1;p->q1=p->q2;p->q2=mobj;
+	}
+	if(p->q2.flags&KONST){
+	  unsigned long l,h;
+	  eval_const(&p->q2.val,t);
+	  l=zum2ul(vumax);
+	  if((t&NQ)!=CHAR){
+	    h=(l>>bitsperbyte)&bytemask;
+	    if(c==AND&&h==0)
+	      emit(f,"\tclra\n");
+	    else if(c==XOR&&h==bytemask)
+	      emit(f,"\tcoma\n");
+	    else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+	      emit(f,"\t%sa\t#%lu\n",s,h);
+	  }
+	  h=l&bytemask;
+	  if(c==AND&&h==0)
+	    emit(f,"\tclrb\n");
+	  else if(c==XOR&&h==bytemask)
+	    emit(f,"\tcomb\n");
+	  else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+	    emit(f,"\t%sb\t#%lu\n",s,h);
+	}else{
+	  if(isreg(q2)){
+	    if(p->q2.reg==acc){
+	      if(c==XOR){
+		emit(f,"\tclrb\n");
+		if((t&NQ)!=CHAR) emit(f,"\tclra\n");
+	      }
+	    }else{
+	      if((t&NQ)==CHAR){
+		emit(f,SPUSH("a"));
+		push(1);
+		emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+		pop(1);
+	      }else{
+		emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+		push(2);
+		emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+		emit(f,"\t%sb\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+		pop(2);
+	      }
+	    }
+	  }else if((p->q2.flags&(REG|DREFOBJ))==DREFOBJ&&(t&NQ)!=CHAR){
+	    int xr=0;
+	    if(!regs[ix]) xr=ix;
+	    else if(!regs[iy]) xr=iy;
+	    else{
+	      xr=ix;
+	      emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[xr]);
+	      push(2);
+
+	    }
+	    BSET(regs_modified,xr);
+	    load_addr(f,xr,&p->q2);
+	    if((t&NQ)==CHAR)
+	      emit(f,"\t%sb\t0,%s\n",s,regnames[xr]);
+	    else{
+	      emit(f,"\t%sa\t0,%s\n",s,regnames[xr]);
+	      emit(f,"\t%sb\t1,%s\n",s,regnames[xr]);
+	    }
+	    if(regs[ix]&&xr==ix){
+	      emit(f,SPULL("x"));
+	      pop(2);
+	    }
+	  }else{
+	    emit(f,"\t%sb\t",s);
+	    if((t&NQ)!=CHAR) inc_addr(&p->q2,1,t);
+	    emit_obj(f,&p->q2,t);
+	    emit(f,"\n");
+	    if((t&NQ)!=CHAR){
+	      inc_addr(&p->q2,-1,t);
+	      emit(f,"\t%sa\t",s);
+	      emit_obj(f,&p->q2,t);
+	      emit(f,"\n");
+	    }
+	  }
+	}
+	cc=0;
+	store_reg(f,reg,&p->z,t);
+	continue;
+      }else if(c==COMPARE){
+	lastcomp=t;
+	if(isreg(q2)){
+	  emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+	  push(2);
+	}
+	if(reg==acc){
+	  if((t&NQ)==CHAR)
+	    emit(f,"\tcmpb\t");
+	  else
+	    emit(f,SCMP("d"));
+	}else if(reg==ix){
+	  emit(f,SCMP("x"));
+	}else if(reg==iy){
+	  emit(f,SCMP("y"));
+	}else if(reg==iu){
+	  emit(f,SCMP("u"));
+	}else
+	  ierror(0);
+	if(isreg(q2)){
+	  if(CPU==6812)
+	    emit(f,"2,%s+\n",regnames[sp]);
+	  else
+	    emit(f,",%s++\n",regnames[sp]);
+	  pop(2);
+	}else{
+	  emit_obj(f,&p->q2,t);emit(f,"\n");
+	}
+	continue;
+      }
+      ierror(0);
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  if(notpopped){
+    gen_pop(f,notpopped);
+    notpopped=0;
+  }
+  function_bottom(f,v,loff);
+  if(debug_info){
+    emit(f,"%s%d:\n",labprefix,++label);
+    dwarf2_function(f,v,label);
+    if(f) section=-1;
+  }     
+}
+
+int shortcut(int c,int t)
+{
+  if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
+  if((c==LSHIFT||c==RSHIFT)&&ISCHWORD(t&NQ)) return 1;
+  return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+  struct fpconstlist *p;
+  unsigned char *ip;
+  if(f&&stack_check)
+    emit(f,"\t.global\t%s__stack_check\n",idprefix);
+  while(p=firstfpc){
+    if(f){
+      if(section!=RODATA){
+	emit(f,rodataname);if(f) section=RODATA;
+      }
+      emit(f,"%s%d\n\t%s\t",labprefix,p->label,dct[LONG]);
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+      emit(f,"\n");
+    }
+    firstfpc=p->next;
+    free(p);
+  }
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+  if(p->gpr) return 0;
+  if(ISSCALAR(t->flags)&&!ISFLOAT(t->flags)&&!ISLWORD(t->flags)){
+    p->gpr=1;
+    return acc;
+  }
+  return 0;
+}
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+  t&=NU;
+  if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}  
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==NPOINTER) {p->vuint=vuint;return;}
+  if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==BIT){
+	if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
+      }else if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==BIT){
+	if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
+      }else if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      if(f==NPOINTER)
+	vumax=zui2zum(p->vuint);
+      else
+	vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==BIT){vmax=zc2zm(p->vchar);fprintf(f,"B%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);fprintf(f,"UB%d",!zumeqto(vmax,ul2zum(0UL)));}
+  if(t==CHAR){vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT) printzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+} 
+void emitval(FILE *f,union atyps *p,int t)
+{
+  t&=NU;
+  if((t&NQ)==NPOINTER) t=(UNSIGNED|INT);
+  if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT) emitzm(f,p->vmax);
+  if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+  char *attr;
+  while(p){
+    if(ISPOINTER(p->flags)){
+      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+      if(attr=p->next->attr){
+	if(strstr(attr,STR_NEAR))
+	  p->flags=((p->flags&~NU)|NPOINTER);
+	if(strstr(attr,STR_FAR))
+	  p->flags=((p->flags&~NU)|FPOINTER);
+	if(strstr(attr,STR_HUGE))
+	  p->flags=((p->flags&~NU)|HPOINTER);
+      }
+    }
+    if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+      p->flags=((p->flags&~NU)|BIT);
+    p=p->next;
+  }
+}
+
+void init_db(FILE *f)
+{
+  dwarf2_setup(sizetab[HPOINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+  dwarf2_print_comp_unit_header(f);
+}
+void cleanup_db(FILE *f)
+{
+  dwarf2_cleanup(f);
+  if(f) section=-1;
+} 
diff --git a/machines/rf12/machine.dt b/machines/rf12/machine.dt
new file mode 100755
index 0000000..7d54552
--- /dev/null
+++ b/machines/rf12/machine.dt
@@ -0,0 +1,14 @@
+S12BS
+S12BU
+S24BS
+S24BU
+S24BS
+S24BU
+S48BS
+S48BU
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S48BU
diff --git a/machines/rf12/machine.h b/machines/rf12/machine.h
new file mode 100755
index 0000000..a90ae8f
--- /dev/null
+++ b/machines/rf12/machine.h
@@ -0,0 +1,188 @@
+/*  Example of a code-generator for Motorola 68hc12 16bit microcontrollers.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them:      */
+/* - #define HAVE_EXT_TYPES
+   - #undef all standard types
+   - #define all standard types plus new types
+   - write eval_const and insert_const
+   - write typedefs for zmax and zumax
+   - write typname[]
+   - write conv_typ()
+   - optionally #define ISPOINTER, ISARITH, ISINT etc.
+   - optionally #define HAVE_TGT_PRINTVAL and write printval
+   - optionally #define POINTER_TYPE
+   - optionally #define HAVE_TGT_FALIGN and write falign
+   - optionally #define HAVE_TGT_SZOF and write szof
+   - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+};
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Not used in this code-generrator.                               */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+    struct Var *v;
+};
+
+/* This type will be added to every IC. Can be used by the cg.      */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+  int flags;
+  int r;
+  long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 6
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+extern int MINADDI2P;
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+extern int switchsubs;
+#define SWITCHSUBS switchsubs
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+  int gpr;
+};
+
+/*  We use unsigned int as size_t rather than unsigned long which   */
+/*  is the default setting.                                         */
+#define HAVE_INT_SIZET 1
+
+/*  We have register pairs.                                         */
+#define HAVE_REGPAIRS 1
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define HAVE_POF2OPT 1
diff --git a/machines/src/machine.c b/machines/src/machine.c
new file mode 100755
index 0000000..f4f25af
--- /dev/null
+++ b/machines/src/machine.c
@@ -0,0 +1,1092 @@
+/*  C src backend for vbcc
+ */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc C source code-generator V0.1a (c) in 2011 by Volker Barthelmann";
+
+
+int g_flags[MAXGF]={0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={0};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__GENERIC__",
+		       0};
+
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+  *dataname="\t.data\n",
+  *bssname="",
+  *rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+   a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | return-address [size=4]                      |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize+4-off-zm2l(maxalign);
+  }
+
+#if FIXED_SP
+  off+=argsize;
+#else
+  off+=stackoffset;
+#endif
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if(!(o->flags&VAR)) ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    if(THREE_ADDR){
+      emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+    }else{
+      emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+      if(off)
+	emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+    }
+  }else{
+    emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+   general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NU;
+  if(o->flags&VARADR){
+    load_address(f,r,o,POINTER);
+  }else{
+    if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+      return;
+    emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NQ;
+  emit(f,"\tmov.%s\t",dt(type));
+  emit_obj(f,o,type);
+  emit(f,",%s\n",regnames[r]);
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r;
+
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+
+  if(isreg(z)){
+    zreg=p->z.reg;
+  }else{
+    if(ISFLOAT(ztyp(p)))
+      zreg=f1;
+    else
+      zreg=t1;
+  }
+  
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q1,q1typ(p));
+    p->q1.reg=t1;
+    p->q1.flags|=(REG|DREFOBJ);
+  }
+  if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+    if(ISFLOAT(q1typ(p)))
+      q1reg=f1;
+    else
+      q1reg=t1;
+    load_reg(f,q1reg,&p->q1,q1typ(p));
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q2,q2typ(p));
+    p->q2.reg=t1;
+    p->q2.flags|=(REG|DREFOBJ);
+  }
+  if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+    if(ISFLOAT(q2typ(p)))
+      q2reg=f2;
+    else
+      q2reg=t2;
+    load_reg(f,q2reg,&p->q2,q2typ(p));
+    p->q2.reg=q2reg;
+    p->q2.flags=REG;
+  }
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->z,POINTER);
+    p->z.reg=t2;
+    p->z.flags|=(REG|DREFOBJ);
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if(p->am){
+    if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+    if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+    }
+  }
+  if(p->flags&KONST){
+    emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* Try const(reg) */
+    if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=IMM_IND;
+		am->base=base;
+		am->offset=zm2l(of);
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)==LLONG) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)==LLONG) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)==LLONG) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=GPR_IND;
+              am->base=base;
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  rsavesize=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  emit(f,ret);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(8L);
+  char_bit=l2zm(8L);
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  regnames[0]="noreg";
+  for(i=FIRST_GPR;i<=LAST_GPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+    regsize[i]=l2zm(4L);
+    regtype[i]=&ltyp;
+  }
+  for(i=FIRST_FPR;i<=LAST_FPR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+    regsize[i]=l2zm(8L);
+    regtype[i]=&ldbl;
+  }
+  for(i=FIRST_CCR;i<=LAST_CCR;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+    regsize[i]=l2zm(1L);
+    regtype[i]=&lchar;
+  }
+
+  /*  Use multiple ccs.   */
+  multiple_ccs=0;
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  sp=FIRST_GPR;
+  t1=FIRST_GPR+1;
+  t2=FIRST_GPR+2;
+  f1=FIRST_FPR;
+  f2=FIRST_FPR+1;
+  regsa[t1]=regsa[t2]=1;
+  regsa[f1]=regsa[f2]=1;
+  regsa[sp]=1;
+  regscratch[t1]=regscratch[t2]=0;
+  regscratch[f1]=regscratch[f2]=0;
+  regscratch[sp]=0;
+
+  for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+    regscratch[i]=1;
+  for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+    regscratch[i]=1;
+
+  target_macros=marray;
+
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(ISFLOAT(t->flags)) 
+    return FIRST_FPR+2;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 
+    return 0;
+  if(zmleq(szof(t),l2zm(4L))) 
+    return FIRST_GPR+3;
+  else
+    return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    if(!LOAD_STORE)
+      return 0;
+    if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+      return 4;
+    else
+      return 2;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  t&=NQ;
+  if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+    return 1;
+  if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+    return 1;
+  if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+    return 1;
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the PowerPC cpu pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(v->clist||section==SPECIAL){
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||section==SPECIAL){
+	gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  emit(f,"\tdc.%s\t",dt(t&NQ));
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    emit_obj(f,&p->tree->o,t&NU);
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i;
+  struct IC *m;
+  argsize=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  maxpushed=0;
+
+  /*FIXME*/
+  ret="\trts\n";
+
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+    /* convert MULT/DIV/MOD with powers of two */
+    if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  p->typf2=INT;
+	}
+      }
+    }
+#if FIXED_SP
+    if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+  }
+  peephole(p);
+
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+
+  localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+  /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+  function_top(f,v,localsize);
+  pushed=0;
+
+  for(;p;p=p->next){
+    c=p->code;t=p->typf;
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(t==exit_label&&framesize==0)
+	emit(f,ret);
+      else
+	emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      emit(f,"\tb%s\t",ccs[c-BEQ]);
+      if(isreg(q1)){
+	emit_obj(f,&p->q1,0);
+	emit(f,",");
+      }
+      emit(f,"%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      ierror(0);
+    }
+    p=preload(f,p);
+    c=p->code;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+      if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+	if(q1typ(p)&UNSIGNED)
+	  emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+	else
+	  emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+      }
+      save_result(f,p);
+      continue;
+    }
+    if(c==KOMPLEMENT){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==SETRETURN){
+      load_reg(f,p->z.reg,&p->q1,t);
+      BSET(regs_modified,p->z.reg);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+	save_result(f,p);
+      }else
+        p->z.flags=0;
+      continue;
+    }
+    if(c==CALL){
+      int reg;
+      /*FIXME*/
+#if 0      
+      if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	  stack=framesize+zum2ul(p->q1.v->fi->stack1);
+      }else
+	stack_valid=0;
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+	emit(f,"\tcall\t");
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+      }
+      /*FIXME*/
+#if FIXED_SP
+      pushed-=zm2l(p->q2.val.vmax);
+#endif
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+	int i;
+	for(i=1;i<=MAXR;i++){
+	  if(regscratch[i]) BSET(regs_modified,i);
+	}
+      }
+      continue;
+    }
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(c==PUSH){
+#if FIXED_SP
+	emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	pushed+=zm2l(p->q2.val.vmax);
+#else
+	emit(f,"\tpush.%s\t",dt(t));
+	emit_obj(f,&p->q1,t);
+	emit(f,"\n");
+	push(zm2l(p->q2.val.vmax));
+#endif
+	continue;
+      }
+      if(c==ASSIGN){
+	load_reg(f,zreg,&p->q1,t);
+	save_result(f,p);
+      }
+      continue;
+    }
+    if(c==ADDRESS){
+      load_address(f,zreg,&p->q1,POINTER);
+      save_result(f,p);
+      continue;
+    }
+    if(c==MINUS){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==TEST){
+      emit(f,"\ttst.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if(c==COMPARE){
+      emit(f,"\tcmp.%s\t",dt(t));
+      if(multiple_ccs)
+	emit(f,"%s,",regnames[zreg]);
+      emit_obj(f,&p->q1,t);
+      emit(f,",");
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      if(multiple_ccs)
+	save_result(f,p);
+      continue;
+    }
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+      if(!THREE_ADDR)
+	load_reg(f,zreg,&p->q1,t);
+      if(c>=OR&&c<=AND)
+	emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+      else
+	emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+      if(THREE_ADDR){
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+      }
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      save_result(f,p);
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+  function_bottom(f,v,localsize);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=stack;
+  }
+  emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+  f=t->flags&NQ;
+  if(f<=LONG||f==POINTER){
+    if(m->gregs>=GPR_ARGS)
+      return 0;
+    else
+      return FIRST_GPR+3+m->gregs++;
+  }
+  if(ISFLOAT(f)){
+    if(m->fregs>=FPR_ARGS)
+      return 0;
+    else
+      return FIRST_FPR+2+m->fregs++;
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
diff --git a/machines/src/machine.dt b/machines/src/machine.dt
new file mode 100755
index 0000000..7ece518
--- /dev/null
+++ b/machines/src/machine.dt
@@ -0,0 +1,14 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
diff --git a/machines/src/machine.h b/machines/src/machine.h
new file mode 100755
index 0000000..98a944f
--- /dev/null
+++ b/machines/src/machine.h
@@ -0,0 +1,125 @@
+/*  C src backend for vbcc
+*/
+
+/* buil-time configurable options: */
+#define SCHAR_REGS 64
+#define UCHAR_REGS 64
+#define SSHORT_REGS 64
+#define USHORT_REGS 64
+#define SINT_REGS 64
+#define UINT_REGS 64
+#define SLONG_REGS 64
+#define ULONG_REGS 64
+#define SLLONG_REGS 64
+#define ULLONG_REGS 64
+#define FLOAT_REGS 64
+#define DOUBLE_REGS 64
+#define LDOUBLE_REGS 64
+#define POINTER_REGS 64
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_SCHAR 1
+#define LAST_SCHAR (FIRST_SCHAR+SCHAR_REGS)
+#define FIRST_UCHAR (LAST_SCHAR+1)
+#define LAST_UCHAR (FIRST_UCHAR+UCHAR_REGS)
+
+#define FIRST_SSHORT (LAST_UCHAR+1)
+#define LAST_SSHORT (FIRST_SSHORT+SSHORT_REGS)
+#define FIRST_USHORT (LAST_SSHORT+1)
+#define LAST_USHORT (FIRST_USHORT+USHORT_REGS)
+
+#define FIRST_SINT (LAST_USHORT+1)
+#define LAST_SINT (FIRST_SINT+SINT_REGS)
+#define FIRST_UINT (LAST_SINT+1)
+#define LAST_UINT (FIRST_UINT+UINT_REGS)
+
+#define FIRST_SLONG (LAST_UINT+1)
+#define LAST_SLONG (FIRST_SLONG+SLONG_REGS)
+#define FIRST_ULONG (LAST_SLONG+1)
+#define LAST_ULONG (FIRST_ULONG+ULONG_REGS)
+
+#define FIRST_SLLONG (LAST_ULONG+1)
+#define LAST_SLLONG (FIRST_SLLONG+SLLONG_REGS)
+#define FIRST_ULLONG (LAST_SLLONG+1)
+#define LAST_ULLONG (FIRST_ULLONG+ULLONG_REGS)
+
+#define FIRST_FLOAT (LAST_ULLONG+1)
+#define LAST_FLOAT (FIRST_FLOAT+FLOAT_REGS)
+
+#define FIRST_DOUBLE (LAST_FLOAT+1)
+#define LAST_DOUBLE (DOUBLE_FLOAT+DOUBLE_REGS)
+
+#define FIRST_LDOUBLE (LAST_DOUBLE+1)
+#define LAST_LDOUBLE (LDOUBLE_FLOAT+LDOUBLE_REGS)
+
+#define FIRST_POINTER (LAST_LDOUBLE+1)
+#define LAST_POINTER (POINTER_FLOAT+POINTER_REGS)
+
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+  int dummy;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR LAST_POINTER
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 1
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P CHAR
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 1
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 0
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 0
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 0
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#define ORDERED_PUSH FIXED_SP
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
diff --git a/machines/vidcore/machine.c b/machines/vidcore/machine.c
new file mode 100644
index 0000000..420a4d0
--- /dev/null
+++ b/machines/vidcore/machine.c
@@ -0,0 +1,1774 @@
+/*  Backend for VideoCore IV
+    (c) in 2013 by Volker Barthelmann
+*/
+
+/* TODO:
+   - extended registers
+   - floating point
+   - long long
+   - memcpy
+   - addcmp
+   - bcc reg
+   - cond. ins
+   - vector
+   - non-pc addressing
+*/
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/*  Public data that MUST be there.                             */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc VideoCore IV code-generator V0.1 (c) in 2013 by Volker Barthelmann";
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+   they collide with the frontend */
+char *g_flags_name[MAXGF]={"use-commons","use-framepointer",
+			   "short-double","one-section",
+			   "no-delayed-popping"};
+
+int g_flags[MAXGF]={0,0,
+		    0};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/*  Alignment-requirements for all types in bytes.              */
+zmax align[MAX_TYPE+1];
+
+/*  Alignment that is sufficient for every object.              */
+zmax maxalign;
+
+/*  CHAR_BIT for the target machine.                            */
+zmax char_bit;
+
+/*  sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/*  Names of all registers. will be initialized in init_cg(),
+    register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/*  The Size of each register in bytes.                         */
+zmax regsize[MAXR+1];
+
+/*  a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/*  regsa[reg]!=0 if a certain register is allocated and should */
+/*  not be used by the compiler pass.                           */
+int regsa[MAXR+1];
+
+/*  Specifies which registers may be scratched by functions.    */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+   estimated cost-saving can be obtained by several registers, the
+   one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes.                */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/*  Private data and functions.         */
+/****************************************/
+
+/* addressing modes */
+#define AM_IMM_IND 1
+#define AM_GPR_IND 2
+#define AM_POSTINC 3
+#define AM_PREDEC  4
+
+#define USE_COMMONS (g_flags[0]&USEDFLAG)
+#define USE_FP      (g_flags[1]&USEDFLAG)
+#define SHORT_DOUBLE (g_flags[2]&USEDFLAG)
+#define ONESEC      (g_flags[3]&USEDFLAG)
+#define NODELAYEDPOP (g_flags[4]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]=  {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+		       "__VIDEOCORE__",
+		       0, /* __SHORT_DOUBLE__ */
+		       0};
+
+/* special registers */
+enum{
+  r0=1,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,
+  r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31,
+  r0r1,r2r3,r4r5,r6r7,r8r9,r10r11,r12r13,r14r15,
+  r16r17,r18r19,r20r21,r22r23,r24r25,r26r27,r28r29,r30r31
+};
+
+static int sd=r24;
+static int sp=r25;
+static int lr=r26;
+static int sr=r30;
+static int pc=r31;
+static int t1=r15;
+static int t2=r14;
+
+static int last_saved;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+#define sdt(t) (udt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","b","hs","","","ll","","d","ld","v",""};
+static char *udt[MAX_TYPE+1]={"??","b","h","","","ull","","d","ld","v",""};
+
+static char *dct[]={"","byte","2byte","4byte","4byte","4byte","4byte","4byte","4byte"};
+
+static int no_suffix;
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+  *dataname="\t.data\n",
+  *bssname="",
+  *rodataname="\t.section\t.rodata\n";
+
+/* conditional execution */
+static char *cc;
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if 0
+/* variables to calculate the size and partitioning of the stack-frame
+   in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+   a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+   stack-pointer; we use a layout like this:
+   ------------------------------------------------
+   | arguments to this function                   |
+   ------------------------------------------------
+   | return-address [size=4]                      |
+   ------------------------------------------------
+   | caller-save registers [size=rsavesize]       |
+   ------------------------------------------------
+   | local variables [size=localsize]             |
+   ------------------------------------------------
+   | arguments to called functions [size=argsize] |
+   ------------------------------------------------
+   All sizes will be aligned as necessary.
+   In the case of FIXED_SP, the stack-pointer will be adjusted at
+   function-entry to leave enough space for the arguments and have it
+   aligned to 16 bytes. Therefore, when calling a function, the
+   stack-pointer is always aligned to 16 bytes.
+   For a moving stack-pointer, the stack-pointer will usually point
+   to the bottom of the area for local variables, but will move while
+   arguments are put on the stack.
+
+   This is just an example layout. Other layouts are also possible.
+*/
+
+static void push(long l)
+{
+  stackoffset-=l;
+  if(stackoffset<maxpushed) 
+    maxpushed=stackoffset;
+  if(-maxpushed>stack)
+    stack=-maxpushed;
+}
+
+static void pop(long l)
+{
+  stackoffset+=l;
+}
+
+static long real_offset(struct obj *o)
+{
+  long off=zm2l(o->v->offset);
+  if(off<0){
+    /* function parameter */
+    off=localsize+rsavesize-off-zm2l(maxalign);
+  }
+
+  off-=stackoffset;
+
+  off+=zm2l(o->val.vmax);
+  return off;
+}
+
+/*  Initializes an addressing-mode structure and returns a pointer to
+    that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+  static struct obj obj;
+  static struct AddressingMode am;
+  obj.am=&am;
+  am.flags=flags;
+  am.base=base;
+  am.offset=offset;
+  return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+  char *sec;
+  if(!v->vattr) return 0;
+  sec=strstr(v->vattr,"section(");
+  if(!sec) return 0;
+  sec+=strlen("section(");
+  emit(f,"\t.section\t");
+  while(*sec&&*sec!=')') emit_char(f,*sec++);
+  emit(f,"\n");
+  if(f) section=SPECIAL;
+  return 1;
+}
+
+static unsigned long pushmask;
+
+static int ic_uses_reg(struct IC *p,int r,int onlyuses)
+{
+  if(reg_pair(r,&rp)){
+    return ic_uses_reg(p,rp.r1,onlyuses)||ic_uses_reg(p,rp.r2,onlyuses);
+  }
+  /*FIXME: handle regpairs */
+  if((p->q1.flags&REG)&&p->q1.reg==r) return 1;
+  if((p->q2.flags&REG)&&p->q2.reg==r) return 1;
+  if(onlyuses){
+    if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg==r) return 1;
+  }else{
+    if((p->z.flags&REG)&&p->z.reg==r) return 1;
+  }
+  if(p->q1.am){
+    if(p->q1.am->base==r) return 1;
+    if(p->q1.am->flags==AM_GPR_IND&&p->q1.am->offset==r) return 1;
+  }
+  if(p->q2.am){
+    if(p->q2.am->base==r) return 1;
+    if(p->q2.am->flags==AM_GPR_IND&&p->q2.am->offset==r) return 1;
+  }
+  if(p->z.am){
+    if(p->z.am->base==r) return 1;
+    if(p->z.am->flags==AM_GPR_IND&&p->z.am->offset==r) return 1;
+  }
+  return 0;
+}
+
+static int reg_is_scratched(struct IC *p,int r)
+{
+  for(p=p->next;p;p=p->next){
+    int c=p->code;
+    if(c>=LABEL&&c<=BRA)
+      return 0;
+    if(c==FREEREG&&p->q1.reg==r)
+      return 1;
+    if(ic_uses_reg(p,r,1))
+      return 0;
+    if((p->q1.flags&(REG|DREFOBJ))==REG&&p->z.reg==r)
+      return 1;
+  }    
+  return 0;
+}
+
+static int get_reg(FILE *f,struct IC *p)
+{
+  int r;
+  for(r=r0;r<=r31;r++){
+    if(!regs[r]&&regused[r]&&!ic_uses_reg(p,r,0)){
+      regs[r]=1;
+      return r;
+    }
+  }
+  for(r=r0;r<=r31;r++){
+    if(!regs[r]&&!ic_uses_reg(p,r,0)){
+      regs[r]=1;
+      return r;
+    }
+  }
+  for(r=r0;r<=r31;r++){
+    if(!ic_uses_reg(p,r,0))
+      break;
+  }
+  argsize+=4;
+  emit(f,"\tst\t%s,--(%s)\n",regnames[r],regnames[sp]);
+  push(4);
+  pushmask|=(1<<(r-1));
+  regs[r]=1;
+  return r;
+}
+
+static void free_reg(FILE *f,int r)
+{
+  if(pushmask&(1<<(r-1))){
+    emit(f,"\tld\t%s,(%s)++\n",regnames[r],regnames[sp]);
+    pop(4);
+    argsize-=4;
+  }else
+    regs[r]=0;
+  pushmask&=~(1<<(r-1));
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/*  Generates code to load the address of a variable into register r.   */
+{
+  if(!(o->flags&VAR)) ierror(0);
+  if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+    long off=real_offset(o);
+    emit(f,"\tadd%s\t%s,%s,%ld\n",cc,regnames[r],regnames[sp],off);
+  }else{
+    emit(f,"\tlea%s\t%s,",cc,regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }
+}
+/* Generates code to load a memory object into register r. tmp is a
+   general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+  type&=NU;
+  if(reg_pair(r,&rp)) ierror(0);
+  if(o->flags&VARADR){
+    load_address(f,r,o,POINTER);
+  }else if(o->flags&KONST){
+    emit(f,"\tmov%s\t%s,",cc,regnames[r]);
+    emit_obj(f,o,type);
+    emit(f,"\n");
+  }else{
+    if((o->flags&(REG|DREFOBJ))==REG){
+      if(o->reg!=r)
+	emit(f,"\tmov%s\t%s,%s\n",cc,regnames[r],regnames[o->reg]);
+    }else{
+      if(SHORT_DOUBLE&&ISFLOAT(type)) type=FLOAT;
+      emit(f,"\tld%s%s\t%s,",dt(type),cc,regnames[r]);
+      emit_obj(f,o,type);
+      emit(f,"\n");
+    }
+  }
+}
+
+/*  Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+  if(reg_pair(r,&rp)) ierror(0);
+  type&=NQ;
+  if(SHORT_DOUBLE&&ISFLOAT(type)) type=FLOAT;
+  emit(f,"\tst%s%s\t%s,",sdt(type),cc,regnames[r]);
+  emit_obj(f,o,type);
+  emit(f,"\n");
+}
+
+/*  Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+  zumax p;int ln=1;
+  p=ul2zum(1L);
+  while(ln<=32&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *ccu[]={"eq","ne","cs","cc","ls","hi",""};
+static char *logicals[]={"or","eor","and"};
+static char *arithmetics[]={"lsl","asr","add","sub","mul","divs","mod"};
+static char *uarithmetics[]={"lsl","lsr","add","sub","mul","divu","mod"};
+static char *farithmetics[]={"--","--","fadd","fsub","fmul","fdiv","--"};
+
+
+/* Does some pre-processing like fetching operands from memory to
+   registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+  int r,load;
+
+  if(isreg(q1))
+    q1reg=p->q1.reg;
+  else
+    q1reg=0;
+
+  if(isreg(q2))
+    q2reg=p->q2.reg;
+  else
+    q2reg=0;
+
+  if(isreg(z)){
+    zreg=p->z.reg;
+  }else{
+    zreg=t1;
+  }
+  
+  if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+    p->q1.flags&=~DREFOBJ;
+    load_reg(f,t1,&p->q1,POINTER);
+    p->q1.reg=t1;
+    p->q1.flags|=(REG|DREFOBJ);
+  }
+  if(p->q1.flags&&!isreg(q1)&&p->code!=ASSIGN&&p->code!=PUSH&&p->code!=SETRETURN/*&&!(p->q1.flags&KONST)*/){
+    q1reg=zreg;
+    load_reg(f,q1reg,&p->q1,q1typ(p));
+    p->q1.reg=q1reg;
+    p->q1.flags=REG;
+  }
+
+  if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+    p->q2.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->q2,POINTER);
+    p->q2.reg=t2;
+    p->q2.flags|=(REG|DREFOBJ);
+  }
+
+  if(p->q2.flags){
+    load=1;
+    if(isreg(q2)) load=0;
+    if((p->q2.flags&KONST)&&!ISFLOAT(p->typf)&&(p->code==ADD||p->code==SUB||p->code==ADDI2P||p->code==COMPARE||p->code==SUBIFP||p->code==SUBPFP))
+      load=0;
+    if(p->code>=OR&&p->code<=MOD&&(p->q2.flags&KONST)&&!ISFLOAT(p->typf)){
+      unsigned long v;
+      eval_const(&p->q2.val,q2typ(p));
+      v=zum2ul(vumax);
+      if(v<=31) load=0;
+    }
+    if(load){
+      q2reg=t2;
+      load_reg(f,q2reg,&p->q2,q2typ(p));
+      p->q2.reg=q2reg;
+      p->q2.flags=REG;
+    }
+  }
+  return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+  if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+    p->z.flags&=~DREFOBJ;
+    load_reg(f,t2,&p->z,POINTER);
+    p->z.reg=t2;
+    p->z.flags|=(REG|DREFOBJ);
+  }
+  if(isreg(z)){
+    if(p->z.reg!=zreg)
+      emit(f,"\tmov%s\t%s,%s\n",cc,regnames[p->z.reg],regnames[zreg]);
+  }else{
+    store_reg(f,zreg,&p->z,ztyp(p));
+  }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+  if((p->flags&DREFOBJ)&&p->am){
+    if(p->am->flags==AM_GPR_IND) emit(f,"(%s,%s)",regnames[p->am->base],regnames[p->am->offset]);
+    if(p->am->flags==AM_IMM_IND) emit(f,"%ld(%s)",p->am->offset,regnames[p->am->base]);
+    if(p->am->flags==AM_POSTINC) emit(f,"(%s)++",regnames[p->am->base]);
+    if(p->am->flags==AM_PREDEC) emit(f,"--(%s)",regnames[p->am->base]);
+    return;
+  }
+  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+    emitval(f,&p->val,p->dtyp&NU);
+    return;
+  }
+  if(p->flags&DREFOBJ) emit(f,"(");
+  if(p->flags&REG){
+    emit(f,"%s",regnames[p->reg]);
+  }else if(p->flags&VAR) {
+    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+      emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+    else{
+      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+      if(p->v->storage_class==STATIC){
+        emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+      }else{
+        emit(f,"%s%s",idprefix,p->v->identifier);
+      }
+      if(!no_suffix)
+	emit(f,"(%s)",regnames[pc]);
+    }
+  }
+  if(p->flags&KONST){
+    if(ISFLOAT(t)){
+      unsigned char *ip;
+      eval_const(&p->val,t);
+      ip=(unsigned char *)&vfloat;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+    }else
+      emitval(f,&p->val,t&NU);
+  }
+  if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/*  Test if there is a sequence of FREEREGs containing FREEREG reg.
+    Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+  while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+    if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+    p=p->next;
+  }
+  return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+  int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+  for(;p;p=p->next){
+    c=p->code;
+    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+    if(c==LABEL) exit_label=p->typf;
+
+    /* -(ax) */
+    if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=8&&isconst(q2)){
+      zmax sz;
+      int t;
+      r=p->q1.reg;
+      eval_const(&p->q2.val,q2typ(p));
+      sz=zm2l(vmax);
+      if(sz==1||sz==2||sz==4){
+        for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)&&(
+c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
+            t=(q1typ(p2)&NQ);
+            if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))){
+              p2->q1.am=am=mymalloc(sizeof(*am));
+              p2->q1.val.vmax=l2zm(0L);
+              am->base=r;
+              am->flags=AM_PREDEC;
+              p->code=NOP;
+              p->q1.flags=p->q2.flags=p->z.flags=0;
+              break;
+            }
+          }
+         if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)){
+            t=(q2typ(p2)&NQ);
+            if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))){
+              p2->q2.am=am=mymalloc(sizeof(*am));
+              p2->q2.val.vmax=l2zm(0L);
+              am->base=r;
+              am->flags=AM_PREDEC;
+              p->code=NOP;
+              p->q1.flags=p->q2.flags=p->z.flags=0;
+              break;
+            }
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)){
+            t=(ztyp(p2)&NQ);
+            if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))){
+              p2->z.am=am=mymalloc(sizeof(*am));
+              p2->z.val.vmax=l2zm(0L);
+              am->base=r;
+              am->flags=AM_PREDEC;
+              p->code=NOP;
+              p->q1.flags=p->q2.flags=p->z.flags=0;
+              break;
+            }
+          }
+          if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+          if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+          if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+          if((p2->z.flags&REG)&&p2->z.reg==r) break;
+        }
+      }
+    }
+
+    /* (ax)+ in q1 */
+    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(c!=CONVERT||(q1typ(p)&NQ)<=(ztyp(p)&NQ))){
+      int t=(q1typ(p)&NQ);
+      long sz=zm2l(sizetab[t]);
+      r=p->q1.reg;
+      if((sz==1||sz==2||sz==4)&&(ISINT(t)||ISPOINTER(t)||ISFLOAT(t))&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+        for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+          if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+            eval_const(&p2->q2.val,q2typ(p2));
+            if(zmeqto(vmax,l2zm(sz))){
+              p->q1.am=am=mymalloc(sizeof(*am));
+              p->q1.val.vmax=l2zm(0L);
+	      am->flags=AM_POSTINC;
+              am->base=r;
+              am->offset=0;
+              p2->code=NOP;
+              p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+              break;
+            }
+          }
+          if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+          if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+          if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+          if((p2->z.flags&REG)&&p2->z.reg==r) break;
+        }
+      }
+    }
+    /* (ax)+ in q2 */
+    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(c!=CONVERT||(q2typ(p)&NQ)<=(ztyp(p)&NQ))){
+      int t=(q2typ(p)&NQ);
+      long sz=zm2l(sizetab[t]);
+      r=p->q2.reg;
+      if((sz==1||sz==2||sz==4)&&(ISINT(t)||ISPOINTER(t)||ISFLOAT(t))&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
+        for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+          if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+            eval_const(&p2->q2.val,q2typ(p2));
+            if(zmeqto(vmax,l2zm(sz))){
+              p->q2.am=am=mymalloc(sizeof(*am));
+              p->q2.val.vmax=l2zm(0L);
+	      am->flags=AM_POSTINC;
+              am->base=r;
+              am->offset=0;
+              p2->code=NOP;
+              p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+              break;
+            }
+          }
+          if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+          if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+          if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+          if((p2->z.flags&REG)&&p2->z.reg==r) break;
+        }
+      }
+    }
+    /* (ax)+ in z */
+    if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg<=8&&(c!=CONVERT||(q2typ(p)&NQ)<=(ztyp(p)&NQ))){
+      int t=(ztyp(p)&NQ);
+      long sz=zm2l(sizetab[t]);
+      r=p->z.reg;
+      if((sz==1||sz==2||sz==4)&&(ISINT(t)||ISPOINTER(t)||ISFLOAT(t))&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)){
+        for(p2=p->next;p2;p2=p2->next){
+          c2=p2->code;
+          if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+            eval_const(&p2->q2.val,q2typ(p2));
+            if(zmeqto(vmax,l2zm(sz))){
+              p->z.am=am=mymalloc(sizeof(*am));
+              p->z.val.vmax=l2zm(0L);
+	      am->flags=AM_POSTINC;
+              am->base=r;
+              am->offset=0;
+              p2->code=NOP;
+              p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+              break;
+            }
+          }
+          if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+          if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
+          if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
+          if((p2->z.flags&REG)&&p2->z.reg==r) break;
+        }
+      }
+    }
+    /* Try const(reg) */
+    if((c==ADDI2P/*||c==SUBIFP*/)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+      int base;zmax of;struct obj *o;
+      eval_const(&p->q2.val,p->typf);
+      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+      if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+	r=p->z.reg;
+	if(isreg(q1)) base=p->q1.reg; else base=r;
+	o=0;
+	for(p2=p->next;p2;p2=p2->next){
+	  c2=p2->code;
+	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+	  if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+	  if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+	  if((c2==ASSIGN||c2==PUSH)&&(!ISSCALAR(p2->typf)||!zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ]))){
+	    if((p->q1.flags&REG)&&p->q1.reg==base)
+	      break;
+	    if((p->z.flags&REG)&&p->z.reg==base)
+	      break;
+	  }
+	  if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+	    if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+	      if(o) break;
+	      o=&p2->q1;
+	    }
+	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+	      if(o) break;
+	      o=&p2->q2;
+	    }
+	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+	      if(o) break;
+	      o=&p2->z;
+	    }
+	  }
+	  if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+	    int m;
+	    if(c2==FREEREG)
+	      m=p2->q1.reg;
+	    else
+	      m=p2->z.reg;
+	    if(m==r){
+	      if(o){
+		o->am=am=mymalloc(sizeof(*am));
+		am->flags=AM_IMM_IND;
+		am->base=base;
+		am->offset=zm2l(of);
+		if(isreg(q1)){
+		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+		}else{
+		  p->code=c=ASSIGN;p->q2.flags=0;
+		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+		}
+	      }
+	      break;
+	    }
+	    if(c2!=FREEREG&&m==base) break;
+	    continue;
+	  }
+        }
+      }
+    }
+    /* Try reg,reg */
+    if(c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+      int base,idx;struct obj *o;
+      r=p->z.reg;idx=p->q2.reg;
+      if(isreg(q1)) base=p->q1.reg; else base=r;
+      o=0;
+      for(p2=p->next;p2;p2=p2->next){
+        c2=p2->code;
+        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+	
+        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+            if(o||(q1typ(p2)&NQ)!=CHAR) break;
+            o=&p2->q1;
+          }
+          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+            if(o||(q2typ(p2)&NQ)!=CHAR) break;
+            o=&p2->q2;
+          }
+          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+            if(o||(ztyp(p2)&NQ)!=CHAR) break;
+            o=&p2->z;
+          }
+        }
+        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+          int m;
+          if(c2==FREEREG)
+            m=p2->q1.reg;
+          else
+            m=p2->z.reg;
+          if(m==r){
+            if(o){
+              o->am=am=mymalloc(sizeof(*am));
+              am->flags=AM_GPR_IND;
+              am->base=base;
+              am->offset=idx;
+	      if(isreg(q1)){
+		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+	      }else{
+		p->code=c=ASSIGN;p->q2.flags=0;
+		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+	      }
+            }
+            break;
+          }
+          if(c2!=FREEREG&&m==base) break;
+          continue;
+        }
+      }
+    }
+  }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+  int i;
+  rsavesize=0;
+  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;} 
+  emit(f,"\t.align\t1\n");
+  if(v->storage_class==EXTERN){
+    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    emit(f,"%s%s:\n",idprefix,v->identifier);
+  }else
+    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+  last_saved=0;
+  for(i=r6;i<t2;i++){
+    if(regused[i])
+      last_saved=i;
+  }
+  if(last_saved){
+    emit(f,"\tpush\t%s-%s",regnames[r6],regnames[last_saved]);
+    rsavesize=(last_saved-r6+1)*4;
+    if(function_calls){
+      emit(f,",lr");
+      rsavesize+=4;
+    }
+    emit(f,"\n");
+  }else if(function_calls){
+    emit(f,"\tpush\t%s-%s,lr\n",regnames[r6],regnames[r6]);
+    rsavesize+=8;
+  }
+  if(offset){
+    emit(f,"\tsub\t%s,%ld\n",regnames[sp],offset);
+  }
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+  if(offset){
+    emit(f,"\tadd\t%s,%ld\n",regnames[sp],offset);
+  }
+  if(last_saved){
+    emit(f,"\tpop\t%s-%s",regnames[r6],regnames[last_saved]);
+    if(function_calls){
+      emit(f,",pc");
+    }
+    emit(f,"\n");
+  }else if(function_calls){
+    emit(f,"\tpop\t%s-%s,pc\n",regnames[r6],regnames[r6]);
+  }  
+  if(!function_calls)
+    emit(f,ret);
+}
+
+/****************************************/
+/*  End of private data and functions.  */
+/****************************************/
+
+/*  Does necessary initializations for the code-generator. Gets called  */
+/*  once at the beginning and should return 0 in case of problems.      */
+int init_cg(void)
+{
+  int i;
+  /*  Initialize some values which cannot be statically initialized   */
+  /*  because they are stored in the target's arithmetic.             */
+  maxalign=l2zm(4L);
+  char_bit=l2zm(8L);
+  stackalign=l2zm(4);
+
+  for(i=0;i<=MAX_TYPE;i++){
+    sizetab[i]=l2zm(msizetab[i]);
+    align[i]=l2zm(malign[i]);
+  }
+
+  if(SHORT_DOUBLE){
+    sizetab[DOUBLE]=sizetab[FLOAT];
+    align[DOUBLE]=align[FLOAT];
+    sizetab[LDOUBLE]=sizetab[FLOAT];
+    align[LDOUBLE]=align[FLOAT];
+  }
+
+  regnames[0]="noreg";
+  for(i=1;i<=32;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"r%d",i-1);
+    regsize[i]=l2zm(4L);
+    regtype[i]=&ltyp;
+  }
+  for(i=33;i<=48;i++){
+    regnames[i]=mymalloc(10);
+    sprintf(regnames[i],"r%d/r%d",i-33,i-32);
+    regsize[i]=l2zm(8L);
+    regtype[i]=&ldbl;
+  }
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LONG]=t_min(INT);
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=ul2zum(2147483647UL);
+  t_max[LONG]=t_max(INT);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=ul2zum(4294967295UL);
+  tu_max[LONG]=t_max(UNSIGNED|INT);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+  
+  /*  Reserve a few registers for use by the code-generator.      */
+  /*  This is not optimal but simple.                             */
+  regsa[t1]=regsa[t2]=1;
+  regsa[pc]=regsa[lr]=regsa[sp]=regsa[sr]=1;
+  regscratch[t1]=regscratch[t2]=0;
+  regscratch[pc]=regscratch[lr]=regscratch[sp]=regscratch[sr]=1;
+
+  for(i=r16;i<=r31;i++)
+    regscratch[i]=regsa[i]=1;
+  
+  for(i=1;i<=6;i++)
+    regscratch[i]=1;
+
+  if(ONESEC){
+    bssname=codename;
+    dataname=codename;
+    rodataname=codename;
+  }
+
+  if(SHORT_DOUBLE) marray[2]="__SHORT_DOUBLE__=1";
+  target_macros=marray;
+
+
+  declare_builtin("__mulint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__addint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__subint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__andint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__orint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__eorint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__negint64",LLONG,LLONG,r0r1,0,0,1,0);
+  declare_builtin("__lslint64",LLONG,LLONG,r0r1,INT,r2,1,0);
+
+  declare_builtin("__divsint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r0r1,UNSIGNED|LLONG,r2r3,1,0);
+  declare_builtin("__modsint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r0r1,UNSIGNED|LLONG,r2r3,1,0);
+  declare_builtin("__lsrsint64",LLONG,LLONG,r0r1,INT,r2,1,0);
+  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r0r1,INT,r2,1,0);
+  declare_builtin("__cmpsint64",INT,LLONG,r0r1,LLONG,r2r3,1,0);
+  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,r0r1,UNSIGNED|LLONG,r2r3,1,0);
+  declare_builtin("__sint64toflt32",FLOAT,LLONG,r0r1,0,0,1,0);
+  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,r0r1,0,0,1,0);
+  declare_builtin("__sint64toflt64",LDOUBLE,LLONG,r0r1,0,0,1,0);
+  declare_builtin("__uint64toflt64",LDOUBLE,UNSIGNED|LLONG,r0r1,0,0,1,0);
+  declare_builtin("__flt32tosint64",LLONG,FLOAT,r0,0,0,1,0);
+  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,r0,0,0,1,0);
+  declare_builtin("__flt64tosint64",LLONG,LDOUBLE,r0r1,0,0,1,0);
+  declare_builtin("__flt64touint64",UNSIGNED|LLONG,LDOUBLE,r0r1,0,0,1,0);
+
+  declare_builtin("__flt32toflt64",LDOUBLE,FLOAT,r0,0,0,1,0);
+  declare_builtin("__flt64toflt32",FLOAT,LDOUBLE,r0r1,0,0,1,0);
+
+  declare_builtin("__addflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+  declare_builtin("__subflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+  declare_builtin("__mulflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+  declare_builtin("__divflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+  declare_builtin("__negflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+  declare_builtin("__cmpflt64",INT,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+
+
+  return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/*  Returns the register in which variables of type t are returned. */
+/*  If the value cannot be returned in a register returns 0.        */
+/*  A pointer MUST be returned in a register. The code-generator    */
+/*  has to simulate a pseudo register if necessary.                 */
+{
+  if(SHORT_DOUBLE&&ISFLOAT(t->flags)) return r0;
+  if(ISSTRUCT(t->flags)||ISUNION(t->flags)) 
+    return 0;
+  if(zmleq(szof(t),l2zm(4L))) 
+    return r0;
+  if(zmeqto(szof(t),l2zm(8L))) 
+    return r0r1;
+  return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  if(r>=r0r1&&r<=r30r31){
+    p->r1=(r-r0r1)*2+r0;
+    p->r2=(r-r0r1)*2+r1;
+    return 1;
+  }
+  return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+   register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST){
+    return 0;
+  }
+  if(o->flags&DREFOBJ)
+    return 4;
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+
+int regok(int r,int t,int mode)
+/*  Returns 0 if register r cannot store variables of   */
+/*  type t. If t==POINTER and mode!=0 then it returns   */
+/*  non-zero only if the register can store a pointer   */
+/*  and dereference a pointer to mode.                  */
+{
+  if(r==0)
+    return 0;
+  t&=NQ;
+  if(ISINT(t)||ISFLOAT(t)||ISPOINTER(t)){
+    if(zmeqto(sizetab[t],l2zm(8L))){
+      if(r>=r0r1&&r<=r30r31)
+	return 1;
+      else
+	return 0;
+    }
+    if(r>=r0&&r<=r31)
+      return 1;
+    else
+      return 0;
+  }
+  return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/*  Returns zero if the IC p can be safely executed     */
+/*  without danger of exceptions or similar things.     */
+/*  vbcc may generate code in which non-dangerous ICs   */
+/*  are sometimes executed although control-flow may    */
+/*  never reach them (mainly when moving computations   */
+/*  out of loops).                                      */
+/*  Typical ICs that generate exceptions on some        */
+/*  machines are:                                       */
+/*      - accesses via pointers                         */
+/*      - division/modulo                               */
+/*      - overflow on signed integer/floats             */
+{
+  int c=p->code;
+  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+    return 1;
+  if((c==DIV||c==MOD)&&!isconst(q2))
+    return 1;
+  return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/*  Returns zero if code for converting np to type t    */
+/*  can be omitted.                                     */
+/*  On the VideCore IV pointers and 32bit               */
+/*  integers have the same representation and can use   */
+/*  the same registers.                                 */
+{
+  int op=o&NQ,tp=t&NQ;
+  if(SHORT_DOUBLE){
+    if(op==DOUBLE||op==LDOUBLE) op=FLOAT;
+    if(tp==DOUBLE||tp==LDOUBLE) tp=FLOAT;
+  }
+  if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+    return 0;
+  if(op==FLOAT&&tp==FLOAT) return 0;
+  if(op==DOUBLE&&tp==LDOUBLE) return 0;
+  if(op==LDOUBLE&&tp==DOUBLE) return 0;
+  return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/*  This function has to create <size> bytes of storage */
+/*  initialized with zero.                              */
+{
+  if(newobj&&!ONESEC&&section!=SPECIAL)
+    emit(f,"%ld\n",zm2l(size));
+  else
+    emit(f,"\t.space\t%ld\n",zm2l(size));
+  newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/*  This function has to make sure the next data is     */
+/*  aligned to multiples of <align> bytes.              */
+{
+  if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/*  This function has to create the head of a variable  */
+/*  definition, i.e. the label and information for      */
+/*  linkage etc.                                        */
+{
+  int constflag;char *sec;
+  if(v->clist) constflag=is_const(v->vtyp);
+  if(v->storage_class==STATIC){
+    if(ISFUNC(v->vtyp->flags)) return;
+    if(!special_section(f,v)){
+      if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+      if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+    }
+    if(v->clist||ONESEC||section==SPECIAL){
+      gen_align(f,falign(v->vtyp));
+      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+    }else
+      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+    newobj=1;
+  }
+  if(v->storage_class==EXTERN){
+    emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+    if(v->flags&(DEFINED|TENTATIVE)){
+      if(!special_section(f,v)){
+	if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
+	if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
+      }
+      if(v->clist||ONESEC||section==SPECIAL){
+	gen_align(f,falign(v->vtyp));
+        emit(f,"%s%s:\n",idprefix,v->identifier);
+      }else
+        emit(f,"\t.%scomm\t%s%s,",(USE_COMMONS?"":"l"),idprefix,v->identifier);
+      newobj=1;
+    }
+  }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/*  This function has to create static storage          */
+/*  initialized with const-list p.                      */
+{
+  if((t&NQ)==POINTER) t=UNSIGNED|LONG;
+  emit(f,"\t.%s\t",dct[t&NQ]);
+  if(!p->tree){
+    if(ISFLOAT(t)){
+      /*  auch wieder nicht sehr schoen und IEEE noetig   */
+      unsigned char *ip;
+      if(SHORT_DOUBLE){
+	eval_const(&p->val,t);
+	ip=(unsigned char *)&vfloat;
+	t=FLOAT;
+      }else
+	ip=(unsigned char *)&p->val.vdouble;
+      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+      if((t&NQ)!=FLOAT){
+        emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+      }
+    }else if((t&NQ)==LLONG){
+      zumax tmp;
+      eval_const(&p->val,t);
+      tmp=vumax;
+      vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); 
+      gval.vulong=zum2zul(vumax);
+      emitval(f,&gval,UNSIGNED|LONG);
+      emit(f,",");
+      vumax=zumand(tmp,ul2zum(0xffffffff)); 
+      gval.vulong=zum2zul(vumax);
+      emitval(f,&gval,UNSIGNED|LONG);
+    }else{
+      emitval(f,&p->val,t&NU);
+    }
+  }else{
+    no_suffix=1;
+    emit_obj(f,&p->tree->o,t&NU);
+    no_suffix=0;
+  }
+  emit(f,"\n");newobj=0;
+}
+
+
+/*  The main code-generation routine.                   */
+/*  f is the stream the code should be written to.      */
+/*  p is a pointer to a doubly linked list of ICs       */
+/*  containing the function body to generate code for.  */
+/*  v is a pointer to the function.                     */
+/*  offset is the size of the stackframe the function   */
+/*  needs for local variables.                          */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/*  The main code-generation.                                           */
+{
+  int c,t,i,lastcomp;
+  int q1wasreg,q2wasreg,zwasreg;
+  struct IC *m;
+  argsize=0;
+  if(DEBUG&1) printf("gen_code()\n");
+  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+  stackoffset=notpopped=dontpop=maxpushed=0;
+
+
+  /*FIXME*/
+  ret="\trts\n";
+
+  cc="";
+
+  for(m=p;m;m=m->next){
+    c=m->code;t=m->typf&NU;
+    if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+        emit(f,"\tadd\t%s,%ld\n",regnames[sp],notpopped);
+        pop(notpopped);notpopped=0;
+      }
+    }
+
+
+    /* convert MULT/DIV/MOD with powers of two */
+    if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+      eval_const(&m->q2.val,t);
+      i=pof2(vmax);
+      if(i){
+        if(c==MOD){
+          vmax=zmsub(vmax,l2zm(1L));
+          m->code=AND;
+        }else{
+          vmax=l2zm(i-1);
+          if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+        }
+        c=m->code;
+	gval.vmax=vmax;
+	eval_const(&gval,MAXINT);
+	if(c==AND){
+	  insert_const(&m->q2.val,t);
+	}else{
+	  insert_const(&m->q2.val,INT);
+	  p->typf2=INT;
+	}
+      }
+    }
+    if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+  }
+  peephole(p);
+
+  for(c=1;c<=MAXR;c++){
+    if(regsa[c]||regused[c]){
+      BSET(regs_modified,c);
+    }
+  }
+
+  localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+  /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+  function_top(f,v,localsize);
+
+  for(;p;p=p->next){
+    c=p->code;t=p->typf;
+    if(c==NOP) {p->z.flags=0;continue;}
+    if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+    if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+
+    if(DEBUG&256){emit(f,"# "); pric2(f,p);}
+    if(DEBUG&512) emit(f,"# stackoffset=%ld, notpopped=%ld, dontpop=%ld\n",stackoffset,notpopped,dontpop);
+    if(notpopped&&!dontpop){
+      int flag=0;
+      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+        emit(f,"\tadd\t%s,%ld\n",regnames[sp],notpopped);
+        pop(notpopped);notpopped=0;
+      }
+    }
+
+    if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+    if(c==BRA){
+      if(0/*t==exit_label&&framesize==0*/)
+	emit(f,ret);
+      else
+	emit(f,"\tb\t%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c>=BEQ&&c<BRA){
+      if(lastcomp&UNSIGNED)
+	emit(f,"\tb%s\t",ccu[c-BEQ]);
+      else
+	emit(f,"\tb%s\t",ccs[c-BEQ]);
+      if(isreg(q1)){
+	emit_obj(f,&p->q1,0);
+	emit(f,",");
+      }
+      emit(f,"%s%d\n",labprefix,t);
+      continue;
+    }
+    if(c==MOVETOREG){
+      load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+      continue;
+    }
+    if(c==MOVEFROMREG){
+      store_reg(f,p->q1.reg,&p->z,regtype[p->q1.reg]->flags);
+      continue;
+    }
+    if(c==PUSH)
+      dontpop+=zm2l(p->q2.val.vmax);
+    if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+      int i,cnt,unit,lab,treg,acnt=0,atreg=0;
+      long size;
+      char *ut;
+      if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&reg_is_scratched(p,p->q1.reg)){
+	q1reg=p->q1.reg;
+	if(p->q1.am) ierror(0);
+      }else{
+	q1reg=t1;
+	if(p->q1.flags&(REG|DREFOBJ)){
+	  p->q1.flags&=~DREFOBJ;
+	  load_reg(f,q1reg,&p->q1,POINTER);
+	}else
+	  load_address(f,q1reg,&p->q1,POINTER);
+      }
+      if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&reg_is_scratched(p,p->z.reg)){
+	zreg=p->z.reg;
+	if(p->z.am) ierror(0);
+      }else if(c==PUSH){
+	zreg=sp;
+      }else{
+	if(q1reg==t1)
+	  zreg=t2;
+	else
+	  zreg=t1;
+	if(p->z.flags&(REG|DREFOBJ)){
+	  p->z.flags&=~DREFOBJ;
+	  load_reg(f,zreg,&p->z,POINTER);
+	}else
+	  load_address(f,zreg,&p->z,POINTER);
+      }      
+      if(zreg==t2){
+	treg=get_reg(f,p);
+	atreg=1;
+      }else if(zreg==t1||q1reg==t1)
+	treg=t2;
+      else
+	treg=t1;
+
+      unit=1;ut="b";
+      size=zm2l(p->q2.val.vmax);
+
+      if(c==PUSH)
+	emit(f,"\tadd\t%s,%ld\n",regnames[q1reg],size);
+
+      if(size/unit>=8){
+	if(treg!=t2&&zreg!=t2)
+	  cnt=t2;
+	else{
+	  cnt=get_reg(f,p);
+	  acnt=1;
+	}
+	emit(f,"\tmov\t%s,%ld\n",regnames[cnt],(size/unit)>>2);
+	emit(f,"%s%d:\n",labprefix,++label);
+      }
+
+      for(i=0;i<((size/unit>4)?4:size/unit);i++){
+	if(c!=PUSH){
+	  emit(f,"\tld%s\t%s,(%s)++\n",ut,regnames[treg],regnames[q1reg]);
+	  emit(f,"\tst%s\t%s,(%s)++\n",ut,regnames[treg],regnames[zreg]);
+	}else{
+	  emit(f,"\tld%s\t%s,--(%s)\n",ut,regnames[treg],regnames[q1reg]);
+	  emit(f,"\tst%s\t%s,--(%s)\n",ut,regnames[treg],regnames[zreg]);
+	}
+      }
+      if(size/unit>=8){
+	emit(f,"\taddcmpbne\t%s,-1,0,%s%d\n",regnames[cnt],labprefix,label);
+      }
+      for(i=0;i<((size/unit)&3);i++){
+	if(c!=PUSH){
+	  emit(f,"\tld%s\t%s,(%s)++\n",ut,regnames[treg],regnames[q1reg]);
+	  emit(f,"\tst%s\t%s,(%s)++\n",ut,regnames[treg],regnames[zreg]);
+	}else{
+	  emit(f,"\tld%s\t%s,--(%s)\n",ut,regnames[treg],regnames[q1reg]);
+	  emit(f,"\tst%s\t%s,--(%s)\n",ut,regnames[treg],regnames[zreg]);
+	}
+      }
+      if(c==PUSH)
+	push(size);
+      if(acnt) free_reg(f,cnt);
+      if(atreg) free_reg(f,treg);
+      continue;
+    }
+
+    if(c==CALL){
+      int reg;
+      /*FIXME*/
+#if 0      
+      if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+	if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+	  stack=framesize+zum2ul(p->q1.v->fi->stack1);
+      }else
+	stack_valid=0;
+#endif
+      /*FIXME: does not work with fixed parameters on stack */
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+	emit(f,"\tadd\t%s,%s,%ld\n",regnames[r0],regnames[sp],localsize+rsavesize-stackoffset);
+	continue;
+      }
+
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+        emit_inline_asm(f,p->q1.v->fi->inline_asm);
+      }else{
+	if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+	  p->q1.flags&=~DREFOBJ;
+	  load_reg(f,t1,&p->q1,POINTER);
+	  p->q1.flags|=(DREFOBJ|REG);
+	  p->q1.reg=t1;
+	}
+	emit(f,"\tbl\t");
+	if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+	  emit(f,"%s",regnames[p->q1.reg]);
+	}else{
+	  no_suffix=1;
+	  emit_obj(f,&p->q1,t);
+	  no_suffix=0;
+	}
+	emit(f,"\n");
+      }
+
+      if(!zmeqto(p->q2.val.vmax,l2zm(0L))){
+        notpopped+=zm2l(p->q2.val.vmax);
+        dontpop-=zm2l(p->q2.val.vmax);
+        if(!NODELAYEDPOP&&!vlas&&stackoffset==-notpopped){
+          /*  Entfernen der Parameter verzoegern  */
+        }else{
+	  emit(f,"\tadd\t%s,%ld\n",regnames[sp],zm2l(p->q2.val.vmax));
+          pop(zm2l(p->q2.val.vmax));
+          notpopped-=zm2l(p->q2.val.vmax);
+        }
+      }
+
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+      }else{
+	int i;
+	for(i=1;i<=MAXR;i++){
+	  if(regscratch[i]) BSET(regs_modified,i);
+	}
+      }
+      continue;
+    }
+
+    if(c==ADDRESS){
+      if(isreg(z))
+	zreg=p->z.reg;
+      else
+	zreg=t1;
+      load_address(f,zreg,&p->q1,POINTER);
+      save_result(f,p);
+      continue;
+    }
+
+    if(isreg(q1)) q1wasreg=1; else q1wasreg=0;
+    if(isreg(q2)) q2wasreg=1; else q2wasreg=0;
+    if(isreg(z)) zwasreg=1; else zwasreg=0;
+
+    p=preload(f,p);
+    c=p->code;
+    if(c==SUBPFP) c=SUB;
+    if(c==ADDI2P) c=ADD;
+    if(c==SUBIFP) c=SUB;
+    if(c==CONVERT){
+      if(ISFLOAT(q1typ(p))){
+	if(ztyp(p)&UNSIGNED) ierror(0);
+	if(ISFLOAT(ztyp(p)))
+	  emit(f,"\tmov%s\t%s,%s\n",cc,regnames[zreg],regnames[q1reg]);
+	else
+	  emit(f,"\tftrunc%s\t%s,%s\n",cc,regnames[zreg],regnames[q1reg]);
+	save_result(f,p);
+	continue;
+      }
+      if(ISFLOAT(ztyp(p))){
+	emit(f,"\tflt%c%s\t%s,%s\n",(q1typ(p)&UNSIGNED)?'u':'s',cc,regnames[zreg],regnames[q1reg]);
+	save_result(f,p);
+	continue;
+      }
+      if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+	int mask;
+	if((q1typ(p)&NQ)==CHAR)
+	  mask=7;
+	else
+	  mask=15;
+	if(q1typ(p)&UNSIGNED)
+	  mask++;
+	if(q1wasreg||(q1typ(p)&NU)==CHAR)
+	  emit(f,"\text%c%s\t%s,%s,%d\n",(q1typ(p)&UNSIGNED)?'u':'s',cc,regnames[zreg],regnames[q1reg],mask);
+      }else{
+	zreg=q1reg;
+      }	  
+      save_result(f,p);
+      continue;
+    }
+    if(c==KOMPLEMENT){
+      emit(f,"\tmvn%s\t%s,%s\n",cc,regnames[zreg],regnames[q1reg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==SETRETURN){
+      if(isreg(q1)){
+	if(p->q1.reg!=p->z.reg)
+	  emit(f,"\tmov%s\t%s,%s\n",cc,regnames[p->z.reg],regnames[p->q1.reg]);
+      }else
+	load_reg(f,p->z.reg,&p->q1,t);
+      BSET(regs_modified,p->z.reg);
+      continue;
+    }
+    if(c==GETRETURN){
+      if(p->q1.reg){
+        zreg=p->q1.reg;
+	save_result(f,p);
+      }else
+        p->z.flags=0;
+      continue;
+    }
+
+    if(c==ASSIGN||c==PUSH){
+      if(t==0) ierror(0);
+      if(c==PUSH){
+	if(!q1reg){
+	  q1reg=t1;
+	  load_reg(f,q1reg,&p->q1,t);
+	}
+	if(SHORT_DOUBLE&&ISFLOAT(t)) t=FLOAT;
+	emit(f,"\tst%s%s\t%s,--(%s)\n",sdt(t),cc,regnames[q1reg],regnames[sp]);
+	push(zm2l(p->q2.val.vmax));
+	continue;
+      }
+      if(c==ASSIGN){
+	if(isreg(q1)){
+	  if(isreg(z))
+	    emit(f,"\tmov%s\t%s,%s\n",cc,regnames[zreg],regnames[p->q1.reg]);
+	  else
+	    zreg=p->q1.reg;
+	}else
+	  load_reg(f,zreg,&p->q1,t);
+	save_result(f,p);
+      }
+      continue;
+    }
+    if(c==MINUS){
+      load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tneg%s\t%s,%s\n",cc,regnames[zreg],regnames[zreg]);
+      save_result(f,p);
+      continue;
+    }
+    if(c==TEST){
+      emit(f,"\tcmp%s\t",cc);
+      emit_obj(f,&p->q1,t);
+      emit(f,",0\n");
+      lastcomp=t;
+      continue;
+    }
+    if(c==COMPARE){
+      if(ISFLOAT(t))
+	emit(f,"\tfcmp%s\t%s,",cc,regnames[t1]);
+      else
+	emit(f,"\tcmp%s\t",cc);
+      emit_obj(f,&p->q1,t);
+      emit(f,",");
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      lastcomp=t;
+      continue;
+    }
+    if(c==MOD){
+      /* TODO: is there a faster way? */
+      int m;
+      if(q2reg!=t2)
+	m=t2;
+      else
+	m=get_reg(f,p);
+      if(!isreg(q1)||p->q1.reg!=zreg)
+	load_reg(f,zreg,&p->q1,t);
+      emit(f,"\tdiv%c%s\t%s,%s,",(t&UNSIGNED)?'u':'s',cc,regnames[m],regnames[zreg]);
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      emit(f,"\tmul%s\t%s,",cc,regnames[m]);
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      emit(f,"\tsub%s\t%s,%s,%s\n",cc,regnames[zreg],regnames[zreg],regnames[m]);
+      free_reg(f,m);
+      save_result(f,p);
+      continue;
+    }      
+    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<MOD)){
+      if(c>=OR&&c<=AND)
+	emit(f,"\t%s%s\t%s,",logicals[c-OR],cc,regnames[zreg]);
+      else{
+	if(ISFLOAT(t))
+	  emit(f,"\t%s%s\t%s,",farithmetics[c-LSHIFT],cc,regnames[zreg]);
+	else
+	  emit(f,"\t%s%s\t%s,",(t&UNSIGNED)?uarithmetics[c-LSHIFT]:arithmetics[c-LSHIFT],cc,regnames[zreg]);
+      }
+      if(!isreg(q1)||p->q1.reg!=zreg||*cc||c==DIV||ISFLOAT(t)){
+	emit_obj(f,&p->q1,t);
+	emit(f,",");
+      }
+      emit_obj(f,&p->q2,t);
+      emit(f,"\n");
+      save_result(f,p);
+      continue;
+    }
+    pric2(stdout,p);
+    ierror(0);
+  }
+
+  if(notpopped){
+    emit(f,"\tadd\t%s,%ld\n",regnames[sp],notpopped);
+    pop(notpopped);notpopped=0;
+  }
+
+  function_bottom(f,v,localsize);
+  if(stack_valid){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    v->fi->stack1=stack;
+  }
+  /*emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");*/
+}
+
+int shortcut(int code,int typ)
+{
+  return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+  int f;
+
+  if(vararg)
+    return 0;
+
+  f=t->flags&NQ;
+  if(ISINT(f)||ISFLOAT(f)||f==POINTER){
+    if(zmeqto(sizetab[f],l2zm(8L))){
+      if(m->gregs<=r4){
+	m->gregs=(m->gregs+1)&0xfe;
+	m->gregs+=2;
+	if(m->gregs==r1)
+	  return r0r1;
+	else if(m->gregs==r3)
+	  return r2r3;
+	else if(m->gregs==r5)
+	  return r4r5;
+	else
+	  ierror(0);
+      }else
+	return 0;
+    }else{
+      if(m->gregs<=r4)
+	return ++m->gregs;
+      else
+	return 0;
+    }
+  }
+  return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+  if(f) section=-1;
+}
+
+char *use_libcall(int c,int t,int t2)
+/* Return name of library function, if this node should be
+   implemented via libcall. */
+{
+  static char fname[16];
+  char *ret = NULL;
+
+  if(c==COMPARE){
+    if((t&NQ)==DOUBLE) t=(SHORT_DOUBLE)?FLOAT:LDOUBLE;
+    if((t&NQ)==LLONG||t==LDOUBLE){
+      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+      ret=fname;
+    }
+  }else{
+    t&=NU;
+    t2&=NU;
+    if(SHORT_DOUBLE){
+      if(ISFLOAT(t)) t=FLOAT;
+      if(ISFLOAT(t2)) t2=FLOAT;
+    }else{
+      if(t==DOUBLE) t=LDOUBLE;
+      if(t2==DOUBLE) t2=LDOUBLE;
+    }
+    if(c==CONVERT){
+      if(t==t2) return 0;
+      if(t==FLOAT&&t2==LDOUBLE) return "__flt64toflt32";
+      if(t==LDOUBLE&&t2==FLOAT) return "__flt32toflt64";
+      if(t!=LDOUBLE&&t2!=LDOUBLE&&(t&NQ)!=LLONG&&(t2&NQ)!=LLONG) return 0;
+      if(ISFLOAT(t)){
+        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+        ret=fname;
+      }
+      if(ISFLOAT(t2)&&(t&NU)==LLONG){
+        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+        ret=fname;
+      }
+    }
+    if((t&NQ)==LLONG||t==DOUBLE){
+      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+        if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+          sprintf(fname,"__%suint64",ename[c]);
+          ret=fname;
+        }else if((t&NQ)==LLONG){
+          sprintf(fname,"__%sint64",ename[c]);
+          ret=fname;
+        }else{
+          sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+          ret=fname;
+        }
+      }
+    }
+  }
+
+  return ret;
+}
diff --git a/machines/vidcore/machine.dt b/machines/vidcore/machine.dt
new file mode 100644
index 0000000..526c8d4
--- /dev/null
+++ b/machines/vidcore/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/vidcore/machine.h b/machines/vidcore/machine.h
new file mode 100644
index 0000000..408e581
--- /dev/null
+++ b/machines/vidcore/machine.h
@@ -0,0 +1,131 @@
+/*  Backend for VideoCore IV
+    (c) in 2013 by Volker Barthelmann
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 48
+
+#include "dt.h"
+
+
+/*  This struct can be used to implement machine-specific           */
+/*  addressing-modes.                                               */
+/*  Currently possible are (const,gpr) and (gpr,gpr)                */
+struct AddressingMode{
+    int flags;
+    int base;
+    long offset;
+};
+
+/*  The number of registers of the target machine.                  */
+#define MAXR 48
+
+/*  Number of commandline-options the code-generator accepts.       */
+#define MAXGF 20
+
+/*  If this is set to zero vbcc will not generate ICs where the     */
+/*  target operand is the same as the 2nd source operand.           */
+/*  This can sometimes simplify the code-generator, but usually     */
+/*  the code is better if the code-generator allows it.             */
+#define USEQ2ASZ 0
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MINADDI2P INT
+
+/*  This specifies the smallest integer type that can be added to a */
+/*  pointer.                                                        */
+#define MAXADDI2P INT
+
+/*  If the bytes of an integer are ordered most significant byte    */
+/*  byte first and then decreasing set BIGENDIAN to 1.              */
+#define BIGENDIAN 0
+
+/*  If the bytes of an integer are ordered lest significant byte    */
+/*  byte first and then increasing set LITTLEENDIAN to 1.           */
+#define LITTLEENDIAN 1
+
+/*  Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive.    */
+
+/*  If switch-statements should be generated as a sequence of       */
+/*  SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1.      */
+/*  This can yield better code on some machines.                    */
+#define SWITCHSUBS 1
+
+/*  In optimizing compilation certain library memcpy/strcpy-calls   */
+/*  with length known at compile-time will be inlined using an      */
+/*  ASSIGN-IC if the size is less or equal to INLINEMEMCPY.         */
+/*  The type used for the ASSIGN-IC will be UNSIGNED|CHAR.          */
+#define INLINEMEMCPY 1024
+
+/*  Parameters are sometimes passed in registers without __reg.     */
+#define HAVE_REGPARMS 1
+
+/*  Parameters on the stack should be pushed in order rather than   */
+/*  in reverse order.                                               */
+#undef ORDERED_PUSH
+
+/*  Structure for reg_parm().                                       */
+struct reg_handle{
+    unsigned long gregs;
+};
+
+/*  We have some target-specific variable attributes.               */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/*  We keep track of all registers modified by a function.          */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt 
+   register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+   peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/*  We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+   optimizations on code which can already be implemented by efficient
+   assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+   etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we need register-pairs */
+#define HAVE_REGPAIRS 1
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 0
+
+#define HAVE_LIBCALLS 1
diff --git a/machines/z/machine.c b/machines/z/machine.c
new file mode 100755
index 0000000..a242fff
--- /dev/null
+++ b/machines/z/machine.c
@@ -0,0 +1,2719 @@
+/* z/machine.c
+ * Code generator for the Z-machine.
+ * (C) David Given 2001
+ * conversion to vbcc 0.8 by Volker Barthelmann
+ */
+
+/* This code is licensed under the MIT open source license.
+ *
+ * Copyright (c) 2001, David Given
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* This code generator produces code for the Z-machine. The Z-machine is the
+ * highly peculiar virtual machine used for the old Infocom text adventures;
+ * these days, an extended form is still used in the interactive fiction genre
+ * of games. Usually, a dedicated compiler called Inform is used to generate
+ * code, but it would be nice to be able to use real C, so here we are.
+ *
+ * The Z-machine is (mostly) a semi-stack-based Harvard architecture machine.
+ * (Split code and data space, although they can share if you're clever. And
+ * mad.) It has no registers, but it does have procedure local variables which
+ * will do instead. It has a dedicated stack but as it's not accessible by
+ * ordinary memory it's not useful for C. It uses 8 and 16 bit words, so we'll
+ * have to emulate 32-bit arithmetic.
+ *
+ * For more information, including code for Inform, various interpreters, more
+ * documentation than you can shake a stick at, and the full technical reference
+ * for the Z-machine, check out the Interactive Fiction archive, at
+ * http://www.ifarchive.org.
+ *
+ * Things to note: there is no Z-machine assembler. (Well, there's zasm, but it's
+ * really just a rumour.) Luckily, Inform has an assembler mode, where it'll
+ * generate raw Z-machine opcodes. Unluckily, it's horribly buggy... So we're
+ * going to have to generate Inform source, which seems at first to be rather
+ * silly, but as Inform is quite a simple compiler we can make sure that it's
+ * only going to generate the instructions we want it to generate.
+ */
+
+/* vbcc-mandated header. */
+
+#include "supp.h"
+static char FILE_[]=__FILE__;
+char cg_copyright[]="vbcc code-generator for Z-machine V0.0a (c) in 2001 by David Given";
+
+/* Command-line flags. */
+
+int g_flags[MAXGF] = {
+	STRINGFLAG,
+	0,
+	0,
+	0,
+	0,
+	0
+};
+char *g_flags_name[MAXGF] = {
+	"module-name",
+	"trace-calls",
+	"trace-all",
+	"safe-branches",
+	"comment-ic",
+	"comment-misc"
+};
+union ppi g_flags_val[MAXGF];
+
+/* Type alignment. Much better code is generated if we can use even alignment.
+ */
+
+zmax align[MAX_TYPE+1] = {
+	0,	/* 0: unused */
+	1,	/* 1: CHAR */
+	2,	/* 2: SHORT */
+	2, 	/* 3: INT */
+	2,	/* 4: LONG */
+	2,      /* 5: LLONG */
+	2,	/* 6: FLOAT */
+	2,	/* 7: DOUBLE */
+	2,      /* 8: LDOUBLE */
+	2,	/* 9: VOID */
+	2,	/* 10: POINTER */
+	1,	/* 11: ARRAY */
+	1,	/* 12: STRUCT */
+	1,	/* 13: UNION */
+	1,	/* 14: ENUM */
+	1,	/* 15: FUNKT */
+};
+
+/* Alignment that is valid for all types. */
+
+zmax maxalign = 2;
+
+/* Number of bits in a char. */
+
+zmax char_bit = 8;
+
+/* Sizes of all elementary types, in bytes. */
+
+zmax sizetab[MAX_TYPE+1] = {
+	0,	/* 0: unused */
+	1,	/* 1: CHAR */
+	2,	/* 2: SHORT */
+	2, 	/* 3: INT */
+	4,	/* 4: LONG */
+        8,      /* 5: LLONG */
+	4,	/* 6: FLOAT */
+	8,	/* 7: DOUBLE */
+	8,      /* 8: LDOUBLE */
+	0,	/* 9: VOID */
+	2,	/* 10: POINTER */
+	0,	/* 11: ARRAY */
+	0,	/* 12: STRUCT */
+	0,	/* 13: UNION */
+	2,	/* 14: ENUM */
+	0,	/* 15: FUNKT */
+};
+
+/*  Minimum and Maximum values each type can have.              */
+/*  Must be initialized in init_cg().                           */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all the registers.
+ * We can have 16 local variables per routine. Var 0 is always the C stack
+ * pointer, xp. All the others can be used by the compiler. xp doesn't actually
+ * appear in the register map, so we get 15 main registers. 
+ */
+
+char* regnames[] = {
+	"sp", /* vbcc doesn't use this, but we do */
+	"xp", 	"r0", 	"r1",  	"r2", 	"r3", 	"r4", 	"r5", 	"r6",
+	"r7", 	"r8", 	"r9",	"r10",	"r11",	"r12"};
+#define XP 1
+#define USERREG 2
+
+/* The size of each register, in byes. */
+
+zmax regsize[] = {
+	0,
+	2,	2,	2,	2,	2,	2,	2,	2,
+	2,	2,	2,	2,	2,	2};
+
+/* Type needed to store each register. */
+
+struct Typ ityp = {INT};
+struct Typ* regtype[] = {
+	NULL,
+	&ityp,	&ityp,	&ityp,	&ityp,	&ityp,	&ityp,	&ityp,	&ityp,
+	&ityp,	&ityp,	&ityp,	&ityp,	&ityp,	&ityp};
+	
+/* These registers are those dedicated for use by the backend. These ones will
+ * not be used by the code generator. */
+
+int regsa[] = {
+	0,
+	1,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0};
+
+/* Specifies which registers may be destroyed by function calls. As we're
+ * storing our registers in local variables so they're being automatically
+ * saved for us, none of them.
+ */
+
+int regscratch[] = {
+	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0};
+
+/* Default state for register parameter passing. */
+
+struct reg_handle empty_reg_handle =
+	{USERREG};
+
+/* Prefix for labels. */
+
+static char* labelprefix = "L";
+
+/* Name of the current module; used for generating unique names for statics and
+ * the constant pool. */
+
+static char* modulename;
+
+/* Stack frame layout:
+ *
+ *  --------------
+ *      Arg 4        (Arguments being passed to this function)
+ *      Arg 3
+ *      Arg 2
+ *      Arg 1
+ *  -------------- xp + stackparamadjust + stackoffset
+ *     Local 4       (This function's temp space)
+ *     Local 3
+ *     Local 2
+ *     Local 1
+ *  -------------- xp + stackparamadjust
+ *      Arg 2        (Arguments this function has pushed to pass
+ *      Arg 1         to a called function)
+ *  -------------- xp
+ *
+ * Any area may be zero in size. (Although stackoffset is always at least 2 for
+ * some inadequately explained reason.)
+ */
+
+static int stackoffset;
+static int stackparamadjust;
+
+/* Represents something the Z-machine can use as an instruction operand. */
+
+struct zop {
+	int type;
+	union {
+		int reg;
+		zmax constant;
+		char* identifier;
+	} val;
+};
+
+enum {
+	ZOP_STACK,
+	ZOP_REG,
+	ZOP_CONSTANT,
+	ZOP_EXTERN,
+	ZOP_STATIC,
+	ZOP_CONSTANTADDR
+};
+
+/* Some useful zops. */
+
+struct zop zop_zero = {ZOP_CONSTANT, {constant: 0}};
+struct zop zop_xp = {ZOP_REG, {reg: XP}};
+struct zop zop_stack = {ZOP_STACK, 0};
+
+/* Temporaries used to store comparison register numbers. */
+
+static struct zop compare1;
+static struct zop compare2;
+
+/* Keeps track of whether we've emitted anything or not. Used to determine
+ * whether to emit the seperating ; or not. If it's 1, we haven't emitted
+ * anything. If it's -1, we're doing an array, so we need to emit a final (0)
+ * to finish it off if it's only one byte long. 0 for anything else. */
+
+static int virgin = 1;
+
+/* The current variable we're emitting data for. */
+
+struct variable {
+	int type;
+	union {
+		char* identifier;
+		int number;
+	} val;
+	zint offset;
+};
+
+struct variable currentvar;
+
+/* Inform can't emit variable references inside arrays. So when vbcc wants to
+ * put, say, the address of something in a global variable, we have to write it
+ * in later. A linked list of these structures keeps track of the items that
+ * need fixing up. */
+
+struct fixup {
+	struct fixup* next;
+	struct variable identifier;
+	struct variable value;
+	zmax offset;
+};
+
+static struct fixup* fixuplist = NULL;
+	
+/* 32-bit values are stored in a constant pool, for simplicity. It's kept track
+ * of in this linked list. */
+
+struct constant {
+	struct constant* next;
+	int id;
+	zmax value;
+};
+
+static struct constant* constantlist = NULL;
+static int constantnum = 0;
+
+/* The function we're currently compiling. */
+
+static struct Var* function;
+
+/* Function prototypes. */
+
+static void emit_add(FILE* fp, struct zop* q1, struct zop* q2, struct zop* z);
+static void read_reg(FILE* fp, struct obj* obj, int typf, int reg);
+static int addconstant(zmax value);
+
+/* Emit debugging info. */
+
+static void debugemit(FILE* fp, char* fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (g_flags[5] & USEDFLAG)
+		vfprintf(fp, fmt, ap);
+	va_end(ap);
+}
+
+/* Do we need to emit a ; before the next thing? */
+
+static void reflower(FILE* fp)
+{
+	if (!virgin)
+		fprintf(fp, ";\n");
+	if (virgin == -1)
+	{
+		if (currentvar.offset == 1)
+			fprintf(fp, "(0)");
+		fprintf(fp, ";");
+	}
+	virgin = 0;
+}
+
+/* Extract the sign extended byte n of a value. */
+
+static char xbyte(zmax val, int byte)
+{
+	val <<= (sizeof(val)*8) - (byte*8) - 8;
+	val >>= (sizeof(val)*8) - 8;
+	return (unsigned char) val;
+}
+
+/* Extract the sign extended word n of a value. */
+
+static zshort xword(zmax val, int word)
+{
+	val <<= (sizeof(val)*8) - (word*16) - 16;
+	val >>= (sizeof(val)*8) - 16;
+	return (zshort) val;
+}
+
+/* Debug function: prints the text name of a type. */
+
+static void dump_type(FILE* fp, int typf)
+{
+	switch (typf)
+	{
+		case VOID:	fprintf(fp, "VOID"); break;
+		case CHAR:	fprintf(fp, "CHAR"); break;
+		case SHORT:	fprintf(fp, "SHORT"); break;
+		case INT:	fprintf(fp, "INT"); break;
+		case LONG:	fprintf(fp, "LONG"); break;
+		case POINTER:	fprintf(fp, "POINTER"); break;
+		case STRUCT:	fprintf(fp, "STRUCT"); break;
+		case ARRAY:	fprintf(fp, "ARRAY"); break;
+		case UNION:	fprintf(fp, "UNION"); break;
+		case FUNKT:	fprintf(fp, "FUNKT"); break;
+		default:	fprintf(fp, "unknown %X", typf);
+	}
+}
+
+/* Debug function: outputs the obj. */
+
+static void dump_obj(FILE* fp, struct obj* obj, int typf)
+{
+	int f = obj->flags & (KONST|REG|VAR|DREFOBJ|VARADR);
+
+	if (f == 0)
+	{
+		fprintf(fp, "[]");
+		return;
+	}
+
+	if (f & DREFOBJ)
+		fprintf(fp, "*");
+
+	if (f & VARADR)
+		fprintf(fp, "&");
+
+	if (f == KONST)
+	{
+		switch (typf & NU)
+		{
+			case CHAR:
+				fprintf(fp, "[char #%d]", obj->val.vchar);
+				break;
+
+			case UNSIGNED|CHAR:
+				fprintf(fp, "[uchar #%u]", obj->val.vuchar);
+				break;
+
+			case SHORT:
+				fprintf(fp, "[short #%d]", obj->val.vshort);
+				break;
+
+			case UNSIGNED|SHORT:
+				fprintf(fp, "[ushort #%u]", obj->val.vushort);
+				break;
+
+			case INT:
+				fprintf(fp, "[int #%d]", obj->val.vint);
+				break;
+
+			case UNSIGNED|INT:
+				fprintf(fp, "[uint #%d]", obj->val.vuint);
+				break;
+
+			case LONG:
+				fprintf(fp, "[long #%d]", obj->val.vlong);
+				break;
+
+			case UNSIGNED|LONG:
+				fprintf(fp, "[ulong #%u]", obj->val.vulong);
+				break;
+
+			case FLOAT:
+				fprintf(fp, "[float #%04X]", obj->val.vfloat);
+				break;
+
+			case DOUBLE:
+				fprintf(fp, "[double #%08X]", obj->val.vdouble);
+				break;
+#if 0
+			case POINTER:
+				fprintf(fp, "[pointer #%04X]", obj->val.vpointer);
+				break;
+#endif
+		}
+	}
+	else if (f == REG)
+		fprintf(fp, "[reg %s]", regnames[obj->reg]);
+	else if (f == (REG|DREFOBJ))
+		fprintf(fp, "[deref reg %s]", regnames[obj->reg]);
+	//else if (f & VAR)
+	else
+	{
+		fprintf(fp, "[var ");
+		dump_type(fp, typf);
+		fprintf(fp, " %s", obj->v->identifier);
+
+		if ((obj->v->storage_class == AUTO) ||
+		    (obj->v->storage_class == REGISTER))
+		{
+			zmax offset = obj->v->offset;
+			//if (offset < 0)
+			//	offset = -(offset+maxalign);
+			fprintf(fp, " at fp%+d", offset);
+		}
+
+		fprintf(fp, "+%ld", obj->val.vlong);
+
+		if (f & REG)
+			fprintf(fp, " in %s", regnames[obj->reg]);
+		fprintf(fp, "]");
+	}
+}
+
+/* Debug function: outputs the ic, as a comment. */
+
+static void dump_ic(FILE* fp, struct IC* ic)
+{
+	char* p;
+
+	if (!ic)
+		return;
+
+	if (!(g_flags[4] & USEDFLAG))
+		return;
+
+	if (g_flags[2] & USEDFLAG)
+		fprintf(fp, "print \"");
+	else
+		fprintf(fp, "! ");
+	
+	switch (ic->code)
+	{
+		case ASSIGN:		p = "ASSIGN";		break;
+		case OR:		p = "OR";		break;
+		case XOR:		p = "XOR";		break;
+		case AND:		p = "AND";		break;
+		case LSHIFT:		p = "LSHIFT";		break;
+		case RSHIFT:		p = "RSHIFT";		break;
+		case ADD:		p = "ADD";		break;
+		case SUB:		p = "SUB";		break;
+		case MULT:		p = "MULT";		break;
+		case DIV:		p = "DIV";		break;
+		case MOD:		p = "MOD";		break;
+		case KOMPLEMENT:	p = "KOMPLEMENT";	break;
+		case MINUS:		p = "MINUS";		break;
+		case ADDRESS:		p = "ADDRESS";		break;
+		case CALL:		p = "CALL";		break;
+#if 0
+		case CONVCHAR:		p = "CONVCHAR";		break;
+		case CONVSHORT:		p = "CONVSHORT";	break;
+		case CONVINT:		p = "CONVINT";		break;
+		case CONVLONG:		p = "CONVLONG";		break;
+		case CONVFLOAT:		p = "CONVFLOAT";	break;
+		case CONVDOUBLE:	p = "CONVDOUBLE";	break;
+		case CONVPOINTER:	p = "CONVPOINTER";	break;
+		case CONVUCHAR:		p = "CONVUCHAR";	break;
+		case CONVUSHORT:	p = "CONVUSHORT";	break;
+		case CONVUINT:		p = "CONVUINT";		break;
+		case CONVULONG:		p = "CONVULONG";	break;
+#endif
+		case ALLOCREG:		p = "ALLOCREG";		break;
+		case FREEREG:		p = "FREEREG";		break;
+		case COMPARE:		p = "COMPARE";		break;
+		case TEST:		p = "TEST";		break;
+		case LABEL:		p = "LABEL";		break;
+		case BEQ:		p = "BEQ";		break;
+		case BNE:		p = "BNE";		break;
+		case BLT:		p = "BLT";		break;
+		case BGT:		p = "BGT";		break;
+		case BLE:		p = "BLE";		break;
+		case BGE:		p = "BGE";		break;
+		case BRA:		p = "BRA";		break;
+		case PUSH:		p = "PUSH";		break;
+		case ADDI2P:		p = "ADDI2P";		break;
+		case SUBIFP:		p = "SUBIFP";		break;
+		case SUBPFP:		p = "SUBPFP";		break;
+		case GETRETURN:		p = "GETRETURN";	break;
+		case SETRETURN:		p = "SETRETURN";	break;
+		case MOVEFROMREG:	p = "MOVEFROMREG";	break;
+		case MOVETOREG:		p = "MOVETOREG";	break;
+		case NOP:		p = "NOP";		break;
+		default:		p = "???";
+	}
+
+	fprintf(fp, "%s ", p);
+	dump_type(fp, ic->typf);
+	fprintf(fp, " ");
+
+	switch (ic->code)
+	{
+		case LABEL:
+		case BEQ:
+		case BNE:
+		case BLT:
+		case BGT:
+		case BLE:
+		case BGE:
+		case BRA:
+			fprintf(fp, "%d", ic->typf);
+			goto epilogue;
+	}
+	
+	dump_obj(fp, &ic->q1, ic->typf);
+	fprintf(fp, " ");
+	dump_obj(fp, &ic->q2, ic->typf);
+	fprintf(fp, " -> ");
+	dump_obj(fp, &ic->z, ic->typf);
+
+epilogue:
+	if (g_flags[2] & USEDFLAG)
+		fprintf(fp, "^\";\n");
+	else
+		fprintf(fp, "\n");
+}
+
+/* Initialise the code generator. This is called once. Returns 0 if things go
+ * wrong. */
+
+int init_cg(void)
+{
+	modulename = g_flags_val[0].p;
+	if (!modulename)
+		modulename = "";
+
+  /*  Initialize the min/max-settings. Note that the types of the     */
+  /*  host system may be different from the target system and you may */
+  /*  only use the smallest maximum values ANSI guarantees if you     */
+  /*  want to be portable.                                            */
+  /*  That's the reason for the subtraction in t_min[INT]. Long could */
+  /*  be unable to represent -2147483648 on the host system.          */
+  t_min[CHAR]=l2zm(-128L);
+  t_min[SHORT]=l2zm(-32768L);
+  t_min[INT]=t_min[SHORT];
+  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+  t_min[MAXINT]=t_min(LLONG);
+  t_max[CHAR]=ul2zum(127L);
+  t_max[SHORT]=ul2zum(32767UL);
+  t_max[INT]=t_max[SHORT];
+  t_max[LONG]=ul2zum(2147483647UL);
+  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+  t_max[MAXINT]=t_max(LLONG);
+  tu_max[CHAR]=ul2zum(255UL);
+  tu_max[SHORT]=ul2zum(65535UL);
+  tu_max[INT]=tu_max[SHORT];
+  tu_max[LONG]=ul2zum(4294967295UL);
+  tu_max[LLONG]=zumkompl(ul2zum(0UL));
+  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+	return 1;
+}
+
+/* Returns the register in which variables of type typ are returned (or 0 if it
+ * can't be done). */
+
+int freturn(struct Typ *typ)
+{
+	int s = sizetab[typ->flags & NQ];
+	if ((typ->flags & NQ) == VOID)
+		return USERREG;
+	if ((s <= sizetab[INT]) && (s > 0))
+		return USERREG;
+	return 0;
+}
+
+/* Returns 1 if register reg can store variables of type typ. mode is set
+ * if the register is a pointer and the register is going to be dereferenced.
+ */
+
+int regok(int reg, int typf, int mode)
+{
+	int s = sizetab[typf & NQ];
+	if ((typf & NQ) == VOID)
+		return 1;
+	if ((s <= sizetab[INT]) && (s > 0))
+		return 1;
+	return 0;
+}
+
+/* Returns zero if the IC ic can be safely executed without danger of
+ * exceptions or similar things; for example, divisions or pointer dereferences
+ * are dangerous. This is used by the optimiser for code reordering.
+ */
+
+int dangerous_IC(struct IC *ic)
+{
+	/* Check for dereferences. */
+
+	if ((ic->q1.flags & DREFOBJ) ||
+	    (ic->q2.flags & DREFOBJ) ||
+	    (ic->z.flags & DREFOBJ))
+		return 0;
+
+	/* Division or modulo? */
+
+	if ((ic->code == DIV) ||
+	    (ic->code == MOD))
+		return 0;
+
+	/* Safe, as far as we can tell. */
+
+	return 1;
+}
+
+/* Returns zero if the code for converting type p->ntyp to type typ is a noop.
+ */
+
+int must_convert(int otyp, int typ,int const_expr)
+{
+	int oldtype = otyp & NQ;
+	int newtype = typ & NQ;
+
+	/* ints and shorts are equivalent. */
+
+	if (oldtype == SHORT)
+		oldtype = INT;
+	if (newtype == SHORT)
+		newtype = INT;
+
+	/* Both the same type? */
+
+	if (oldtype == newtype)
+		return 0;
+
+#if 0
+	/* Converting two basic integers? */
+
+	if ((oldtype <= INT) && (newtype <= INT))
+	{
+		/* ... but char to short needs an AND. */
+
+		if ((oldtype == CHAR) && (newtype != CHAR))
+			return 1;
+		return 0;
+	}
+#endif
+
+	/* Pointer to/from int? */
+
+	if (((oldtype == INT) || (oldtype == POINTER)) &&
+	    ((newtype == INT) || (newtype == POINTER)))
+		return 0;
+
+	/* Everything else needs code. */
+
+	return 1;
+}
+
+/* Ensure the output is aligned. A noop on the Z-machine. */
+
+void gen_align(FILE* fp, zmax align)
+{
+}
+
+/* Generate the label part of a variable definition. */
+
+void gen_var_head(FILE* fp, struct Var* var)
+{
+	if (var->storage_class == EXTERN)
+		debugemit(fp, "! Var %s %X\n", var->identifier, var->flags);
+	if (var->storage_class == STATIC)
+		debugemit(fp, "! Var static %ld %s %X\n", var->offset, var->identifier, var->flags);
+
+	/* We only want to emit records for genuinely defined variables. For
+	 * some reason, TENTATIVE is defined for some of this. */
+
+	if ((var->storage_class == EXTERN) &&
+	    !(var->flags & DEFINED) &&
+	    !(var->flags & TENTATIVE))
+		return;
+	
+	reflower(fp);
+	virgin = -1;
+	switch (var->storage_class)
+	{
+		case EXTERN:
+			/* This doesn't actually mean external linkage; it
+			 * means a non-static global that may be referenced
+			 * externally. */
+			fprintf(fp, "Array _%s ->\n",
+				var->identifier);
+			currentvar.type = EXTERN;
+			currentvar.val.identifier = strdup(var->identifier);
+			currentvar.offset = 0;
+			break;
+			
+		case STATIC:
+			fprintf(fp, "Array STATIC_%s_%ld ->\n",
+				modulename, var->offset);
+			currentvar.type = STATIC;
+			currentvar.val.number = var->offset;
+			currentvar.offset = 0;
+			break;
+	}
+}
+
+/* Emit a certain number of bytes of bss data. No bss on the Z-machine,
+ * remember. */
+
+void gen_ds(FILE *fp, zmax size, struct Typ *typ)
+{
+	fprintf(fp, " %ld\n", size);
+	currentvar.offset += size;
+}
+
+/* Emit a certain number of bytes of initialised data. */
+
+void gen_dc(FILE *fp, int typf, struct const_list *p)
+{
+	switch (typf & NQ)
+	{
+		case CHAR:
+			fprintf(fp, " (%d)\n",
+				p->val.vuchar);
+			currentvar.offset += 1;
+			break;
+
+		case SHORT:
+		case INT:
+		reallyanint:
+			fprintf(fp, " (%d) (%d)\n",
+				xbyte(p->val.vint, 1),
+				xbyte(p->val.vint, 0));
+			currentvar.offset += 2;
+			break;
+				
+		case LONG:
+			fprintf(fp, " (%d) (%d) (%d) (%d)\n",
+				xbyte(p->val.vlong, 3),
+				xbyte(p->val.vlong, 2),
+				xbyte(p->val.vlong, 1),
+				xbyte(p->val.vlong, 0));
+			currentvar.offset += 4;
+			break;
+
+		case POINTER:
+			if (!p->tree)
+				goto reallyanint;
+			{
+				struct fixup* fixup = malloc(sizeof(struct fixup));
+				struct obj* obj = &p->tree->o;
+				fixup->next = fixuplist;
+				fixuplist = fixup;
+				fixup->identifier = currentvar;
+
+				switch (obj->v->storage_class)
+				{
+					case EXTERN:
+						fixup->value.type = EXTERN;
+						fixup->value.val.identifier = strdup(obj->v->identifier);
+						break;
+
+					case STATIC:
+						fixup->value.type = STATIC;
+						fixup->value.val.number = obj->v->offset;
+						break;
+
+					default:
+						ierror(0);
+				}
+				fixup->value.offset = 0;
+				fixup->offset = obj->val.vlong;
+				fprintf(fp, " (0) (0)\n");
+				currentvar.offset += 2;
+			}
+			break;
+
+		default:
+			printf("type %d\n", typf);
+			ierror(0);
+	}
+}
+
+/* Returns the offset of the (STATIC or AUTO) given object. */
+
+zmax voff(struct obj* obj)
+{
+	zmax offset = obj->v->offset;
+	if (offset < 0)
+		offset = stackparamadjust + stackoffset - offset - maxalign;
+	else
+		offset += stackparamadjust;
+
+	offset += obj->val.vlong;
+	return offset;
+}
+
+/* When a varargs function is called, we need to find where the parameters are
+ * on the stack in order to make the __va_start magic variable work. This
+ * function does that. */
+
+static int find_varargs(void)
+{
+	int offset = 0;
+	struct reg_handle rh = empty_reg_handle;
+	struct struct_declaration* sd = function->vtyp->exact;
+	int stackalign;
+	int i;
+
+	for (i=0; i<sd->count; i++)
+	{
+		/* Ignore the parameter if it's been assigned a register. */
+
+		if ((*sd->sl)[i].reg != 0)
+			continue;
+
+		/* void shouldn't happen. */
+
+		if (((*sd->sl)[i].styp->flags & NQ) == VOID)
+			ierror(0);
+
+		/* Does the backend want to assign it to a register? */
+
+		if (reg_parm(&rh, (*sd->sl)[i].styp, 0, 0))
+			continue;
+
+		/* Add on the size of this parameter. */
+
+		offset += sizetab[(*sd->sl)[i].styp->flags & NQ];
+
+		/* Stack align. */
+
+		stackalign = align[(*sd->sl)[i].styp->flags & NQ];
+		offset = ((offset+1) / stackalign) * stackalign;
+	}
+
+	return (offset + stackoffset);
+}
+
+/* Output the name of a global. */
+
+static void emit_identifier(FILE* fp, struct obj* obj)
+{
+	switch (obj->v->storage_class)
+	{
+		case STATIC:
+			fprintf(fp, "STATIC_%s_%ld",
+				modulename, obj->v->offset);
+			break;
+
+		case EXTERN:
+			fprintf(fp, "_%s", obj->v->identifier);
+			break;
+
+		default:
+			ierror(0);
+	}
+}
+
+/* Save a register. */
+
+static void write_reg(FILE* fp, struct obj* obj, int typf, int reg)
+{
+	int flags = obj->flags &
+		(KONST|REG|VAR|DREFOBJ|VARADR);
+
+	/* Constant? */
+
+	if (flags == KONST)
+		ierror(0);
+		
+	/* Dereference? */
+
+	if (flags & DREFOBJ)
+		goto dereference;
+
+	/* Register? */
+
+	if ((flags == REG) ||
+	    ((flags & VAR) && (flags & REG) && (obj->v->storage_class == AUTO)) ||
+	    ((flags & VAR) && (flags & REG) && (obj->v->storage_class == REGISTER)))
+	{
+		if (flags & DREFOBJ)
+			fprintf(fp, "\t@store%c %s 0 %s;\n",
+				((typf & NQ) == CHAR) ? 'b' : 'w',
+				regnames[obj->reg], regnames[reg]);
+		else
+		{
+			struct zop in;
+			struct zop out;
+			in.type = ZOP_REG;
+			in.val.reg = reg;
+			out.type = ZOP_REG;
+			out.val.reg = obj->reg;
+			emit_add(fp, &in, &zop_zero, &out);
+		}
+#if 0
+			fprintf(fp, "\t@add %s 0 -> %s;\n",
+				regnames[reg], regnames[obj->reg]);
+#endif
+		return;
+	}
+
+	/* It must be a variable. */
+
+	switch (obj->v->storage_class)
+	{
+		case AUTO:
+		case REGISTER: /* Local variable */
+		{
+			zmax offset = voff(obj);
+
+			if ((typf & NQ) == CHAR)
+				fprintf(fp, "\t@storeb xp 0%+ld %s;\n",
+					offset, regnames[reg]);
+			else
+			{
+				if (offset & 1)
+				{
+					struct zop c;
+					c.type = ZOP_CONSTANT;
+					c.val.constant = offset;
+					emit_add(fp, &zop_xp, &c, &zop_stack);
+					//fprintf(fp, "\t@add xp 0%+ld -> sp;\n", offset);
+					fprintf(fp, "\t@storew sp 0 %s;\n", regnames[reg]);
+				}
+				else
+					fprintf(fp, "\t@storew xp 0%+ld %s;\n",
+						offset >> 1, regnames[reg]);
+			}
+			return;
+		}
+
+		case EXTERN:
+		case STATIC:
+
+			/* Dereference object. */
+
+			if ((typf & NQ) == CHAR)
+			{
+				fprintf(fp, "\t@storeb ");
+				emit_identifier(fp, obj);
+				fprintf(fp, " 0%+ld %s;\n",
+					obj->val.vlong, regnames[reg]);
+			}
+			else
+			{
+				if (obj->val.vlong & 1)
+				{
+					fprintf(fp, "\t@add ");
+					emit_identifier(fp, obj);
+					fprintf(fp, " 0%+ld -> sp;\n",
+						obj->val.vlong);
+					fprintf(fp, "\t@storew sp 0 %s;\n",
+						regnames[reg]);
+				}
+				else
+				{
+					fprintf(fp, "\t@storew ");
+					emit_identifier(fp, obj);
+					fprintf(fp, " 0%+ld %s;\n",
+						obj->val.vlong >> 1, regnames[reg]);
+				}
+			}
+			return;
+#if 0
+		case EXTERN: /* External linkage */
+			if ((typf & NQ) == CHAR)
+				fprintf(fp, "\t@storeb _%s 0%+ld %s;\n",
+					obj->v->identifier, offset, regnames[reg]);
+			else
+			{
+
+				fprintf(fp, "\t@storew _%s 0 %s;\n",
+					obj->v->identifier, regnames[reg]);
+			return;
+
+		case STATIC: /* Static global */
+			if ((typf & NQ) == CHAR)
+				fprintf(fp, "\t@storeb STATIC_%s_%ld 0%+ld %s;\n",
+					modulename, obj->v->offset, offset, regnames[reg]);
+			else
+				fprintf(fp, "\t@storew STATIC_%s_%ld 0 %s;\n",
+					modulename, obj->v->offset, regnames[reg]);
+			return;
+#endif
+
+		default:
+			ierror(0);
+	}
+
+	ierror(0); // Not reached
+dereference:
+	/* These are a *pain*.
+	 *
+	 * The first thing we need to do is to read the old contents of the
+	 * memory cell, to work out the address we need to write to; and then
+	 * do the write. Hurray for the Z-machine stack. */
+
+	obj->flags &= ~DREFOBJ;
+	read_reg(fp, obj, POINTER, 0);
+	fprintf(fp, "\t@store%c sp 0 %s;\n",
+		((typf & NQ) == CHAR) ? 'b' : 'w',
+		regnames[reg]);
+}
+
+/* Move one register to another register. */
+
+static void move_reg(FILE* fp, int reg1, int reg2)
+{
+	struct zop r1;
+	struct zop r2;
+	r1.type = ZOP_REG;
+	r1.val.reg = reg1;
+	r2.type = ZOP_REG;
+	r2.val.reg = reg2;
+	emit_add(fp, &r1, &zop_zero, &r2);
+}
+/* Load a value into a zop. */
+
+static void read_reg(FILE* fp, struct obj* obj, int typf, int reg)
+{
+	int flags = obj->flags &
+		(KONST|REG|VAR|DREFOBJ|VARADR);
+
+	/* The only thing you can do with a function is to take the address of
+	 * it. */
+
+	if ((typf & NQ) == FUNKT)
+		flags &= ~DREFOBJ & ~VARADR;
+
+	/* Is this a memory dereference? */
+
+	if (flags & DREFOBJ)
+		goto dereference;
+	
+	/* Constant? */
+
+	if (flags == KONST)
+	{
+		struct zop c;
+		struct zop r;
+		c.type = ZOP_CONSTANT;
+		//fprintf(fp, "\t@add ");
+		switch (typf & NQ)
+		{
+			case CHAR:		c.val.constant = obj->val.vchar;	break;
+			case UNSIGNED|CHAR:	c.val.constant = obj->val.vuchar;	break;
+			case SHORT:		c.val.constant = obj->val.vshort;	break;
+			case UNSIGNED|SHORT:	c.val.constant = obj->val.vushort;	break;
+		case POINTER:	      ierror(0);
+			case INT:		c.val.constant = obj->val.vint;		break;
+			case UNSIGNED|INT:	c.val.constant = obj->val.vuint;	break;
+			default:
+				ierror(typf);
+		}
+		r.type = ZOP_REG;
+		r.val.reg = reg;
+		emit_add(fp, &c, &zop_zero, &r);
+		//fprintf(fp, " 0 -> %s;\n", regnames[reg]);
+	}
+	else if (flags == REG) /* Register? */
+	{
+		move_reg(fp, obj->reg, reg);
+		//fprintf(fp, "\t@add %s 0 -> %s;\n", regnames[obj->reg], regnames[reg]);
+	}
+	else if ((flags & REG) && ((typf & NQ) == FUNKT)) /* Function pointer? */
+	{
+		move_reg(fp, obj->reg, reg);
+		//fprintf(fp, "\t@add %s 0 -> %s;\n", regnames[obj->reg], regnames[reg]);
+	}
+	else
+	{
+		/* It must be a variable. */
+
+		switch (obj->v->storage_class)
+		{
+			case AUTO:
+			case REGISTER: /* Local variable */
+				if (flags & VARADR)
+				{
+					fprintf(fp, "\t@add xp 0%+ld -> %s;\n",
+						voff(obj), regnames[reg]);
+				}
+				else if (flags & REG)
+				{
+					move_reg(fp, obj->reg, reg);
+					//fprintf(fp, "\t@add %s 0 -> %s;\n",
+					//	regnames[obj->reg], regnames[reg]);
+				}
+				else
+				{
+					zmax offset = voff(obj);
+
+					if ((typf & NQ) == CHAR)
+						fprintf(fp, "\t@loadb xp 0%+ld -> %s;\n",
+							offset, regnames[reg]);
+					else
+					{
+						if (offset & 1)
+						{
+							fprintf(fp, "\t@add xp 0%+ld -> sp;\n", offset);
+							fprintf(fp, "\t@loadw sp 0 -> %s;\n", regnames[reg]);
+						}
+						else
+							fprintf(fp, "\t@loadw xp 0%+ld -> %s;\n",
+								offset >> 1, regnames[reg]);
+					}
+				}
+				break;
+
+			case STATIC:
+			case EXTERN: /* Global variable. Implicit dereference,
+					with the offset in obj->val.vlong. */
+
+				/* ...but functions are never dereferenced. */
+
+				if ((flags & VARADR) ||
+				    ((typf & NQ) == FUNKT))
+				{
+					/* Fetch address of object. */
+
+					fprintf(fp, "\t@add ");
+					emit_identifier(fp, obj);
+					fprintf(fp, " 0%+ld -> %s;\n",
+						obj->val.vlong, regnames[reg]);
+				}
+				else if (strcmp(obj->v->identifier, "__va_start") == 0)
+				{
+					fprintf(fp, "\t@add xp 0%+ld -> %s;\n",
+						find_varargs(), regnames[reg]);
+				}
+				else
+				{
+					/* Dereference object. */
+
+					if ((typf & NQ) == CHAR)
+					{
+						fprintf(fp, "\t@loadb ");
+						emit_identifier(fp, obj);
+						fprintf(fp, " 0%+ld -> %s;\n",
+							obj->val.vlong, regnames[reg]);
+					}
+					else
+					{
+						if (obj->val.vlong & 1)
+						{
+							fprintf(fp, "\t@add ");
+							emit_identifier(fp, obj);
+							fprintf(fp, " 0%+ld -> sp;\n",
+								obj->val.vlong);
+							fprintf(fp, "\t@loadw sp 0 -> %s;\n",
+								regnames[reg]);
+						}
+						else
+						{
+							fprintf(fp, "\t@loadw ");
+							emit_identifier(fp, obj);
+							fprintf(fp, " 0%+ld -> %s;\n",
+								obj->val.vlong >> 1, regnames[reg]);
+						}
+					}
+				}
+				break;
+
+			default:
+				ierror(obj->v->storage_class);
+		}
+	}
+	return;
+
+dereference:
+	/* Do we need to dereference the thing we just fetched? */
+
+	/* Fetch the value to dereference. */
+	obj->flags &= ~DREFOBJ;
+	read_reg(fp, obj, POINTER, 0);
+		
+	if (flags & DREFOBJ)
+	{
+		switch (typf & NQ)
+		{
+			case CHAR:
+				fprintf(fp, "\t@loadb sp 0 -> %s;\n",
+					regnames[reg], regnames[reg]);
+				break;
+
+			case SHORT:
+			case INT:
+			case POINTER:
+			case FUNKT:
+				fprintf(fp, "\t@loadw sp 0 -> %s;\n",
+					regnames[reg], regnames[reg]);
+				break;
+
+			default:
+				ierror(typf & NQ);
+		}
+	}
+}
+
+/* Returns the zop to use for an input parameter, pushing that parameter onto
+ * the stack if necessary. */
+
+static void push_value(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+	int flags = obj->flags &
+		(KONST|REG|VAR|DREFOBJ|VARADR);
+
+	if (flags == KONST)
+	{
+		op->type = ZOP_CONSTANT;
+		switch (typf & NU)
+		{
+			case CHAR:		op->val.constant = obj->val.vchar;	break;
+			case UNSIGNED|CHAR:	op->val.constant = obj->val.vuchar;	break;
+			case SHORT:		op->val.constant = obj->val.vshort;	break;
+			case UNSIGNED|SHORT:	op->val.constant = obj->val.vushort;	break;
+			case INT:		op->val.constant = obj->val.vint;	break;
+			case UNSIGNED|INT:	op->val.constant = obj->val.vuint;	break;
+		case POINTER:		ierror(0);
+			default:
+				fprintf(fp, "XXX !!! bad konst type %X\n", typf);
+		}
+		return;
+	}
+
+	/* The only thing you can do with a function is to take the address of it. */
+
+	if ((typf & NQ) == FUNKT)
+		flags &= ~DREFOBJ & ~VARADR;
+
+	/* This is used by the long code. The longop functions can only operate
+	 * on pointers to longs; so if we need to pass in a constant, we have
+	 * to stash it on the stack and return a pointer. */
+
+	if (flags == (KONST|VARADR))
+	{
+		op->type = ZOP_CONSTANTADDR;
+		op->val.constant = addconstant(obj->val.vlong);
+		return;
+	}
+	
+	if (flags == REG)
+	{
+		debugemit(fp, "! zop reg %d\n", obj->reg);
+		op->type = ZOP_REG;
+		op->val.reg = obj->reg;
+		return;
+	}
+
+	if ((flags == (VAR|REG)) &&
+	    ((obj->v->storage_class == AUTO) ||
+	     (obj->v->storage_class == REGISTER)))
+	{
+		debugemit(fp, "! zop var reg %d\n", obj->reg);
+		op->type = ZOP_REG;
+		op->val.reg = obj->reg;
+		return;
+	}
+
+	if ((flags == (VAR|VARADR)) &&
+	    (obj->v->storage_class == EXTERN) &&
+	    (obj->v->offset == 0))
+	{
+		debugemit(fp, "! zop varaddr extern %s\n", obj->v->identifier);
+		op->type = ZOP_EXTERN;
+		op->val.identifier = obj->v->identifier;
+		return;
+	}
+
+	if ((flags == (VAR|VARADR)) &&
+	    (obj->v->storage_class == STATIC) &&
+	    (obj->v->offset == 0))
+	{
+		debugemit(fp, "! zop varaddr static %ld\n", obj->v->offset);
+		op->type = ZOP_STATIC;
+		op->val.constant = obj->v->offset;
+		return;
+	}
+
+	if ((flags & VAR) &&
+	    ((obj->v->vtyp->flags & NQ) == FUNKT))
+	{
+		if (obj->v->storage_class == EXTERN)
+		{
+			op->type = ZOP_EXTERN;
+			op->val.identifier = obj->v->identifier;
+		}
+		else
+		{
+			op->type = ZOP_STATIC;
+			op->val.constant = obj->v->offset;
+		}
+		return;
+	}
+	
+	read_reg(fp, obj, typf, 0);
+	op->type = ZOP_STACK;
+}
+
+/* Same as push_value(), but returns a zop for the *address* of the object, not
+ * the object itself. Used a lot by the long code. */
+
+static void push_addrof(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+	if (obj->flags & DREFOBJ)
+		obj->flags &= ~DREFOBJ;
+	else
+		obj->flags |= VARADR;
+	push_value(fp, obj, POINTER, op);
+}
+
+/* Returns the zop to use for an output parameter. Unlike push_value, this does
+ * not emit a pop; that must be done later, if the return parameter is zero. */
+
+static void pop_value(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+	int flags = obj->flags &
+		(KONST|REG|VAR|DREFOBJ|VARADR);
+
+	/* We don't even *try* to handle dereferences here. */
+
+	if (flags & DREFOBJ)
+		goto stack;
+
+	if (flags == REG)
+		goto reg;
+
+	if ((flags == (VAR|REG)) &&
+	    ((obj->v->storage_class == AUTO) ||
+	     (obj->v->storage_class == REGISTER)))
+		goto reg;
+
+stack:
+	op->type = ZOP_STACK;
+	return;
+
+reg:
+	op->type = ZOP_REG;
+	op->val.reg = obj->reg;
+}
+
+/* Writes code for a zop. */
+
+static void emit_zop(FILE* fp, struct zop* op)
+{
+	switch (op->type)
+	{
+		case ZOP_STACK:
+			fprintf(fp, "sp");
+			return;
+
+		case ZOP_REG:
+			fprintf(fp, "%s", regnames[op->val.reg]);
+			return;
+
+		case ZOP_CONSTANT:
+			fprintf(fp, "0%+ld", (zshort)op->val.constant);
+			return;
+
+		case ZOP_EXTERN:
+			fprintf(fp, "_%s", op->val.identifier);
+			return;
+
+		case ZOP_STATIC:
+			fprintf(fp, "STATIC_%s_%ld",
+				modulename, op->val.constant);
+			return;
+
+		case ZOP_CONSTANTADDR:
+			fprintf(fp, "CONSTANT_%s_%ld",
+				modulename, op->val.constant);
+			return;
+
+		default:
+			ierror(op->type);
+	}
+}
+
+/* This is used in conjunction with pop_value(). pop_value() returns a zop that
+ * represents the return value for a function. If that return value is the
+ * stack, the value on the stack needs to be written back into memory. That's
+ * what this function does. */
+
+static void fin_zop(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+	switch (op->type)
+	{
+		case ZOP_STACK:
+			write_reg(fp, obj, typf, 0);
+			return;
+
+		case ZOP_REG:
+			return;
+
+		default:
+			ierror(0);
+	}
+}
+
+/* Emit a basic ADD instruction.
+ * This routine tests for all the various special cases, of which there are
+ * many, and attempts to produce optimal code.
+ */
+
+static void emit_add(FILE* fp, struct zop* q1, struct zop* q2, struct zop* z)
+{
+	/* Sometimes we get ZOP_REG with reg=0. This actually means the stack. */
+
+	if ((q1->type == ZOP_REG) && (q1->val.reg == 0))
+		q1 = &zop_stack;
+	if ((q2->type == ZOP_REG) && (q2->val.reg == 0))
+		q2 = &zop_stack;
+	if ((z->type == ZOP_REG) && (z->val.reg == 0))
+		z = &zop_stack;
+
+	/* If q2 is a constant and 0, then this might be a register move of
+	 * some kind. */
+
+	if ((q2->type == ZOP_CONSTANT) && (q2->val.constant == 0))
+	{
+		/* Left is a register? */
+		if (q1->type == ZOP_REG)
+		{
+			/* Right is a register? */
+			if (z->type == ZOP_REG)
+			{
+				/* They're the *same* register? */
+				if (q1->val.reg == z->val.reg)
+				{
+					/* No code need be emitted. */
+					return;
+				}
+
+				/* Emit a @store instruction. Unfortunately, I
+				 * can't work out the syntax for Inform's
+				 * @store opcode, so we emit a high-level
+				 * assignment instead and let Inform work it
+				 * out. */
+
+				fprintf(fp, "\t");
+				emit_zop(fp, z);
+				fprintf(fp, " = ");
+				emit_zop(fp, q1);
+				fprintf(fp, ";\n");
+				return;
+			}
+
+			/* Right is the stack? */
+			if (z->type == ZOP_STACK)
+			{
+				/* We're pushing the single parameter onto the
+				 * stack. */
+
+				fprintf(fp, "\t@push ");
+				emit_zop(fp, q1);
+				fprintf(fp, ";\n");
+				return;
+			}
+		}
+
+		/* Left is the stack? */
+		if (q1->type == ZOP_STACK)
+		{
+			/* Right is a register? */
+			if (z->type == ZOP_REG)
+			{
+				/* We're popping the single parameter off the
+				 * stack. */
+
+				fprintf(fp, "\t@pull ");
+				emit_zop(fp, z);
+				fprintf(fp, ";\n");
+				return;
+			}
+		}
+	}
+
+	/* Fall back on an ordinary @add. */
+
+	fprintf(fp, "\t@add ");
+	emit_zop(fp, q1);
+	fprintf(fp, " ");
+	emit_zop(fp, q2);
+	fprintf(fp, " -> ");
+	emit_zop(fp, z);
+	fprintf(fp, ";\n");
+}
+
+/* Copy a value from one zop to another. This is not quite as simple as you
+ * might think, because there are a number of optimisation cases to take into
+ * account.
+ *
+ * NOTE: for simplicity, this function will never emit just a single
+ * instruction --- the assignment is always done via the stack. FIXME. */
+
+static void move_value(FILE* fp, struct obj* q1o, struct obj* zo, int typf)
+{
+	struct zop q1;
+	struct zop z;
+
+	pop_value(fp, zo, typf, &z);
+	push_value(fp, q1o, typf, &q1);
+	debugemit(fp, "! L=%d R=%d\n", q1.type, z.type);
+	/* In all cases except when push_value() and fin_zop() *both* emit
+	 * code, we need to insert an assignment here. As they only emit code
+	 * in the ZOP_STACK case... */
+	if ((q1.type != ZOP_STACK) || (z.type != ZOP_STACK))
+	{
+		emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+		fprintf(fp, "\t@add ");
+		emit_zop(fp, &q1);
+		fprintf(fp, " 0 -> ");
+		emit_zop(fp, &z);
+		fprintf(fp, ";\n");
+#endif
+	}
+	fin_zop(fp, zo, typf, &z);
+}
+	
+/* Copy a 32-bit value from one obj to another. */
+
+static void move_long_value(FILE* fp, struct obj* q1, struct obj* z, int typf)
+{
+	int flags = q1->flags &
+		(KONST|REG|VAR|DREFOBJ|VARADR);
+	struct zop q1z;
+	struct zop zz;
+	
+	if (flags == KONST)
+	{
+		int hi = xword(q1->val.vlong, 1);
+		int lo = xword(q1->val.vlong, 0);
+
+		push_addrof(fp, z, POINTER, &zz);
+		fprintf(fp, "\t@call_vn __long_loadconst ");
+		emit_zop(fp, &zz);
+		fprintf(fp, " 0%+ld 0%+ld;\n", (short)hi, (short)lo);
+		return;
+	}
+
+	push_addrof(fp, z, POINTER, &zz);
+	push_addrof(fp, q1, POINTER, &q1z);
+	fprintf(fp, "\t@copy_table ");
+	emit_zop(fp, &q1z);
+	fprintf(fp, " ");
+	emit_zop(fp, &zz);
+	fprintf(fp, " 4;\n");
+}
+
+/* The code generator itself.
+ * This big, complicated, hairy and scary function does the work to actually
+ * produce the code.  fp is the output stream, ic the beginning of the ic
+ * chain, func is a pointer to the actual function and stackframe is the size
+ * of the function's stack frame.
+ */
+
+void gen_code(FILE* fp, struct IC *ic, struct Var* func, zmax stackframe)
+{
+	int i;
+	struct zop q1;
+	struct zop q2;
+	struct zop z;
+	int code, typf; // ...of the IC under consideration
+
+    int c,t,lastcomp=0,reg;
+	    
+    	function = func;
+
+	/* r0..r5 are always used for parameter passing. */
+
+	regused[2] = 1;
+	regused[3] = 1;
+	regused[4] = 1;
+	regused[5] = 1;
+	regused[6] = 1;
+	regused[7] = 1;
+
+	/* This is the offset of the stack frame, relative to the current stack
+	 * pointer. */
+
+	stackoffset = stackframe;
+
+	/* No parameters pushed yet. */
+
+	stackparamadjust = 0;
+
+	reflower(fp);
+
+	if (func->storage_class == STATIC)
+		fprintf(fp, "[ STATIC_%s_%ld xp\n", modulename, func->offset);
+	else
+		fprintf(fp, "[ _%s xp\n", func->identifier);
+
+	/* Tell Inform what registers the function is using. */
+
+	for (i=1; i<=MAXR; i++)
+	{
+		//fprintf(fp, "! i=%d used %d scratch %d alloc %d\n",
+		//		i, regused[i], regscratch[i], regsa[i]);
+		if (regused[i] && !regsa[i])
+			fprintf(fp, "\t%s\n", regnames[i]);
+	}
+	fprintf(fp, ";\n");
+
+	/* Trace the function name. */
+
+	if (g_flags[1] & USEDFLAG)
+	{
+		if (func->storage_class == STATIC)
+			fprintf(fp, "print \"STATIC_%s_%ld^\";\n", modulename, func->offset);
+		else
+			fprintf(fp, "print \"_%s^\";\n", func->identifier);
+	}
+	
+	/* Adjust stack for locals. */
+
+	if (stackframe)
+		fprintf(fp, "\t@sub xp 0%+ld -> xp;\n", stackframe);
+	//if (stackoffset)
+	//	fprintf(fp, "\txp = xp - %ld\n", stackframe);
+
+    
+    	/* Iterate through all ICs. */
+
+	for (; dump_ic(fp, ic), ic; ic=ic->next)
+	{
+        c=ic->code;t=ic->typf;
+		code = ic->code;
+		typf = ic->typf;
+
+		/* Do nothing for NOPs. */
+
+		if (code == NOP)
+			continue;
+
+		/* Has the stack been adjusted due to a call? */
+
+#if 0
+		if (stackcalladjustment)
+		{
+			if ((code != GETRETURN) &&
+			    (code != FREEREG) &&
+			    (code != ALLOCREG))
+			{
+				debugemit(fp, "! stack reset %d %d\n",
+					stackparamadjust, stackcallparamsize);
+				fprintf(fp, "\t@add xp %d -> xp;\n",
+					stackparamadjust+stackcallparamsize);
+				stackparamadjust = 0;
+				stackcallparamsize = 0;
+				stackcalladjustment = 0;
+			}
+		}
+#endif
+
+#if 0
+        if(notpopped&&!dontpop){
+            int flag=0;
+            if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+                fprintf(fp,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+                stackoffset+=notpopped;notpopped=0;
+            }
+        }
+#endif
+		/* These opcodes turn into other opcodes. */
+
+		switch (code)
+		{
+			case SUBPFP:
+			case SUBIFP:
+				code = SUB;
+				break;
+
+			case ADDI2P:
+				code = ADD;
+				break;
+		}
+
+		/* And now the big opcode switch. */
+
+		switch (code)
+		{
+			case ALLOCREG: /* Mark register in use */
+				regs[ic->q1.reg] = 1;
+				continue;
+
+			case FREEREG: /* Mark register not in use */
+				regs[ic->q1.reg] = 0;
+				continue;
+
+			case LABEL: /* Emit jump target */
+				fprintf(fp, ".%s%d;\n",
+					labelprefix, typf);
+				continue;
+
+			case BRA: /* Unconditional jump */
+				fprintf(fp, "\tjump %s%d;\n",
+					labelprefix, typf);
+				continue;
+
+			case GETRETURN: /* Read the last function call's return parameter */
+				switch (typf & NQ)
+				{
+					case CHAR:
+						//if (ic->q2.val.vlong != 1)
+						//	goto copy_struct;
+						/* fall through */
+					case SHORT:
+					case INT:
+					case POINTER:
+						write_reg(fp, &ic->z, typf, 2);
+						break;
+
+						/* Ignore the following; the
+						 * front-end will automatically
+						 * pass in an implicit
+						 * parameter to the function
+						 * containing the address of
+						 * the return parameter, so
+						 * GETRETURN ought to be a
+						 * noop. */
+					case LONG:
+					case STRUCT:
+					case VOID:
+					case ARRAY:
+						break;
+#if 0
+					copy_struct:
+						push_addrof(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@copy_table xp ");
+						emit_zop(fp, &z);
+						fprintf(fp, " %ld;\n", szof(ic->z.v->vtyp));
+						break;
+#endif
+
+					default:
+						ierror(typf & NQ);
+				}
+				//fprintf(fp, "\tr0 = ");
+				//emit_object(fp, &ic->q1, typf);
+				//fprintf(fp, ";\n");
+				//write_reg(fp, &ic->z, typf, 2);
+				continue;
+
+			case SETRETURN: /* Set this function's return parameter */
+				switch (typf & NQ)
+				{
+					case CHAR:
+						//if (ic->q2.val.vlong != 1)
+						//	goto setreturn_copy_struct;
+
+						/* fall through */
+					case SHORT:
+					case INT:
+					case POINTER:
+						read_reg(fp, &ic->q1, typf, 2);
+						break;
+
+					case LONG:
+					case STRUCT:
+					case VOID:
+					case ARRAY:
+#if 0
+					setreturn_copy_struct:
+						fprintf(fp, "\t@add xp %ld -> sp;\n",
+							stackoffset);
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@copy_table ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " sp %ld;\n", szof(ic->q1.v->vtyp));
+						break;
+#endif
+
+					default:
+						ierror(typf & NQ);
+				}
+				//fprintf(fp, "\tr0 = ");
+				//emit_object(fp, &ic->q1, typf);
+				//fprintf(fp, ";\n");
+				continue;
+
+			case MINUS: /* Unary minus */
+				switch (typf & NQ)
+				{
+					case CHAR:
+					case SHORT:
+					case INT:
+						push_value(fp, &ic->q1, typf, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@sub 0 ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " -> ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+
+					case LONG:
+						push_addrof(fp, &ic->z, typf, &z);
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@call_vn __long_neg ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						break;
+
+					default:
+						ierror(0);
+				}
+				continue;
+
+			case KOMPLEMENT: /* Unary komplement */
+				/* INFORM BUG! */
+				/* The @not opcode doesn't work. We have to use a
+				 * wrapper function instead. */
+				
+				push_value(fp, &ic->q1, typf, &q1);
+				pop_value(fp, &ic->z, typf, &z);
+				fprintf(fp, "\t@call_2s __not ");
+				emit_zop(fp, &q1);
+				fprintf(fp, " -> ");
+				emit_zop(fp, &z);
+				fprintf(fp, ";\n");
+				fin_zop(fp, &ic->z, typf, &z);
+				continue;
+
+			case MOVEFROMREG: /* Write a register to memory */
+				write_reg(fp, &ic->z, typf, ic->q1.reg);
+				continue;
+
+			case MOVETOREG: /* Read a register from memory */
+				read_reg(fp, &ic->q1, typf, ic->z.reg);
+				continue;
+
+			case ASSIGN: /* Move something to somewhere else */
+				debugemit(fp, "! ASSIGN size %d typf %d\n", ic->q2.val.vlong, typf & NQ);
+				switch (typf & NQ)
+				{
+					case CHAR:
+						if (ic->q2.val.vlong != 1)
+							goto assign_copy_struct;
+						/* fall through */
+					case SHORT:
+					case INT:
+					case POINTER:
+						move_value(fp, &ic->q1, &ic->z, typf);
+						break;
+
+					case LONG:
+						move_long_value(fp, &ic->q1, &ic->z, typf);
+						break;
+
+					case STRUCT:
+					case VOID:
+					case ARRAY:
+					assign_copy_struct:
+						push_addrof(fp, &ic->z, typf, &z);
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@copy_table ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						emit_zop(fp, &z);
+						fprintf(fp, " 0%+ld;\n", ic->q2.val.vlong);
+						break;
+
+					default:
+						ierror(typf & NQ);
+				}
+				continue;
+
+			case ADDRESS: /* Fetch the address of something, always
+					 AUTO or STATIC */
+				i = voff(&ic->q1);
+				pop_value(fp, &ic->z, typf, &z);
+				fprintf(fp, "\t@add xp 0%+ld -> ", i);
+				emit_zop(fp, &z);
+				fprintf(fp, ";\n");
+				fin_zop(fp, &ic->z, typf, &z);
+				continue;
+
+			case PUSH: /* Push a value onto the stack */
+				fprintf(fp, "\t@sub xp 0%+ld -> xp;\n",
+					ic->q2.val.vlong);
+				//stackoffset += ic->q2.val.vlong;
+				stackparamadjust += ic->q2.val.vlong;
+
+				switch (ic->q2.val.vlong)
+				{
+					case 1:
+						push_value(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@storeb xp 0 ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+
+					case 2:
+						push_value(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@storew xp 0 ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+
+					default:
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@copy_table ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " xp 0%+ld;\n", ic->q2.val.vlong);
+						break;
+				}
+				continue;
+
+			case ADD: /* Add two numbers */
+			case SUB: /* Subtract two numbers */
+			case MULT: /* Multiply two numbers */
+			case DIV: /* Divide two numbers */
+			case MOD: /* Modulo two numbers */
+			case OR: /* Bitwise or */
+			case XOR: /* Bitwise xor */
+			case AND: /* Bitwise and */
+			case LSHIFT: /* Shift left */
+			case RSHIFT: /* Shift right */
+				switch (typf & NQ)
+				{
+					case CHAR:
+					case SHORT:
+					case INT:
+					case POINTER:
+						/* Second parameter first! */
+						push_value(fp, &ic->q2, typf, &q2);
+
+						if (code == RSHIFT)
+						{
+							fprintf(fp, "\t@sub 0 ");
+							emit_zop(fp, &q2);
+							fprintf(fp, " -> sp;\n");
+							q2.type = ZOP_STACK;
+						}
+
+						push_value(fp, &ic->q1, typf, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						//fprintf(fp, "\t");
+						//emit_object(fp, &ic->z, typf);
+						//fprintf(fp, " = ");
+						//emit_object(fp, &ic->q1, typf);
+						switch (code)
+						{
+							case ADD:
+								fprintf(fp, "\t@add ");
+								break;
+
+							case SUB:
+								fprintf(fp, "\t@sub ");
+								break;
+
+							case MULT:
+								fprintf(fp, "\t@mul ");
+								break;
+
+							case DIV:
+								if (typf & UNSIGNED)
+									fprintf(fp, "\t@call_vs __unsigned_div ");
+								else
+									fprintf(fp, "\t@div ");
+								break;
+
+							case MOD:
+								if (typf & UNSIGNED)
+									fprintf(fp, "\t@call_vs __unsigned_mod ");
+								else
+									fprintf(fp, "\t@mod ");
+								break;
+
+							case AND:
+								fprintf(fp, "\t@and ");
+								break;
+
+							case XOR:
+								fprintf(fp, "\t@call_vs __xor ");
+								break;
+
+							case OR:
+								fprintf(fp, "\t@or ");
+								break;
+
+							case LSHIFT:
+							case RSHIFT:
+								if (typf & UNSIGNED)
+									fprintf(fp, "\t@log_shift ");
+								else
+									fprintf(fp, "\t@art_shift ");
+								break;
+
+							default:
+								/* Should never get here! */
+								ierror(0);
+						}
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						emit_zop(fp, &q2);
+						fprintf(fp, " -> ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						fin_zop(fp, &ic->z, typf, &z);
+						//emit_object(fp, &ic->q2, typf);
+						break;
+
+					case LONG:
+						/* Destination parameter first! */
+
+						push_addrof(fp, &ic->z, typf, &z);
+						push_addrof(fp, &ic->q2, typf, &q2);
+						push_addrof(fp, &ic->q1, typf, &q1);
+
+						fprintf(fp, "\t@call_vn __long_");
+						switch (code)
+						{
+							case ADD:
+								fprintf(fp, "add");
+								break;
+
+							case SUB:
+								fprintf(fp, "sub");
+								break;
+
+							case MULT:
+								fprintf(fp, "mul");
+								break;
+
+							case DIV:
+								if (typf & UNSIGNED)
+									fprintf(fp, "unsigned_div");
+								else
+									fprintf(fp, "div");
+								break;
+
+							case MOD:
+								if (typf & UNSIGNED)
+									fprintf(fp, "unsigned_mod");
+								else
+									fprintf(fp, "mod");
+								break;
+
+							case AND:
+								fprintf(fp, "and");
+								break;
+
+							case XOR:
+								fprintf(fp, "xor");
+								break;
+
+							case OR:
+								fprintf(fp, "or");
+								break;
+
+							case LSHIFT:
+								fprintf(fp, "lsl");
+								break;
+								
+							case RSHIFT:
+								if (typf & UNSIGNED)
+									fprintf(fp, "lsr");
+								else
+									fprintf(fp, "asr");
+								break;
+
+							default:
+								/* Should never get here! */
+								ierror(0);
+						}
+						fprintf(fp, " ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						emit_zop(fp, &q2);
+						fprintf(fp, " ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						break;
+
+					default:
+						ierror(0);
+				}
+				continue;
+
+		case CONVERT:
+		  if((q1typ(ic)&NU)==CHAR){
+				switch (ztyp(ic) & NU)
+				{
+					case CHAR:
+					case UNSIGNED|CHAR:
+					case UNSIGNED|SHORT:
+					case UNSIGNED|INT:
+					case SHORT:
+					case INT:
+						push_value(fp, &ic->q1, CHAR, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@log_shift ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " 8 -> sp;\n");
+						fprintf(fp, "\t@art_shift sp 0-8 -> ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+					
+					case LONG:
+						push_value(fp, &ic->q1, INT, &q1);
+						push_addrof(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@call_vn __long_fromchar");
+						emit_zop(fp, &z);
+						fprintf(fp, " ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+
+					default:
+						ierror(0);
+				}
+				continue;
+		  }
+		  if((q1typ(ic)&NU)==(UNSIGNED|CHAR)){
+
+				switch (ztyp(ic) & NQ)
+				{
+					case CHAR:
+					case SHORT:
+					case INT:
+						push_value(fp, &ic->q1, UNSIGNED|CHAR, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+						{
+							emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+							fprintf(fp, "\t@add ");
+							emit_zop(fp, &q1);
+							fprintf(fp, " 0 -> ");
+							emit_zop(fp, &z);
+							fprintf(fp, ";\n");
+#endif
+						}
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+					
+					case LONG:
+						push_value(fp, &ic->q1, UNSIGNED|CHAR, &q1);
+						push_addrof(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@call_vn __long_fromint");
+						emit_zop(fp, &z);
+						fprintf(fp, " 0 ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+						
+					default:
+						ierror(0);
+				}
+				continue;
+		  }
+		  if((q1typ(ic)&NU)==SHORT||(q1typ(ic)&NU)==INT){
+				switch (ztyp(ic) & NU)
+				{
+					case CHAR:
+					case UNSIGNED|CHAR:
+					case UNSIGNED|SHORT:
+					case UNSIGNED|INT:
+					case SHORT:
+					case INT:
+						push_value(fp, &ic->q1, INT, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+						{
+							emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+							fprintf(fp, "\t@add ");
+							emit_zop(fp, &q1);
+							fprintf(fp, " 0 -> ");
+							emit_zop(fp, &z);
+							fprintf(fp, ";\n");
+#endif
+						}
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+
+					case LONG:
+						push_value(fp, &ic->q1, INT, &q1);
+						push_addrof(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@call_vn __long_fromint ");
+						emit_zop(fp, &z);
+						fprintf(fp, " ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+
+					case UNSIGNED|LONG:
+						push_value(fp, &ic->q1, INT, &q1);
+						push_addrof(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@call_vn __long_loadconst ");
+						emit_zop(fp, &z);
+						fprintf(fp, " 0 ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+					
+					default:
+						ierror(typf);
+				}
+				continue;
+		}
+		if((q1typ(ic)&NU)==(UNSIGNED|SHORT)||(q1typ(ic)&NU)==(UNSIGNED|INT)||(q1typ(ic)&NU)==POINTER){
+
+				switch (ztyp(ic) & NQ)
+				{
+					case CHAR:
+					case SHORT:
+					case INT:
+						push_value(fp, &ic->q1, INT, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+						{
+							emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+							fprintf(fp, "\t@add ");
+							emit_zop(fp, &q1);
+							fprintf(fp, " 0 -> ");
+							emit_zop(fp, &z);
+							fprintf(fp, ";\n");
+#endif
+						}
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+
+					case LONG:
+						push_value(fp, &ic->q1, INT, &q1);
+						push_addrof(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@call_vn __long_loadconst ");
+						emit_zop(fp, &z);
+						fprintf(fp, " 0 ");
+						emit_zop(fp, &q1);
+						fprintf(fp, ";\n");
+						break;
+#if 0
+					case SHORT:
+					case INT:
+						fprintf(fp, "\t");
+						emit_object(fp, &ic->z, typf);
+						fprintf(fp, " = (");
+						emit_object(fp, &ic->q1, CHAR);
+						fprintf(fp, ") << 8 >> 8;\n");
+						break;
+#endif
+					
+					default:
+						printf("%X\n", typf);
+						ierror(0);
+				}
+				continue;
+		}
+		if((q1typ(ic)&NU)==(UNSIGNED|LONG)||(q1typ(ic)&NU)==LONG){
+
+				switch (ztyp(ic) & NQ)
+				{
+					case CHAR:
+						push_addrof(fp, &ic->q1, LONG, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@loadb ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " 3 -> ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+
+					case SHORT:
+					case INT:
+						push_addrof(fp, &ic->q1, LONG, &q1);
+						pop_value(fp, &ic->z, typf, &z);
+						fprintf(fp, "\t@loadw ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " 1 -> ");
+						emit_zop(fp, &z);
+						fprintf(fp, ";\n");
+						fin_zop(fp, &ic->z, typf, &z);
+						break;
+					
+					default:
+						ierror(typf & NQ);
+				}
+				continue;
+		}
+			case COMPARE:
+				/* COMPARE is special. The next instruction is
+				 * always a branch.  The Z-machine does
+				 * branches in the form:
+				 *
+				 * @j{e,g,l} <var1> <var2> [~]@<label>
+				 *
+				 * However, we don't know what short of branch
+				 * to emit until the next instruction (which is
+				 * the IC for a branch). So we have to stash
+				 * the zops that we're using for the
+				 * compare here, for use later. This is done
+
+				 * using the globals compare1 and compare2.
+				 */
+
+				switch (typf & NU)
+				{
+					case CHAR:
+					case SHORT:
+					case INT:
+					case POINTER:
+						/* Second parameter first! */
+						push_value(fp, &ic->q2, typf, &compare2);
+						push_value(fp, &ic->q1, typf, &compare1);
+						break;
+
+					case UNSIGNED|CHAR:
+					case UNSIGNED|SHORT:
+					case UNSIGNED|INT:
+						/* Because the Z-machine only
+						 * has signed comparisons, we
+						 * need a dodgy algorithm to
+						 * do this, which works as
+						 * follows: in the signed
+						 * domain, 0-7FFF compares
+						 * greater than 8000-FFFF. In
+						 * the unsigned domain, it's
+						 * the other way around. So,
+						 * by flipping the sign bits
+						 * we do the logical
+						 * equivalent of shifting the
+						 * unsigned range up/down by
+						 * 8000 which makes it fit
+						 * the signed range. There.
+						 * Did you understand that?
+						 * Neither did I, the first
+						 * few times it was explained
+						 * to me. */
+						read_reg(fp, &ic->q2, typf, 0);
+						fprintf(fp, "\t@add sp $8000 -> sp;\n");
+						read_reg(fp, &ic->q1, typf, 0);
+						fprintf(fp, "\t@add sp $8000 -> sp;\n");
+						compare1.type = ZOP_STACK;
+						compare2.type = ZOP_STACK;
+						break;
+
+					case LONG:
+						push_addrof(fp, &ic->q2, typf, &q2);
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@call_vs __long_compare ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						emit_zop(fp, &q2);
+						fprintf(fp, " -> sp;\n");
+						compare1.type = ZOP_STACK;
+						compare2.type = ZOP_CONSTANT;
+						compare2.val.constant = 0;
+						break;
+
+					case UNSIGNED|LONG:
+						push_addrof(fp, &ic->q2, typf, &q2);
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@call_vs __long_unsigned_compare ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						emit_zop(fp, &q2);
+						fprintf(fp, " -> sp;\n");
+						compare1.type = ZOP_STACK;
+						compare2.type = ZOP_CONSTANT;
+						compare2.val.constant = 0;
+						break;
+
+					default:
+						ierror(typf & NQ);
+				}
+				continue;
+
+			case TEST:
+				/* TEST is a special COMPARE. It takes one
+				 * parameter and always tests it against 0; it
+				 * is guaranteed to be followed by BNE or BEQ.
+				 * */
+
+				switch (typf & NQ)
+				{
+					case CHAR:
+					case SHORT:
+					case INT:
+					case POINTER:
+						push_value(fp, &ic->q1, typf, &compare1);
+						compare2.type = ZOP_CONSTANT;
+						compare2.val.constant = 0;
+						break;
+
+					case LONG:
+						push_addrof(fp, &ic->q1, typf, &q1);
+						fprintf(fp, "\t@call_vs __long_compare ");
+						emit_zop(fp, &q1);
+						fprintf(fp, " ");
+						q2.type = ZOP_CONSTANTADDR;
+						q2.val.constant = addconstant(0);
+						emit_zop(fp, &q2);
+						fprintf(fp, " -> sp;\n", i);
+						compare1.type = ZOP_STACK;
+						compare2.type = ZOP_CONSTANT;
+						compare2.val.constant = 0;
+						break;
+
+					default:
+						ierror(typf & NQ);
+				}
+				continue;
+
+			case BEQ:
+			case BNE:
+			case BLT:
+			case BGE:
+			case BLE:
+			case BGT:
+			{
+				static int branchlabel = 0;
+
+				fprintf(fp, "\t@j");
+				switch (code)
+				{
+					case BNE:
+					case BEQ:	fprintf(fp, "e ");	break;
+					case BLT:
+					case BGE:	fprintf(fp, "l ");	break;
+					case BGT:
+					case BLE:	fprintf(fp, "g ");	break;
+				}
+
+				emit_zop(fp, &compare1);
+				fprintf(fp, " ");
+				emit_zop(fp, &compare2);
+				fprintf(fp, " ?");
+
+				if (g_flags[3] & USEDFLAG)
+				{
+					if (!((code == BNE) || (code == BGE) || (code == BLE)))
+						fprintf(fp, "~");
+					fprintf(fp, "LL%d;\n", branchlabel);
+					fprintf(fp, "\tjump %s%d;\n", labelprefix, typf);
+					fprintf(fp, ".LL%d;\n", branchlabel++);
+				}
+				else
+				{
+					if ((code == BNE) || (code == BGE) || (code == BLE))
+						fprintf(fp, "~");
+					fprintf(fp, "%s%d;\n", labelprefix, typf);
+				}
+				continue;
+			}
+
+			case CALL:
+			{
+#if 0
+				/* Calculate the amount of stack to reserve for
+				 * the return parameter. ints and smaller go in
+				 * the return register. */
+
+				stackcallparamsize = szof(ic->q1.v->vtyp->next);
+				if (stackcallparamsize <= sizetab[INT])
+					stackcallparamsize = 0;
+
+				if (stackcallparamsize)
+					fprintf(fp, "\t@sub xp %d -> xp;\n",
+						stackcallparamsize);
+#endif
+
+				/* Is this actually an inline assembly function? */
+
+				if ((ic->q1.flags & VAR) &&
+				    ic->q1.v->fi &&
+				    ic->q1.v->fi->inline_asm)
+				{
+					/* Yes. Emit the assembly code. */
+
+					fprintf(fp, "%s", ic->q1.v->fi->inline_asm);
+				}
+				else
+				{
+					/* No; so emit a call. */
+				
+					push_value(fp, &ic->q1, typf, &q1);
+					fprintf(fp, "\t@call_vs2 ");
+					emit_zop(fp, &q1);
+					fprintf(fp, " xp r0 r1 r2 r3 r4 r5 -> r0;\n");
+				}
+
+				//stackcalladjustment = 1;
+
+				/* If any parameters have been pushed, adjust
+				 * the stack to pop them. */
+
+				if (stackparamadjust)
+				{
+					fprintf(fp, "\t@add xp 0%+ld -> xp;\n",
+						stackparamadjust);
+					//stackoffset -= stackparamadjust;
+					stackparamadjust = 0;
+				}
+				continue;
+			}
+
+			default:
+				ierror(code);
+		}
+						
+	}
+
+	/* We really ought to tidy the stack up; but there's no need, because
+	 * the old value of xp will be restored when the function exits. */
+
+    	//if (stackframe)
+	//	fprintf(fp, "\t@add xp %ld -> xp;\n", stackframe);
+	
+	fprintf(fp, "\t@ret r0;\n");
+	fprintf(fp, "]\n");
+
+//    function_bottom(fp, func, loff);
+}
+
+int shortcut(int code, int typ)
+{
+    return(0);
+}
+
+// Add a constant to the constant pool.
+
+static int addconstant(zmax value)
+{
+	struct constant* c;
+	
+	/* Check to see if the constant's already in the pool. */
+
+	c = constantlist;
+	while (c)
+	{
+		if (c->value == value)
+			return c->id;
+		c = c->next;
+	}
+
+	/* It's not; add it. */
+	
+	c = malloc(sizeof(struct constant));
+	c->next = constantlist;
+	c->id = constantnum++;
+	c->value = value;
+	constantlist = c;
+	return c->id;
+}
+
+void cleanup_cg(FILE *fp)
+{
+	struct fixup* fixup = fixuplist;
+
+	/* Have we actually emitted anything? */
+
+	if (!fp)
+		return;
+
+	reflower(fp);
+
+	/* Emit the constant pool. */
+
+	{
+		struct constant* constant = constantlist;
+
+		while (constant)
+		{
+			fprintf(fp, "Array CONSTANT_%s_%ld -->\n",
+				modulename, constant->id);
+			fprintf(fp, " 0%+ld 0%+ld;\n",
+				xword(constant->value, 1),
+				xword(constant->value, 0));
+			constant = constant->next;
+		}
+	}
+
+	/* Emit the code to initialise the data area. */
+
+	{
+		struct fixup* fixup = fixuplist;
+
+		fprintf(fp, "[ __init_vars_%s;\n", modulename);
+		while (fixup)
+		{
+			fprintf(fp, "\t@add 0%+ld ", fixup->offset);
+
+			switch (fixup->value.type)
+			{
+				case STATIC:
+					fprintf(fp, "STATIC_%s_%ld -> sp;\n",
+						modulename, fixup->value.val.number);
+					break;
+
+				case EXTERN:
+					fprintf(fp, "_%s -> sp;\n",
+						fixup->value.val.identifier);
+					break;
+
+				default:
+					ierror(0);
+			}
+
+			switch (fixup->identifier.type)
+			{
+				case STATIC:
+					fprintf(fp, "\t@storew STATIC_%s_%ld 0%+ld sp;\n",
+						modulename, fixup->identifier.val.number,
+						fixup->identifier.offset);
+					break;
+
+				case EXTERN:
+					fprintf(fp, "\t@storew _%s 0%+ld sp;\n",
+						fixup->identifier.val.identifier,
+						fixup->identifier.offset);
+					break;
+
+				default:
+					ierror(0);
+			}
+
+			fixup = fixup->next;
+		}
+		fprintf(fp, "];\n");
+	}
+}
+
+/* The code generator's asking us to pass a parameter in a register. */
+
+int reg_parm(struct reg_handle *rh, struct Typ *typ, int vararg, struct Typ *ft)
+{
+	/* Vararg parameters never go in registers. */
+
+	if (vararg)
+		return 0;
+
+	/* Will the parameter fit? */
+
+	if (sizetab[typ->flags & NQ] > 2)
+		return 0;
+
+	/* Still enough registers? */
+
+	if (rh->reg >= NUM_REGPARMS+USERREG)
+		return 0;
+
+	return (rh->reg++);
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r  */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two   */
+/* elements.                                            */
+{
+  return 0;
+}                                                                               
+void init_db(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+}
diff --git a/machines/z/machine.dt b/machines/z/machine.dt
new file mode 100755
index 0000000..41828bc
--- /dev/null
+++ b/machines/z/machine.dt
@@ -0,0 +1,14 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEEBE S32BIEEELE
+S64BIEEEBE S64BIEEELE
+S64BIEEEBE S64BIEEELE
+S16BULE S16BUBE
diff --git a/machines/z/machine.h b/machines/z/machine.h
new file mode 100755
index 0000000..6f43fc8
--- /dev/null
+++ b/machines/z/machine.h
@@ -0,0 +1,81 @@
+/* Z-machine code generator
+ * David Given
+ */
+
+#include "dt.h"
+
+/* Machine specific addressing-modes. Not used. */
+
+struct AddressingMode{
+	int never_used;
+};
+
+/* The number of registers we support. We don't really have any, but we
+ * use local variables instead; we have 14.
+ */
+
+#define MAXR 14
+
+/* Number of command-line options we accept. */
+
+#define MAXGF 6
+
+/* If this is set to zero vbcc will not generate ICs where the target operand
+ * is the same as the 2nd source operand. This can sometimes simplify the
+ * code-generator, but usually the code is better if the code-generator allows
+ * it. 
+ */
+
+#define USEQ2ASZ 1
+
+/* The smallest and largest integer type that can be added to a pointer. */
+
+#define MINADDI2P INT
+#define MAXADDI2P INT
+
+/* Big-endian? */
+
+#define BIGENDIAN 1
+
+/* Little-endian? */
+
+#define LITTLEENDIAN 0
+
+/* If switch-statements should be generated as a sequence of SUB,TST,BEQ ICs
+ * rather than COMPARE,BEQ ICs set this to 1.  This can yield better code on
+ * some machines.
+ */
+
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls with length
+ * known at compile-time will be inlined using an ASSIGN-IC if the size is less
+ * or equal to INLINEMEMCPY.  The type used for the ASSIGN-IC will be
+ * UNSIGNED|CHAR. On the Z-machine, memcpy can be done in `hardware' with the
+ * @copy_table opcode, so always inline them if possible.
+ */
+
+#define INLINEMEMCPY 65536
+
+/* Do we want to pass parameters to functions in registers? */
+
+#define HAVE_REGPARMS 1
+
+/* If so, how many? Max 7 due to the architecture, but one is always xp. */
+
+#define NUM_REGPARMS 6
+
+/* This structure is used to keep track of where register parameters go. */
+
+struct reg_handle {
+	int reg;
+};
+
+/* Do we want to use zuint for size_t rather than the default zulong? */
+
+#define HAVE_INT_SIZET 1
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5e102f4
--- /dev/null
+++ b/main.c
@@ -0,0 +1,2010 @@
+/*  $VER: vbcc (main.c) $Revision: 1.67 $    */
+#include "vbcc_cpp.h"
+#include "vbc.h"
+#include "opt.h"
+static char FILE_[]=__FILE__;
+void do_function(Var *);
+static function_info *current_fi;
+token *ctok;
+lexer_state ls;
+int endok=1;
+int line,errors;
+bvtype task_preempt_regs[RSIZE/sizeof(bvtype)];
+bvtype task_schedule_regs[RSIZE/sizeof(bvtype)];
+char *multname[]={"","s"};
+
+typedef struct deplist {char *name; struct deplist *next;} deplist;
+deplist *deps;
+FILE *depout;
+void handle_deps(char *name,int string)
+{
+  deplist *p=deps;
+  if(!depout||!name||!*name) return;
+  /* by default omit <...> includes */
+  if(!string&&!(c_flags[51]&USEDFLAG)) return;
+  while(p){
+    if(!strcmp(p->name,name)) return;
+    p=p->next;
+  }
+  p=mymalloc(sizeof(*p));
+  p->name=mymalloc(strlen(name)+1);
+  strcpy(p->name,name);
+  p->next=deps;
+  deps=p;
+  fprintf(depout," %s",name);
+}
+
+void raus(void)
+/*  Beendet das Programm                                            */
+{
+  static int inraus;
+  if(inraus) return;
+  inraus = 1;
+  if(DEBUG) printf("raus()\n");
+  if(!endok) fprintf(stderr,"unexpected end of file\n");
+  if(errors) fprintf(stderr,"%d error%s found!\n",errors,multname[errors>1]);
+  if(debug_info&&out)
+    cleanup_db(out);
+  while(nesting>=0) leave_block();
+  /*FIXME: do I have to close input-file? */
+  if(!wpo)
+    cleanup_cg(out);
+  emit_flush(out);
+  if(cmdfile) fclose(cmdfile);
+  if(out) fclose(out);
+  if(ic1) fclose(ic1);
+  if(ic2) fclose(ic2);
+  /*FIXME: need to cleanup something for ucpp?*/;
+  if(endok&&!errors) exit(EXIT_SUCCESS); else exit(EXIT_FAILURE);
+}
+int eof;
+void translation_unit(void)
+/*  bearbeitet translation_unit                                     */
+/*  hier z.Z. nur provisorisch                                      */
+{
+  Var *p;
+  if(cross_module){
+    for(p=first_ext;p;p=p->next)
+      if(!(p->flags&BUILTIN))
+	p->flags|=NOTINTU;
+  }
+  while(1){
+    killsp();
+    if(eof||ctok->type!=NAME){
+      if(!eof){
+	error(369);
+	next_token();
+	continue;
+      }else{
+	if(cross_module){
+	  int n=0;
+	  if(last_tunit){
+	    last_tunit->next=mymalloc(sizeof(*first_tunit));
+	    last_tunit=last_tunit->next;
+	  }else{
+	    first_tunit=last_tunit=mymalloc(sizeof(*first_tunit));
+	  }
+	  last_tunit->next=0;
+	  for(p=first_var[0];p;p=p->next){
+	    if(p->storage_class==STATIC) n++;
+	  }
+	  last_tunit->statics=first_var[0];
+	  return;
+	}else{
+	  raus();
+	}
+      }
+    }
+    endok=0;
+    var_declaration();
+    endok=1;
+  }
+}
+void reserve_reg(char *p)
+     /* reserviert ein Register */
+{
+  int i;
+  if(*p!='=') error(4,"-reserve-reg");
+  for(i=1;i<=MAXR;i++){
+    if(!strcmp(p+1,regnames[i]))
+      break;
+  }
+  if(i>MAXR){
+    error(331,p+1);
+  }else{
+    regsa[i]=1;
+  }
+}
+
+void dontwarn(char *p)
+/*  schaltet flags fuer Meldung auf DONTWARN    */
+{
+  if(*p!='=') error(4,"-dontwarn");
+  do{
+    int i=atoi(p+1);
+    if(i>=err_num) error(159,i);
+    if(i<0){
+      for(i=0;i<err_num;i++)
+        if(!(err_out[i].flags&(ANSIV|FATAL)))
+    err_out[i].flags|=DONTWARN;
+      return;
+    }
+    if(err_out[i].flags&(ANSIV|FATAL)) error(160,i);
+    err_out[i].flags|=DONTWARN;
+    p=strchr(p+1,',');
+  } while(p);
+}
+
+
+
+#define MISRA_98_RULE_NUMBER	127
+#define MISRA_04_CHAPTER			21
+#define MISRA_04_MAX_RULE_IN_CHAPTER 17
+
+static int misra_98_warn_flag[MISRA_98_RULE_NUMBER] = { 0 };
+static int misra_04_warn_flag[MISRA_04_CHAPTER][MISRA_04_MAX_RULE_IN_CHAPTER] = { 0 };
+
+void misrawarn(char *p) {
+	int rule,subrule,misraoldrule;
+	char* last;
+	int not_found;
+	tmisra_err_out* misr_err;
+	rule = 0;
+	subrule = 0;
+	misraoldrule = 0;
+  if(*p!='=') error(4,"-misrawarn");
+	p++;
+	if (!(strncmp("chapter",p,6))) {
+		if (sscanf((p+7),"%d",&rule) != 1) {
+			error(327,"-misrawarn");
+		}
+	} else if ( !(strncmp("misra98rule",p,11))) {
+		if (sscanf((p+12),"%d",&misraoldrule) != 1) {
+			error(327,"-misrawarn");
+		}
+	} else {
+		if (last = strchr(p,'.')) {
+			*last = 0;
+			last++;
+			if (sscanf(last,"%d",&subrule) != 1) error(327,"-misrawarn");
+			if (sscanf(p,"%d",&rule) != 1) error(327,"-misrawarn");
+			last--;
+			*last='.';
+		} else error(327,"-misrawarn");
+	}
+
+	p--;
+	if (!misracheck) misracheck = 1;
+	if (misraoldrule) {
+		if (misraversion==2004) error(328,misraversion,"-misrawarn",p);
+		if (!misraversion) misraversion=1998;
+		if ((misraoldrule < 1) || (misraoldrule>MISRA_98_RULE_NUMBER)) error(329,misraoldrule,"-misrawarn",p);
+		misra_98_warn_flag[misraoldrule-1] = 1;
+	} else {
+		if (misraversion==1998) error(328,misraversion,"-misrawarn",p);
+		if (!misraversion) misraversion=2004;
+		if (subrule) {
+			misr_err = misra_err_out;
+		  not_found = 1;
+			while ( misr_err->text ) {
+				if ((misr_err->chapter == rule) && (misr_err->rule == subrule)) {
+					not_found = 0;
+					break;
+				}
+				misr_err++;
+			}
+			if (not_found) error(330,rule,subrule,"-misrawarn",p);
+			misra_04_warn_flag[rule-1][subrule-1] = 1;
+		} else {
+			misr_err = misra_err_out;
+		  not_found = 1;
+			while ( misr_err->text ) {
+				if (misr_err->chapter == rule) {
+					not_found = 0;
+					misra_04_warn_flag[misr_err->chapter-1][misr_err->rule-1] = 1;
+				}
+				misr_err++;
+			}
+			if (not_found) error(330,rule,subrule,"-misrawarn",p);
+		}
+	}
+
+}
+
+
+void misradontwarn(char *p) {
+	int rule,subrule,misraoldrule;
+	char* last;
+	int not_found;
+	tmisra_err_out* misr_err;
+	rule = 0;
+	subrule = 0;
+	misraoldrule = 0;
+  if(*p!='=') error(4,"-misradontwarn");
+	p++;
+	if (!(strncmp("chapter",p,6))) {
+		if (sscanf((p+7),"%d",&rule) != 1) {
+			error(327,"-misradontwarn");
+		}
+	} else if ( !(strncmp("misra98rule",p,11))) {
+		if (sscanf((p+12),"%d",&misraoldrule) != 1) {
+			error(327,"-misradontwarn");
+		}
+	} else {
+		if (last = strchr(p,'.')) {
+			*last = 0;
+			last++;
+			if (sscanf(last,"%d",&subrule) != 1) error(327,"-misradontwarn");
+			if (sscanf(p,"%d",&rule) != 1) error(327,"-misradontwarn");
+			last--;
+			*last='.';
+		} else error(327,"-misradontwarn");
+	}
+
+	p--;
+	if (misraoldrule) {
+		if (misraversion==2004) error(328,misraversion,"-misradontwarn",p);
+		if ((misraoldrule < 1) || (misraoldrule>MISRA_98_RULE_NUMBER)) error(329,misraoldrule,"-misradontwarn",p);
+		misra_98_warn_flag[misraoldrule-1] = -1;
+	} else {
+		if (misraversion==1998) error(328,misraversion,"-misradontwarn",p);
+		if (subrule) {
+			misr_err = misra_err_out;
+		  not_found = 1;
+			while ( misr_err->text ) {
+				if ((misr_err->chapter == rule) && (misr_err->rule == subrule)) {
+					not_found = 0;
+					break;
+				}
+				misr_err++;
+			}
+			if (not_found) error(330,rule,subrule,"-misradontwarn",p);
+			misra_04_warn_flag[rule-1][subrule-1] = -1;
+		} else {
+			misr_err = misra_err_out;
+		  not_found = 1;
+			while ( misr_err->text ) {
+				if (misr_err->chapter == rule) {
+					not_found = 0;
+					misra_04_warn_flag[misr_err->chapter-1][misr_err->rule-1] = -1;
+				}
+				misr_err++;
+			}
+			if (not_found) error(330,rule,subrule,"-misradontwarn",p);
+		}
+	}
+
+}
+
+
+
+void warn(char *p)
+/*  schaltet Warnung fuer Meldung ein           */
+/*  wenn Nummer<0 sind alle Warnungen ein       */
+{
+  int i;
+  if(*p!='=') error(4,"-warn");
+  i=atoi(p+1);
+  if(i>=err_num) error(159,i);
+  if(i<0){
+    for(i=0;i<err_num;i++) err_out[i].flags&=~DONTWARN;
+    return;
+  }else err_out[i].flags&=~DONTWARN;
+}
+void gen_function(FILE *f,Var *v,int real_gen)
+{
+  IC *p,*new;int i,had_regs;
+  if(DEBUG&1) printf("gen_function <%s>,f=%p,real_gen=%d\n",v->identifier,(void*)f,real_gen);
+  if(!v->fi) ierror(0);
+  if(errors!=0) return;
+  first_ic=last_ic=0;
+  for(i=1;i<=MAXR;i++) {regs[i]=regused[i]=regsa[i];regsbuf[i]=0;}
+  function_calls=0;vlas=0;
+  if(!real_gen){
+    for(p=v->fi->first_ic;p;p=p->next){
+      new=new_IC();
+      *new=*p;
+      p->copy=new;
+      add_IC(new);
+      new->file=p->file;
+      new->line=p->line;
+      if(p->code==CALL){
+	int i;
+	function_calls++;
+	if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"__allocvla")){
+          vlas=1;
+          v->fi->flags|=USES_VLA;
+        }
+	new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+	for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=p->arg_list[i]->copy;      
+      }
+    }
+  }else{
+    for(i=1;i<=MAXR;i++) regused[i]=0;
+    for(p=v->fi->opt_ic;p;p=p->next){
+      if(p->code==ALLOCREG){
+	regused[p->q1.reg]=1;
+	if(reg_pair(p->q1.reg,&rp)){
+	  regused[rp.r1]=1;
+	  regused[rp.r2]=1;
+	}
+      }
+      if(p->code==CALL){
+	if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"__allocvla")) vlas=1;
+	function_calls++;
+      }
+    }
+  }
+  if(vlas&&FPVLA_REG) regs[FPVLA_REG]=regused[FPVLA_REG]=regsa[FPVLA_REG]=regscratch[FPVLA_REG]=1;
+      
+  if(!real_gen&&(c_flags[2]&USEDFLAG)&&ic1){
+    fprintf(ic1,"function %s\n",v->identifier);
+    pric(ic1,first_ic);
+  }
+  vl0=first_ext;
+  vl1=v->fi->statics;
+  vl2=0;
+  vl3=v->fi->vars;
+  nesting=1;
+  first_var[nesting]=last_var[nesting]=0;
+  cur_func=v->identifier;
+  if(!real_gen){
+    optimize(optflags,v);
+    if((force_statics||prefer_statics)&&first_var[nesting]){
+      
+      last_var[nesting]->next=v->fi->vars;
+      v->fi->vars=first_var[nesting];
+    }
+    memset(regs_modified,0,RSIZE);
+    /* pseudeo generator pass to get regs_modified */
+    v->fi->opt_ic=clone_ic(first_ic);
+    v->fi->max_offset=max_offset;
+    if(v->fi&&(v->fi->flags&ALL_REGS))
+      had_regs=1;
+    else
+      had_regs=0;
+    gen_code(0,first_ic,v,max_offset);
+#ifdef HAVE_REGS_MODIFIED
+    if(!v->fi) v->fi=new_fi();
+    {
+      int i;IC *p;
+      for(i=1;i<=MAXR;i++){
+	if(BTST(regs_modified,i)&&reg_pair(i,&rp)){
+	  BSET(regs_modified,rp.r1);
+	  BSET(regs_modified,rp.r2);
+	}
+      }
+#if 1
+      for(i=1;i<=MAXR;i++){
+	if(reg_pair(i,&rp)){
+	  if(BTST(regs_modified,rp.r1)||BTST(regs_modified,rp.r2))
+	    BSET(regs_modified,i);
+	}
+      }
+#endif
+      if(had_regs){
+	if(memcmp(regs_modified,v->fi->regs_modified,RSIZE))
+	  error(321,v->identifier);
+      }else
+	memcpy(v->fi->regs_modified,regs_modified,RSIZE);
+#if 0
+      printf("regs for %s (ALL_REGS=%d):\n",v->identifier,v->fi->flags&ALL_REGS);
+      for(i=1;i<MAXR;i++) if(BTST(regs_modified,i)) printf("%s ",regnames[i]);
+      printf("\n");
+#endif
+    }
+#endif
+    v->flags|=GENERATED;
+    free_IC(first_ic);
+    first_ic=last_ic=0;
+    /*free_var(first_var[nesting]);*/
+    nesting=0;
+  }else{
+    if((c_flags[3]&USEDFLAG)&&ic2){
+      fprintf(ic2,"function %s\n",v->identifier);
+      pric(ic2,v->fi->opt_ic);
+    }
+    gen_code(f,v->fi->opt_ic,v,v->fi->max_offset);
+    static_stack_check(v);
+  }
+}
+/* handle functions in a const list before caller */
+static void do_clist_calls(const_list *cl)
+{
+  while(cl){
+    if(cl->tree&&(cl->tree->o.flags&VARADR)){
+      Var *v=cl->tree->o.v;
+      if(ISFUNC(v->vtyp->flags)){
+	if(DEBUG&1)
+	  printf(":: %s\n",v->identifier);
+	do_function(v);
+      }
+    }
+    if(cl->other)
+      do_clist_calls(cl->other);
+    cl=cl->next;
+  }
+}
+void do_function(Var *v)
+{
+  int i;IC *p;
+  if((v->flags&(GENERATED|DEFINED))!=DEFINED) return;
+  v->flags|=GENERATED;
+  if(!v->fi) v->fi=new_fi();
+#if 0  
+  for(i=0;i<v->fi->call_cnt;i++){
+    if(v->fi->call_list[i].v->flags&DEFINED)
+      do_function(v->fi->call_list[i].v);
+  }
+#endif
+  /* handle callees before caller */
+  for(p=v->fi->first_ic;p;p=p->next){
+    /* direct call */
+    if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR)
+      do_function(p->q1.v);
+    /* function address is also a candidate */
+    if((p->q1.flags&(VAR|VARADR))&&ISFUNC(p->q1.v->vtyp->flags))
+      do_function(p->q1.v);
+    if((p->q2.flags&(VAR|VARADR))&&ISFUNC(p->q2.v->vtyp->flags))
+      do_function(p->q2.v);
+    if((p->z.flags&(VAR|VARADR))&&ISFUNC(p->z.v->vtyp->flags))
+      do_function(p->z.v);
+    /* indirect call, handle special case */
+    if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+      Var *v=p->q1.v;
+      if(v->storage_class==AUTO||v->storage_class==REGISTER){
+	IC *m=p->prev;Var *tmp=0;
+	while(m&&(m->code<LABEL||m->code>=BRA)){
+	  if(!tmp&&(m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==v&&
+	     (m->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))
+	    tmp=m->q1.v;
+	  if(tmp&&(m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==tmp&&
+	     (m->q1.flags&(VAR|VARADR))==(VAR|VARADR)&&
+	     m->q1.v->clist&&is_const(m->q1.v->vtyp)){
+	    do_clist_calls(m->q1.v->clist);
+	  }
+	  m=m->prev;
+	}
+      }
+    }
+  }
+  gen_function(0,v,0);
+}
+
+
+
+extern char *copyright;
+int main(int argc,char *argv[])
+{
+  int i,j,*fname=malloc(argc*sizeof(int)),files=0;
+  unsigned long ucpp_flags=LEXER|WARN_TRIGRAPHS|WARN_STANDARD|WARN_ANNOYING/*|CCHARSET*/|HANDLE_PRAGMA|COPY_LINE|WARN_TRIGRAPHS_MORE|HANDLE_TRIGRAPHS;
+  if(!fname) ierror(0);
+  memset(fname,0,argc*sizeof(int));
+  c_flags_val[9].f=dontwarn;
+  c_flags_val[10].f=warn;
+  c_flags_val[42].f=misrawarn;
+  c_flags_val[43].f=misradontwarn;
+  c_flags_val[44].f=reserve_reg;
+  for(i=1;i<argc;i++){
+    if(*argv[i]!='-'){  /*  kein Flag   */
+      fname[i]=1;
+      files++;
+      if(!inname) inname=argv[i];
+    }else{
+      int flag=0;
+      if(argv[i][1]=='D'||argv[i][1]=='I') flag=1;
+      for(j=0;j<MAXCF&&flag==0;j++){
+	size_t l;
+	if(!c_flags_name[j]) continue;
+	l=strlen(c_flags_name[j]);
+	if(l>0&&!strncmp(argv[i]+1,c_flags_name[j],l)&&(argv[i][1+l]==0||argv[i][1+l]=='=')){
+	  flag=1;
+	  if((c_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(2,argv[i]);break;}
+	  c_flags[j]|=USEDFLAG;
+	  if(c_flags[j]&STRINGFLAG){
+	    if(argv[i][l+1]!='='){error(3,argv[i]);}
+	    if(argv[i][l+2]||i>=argc-1)
+	      c_flags_val[j].p=&argv[i][l+2];
+	    else
+	      c_flags_val[j].p=&argv[++i][0];
+	  }
+	  if(c_flags[j]&VALFLAG){
+	    if(argv[i][l+1]!='='){error(4,argv[i]);}
+	    if(argv[i][l+2]||i>=argc-1)
+	      c_flags_val[j].l=atol(&argv[i][l+2]);
+	    else
+	      c_flags_val[j].l=atol(&argv[++i][0]);
+	  }
+	  if(c_flags[j]&FUNCFLAG) c_flags_val[j].f(&argv[i][l+1]);
+	}
+      }
+      for(j=0;j<MAXGF&&flag==0;j++){
+	size_t l;
+	if(!g_flags_name[j]) continue;
+	l=strlen(g_flags_name[j]);
+	if(l>0&&!strncmp(argv[i]+1,g_flags_name[j],l)){
+	  flag=1;
+	  if((g_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(2,argv[i]);break;}
+	  g_flags[j]|=USEDFLAG;
+	  if(g_flags[j]&STRINGFLAG){
+	    if(argv[i][l+1]!='='){error(3,argv[i]);}
+	    if(argv[i][l+2]||i>=argc-1)
+	      g_flags_val[j].p=&argv[i][l+2];
+	    else
+	      g_flags_val[j].p=&argv[++i][0];
+	  }
+	  if(g_flags[j]&VALFLAG){
+	    if(argv[i][l+1]!='='){error(4,argv[i]);}
+	    if(argv[i][l+2]||i>=argc-1)
+	      g_flags_val[j].l=atol(&argv[i][l+2]);
+	    else
+	      g_flags_val[j].l=atol(&argv[++i][0]);
+	  }
+	  if(g_flags[j]&FUNCFLAG) g_flags_val[j].f(&argv[i][l+1]);
+	}
+      }
+      if(!flag){error(5,argv[i]);}
+    }
+  }
+  if(!(c_flags[6]&USEDFLAG)){
+#ifdef SPECIAL_COPYRIGHT
+    printf("%s\n",SPECIAL_COPYRIGHT);
+#else
+    printf("%s\n",copyright);
+    printf("%s\n",cg_copyright);
+#endif
+  }
+  if(c_flags[4]&USEDFLAG) DEBUG=c_flags_val[4].l; else DEBUG=0;
+  if(c_flags[13]&USEDFLAG) ucpp_flags|=CPLUSPLUS_COMMENTS;
+  if(c_flags[14]&USEDFLAG) ucpp_flags|=CPLUSPLUS_COMMENTS;
+  if(c_flags[15]&USEDFLAG) ucpp_flags&=~HANDLE_TRIGRAPHS;
+  if(c_flags[52]&USEDFLAG) ucpp_flags&=~(WARN_STANDARD|WARN_ANNOYING);
+  if(c_flags[16]&USEDFLAG) no_inline_peephole=1;
+  if(c_flags[17]&USEDFLAG) final=1;
+  if(!(c_flags[8]&USEDFLAG)) c_flags_val[8].l=10; /* max. Fehlerzahl */
+  if(c_flags[22]&USEDFLAG) c_flags[7]|=USEDFLAG;   /*  iso=ansi */
+  if(c_flags[7]&USEDFLAG) error(209);
+  if(c_flags[0]&USEDFLAG) optflags=c_flags_val[0].l;
+  if(optflags&16384) cross_module=1;
+  if(c_flags[11]&USEDFLAG) maxoptpasses=c_flags_val[11].l;
+  if(c_flags[12]&USEDFLAG) inline_size=c_flags_val[12].l;
+  if(c_flags[21]&USEDFLAG) fp_assoc=1;
+  if(c_flags[25]&USEDFLAG) unroll_size=c_flags_val[25].l;
+  if(c_flags[23]&USEDFLAG) noaliasopt=1;
+  if(c_flags[27]&USEDFLAG) optspeed=1;
+  if(c_flags[28]&USEDFLAG) optsize=1;
+  if(c_flags[29]&USEDFLAG) unroll_all=1;
+  if(c_flags[30]&USEDFLAG) stack_check=1;  
+  if(c_flags[31]&USEDFLAG) inline_depth=c_flags_val[31].l;
+  if(c_flags[32]&USEDFLAG) debug_info=1;
+  if(c_flags[33]&USEDFLAG) c99=1;
+  if(c_flags[60]&USEDFLAG) c99=0;
+  if(c_flags[34]&USEDFLAG) {wpo=1;no_emit=1;}
+  if(c_flags[36]&USEDFLAG) {noitra=1;}
+  if(c_flags[37]&USEDFLAG) {
+		misracheck=1;
+		if ((misraversion==1998) && (c_flags_val[37].l == 2004)) error(328,c_flags_val[37].l,"-misra","");
+		if ((misraversion==2004) && (c_flags_val[37].l == 1998)) error(328,c_flags_val[37].l,"-misra","");
+		misraversion=c_flags_val[37].l;
+
+		if (!((misraversion==2004) || (misraversion==1998))) error(328,misraversion,"-misra","");
+		if (misraversion==1998) {
+			int misra_set_iterator;
+			for (misra_set_iterator = 0; misra_set_iterator < MISRA_98_RULE_NUMBER; misra_set_iterator++ ) {
+				if (misra_98_warn_flag[misra_set_iterator] != -1) misra_98_warn_flag[misra_set_iterator] = 1;
+			}
+		} else {
+			int m1, m2;
+			for (m1 = 0; m1 < MISRA_04_CHAPTER; m1++) {
+				for (m2 = 0; m2 < MISRA_04_MAX_RULE_IN_CHAPTER; m2++) {
+					if (misra_04_warn_flag[m1][m2] != -1) misra_04_warn_flag[m1][m2] = 1;
+				}
+			}
+		}
+	}
+  if(c_flags[38]&USEDFLAG) {coloring=c_flags_val[38].l;}
+  if(c_flags[39]&USEDFLAG) {dmalloc=1;}
+  if(c_flags[40]&USEDFLAG) {disable=c_flags_val[40].l;}
+  if(c_flags[41]&USEDFLAG) {softfloat=1;}
+  if(c_flags[45]&USEDFLAG) {ecpp=1;}
+  if(c_flags[46]&USEDFLAG) {short_push=1;}
+  if(c_flags[47]&USEDFLAG) {default_unsigned=1;}
+  if(c_flags[48]&USEDFLAG) {opencl=1;}
+  {
+    size_t hs=1000;
+    if(c_flags[53]&USEDFLAG) hs=c_flags_val[53].l;
+    if(hs!=0) hash_ext=new_hashtable(hs);
+  }
+
+
+  if(wpo){
+    cross_module=1;
+    optflags=-1;
+  }
+  if(optsize){
+    if(!(c_flags[25]&USEDFLAG)) unroll_size=0;
+    clist_copy_pointer=clist_copy_stack;
+  }
+
+  if(optspeed){
+    clist_copy_pointer=256;
+  }
+
+  if(ecpp&&c99){
+	  error(333, "c99", "ecpp");
+  }
+  if(c99){
+    ucpp_flags|=CPLUSPLUS_COMMENTS|MACRO_VAARG;
+    err_out[67].flags|=ANSIV;
+    err_out[67].flags&=~DONTWARN;
+    err_out[161].flags|=ANSIV;
+    err_out[161].flags&=~DONTWARN;
+    err_out[155].flags|=ANSIV;
+    err_out[155].flags&=~DONTWARN;
+    err_out[156].flags|=ANSIV;
+    err_out[156].flags&=~DONTWARN;
+  }
+  if(ecpp){
+#ifndef HAVE_ECPP
+	error(334, "EC++");
+#endif
+    ucpp_flags|=CPLUSPLUS_COMMENTS|MACRO_VAARG;
+  }
+  if(!cross_module&&files>1) error(1);
+  if(files<=0&&!(c_flags[35]&USEDFLAG)) error(6);
+  stackalign=l2zm(0L);
+  if(!init_cg()) exit(EXIT_FAILURE);
+
+  if(c_flags[55]&USEDFLAG) {clist_copy_stack=c_flags_val[55].l;}
+  if(c_flags[56]&USEDFLAG) {clist_copy_static=c_flags_val[56].l;}
+  if(c_flags[57]&USEDFLAG) {clist_copy_pointer=c_flags_val[57].l;}
+  if(c_flags[58]&USEDFLAG) {inline_memcpy_sz=c_flags_val[58].l;}
+  if(c_flags[61]&USEDFLAG) {force_statics=1;}
+  if(c_flags[62]&USEDFLAG) {prefer_statics=1;}
+  if(c_flags[63]&USEDFLAG) {range_opt=1;}
+  if(c_flags[64]&USEDFLAG) {merge_strings=1;}
+  if(c_flags[65]&USEDFLAG) {sec_per_obj=1;}
+  if(c_flags[66]&USEDFLAG) {no_eff_ics=1;}
+  if(c_flags[67]&USEDFLAG) {early_eff_ics=1;}
+  if(c_flags[68]&USEDFLAG) {mask_opt=1;}
+
+
+  if(!(optflags&2)){
+    for(i=1;i<=MAXR;i++){
+      sregsa[i]=regsa[i];
+      if(regsa[i]==REGSA_TEMPS) regsa[i]=0;
+    }
+  }
+  if(zmeqto(stackalign,l2zm(0L)))
+    stackalign=maxalign;
+  for(i=0;i<=MAX_TYPE;i++)
+    if(zmeqto(align[i],l2zm(0L)))
+      align[i]=l2zm(1L);
+  for(i=0;i<EMIT_BUF_DEPTH;i++)
+    emit_buffer[i]=mymalloc(EMIT_BUF_LEN);
+  emit_p=emit_buffer[0];
+  /*FIXME: multiple-ccs don't work */
+  if(c_flags[24]&USEDFLAG) multiple_ccs=0;
+  if(!(c_flags[5]&USEDFLAG)){
+    if(c_flags[1]&USEDFLAG){
+      out=open_out(c_flags_val[1].p,0);
+    }else{
+      if(wpo)
+	out=open_out(inname,"o");
+      else
+	out=open_out(inname,"asm");
+    }
+    if(!out){
+      exit(EXIT_FAILURE);
+    }
+  }
+  if(wpo){
+    wpo_key=MAGIC_WPO;
+    fprintf(out,"%cVBCC",0);
+  }
+  if(debug_info) init_db(out);
+  if(c_flags[2]&USEDFLAG) ic1=open_out(inname,"ic1");
+  if(c_flags[3]&USEDFLAG) ic2=open_out(inname,"ic2");
+  c99_compliant=0;
+  init_cpp();
+  if(c_flags[35]&USEDFLAG){
+    /* we have a command file */
+    cmdfile=fopen(c_flags_val[35].p,"r");
+    if(!cmdfile) error(7,c_flags_val[35].p);
+  }
+  for(i=1;cmdfile||i<argc;i++){
+    FILE *in;
+    int first_byte;
+    if(i<argc){
+      if(!fname[i]) continue;
+      inname=argv[i];
+    }else{
+      static char nbuf[1024];
+      if(!fgets(nbuf,1023,cmdfile)) break;
+      inname=nbuf;
+      while(isspace((unsigned char)*inname)) inname++;
+      if(*inname=='\"') inname++;
+      if(inname[strlen(inname)-1]=='\n') inname[strlen(inname)-1]=0;
+      if(inname[strlen(inname)-1]=='\"') inname[strlen(inname)-1]=0;
+      if(!*inname) break;
+    }
+    if(DEBUG&1) printf("starting translation-unit <%s>\n",inname);
+    in=fopen(inname,"r");
+    if(!in) {error(7,inname);}
+    misratok=0;
+    first_byte=fgetc(in);
+    if(first_byte==0){
+      input_wpo=in;
+      if(fgetc(in)!='V') error(300);
+      if(fgetc(in)!='B') error(300);
+      if(fgetc(in)!='C') error(300);
+      if(fgetc(in)!='C') error(300);
+      wpo_key=MAGIC_WPO;
+    }else{
+      ungetc(first_byte,in);
+      input_wpo=0;
+    }
+    if(c_flags[50]&USEDFLAG){
+      char *p;
+      depout=open_out(inname,"dep");
+      /* nicht super schoen (besser letzten Punkt statt ersten), aber kurz.. */
+      if(c_flags[59]&USEDFLAG){
+	fprintf(depout,"%s: %s",c_flags_val[59].p,inname);
+      }else{
+	for(p=inname;*p&&*p!='.';p++) fprintf(depout,"%c",*p);
+	fprintf(depout,".o: %s",inname);
+      }
+    }
+    if(c_flags[18]&USEDFLAG) ppout=open_out(inname,"i");
+    if(!input_wpo){
+      int mcmerk=misracheck;
+      misracheck=0;
+      init_tables(0);
+      init_include_path(0);
+      set_init_filename(inname,1);
+      init_lexer_state(&ls);
+      init_lexer_mode(&ls);
+      ls.flags=ucpp_flags;
+      ls.input=in;
+      for(j=1;j<argc;j++){
+	if(argv[j][0]=='-'&&argv[j][1]=='I')
+	  add_incpath(&argv[j][2]);
+	if(argv[j][0]=='-'&&argv[j][1]=='D')
+	  define_macro(&ls,&argv[j][2]);      
+      }
+      if(target_macros){
+	char **m=target_macros;
+	while(*m)
+	  define_macro(&ls,*m++);
+      }
+      define_macro(&ls,"__VBCC__");
+      define_macro(&ls,"__entry=__vattr(\"entry\")");
+      define_macro(&ls,"__str(x)=#x");
+      define_macro(&ls,"__asm(x)=do{static void inline_assembly()=x;inline_assembly();}while(0)");
+      define_macro(&ls,"__regsused(x)=__vattr(\"regused(\"x\")\")");
+      define_macro(&ls,"__varsused(x)=__vattr(\"varused(\"x\")\")");
+      define_macro(&ls,"__varsmodified(x)=__vattr(\"varchanged(\"x\")\")");
+      define_macro(&ls,"__noreturn=__vattr(\"noreturn()\")");
+      define_macro(&ls,"__alwaysreturn=__vattr(\"alwaysreturn()\")");
+      define_macro(&ls,"__nosidefx=__vattr(\"nosidefx()\")");
+      define_macro(&ls,"__stack(x)=__vattr(__str(stack1(x)))");
+      define_macro(&ls,"__stack2(x)=__vattr(__str(stack2(x)))");
+      define_macro(&ls,"__noinline=__vattr(\"noinline()\")");
+      if(c99)
+	define_macro(&ls,"__STDC_VERSION__=199901L");
+      if(optspeed)
+	define_macro(&ls,"__OPTSPEED__");
+      if(optsize)
+	define_macro(&ls,"__OPTSIZE__");
+      misracheck=mcmerk;
+      enter_file(&ls,ls.flags);
+    }
+    filename=current_filename;
+    switch_count=0;break_label=0;
+    line=0;eof=0;
+    next_token();
+    killsp();
+    nesting=-1;enter_block();
+    translation_unit();
+    fclose(in); /*FIXME: do I have to close??*/   
+    if((c_flags[18]&USEDFLAG)&&ppout) fclose(ppout);
+    if((c_flags[50]&USEDFLAG)&&depout){fprintf(depout,"\n");fclose(depout);}
+    if(!input_wpo)
+      free_lexer_state(&ls);
+  }
+  if(wpo)
+    raus();
+  if(!cross_module){
+    ierror(0);
+  }else{
+    tunit *t;
+    Var *v,*sf;
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(DEBUG&1) printf("first optimizing\n");
+    for(v=first_ext;v;v=v->next){
+      if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED)&&(!v->vattr||!strstr(v->vattr,"taskprio("))){
+	do_function(v);
+      }      
+    }
+    for(t=first_tunit;t;t=t->next){
+      for(v=t->statics;v;v=v->next){
+	if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED)){
+	  do_function(v);
+	}
+      }
+    }
+    if(DEBUG&1) printf("determining used objects\n");
+    for(v=first_ext;v;v=v->next){
+      if((v->flags&(DEFINED|TENTATIVE))&&(v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC){
+	if(!final||!strcmp(v->identifier,"main")||(v->vattr&&strstr(v->vattr,"entry"))){
+#ifndef NO_OPTIMIZER
+	  used_objects(v);
+#endif
+	  if(ISFUNC(v->vtyp->flags)) do_function(v);
+	}
+      }
+    }
+    if(!(c_flags[5]&USEDFLAG)){
+      if(DEBUG&1) printf("generating external functions:\n");
+      for(v=first_ext;v;v=v->next){
+	if(ISFUNC(v->vtyp->flags)&&(v->flags&(REFERENCED|DEFINED))==(REFERENCED|DEFINED)){
+	  gen_function(out,v,1);
+	}
+      }
+      if(DEBUG&1024) printf("generating static functions\n");
+      i=0;
+      for(t=first_tunit;t;t=t->next){
+	if(DEBUG&1) printf("translation-unit %d:\n",++i);
+	if(DEBUG&1) printf("generating statics:\n");
+	for(v=t->statics;v;v=v->next){
+	  if(DEBUG&1) printf(" %s\n",v->identifier);
+	  if(ISFUNC(v->vtyp->flags)&&(v->flags&(REFERENCED|DEFINED))==(REFERENCED|DEFINED)){
+	    gen_function(out,v,1);
+	  }
+	}
+      }
+      
+      if(DEBUG&1) printf("generating vars:\n");
+      gen_vars(first_ext);
+      for(t=first_tunit;t;t=t->next)
+	gen_vars(t->statics);
+      for(v=first_ext;v;v=v->next){
+	if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED))
+	  gen_vars(v->fi->vars);
+      }
+      for(t=first_tunit;t;t=t->next){
+	for(v=t->statics;v;v=v->next){
+	  if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED))
+	    gen_vars(v->fi->vars);
+	}
+      }
+    }
+  }
+  raus();
+}
+int mcmp(const char *s1,const char *s2)
+/*  Einfachere strcmp-Variante.     */
+{
+  char c;
+  do{
+    c=*s1++;
+    if(c!=*s2++) return(1);
+  }while(c);
+  return 0;
+}
+int is_keyword(char *p)
+{
+  char *n=p+1;
+  switch(*p){
+  case 'a':
+    if(!mcmp(n,"uto")) return 1;
+    return 0;
+  case 'b': 
+    if(ecpp&&!mcmp(n,"ool")) return 1;
+    if(!mcmp(n,"reak")) return 1;
+    return 0;
+  case 'c': 
+    if(!mcmp(n,"ase")) return 1;
+    if(ecpp&&!mcmp(n,"atch")) return 1;
+    if(!mcmp(n,"har")) return 1;
+    if(ecpp&&!mcmp(n,"lass")) return 1;
+    if(!mcmp(n,"onst")) return 1;
+    if(ecpp&&!mcmp(n,"ons_cast")) return 1;
+    if(!mcmp(n,"ontinue")) return 1;
+    return 0;
+  case 'd': 
+    if(!mcmp(n,"efault")) return 1;
+    if(ecpp&&!mcmp(n,"elete")) return 1;
+    if(!mcmp(n,"o")) return 1;
+    if(!mcmp(n,"ouble")) return 1;
+    if(ecpp&&!mcmp(n,"ynamic_cast")) return 1;
+    return 0;
+  case 'e': 
+    if(!mcmp(n,"lse")) return 1;
+    if(!mcmp(n,"num")) return 1;
+    if(ecpp&&!mcmp(n,"xplicit")) return 1;
+    if(ecpp&&!mcmp(n,"xport")) return 1;
+    if(!mcmp(n,"xtern")) return 1;
+    return 0;
+  case 'f': 
+    if(ecpp&&!mcmp(n,"alse")) return 1;
+    if(!mcmp(n,"loat")) return 1;
+    if(!mcmp(n,"or")) return 1;
+    if(ecpp&&!mcmp(n,"riend")) return 1;
+    return 0;
+  case 'g': 
+    if(!mcmp(n,"oto")) return 1;
+    return 0;
+  case 'i':
+    if(!mcmp(n,"f")) return 1;
+    if(c99&&!mcmp(n,"nline")) return 1;
+    if(!mcmp(n,"nt")) return 1;
+    return 0;
+  case 'l':
+    if(!mcmp(n,"ong")) return 1;
+    return 0;
+  case 'm': 
+    if(ecpp&&!mcmp(n,"utable")) return 1;
+    return 0;
+  case 'n': 
+    if(ecpp&&!mcmp(n,"amespace")) return 1;
+    if(ecpp&&!mcmp(n,"ew")) return 1;
+    return 0;
+  case 'o': 
+    if(ecpp&&!mcmp(n,"perator")) return 1;
+    return 0;
+  case 'p': 
+    if(ecpp&&!mcmp(n,"rivate")) return 1;
+    if(ecpp&&!mcmp(n,"rotected")) return 1;
+    if(ecpp&&!mcmp(n,"ublic")) return 1;
+    return 0;
+  case 'r': 
+    if(!mcmp(n,"egister")) return 1;
+    if(ecpp&&!mcmp(n,"einterpret_cast")) return 1;
+    if(c99&&!mcmp(n,"estrict")) return 1;
+    if(!mcmp(n,"eturn")) return 1;
+    return 0;
+  case 's':
+    if(!mcmp(n,"hort")) return 1;
+    if(!mcmp(n,"igned")) return 1;
+    if(!mcmp(n,"izeof")) return 1;
+    if(!mcmp(n,"tatic")) return 1;
+    if(ecpp&&!mcmp(n,"tatic_cast")) return 1;
+    if(!mcmp(n,"truct")) return 1;
+    if(!mcmp(n,"witch")) return 1;
+    return 0;
+  case 't':
+    if(ecpp&&!mcmp(n,"emplate")) return 1;
+   /* if(ecpp&&!mcmp(n,"his")) return 1;*/
+    if(ecpp&&!mcmp(n,"hrow")) return 1;
+    if(ecpp&&!mcmp(n,"rue")) return 1;
+    if(ecpp&&!mcmp(n,"ry")) return 1;
+    if(!mcmp(n,"ypedef")) return 1;
+    if(ecpp&&!mcmp(n,"ypeid")) return 1;
+    if(ecpp&&!mcmp(n,"ypename")) return 1;
+    return 0;
+  case 'u': 
+    if(!mcmp(n,"nion")) return 1;
+    if(!mcmp(n,"nsigned")) return 1;
+    if(ecpp&&!mcmp(n,"sing")) return 1;
+    return 0;
+  case 'v': 
+    if(ecpp&&!mcmp(n,"irtual")) return 1;
+    if(!mcmp(n,"oid")) return 1;
+    if(!mcmp(n,"olatile")) return 1;
+    return 0;
+  case 'w':
+    if(ecpp&&!mcmp(n,"char_t")) return 1;
+    if(!mcmp(n,"hile")) return 1;
+    return 0;
+  case '_': 
+    if(c99&&!mcmp(n,"Bool")) return 1;
+    if(c99&&!mcmp(n,"Complex")) return 1;
+    if(c99&&!mcmp(n,"Imaginary")) return 1;
+  default:
+    return 0;
+  }
+}
+void cpbez(char *m,int check_keyword)
+/*  Kopiert den naechsten Bezeichner von s nach m. Wenn check_keyord!=0 */
+/*  wird eine Fehlermeldung ausgegeben, falls das Ergebnis ein          */
+/*  reserviertes Keyword von C ist.                                     */
+{
+  if(ctok->type!=NAME){
+    *m=0;
+    return;
+  }
+  if(strlen(ctok->name)>=MAXI){
+    error(206,MAXI-1);
+    strncpy(m,ctok->name,MAXI-1);
+    m[MAXI-1]=0;
+  }else{
+    strcpy(m,ctok->name);
+  }
+  if(check_keyword&&is_keyword(m))
+    error(216,m);
+}
+void cpnum(char *m)
+/* kopiert die naechste int-Zahl von s nach m   */
+/* muss noch erheblich erweiter werden          */
+{
+  if(ctok->type!=NUMBER){
+    *m=0;
+    return;
+  }
+  strcpy(m,ctok->name);
+}
+void copy_token(token *d,token *s)
+{
+  size_t l;
+  *d=*s;
+  if(S_TOKEN(s->type)){
+    l=strlen(s->name)+1;
+    d->name=mymalloc(l);
+    memcpy(d->name,s->name,l);
+  }else
+    d->name=0;
+}
+static token back_token;
+static int have_back_token;
+void push_token(token *t)
+{
+  static char back_name[MAXI+1];
+  if(have_back_token) ierror(0);
+  back_token=*t;
+  if(S_TOKEN(t->type)){
+    strcpy(back_name,t->name);
+    back_token.name=back_name;
+  }else
+    back_token.name=0;
+  have_back_token=1;
+  ctok=&back_token;
+}
+void next_token(void)
+{
+  if(eof){
+    if(!endok)
+      raus();
+    else
+      return;
+  }
+  if(input_wpo){
+    int c;
+    static token wpo_tok;
+    static size_t sz;
+    char *p;size_t cs;
+  
+    if(have_back_token){
+      have_back_token=0;
+      ctok=&wpo_tok;
+      return;
+    }
+    ctok=&wpo_tok;
+    c=fgetc(input_wpo);
+    if(c==EOF){
+      eof=1;
+      return;
+    }else
+      c^=wpo_key++;
+    wpo_tok.type=(unsigned char)c;
+    /*printf("wpoget: %d (%s)\n",ctok->type,operators_name[ctok->type]);*/
+    if(S_TOKEN(wpo_tok.type)){
+      p=wpo_tok.name;
+      cs=0;
+      do{
+	if(cs>=sz){
+	  sz+=1000;
+	  wpo_tok.name=myrealloc(wpo_tok.name,sz);
+	  p=wpo_tok.name+cs;
+	}
+	c=fgetc(input_wpo);
+	if(c!=EOF){
+	  c^=wpo_key++;
+	  *p++=c;
+	  cs++;
+	}else
+	  eof=1;
+      }while(((unsigned char)c)!=0&&c!=EOF);
+      *p=0;
+      /*printf("name=%s\n",ctok->name);*/
+    }
+    return;
+  }
+  if(have_back_token){
+    have_back_token=0;
+    if(S_TOKEN(ctok->type)&&!ctok->name)
+      ierror(0);
+  }else{
+    static int last_line=1,last_token=NONE;
+    static char *last_fname;static size_t last_size;
+    eof=lex(&ls);
+    if(ctok&&S_TOKEN(ls.ctok->type)&&!ls.ctok->name)
+      ierror(0);
+    if(wpo){
+      fprintf(out,"%c",ls.ctok->type^wpo_key++);
+      if(S_TOKEN(ls.ctok->type)){
+	char *p=ls.ctok->name;
+	while(*p){
+	  fprintf(out,"%c",*p^wpo_key++);
+	  p++;
+	}
+	fprintf(out,"%c",0^wpo_key++);
+      }
+    }
+    if((c_flags[18]&USEDFLAG)&&ppout&&!input_wpo){
+      if(!last_fname){
+	last_fname=mymalloc(1);
+	*last_fname=0;
+      }
+      if(strcmp(last_fname,current_filename)){
+	fprintf(ppout,"\n#line %d \"%s\"\n",(int)ls.ctok->line,current_filename);
+	last_line=ls.ctok->line;
+	if(strlen(current_filename)>=last_size)
+	  last_fname=myrealloc(last_fname,strlen(current_filename)+1);
+	strcpy(last_fname,current_filename);
+      }else{
+	for(;last_line<ls.ctok->line;last_line++)
+	  fprintf(ppout,"\n");
+      }
+      if(S_TOKEN(ls.ctok->type)){
+	if(ls.ctok->type==PRAGMA)
+	  fprintf(ppout,"#pragma");
+	fprintf(ppout," %s",ls.ctok->name);
+      }else
+	fprintf(ppout," %s",operators_name[ls.ctok->type]);
+      last_token=ls.ctok->type;
+    }
+  }
+  ctok=ls.ctok;
+  line=ctok->line;
+  if(misracheck&&ctok->type!=PRAGMA&&ctok->type!=NONE&&ctok->type!=NEWLINE&&ctok->type!=COMMENT)
+    misratok=1;
+  /*FIXME: do not store multiple */
+  if(filename!=current_filename&&strcmp(filename,current_filename)){
+    filename=mymalloc(strlen(current_filename)+1);
+    strcpy(filename,current_filename);
+  }
+  /*filename=current_filename;*/
+  if(DEBUG&2) printf("current token (type %d): %s\n",(int)ctok->type,ucpp_token_name(ctok));
+}
+char *pragma_cpbez(char *buff,char *s);
+/* calculate fi entries (regs_modifed,uses,changes,flags etc.) from
+   attributes */
+void fi_from_attr(Var *v)
+{
+  char *attr;
+  attr=v->vattr;
+  if(!attr) return;
+  while(attr=strstr(attr,"readmem(")){
+    int f;
+    attr+=8;
+    if(sscanf(attr,"%d",&f)!=1) ierror(0);
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_USES;
+    v->fi->use_cnt++;
+    v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+    v->fi->use_list[v->fi->use_cnt-1].v=0;
+    v->fi->use_list[v->fi->use_cnt-1].flags=f;
+  }
+  attr=v->vattr;
+  while(attr=strstr(attr,"writemem(")){
+    int f;
+    attr+=9;
+    if(sscanf(attr,"%d",&f)!=1) ierror(0);
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_MODS;
+    v->fi->change_cnt++;
+    v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+    v->fi->change_list[v->fi->change_cnt-1].v=0;
+    v->fi->change_list[v->fi->change_cnt-1].flags=f;
+  }
+  attr=v->vattr;
+  while(attr=strstr(attr,"varused(")){
+    Var *n;
+    attr+=8;
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_USES;
+    while(1){
+      while(isspace((unsigned char)*attr)) attr++;
+      if(*attr==')') break;
+      attr=pragma_cpbez(buff,attr);
+      if(buff[0]==0){
+	error(76);
+	break;
+      }
+      n=find_ext_var(buff);
+      if(!n){
+	error(82,buff);
+	break;
+      }
+      v->fi->use_cnt++;
+      v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+      v->fi->use_list[v->fi->use_cnt-1].v=n;
+      v->fi->use_list[v->fi->use_cnt-1].flags=n->vtyp->flags;
+      while(isspace((unsigned char)*attr)) attr++;
+      if(*attr==','||*attr=='/') attr++;
+    }
+  }
+  attr=v->vattr;
+  while(attr=strstr(attr,"varchanged(")){
+    Var *n;
+    attr+=11;
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_MODS;
+    while(1){
+      while(isspace((unsigned char)*attr)) attr++;
+      if(*attr==')') break;
+      attr=pragma_cpbez(buff,attr);
+      if(buff[0]==0){
+	error(76);
+	break;
+      }
+      n=find_ext_var(buff);
+      if(!n){
+	error(82,buff);
+	break;
+      }
+      v->fi->change_cnt++;
+      v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+      v->fi->change_list[v->fi->change_cnt-1].v=n;
+      v->fi->change_list[v->fi->change_cnt-1].flags=n->vtyp->flags;
+      while(isspace((unsigned char)*attr)) attr++;
+      if(*attr==','||*attr=='/') attr++;
+    }
+  }
+  attr=v->vattr;
+  while(attr=strstr(attr,"regused(")){
+    int r,i;
+    static char rname[MAXI];
+    attr+=8;
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_REGS;
+    while(1){
+      while(isspace((unsigned char)*attr)) attr++;
+      for(i=0;i<MAXI-1&&*attr&&!isspace((unsigned char)*attr)&&*attr!=','&&*attr!=')'&&*attr!='/';i++)
+	rname[i]=*attr++;
+      rname[i]=0;
+      for(r=1;r<=MAXR;r++){
+	if(!reg_pair(r,&rp)&&!strcmp(rname,regnames[r])){
+	  BSET(v->fi->regs_modified,r);
+	  while(isspace((unsigned char)*attr)) attr++;
+	  if(*attr==','||*attr=='/') attr++;
+	  break;
+	}
+      }
+      if(r>MAXR){
+	if(rname[0]) error(220,rname);
+	break;
+      }
+    }
+  }
+  attr=v->vattr;
+  while(attr=strstr(attr,"stack1(")){
+    unsigned long sz;
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    attr+=7;
+    if(sscanf(attr,"%lu",&sz)!=1) ierror(0); /*FIXME*/
+    v->fi->stack1=ul2zum(sz);
+  }
+  attr=v->vattr;
+  while(attr=strstr(attr,"stack2(")){
+    unsigned long sz;
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALL_STACK;
+    attr+=7;
+    if(sscanf(attr,"%lu",&sz)!=1) ierror(0); /*FIXME*/
+    v->fi->stack2=ul2zum(sz);
+  }  
+  if(strstr(v->vattr,"noreturn()")){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=NEVER_RETURNS;
+  }
+  if(strstr(v->vattr,"alwaysreturn()")){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=ALWAYS_RETURNS;
+  }  
+  if(strstr(v->vattr,"nosidefx()")){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=NOSIDEFX;
+  }
+  if(strstr(v->vattr,"noinline()")){
+    if(!v->fi) v->fi=new_fi();
+    v->fi->flags|=NO_INLINE;
+  }
+}
+#define pragma_killsp() while(isspace((unsigned char)*s)) s++;
+char *pragma_cpbez(char *buff,char *s)
+{
+  int cnt=0;
+  if(*s=='_'||isalpha((unsigned char)*s)){
+    *buff++=*s++;
+    cnt++;
+    while(cnt<MAXI-1&&(*s=='_'||isalnum((unsigned char)*s))){
+      *buff++=*s++;
+      cnt++;
+    }
+  }
+  *buff++=0;
+  return s;
+}
+#define WARNSTACKSIZE 128
+static int widx,warn_num[WARNSTACKSIZE],warn_flags[WARNSTACKSIZE];
+#define PACKSTACKSIZE 128
+static int pidx,pack[PACKSTACKSIZE];
+void do_pragma(char *s)
+{
+  error(163);
+  pragma_killsp();
+  if(!strncmp("opt",s,3)){
+    s+=3;pragma_killsp();
+    c_flags_val[0].l=optflags=atol(s);
+    if(DEBUG&1) printf("#pragma opt %ld\n",c_flags_val[0].l);
+  }else if(!strncmp("dontwarn",s,8)){
+    int i;
+    s+=8;pragma_killsp();
+    if(widx>=WARNSTACKSIZE) ierror(0);
+    if(sscanf(s,"%d",&i)==1){
+      if(i>=err_num) error(159,i);
+      warn_num[widx]=i;
+      warn_flags[widx]=err_out[i].flags;
+      widx++;
+      err_out[i].flags|=DONTWARN;
+    }
+  }else if(!strncmp("warn",s,4)){
+    int i;
+    s+=4;pragma_killsp();
+    if(widx>=WARNSTACKSIZE) ierror(0);
+    if(sscanf(s,"%d",&i)==1){
+      if(i>=err_num) error(159,i);
+      warn_num[widx]=i;
+      warn_flags[widx]=err_out[i].flags;
+      widx++;
+      err_out[i].flags&=~DONTWARN;
+    }
+  }else if(!strncmp("popwarn",s,7)){
+    if(widx<=0) error(303);
+    widx--;
+    err_out[warn_num[widx]].flags=warn_flags[widx];
+  }else if(!strncmp("begin_header",s,12)){
+    header_cnt++;
+  }else if(!strncmp("end_header",s,10)){
+    header_cnt--;
+  }else if(!strncmp("pfi",s,3)){
+    Var *v;
+    s+=3;pragma_killsp();
+    pragma_cpbez(buff,s);
+    if(DEBUG&1) printf("print function_info %s\n",buff);
+    v=find_var(buff,0);
+    if(v&&v->fi) print_fi(stdout,v->fi);
+  }else if(!strncmp("finfo",s,5)){
+    Var *v;
+    s+=5;pragma_killsp();
+    pragma_cpbez(buff,s);
+    if(DEBUG&1) printf("new function_info %s\n",buff);
+    v=find_var(buff,0);
+    if(v){
+      if(!v->fi) v->fi=new_fi();
+      current_fi=v->fi;
+    }
+  }else if(!strncmp("fi_flags",s,8)){
+    unsigned long flags;
+    s+=8;pragma_killsp();
+    sscanf(s,"%lu",&flags);
+    if(DEBUG&1) printf("fi_flags %lu\n",flags);
+    if(current_fi) current_fi->flags=flags;
+  }else if(!strncmp("fi_uses",s,7)){
+    int t;Var *v;
+    s+=7;pragma_killsp();
+    s=pragma_cpbez(buff,s);
+    t=nesting;nesting=0;
+    v=find_var(buff,0);
+    nesting=t;
+    sscanf(s,"%d",&t);
+    if(DEBUG&1) printf("new fi_use %s,%d\n",buff,t);
+    if(current_fi){
+      current_fi->use_cnt++;
+      current_fi->use_list=myrealloc(current_fi->use_list,current_fi->use_cnt*sizeof(varlist));
+      current_fi->use_list[current_fi->use_cnt-1].v=v;
+      current_fi->use_list[current_fi->use_cnt-1].flags=t;
+    }
+  }else if(!strncmp("fi_changes",s,10)){
+    int t;Var *v;
+    s+=10;pragma_killsp();
+    s=pragma_cpbez(buff,s);
+    t=nesting;nesting=0;
+    v=find_var(buff,0);
+    nesting=t;
+    sscanf(s,"%d",&t);
+    if(DEBUG&1) printf("new fi_change %s,%d\n",buff,t);
+    if(current_fi){
+      current_fi->change_cnt++;
+      current_fi->change_list=myrealloc(current_fi->change_list,current_fi->change_cnt*sizeof(varlist));
+      current_fi->change_list[current_fi->change_cnt-1].v=v;
+      current_fi->change_list[current_fi->change_cnt-1].flags=t;
+    }
+  }else if(!strncmp("fi_calls",s,8)){
+    int t;Var *v;
+    s+=8;pragma_killsp();
+    s=pragma_cpbez(buff,s);
+    t=nesting;nesting=0;
+    v=find_var(buff,0);
+    nesting=t;
+    sscanf(s,"%d",&t);
+    if(DEBUG&1) printf("new fi_call %s,%d\n",buff,t);
+    if(current_fi){
+      current_fi->call_cnt++;
+      current_fi->call_list=myrealloc(current_fi->call_list,current_fi->call_cnt*sizeof(varlist));
+      current_fi->call_list[current_fi->call_cnt-1].v=v;
+      current_fi->call_list[current_fi->call_cnt-1].flags=t;
+    }
+  }else if(!strncmp("fi_regs",s,7)){
+    int r;
+    s+=7;pragma_killsp();
+    pragma_cpbez(buff,s);
+    for(r=1;r<=MAXR;r++)
+      if(!strcmp(buff,regnames[r])) break;
+    if(r<=MAXR&&current_fi)
+      BSET(current_fi->regs_modified,r);
+  }else if(!strncmp("printflike",s,10)){
+    Var *v;
+    s+=10;pragma_killsp();
+    pragma_cpbez(buff,s);
+    if(DEBUG&1) printf("printflike %s\n",buff);
+    v=find_var(buff,0);
+    if(v){
+      v->flags|=PRINTFLIKE;
+      if(DEBUG&1) printf("succeeded\n");
+    }
+  }else if(!strncmp("scanflike",s,9)){
+    Var *v;
+    s+=9;pragma_killsp();
+    pragma_cpbez(buff,s);
+    if(DEBUG&1) printf("scanflike %s\n",buff);
+    v=find_var(buff,0);
+    if(v){
+      v->flags|=SCANFLIKE;
+      if(DEBUG&1) printf("succeeded\n");
+    }
+  }else if(!strncmp("only-inline",s,11)){
+    s+=11;pragma_killsp();
+    if(!strncmp("on",s,2)){
+      if(DEBUG&1) printf("only-inline on\n");
+      only_inline=1;
+    }else{
+      if(DEBUG&1) printf("only-inline off\n");
+      only_inline=2;
+    }
+  }else if(!strncmp("pack",s,4)){
+    /* packing of structures */
+    s+=4;pragma_killsp();
+    if(*s=='(') { s++;pragma_killsp();}
+    if(!strncmp("push",s,4)){
+      if(pidx==PACKSTACKSIZE){
+        memmove(pack,pack+1,(PACKSTACKSIZE-1)*sizeof(pack[0]));
+        pidx--;
+      }
+      pack[pidx++]=pack_align;
+      s+=4;pragma_killsp();
+      if(*s==','){
+        s++;pragma_killsp();
+        sscanf(s,"%i",&pack_align);
+      }
+    }else if(!strncmp("pop",s,3)){
+      if(pidx>0) pack_align=pack[--pidx];
+      else pack_align=0;
+    }else if(*s==')')
+      pack_align=0;
+    else
+      sscanf(s,"%i",&pack_align);
+#if 0
+  }else if(!strncmp("type",s,4)){
+    /*  Typ eines Ausdrucks im Klartext ausgeben    */
+    np tree;
+    s+=4;strcat(s,";");
+    tree=expression();
+    if(tree&&type_expression(tree)){
+      printf("type of %s is:\n",string+7);
+      prd(stdout,tree->ntyp);printf("\n");
+    }
+    if(tree) free_expression(tree);
+  }else if(!strncmp("tree",s,4)){
+    /*  gibt eine expression aus    */
+    np tree;
+    s+=4;strcat(s,";");
+    tree=expression();
+    if(tree&&type_expression(tree)){
+      printf("tree of %s is:\n",string+7);
+      pre(stdout,tree);printf("\n");
+    }
+    if(tree) free_expression(tree);
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  }else{
+#ifdef HAVE_TARGET_PRAGMAS
+    handle_pragma(s);
+#endif
+  }
+}
+void killsp(void)
+/*  Ueberspringt Fuellzeichen                   */
+/*  noch einige unschoene Dinge drin            */
+{
+  /*FIXME: #pragma etc. */
+  while(!eof&&(ttWHI(ctok->type)||ctok->type==PRAGMA||(!input_wpo&&!ls.condcomp))){
+    if(ctok->type==PRAGMA)
+      do_pragma(ctok->name);
+    next_token();
+  }
+}
+void enter_block(void)
+/*  Setzt Zeiger/Struckturen bei Eintritt in neuen Block    */
+{
+    if(nesting>=MAXN){error(9,nesting);return;}
+    nesting++;
+    if(DEBUG&1) printf("enter block %d\n",nesting);
+    first_ilist[nesting]=last_ilist[nesting]=0;
+    first_sd[nesting]=last_sd[nesting]=0;
+    first_si[nesting]=last_si[nesting]=0;
+    first_var[nesting]=last_var[nesting]=0;
+    if(nesting==1){
+        first_llist=last_llist=0;
+        first_clist=last_clist=0;
+        merk_varf=merk_varl=0;
+        merk_ilistf=merk_ilistl=0;
+        merk_sif=merk_sil=0;
+/*  struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden,     */
+/*  dass struct-declarations in Prototypen frei werden und dann eine        */
+/*  spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird.      */
+/*  Nicht sehr schoen - wenn moeglich noch mal aendern.                     */
+/*        merk_sdf=merk_sdl=0;*/
+        afterlabel=0;
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+}
+void leave_block(void)
+/*  Setzt Zeiger/Struckturen bei Verlassen eines Blocks     */
+{
+  static int inleave;
+  int i;
+  if(inleave) return;
+  inleave=1;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+  for(i=1;i<=MAXR;i++)
+    if(regbnesting[i]==nesting) regsbuf[i]=0;
+  if(nesting<0){error(10);inleave=0;return;}
+  if(DEBUG&1) printf("leave block %d vla=%p\n",nesting,(void *)block_vla[nesting]);
+  if(block_vla[nesting]) clearvl();
+  if(nesting>0){
+    if(merk_varl) merk_varl->next=first_var[nesting]; else merk_varf=first_var[nesting];
+    if(last_var[nesting]) merk_varl=last_var[nesting];
+    if(merk_sil) merk_sil->next=first_si[nesting]; else merk_sif=first_si[nesting];
+    if(last_si[nesting]) merk_sil=last_si[nesting];
+    if(merk_sdl) merk_sdl->next=first_sd[nesting]; else merk_sdf=first_sd[nesting];
+    if(last_sd[nesting]) merk_sdl=last_sd[nesting];
+    if(merk_ilistl) merk_ilistl->next=first_ilist[nesting]; else merk_ilistf=first_ilist[nesting];
+    if(last_ilist[nesting]) merk_ilistl=last_ilist[nesting];
+  }
+  if(nesting==1){
+    if(cross_module){
+      /* anything to do? */
+    }else{
+      if(merk_varf) gen_vars(merk_varf);
+      if(first_llist) free_llist(first_llist);
+      first_llist=0;
+      if(first_clist) free_clist(first_clist);
+      first_clist=0;
+      if(merk_varf) free_var(merk_varf);
+      merk_varf=0;
+      if(merk_sif) free_si(merk_sif);
+      merk_sif=0;
+      /*  struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden,     */
+      /*  dass struct-declarations in Prototypen frei werden und dann eine        */
+      /*  spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird.      */
+      /*  Nicht sehr schoen - wenn moeglich noch mal aendern.                     */
+      /*        if(merk_sdf) free_sd(merk_sdf);*/
+      if(merk_ilistf) free_ilist(merk_ilistf);
+      merk_ilistf=0;
+    }
+  }
+  if(nesting==0){
+    if(/*ecpp||*/cross_module){
+      /* don't free struct_declarations in EC++ for now, since they can be */
+      /* referenced even when they are not in scope */
+      /* anything to do? */
+    }else{
+      /*  struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden,     */
+      /*  dass struct-declarations in Prototypen frei werden und dann eine        */
+      /*  spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird.      */
+      /*  Nicht sehr schoen - wenn moeglich noch mal aendern.                     */
+      if(first_si[0]) free_si(first_si[0]);
+      if(first_ext)
+	gen_vars(first_ext);
+      if(first_var[0])
+	gen_vars(first_var[0]);
+      if(first_ext)
+	free_var(first_ext);
+      if(first_var[0])
+	free_var(first_var[0]);
+      if(merk_sdf) free_sd(merk_sdf);
+      if(first_sd[0]) free_sd(first_sd[0]);
+      if(first_ilist[0]) free_ilist(first_ilist[0]);
+    }
+  }
+  nesting--;
+  inleave=0;
+}
+void pra(FILE *f,argument_list *p)
+/*  Gibt argument_list umgekehrt auf Bildschirm aus             */
+{
+    if(p->next){ pra(f,p->next);fprintf(f,",");}
+    if(p->arg) pre(f,p->arg);
+}
+void pre(FILE *f,np p)
+/*  Gibt expression auf Bildschirm aus                          */
+{
+    int c;
+    c=p->flags;
+    if(p->sidefx) fprintf(f,"/");
+    if(p->lvalue) fprintf(f,"|");
+    if(c==CALL){fprintf(f,"call-function(");pre(f,p->left);fprintf(f,")(");
+                if(p->alist) pra(f,p->alist);
+                fprintf(f,")");return;}
+    if(c==CAST){fprintf(f,"cast(");pre(f,p->left);
+                fprintf(f,"->");prd(f,p->ntyp);
+                fprintf(f,")");return;}
+    if(c==MEMBER){if(p->identifier) fprintf(f,".%s",p->identifier);return;}
+    if(c==IDENTIFIER){if(p->identifier) fprintf(f,"%s",p->identifier);
+        fprintf(f,"+");printval(f,&p->val,LONG); return;}
+    fprintf(f,"%s(",ename[c]);
+    if(p->left) pre(f,p->left);
+    if(p->right){
+        fprintf(f,",");
+        pre(f,p->right);
+    }
+    fprintf(f,")");
+    if(c==CEXPR||c==PCEXPR){fprintf(f,"(value="); printval(f,&p->val,p->ntyp->flags); fprintf(f,")");}
+}
+static int pp_line;
+void do_error(int errn,va_list vl)
+/*  Behandelt Ausgaben wie Fehler und Meldungen */
+{
+  int type,have_stack=0;
+    int treat_warning_as_error=0;
+    char *errstr="",*txt=filename;
+    if(c_flags_val[8].l&&c_flags_val[8].l<=errors)
+      return;
+    if(errn==-1) errn=158;
+    type=err_out[errn].flags;
+    treat_warning_as_error=(type&WARNING)&&(c_flags[54]&USEDFLAG);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    if(type&DONTWARN) return;
+    if(type&WARNING) errstr="warning";
+    if(type&ERROR) errstr="error";
+    if(input_wpo){
+      fprintf(stderr,"%s %d: ",errstr,errn);
+    }else if((type&NOLINE)/*||((type&PREPROC)&&pp_line<=0)*/){
+      fprintf(stderr,"%s %d: ",errstr,errn);
+    }else if(type&(INFUNC|INIC)){
+      if((type&INIC)&&err_ic&&err_ic->line){
+	fprintf(stderr,"%s %d in line %d of \"%s\": ",errstr,errn,err_ic->line,err_ic->file);
+
+
+      }else{
+	fprintf(stderr,"%s %d in function \"%s\": ",errstr,errn,cur_func);
+      }
+    }else if(!input_wpo){
+      int n;
+      if(eof){
+	fprintf(stderr,">EOF\n");
+      }else{
+	if(ls.cli!=0) ls.copy_line[ls.cli]=0;
+	fprintf(stderr,">%s\n",ls.copy_line);
+      }
+      if(type&PREPROC){
+	      txt=current_filename;
+	      n=pp_line;
+      }else{
+	if(ctok)
+	  n=ctok->line;
+	else
+	  n=-1;
+      }
+      if(c_flags[20]&USEDFLAG){   /*  strip-path from filename */
+	char *p=txt,c;
+	while(c=*p++)
+	  if(c==':'||c=='/'||c=='\\') txt=p;
+      }
+      fprintf(stderr,"%s %d in line %d of \"%s\": ",errstr,errn,n,txt);
+      have_stack=1; /* we can report the include stack */
+    }
+    vfprintf(stderr,err_out[errn].text,vl);
+    fprintf(stderr,"\n");
+    if(have_stack&&(!(c_flags[49]&USEDFLAG))){
+      int i;
+      stack_context *sc = report_context();
+      for(i=0;;i++){
+	if(sc[i].line==-1) break;
+	fprintf(stderr,"\tincluded from file \"%s\":%ld\n",sc[i].long_name?sc[i].long_name:sc[i].name,sc[i].line);
+      }
+    }
+    if(treat_warning_as_error){fprintf(stderr,"warning %d treated as error [-warnings-as-errors]\n",errn);}
+    if(type&ERROR||treat_warning_as_error){
+      errors++;
+      if(c_flags_val[8].l&&c_flags_val[8].l<=errors&&!(type&NORAUS))
+	{fprintf(stderr,"Maximum number of errors reached!\n");raus();}
+    }
+    if(type&FATAL){fprintf(stderr,"aborting...\n");raus();}
+}
+void error(int errn,...)
+{
+  va_list vl;
+  va_start(vl,errn);
+  do_error(errn,vl);
+  va_end(vl);
+}
+void ucpp_ouch(char *fmt, ...)
+{
+  ierror(0);
+}
+void do_ucpp_error(char *fmt,va_list vl)
+{
+  int i;
+  for(i=0;i<err_num;i++){
+    if(!strcmp(fmt,err_out[i].text))
+      break;
+  }
+  if(*fmt=='#'){
+    /* #error/#warning-directive */
+    i=*(fmt+1)=='w'?325:292;
+  }
+  if(i>=err_num){
+    puts(fmt);
+    ierror(0);
+  }
+  do_error(i,vl);
+}
+void ucpp_error(long line, char *fmt, ...)
+{
+  va_list ap;
+  pp_line=line;
+  va_start(ap, fmt);
+  do_ucpp_error(fmt,ap);
+  va_end(ap);
+}
+void ucpp_warning(long line, char *fmt, ...)
+{
+  va_list ap;
+  pp_line=line;
+  va_start(ap, fmt);
+  do_ucpp_error(fmt,ap);
+  va_end(ap);
+}
+
+void misra(int n,...)
+{
+  va_list vl;
+  if(!misracheck) return;
+  va_start(vl,n);
+  fprintf(stderr,"MISRA error %d\n",n);
+  va_end(vl);
+}
+
+void misra_error(int n, int rule, int subrule, int line, ...) {
+	va_list vl;
+	tmisra_err_out* misr_err;
+	char* mis_vers_string;
+	char mis_numb_string[100];
+	char* rule_text;
+	int not_found;
+	if (!misracheck) return;
+	mis_vers_string = 0;
+	va_start(vl,line);
+
+	if (line == 0) line = ctok->line;
+
+	if ((n) && (misraversion==1998)) {
+		if (misra_98_warn_flag[n-1] != 1) return; /* TODO: Zhler setzen wenn nur ein paar nicht ausgegeben werden sollen */
+		mis_vers_string = mystrdup("1998");
+		sprintf(mis_numb_string,"%d",n);
+		misr_err = NULL;			
+	} else if ((rule) && (misraversion==2004)) {
+		if (misra_04_warn_flag[rule-1][subrule-1] != 1) return;/* TODO: Zhler setzen wenn nur ein paar nicht ausgegeben werden sollen */
+		mis_vers_string = mystrdup("2004");
+		sprintf(mis_numb_string,"Chapter %d, Rule %d",rule,subrule);
+		if (subrule) {
+  		misr_err = misra_err_out;
+	  	not_found = 1;
+		  while ( not_found ) {
+				if ((misr_err->chapter == rule) && (misr_err->rule == subrule)) {
+					not_found = 0;
+					break;
+				}
+				misr_err++;
+			}
+		}
+	}
+	if (!mis_vers_string) return;
+	if (misr_err) fprintf(stderr,"MISRA(%s) Rule violation (%s) in line <%d>\n%s\n",mis_vers_string,mis_numb_string,line,misr_err->text);
+	else fprintf(stderr,"MISRA(%s) Rule violation (%s) in line <%d>: No description found\n",mis_vers_string,mis_numb_string,line);
+
+	if (mis_vers_string) free(mis_vers_string);
+
+	va_end(vl);
+}
+
+void misra_neu(int n,int rule,int subrule, int line, ...)
+{
+  va_list vl;
+	int mis_warn = 0;
+	misra_error(n,rule,subrule,line);
+	return;
+	va_start(vl,line);
+  va_end(vl);
+
+}
+
+FILE *open_out(char *name,char *ext)
+/*  Haengt ext an name an und versucht diese File als output zu oeffnen */
+{
+  char *s,*p;FILE *f;
+  if(ext){
+    s=mymalloc(strlen(name)+strlen(ext)+2);
+    strcpy(s,name);
+    p=s+strlen(s);
+    while(p>=s){
+      if(*p=='.'){*p=0;break;}
+      p--;
+    }
+    strcat(s,".");
+    strcat(s,ext);
+  }else
+    s=name;
+  f=fopen(s,"w");
+  if(!f) fprintf(stderr,"Couldn't open <%s> for output!\n",s);
+  if(ext) free(s);
+  return(f);
+}
diff --git a/mbasic.c b/mbasic.c
new file mode 100755
index 0000000..5d7308a
--- /dev/null
+++ b/mbasic.c
@@ -0,0 +1,229 @@
+/*  Test-language for vbcc. */
+
+#include "supp.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+struct Var *fv;
+
+struct Typ tint,mfunc;
+struct struct_declaration msd; /* initialized to zero */
+
+FILE *file;
+char *next;
+
+struct obj expression(),factor(),scalar();
+
+void raus(void)
+{
+    while(fv){
+        struct Var *m=fv->next;
+        free(fv);
+        fv=m;
+    }
+    while(first_ic){
+        struct IC *m=first_ic->next;
+        free(first_ic);
+        first_ic=m;
+    }
+    exit(0);
+}
+void add_IC(struct IC *new)
+{
+    new->next=0;
+    new->prev=last_ic;
+    new->change_cnt=new->use_cnt=0;
+    new->change_list=new->use_list=0;
+    new->line=0;
+    new->file=0;
+    new->q1.am=new->q2.am=new->z.am=0;
+    if(!last_ic){
+        first_ic=new;
+    }else{
+        last_ic->next=new;
+    }
+    last_ic=new;
+}
+struct Var *add_var(char *name,struct Typ *t,int sc)
+{
+    struct Var *v=mymalloc(sizeof(*v));
+    v->vtyp=t;
+    v->storage_class=sc;
+    v->reg=0;
+    v->identifier=name;
+    v->offset=max_offset;
+    if(sc==AUTO) max_offset=zmadd(max_offset,sizetab[t->flags&NQ]);
+    v->priority=1;
+    v->flags=0;
+    v->next=fv;
+    v->clist=0;
+    v->fi=0;
+    v->inline_copy=0;
+    v->nesting=1;
+    fv=v;
+    return v;
+}
+struct Var *add_tmp_var(struct Typ *t)
+{
+    return add_var(empty,t,AUTO);
+}
+struct Var *get_var(char *name)
+{
+    struct Var *v;char *buf;
+    puts("getvar");
+    for(v=fv;v;v=v->next){
+        if(!strcmp(name,v->identifier)) return v;
+    }
+    buf=mymalloc(strlen(name)+1);
+    strcpy(buf,name);
+    return add_var(buf,&tint,AUTO);
+}
+
+char *identifier(void)
+{
+  static char id[1024];
+  char *s=id;
+  puts("identifier");
+  while(isalnum(*next)) *s++=*next++;
+  puts("done");
+  return id;
+}
+struct obj scalar(void)
+{
+  struct obj o;
+  zmax val;
+  puts("scalar");
+  if(isdigit(*next)){
+    o.flags=KONST;
+    val=l2zm(0L);
+    while(isdigit(*next)){
+      val=zmmult(val,l2zm(10L));
+      val=zmadd(val,l2zm((long)(*next-'0')));
+      next++;
+    }
+    o.val.vint=zm2zi(val);
+    return o;
+  }
+  if(*next=='('){
+    next++;
+    o=expression();
+    next++;
+    return o;
+  }
+  o.flags=VAR;
+  o.val.vmax=l2zm(0L);
+  o.v=get_var(identifier());
+  return o;
+}
+struct obj factor(void)
+{
+  struct obj o;
+  struct IC *new;
+  puts("factor");
+  o=scalar();
+  while(*next=='*'||*next=='/'){
+    new=new_IC();
+    if(*next=='*') new->code=MULT; else new->code=DIV;
+    next++;
+    new->typf=INT;
+    new->q1=o;
+    new->q2=scalar();
+    o.flags=VAR;
+    o.v=add_tmp_var(&tint);
+    o.val.vmax=l2zm(0L);
+    new->z=o;
+    add_IC(new);
+  }
+  return o;
+}
+struct obj expression(void)
+{
+  struct obj o;
+  struct IC *new;
+  puts("expression");
+  o=factor();
+  while(*next=='+'||*next=='-'){
+    new=new_IC();
+    if(*next=='+') new->code=ADD; else new->code=SUB;
+    next++;
+    new->typf=INT;
+    new->q1=o;
+    new->q2=factor();
+    o.flags=VAR;
+    o.v=add_tmp_var(&tint);
+    o.val.vmax=l2zm(0L);
+    new->z=o;
+    add_IC(new);
+  }
+  return o;
+}
+void compile(void)
+{
+  struct IC *new;
+  char line[1024],*s;
+  struct obj o,last;
+  puts("compile");
+  while(fgets(line,1023,file)){
+    next=line;
+    s=identifier();
+    if(*next=='='){
+      struct Var *v=get_var(s);
+      next++;
+      o=expression();
+      new=new_IC();
+      new->code=ASSIGN;
+      new->typf=INT;
+      new->q1=o;
+      new->z.flags=VAR;
+      new->z.v=v;
+      new->z.val.vmax=l2zm(0L);
+      new->q2.flags=0;
+      new->q2.val.vmax=sizetab[INT];
+      last=new->z;
+      add_IC(new);
+      continue;
+    }
+  }
+  new=new_IC();
+  new->code=SETRETURN;
+  new->typf=INT;
+  new->q1=last;
+  new->q2.flags=new->z.flags=0;
+  new->q2.val.vmax=sizetab[INT];
+  new->z.reg=freturn(&tint);
+  if(!new->z.reg) puts("problem!");
+  add_IC(new);
+}
+void error(int n,...)
+{
+    printf("error %d\n",n);
+    raus();
+}
+void savescratch()
+{}
+
+main(int argc,char **argv)
+{
+    struct Var *main;
+    max_offset=l2zm(0L);
+    if(!init_cg()) raus();
+    tint.flags=INT;
+    tint.next=0;
+    mfunc.flags=FUNKT;
+    mfunc.next=&tint;
+    mfunc.exact=&msd;
+    main=add_var("main",&mfunc,EXTERN);
+    file=fopen(argv[1],"r");
+    if(!file) {printf("Error opening file\n");raus();}
+    compile();
+    scanf("%ld",&optflags);
+    pric(stdout,first_ic);
+    vl1=vl3=0;
+    vl2=fv;
+    optimize(optflags,main);
+    pric(stdout,first_ic);
+    gen_code(stdout,first_ic,main,max_offset);
+    raus();
+}
+
diff --git a/minicomp.c b/minicomp.c
new file mode 100755
index 0000000..1bf274b
--- /dev/null
+++ b/minicomp.c
@@ -0,0 +1,913 @@
+#include "minicomp.h"
+
+#define clone_type clone_typ
+#define free_type freetyp
+#define new_icode new_IC
+#define add_icode add_IC
+#define free_all_icode() free_IC(first_ic)
+#define get_first_icode() first_ic
+typedef struct IC icode;
+
+static int errors;
+var *store_locals;
+
+struct rpair rp;
+
+char *copyright="minicomp/vbcc (c) in 2002 Volker Barthelmann";
+char *inname,*outname;
+struct struct_declaration *first_sd;
+struct Var *first_ext,*merk_varf;
+char **target_macros;
+
+FILE *out;
+
+void raus(void)
+{
+  var *v;
+  for(v=first_var[0];v;v=v->next)
+    if(v->type->flags!=FUNCTION){
+      gen_align(out,falign(v->type));
+      gen_var_head(out,v->vbccvar);
+      gen_ds(out,szof(v->type),v->type);
+    }
+
+  cleanup_cg(out);
+
+  if(errors>0)
+    exit(EXIT_FAILURE);
+  else
+    exit(EXIT_SUCCESS);
+}
+
+main(int argc,char **argv)
+{
+  int i,j,flag;
+  type *nt;
+
+  for(i=1;i<argc;i++){
+    if(*argv[i]!='-'){
+      if(inname)
+	error(18,"multiple input files");
+      inname=argv[i];
+    }else{
+      flag=0;
+      if((!strcmp("-o",argv[i]))&&i<argc-1){
+	flag=1;
+	outname=argv[++i];
+	continue;
+      }
+      if(!strncmp("-debug=",argv[i],7)){
+	flag=1;
+	sscanf(argv[i]+7,"%d",&j);
+	DEBUG=j;
+	continue;
+      }
+      if(!strncmp("-unroll-size=",argv[i],13)){
+	flag=1;
+	sscanf(argv[i]+13,"%d",&j);
+	unroll_size=j;
+	continue;
+      }
+      if(!strncmp("-inline-size=",argv[i],13)){
+	flag=1;
+	sscanf(argv[i]+13,"%d",&j);
+	inline_size=j;
+	continue;
+      }
+      if(!strncmp("-maxoptpasses=",argv[i],14)){
+	flag=1;
+	sscanf(argv[i]+14,"%d",&j);
+	maxoptpasses=j;
+	continue;
+      }
+      for(j=0;j<MAXGF&&flag==0;j++){
+        size_t l;
+        if(!g_flags_name[j]) continue;
+        l=strlen(g_flags_name[j]);
+        if(l>0&&!strncmp(argv[i]+1,g_flags_name[j],l)){
+          flag=1;
+          if((g_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(19,"multiple option");break;}
+	  g_flags[j]|=USEDFLAG;
+          if(g_flags[j]&STRINGFLAG){
+            if(argv[i][l+1]!='='){error(21,"string expected");}
+            if(argv[i][l+2]||i>=argc-1)
+              g_flags_val[j].p=&argv[i][l+2];
+            else
+              g_flags_val[j].p=&argv[++i][0];
+          }
+          if(g_flags[j]&VALFLAG){
+            if(argv[i][l+1]!='='){error(20,"value expected");}
+            if(argv[i][l+2]||i>=argc-1)
+              g_flags_val[j].l=atol(&argv[i][l+2]);
+            else
+              g_flags_val[j].l=atol(&argv[++i][0]);
+          }
+          if(g_flags[j]&FUNCFLAG) g_flags_val[j].f(&argv[i][l+1]);
+	}
+      }
+      if(!flag) error(23,"unknown option");
+    }
+  }
+
+  if(!inname)
+    error(22,"no input file");
+  infile=fopen(inname,"r");
+  if(!infile)
+    error(18,"could not open output file");
+  if(!outname)
+    error(23,"no output file");
+  out=fopen(outname,"w");
+  if(!out){
+    error(24,"could not open input file");
+  }
+  nt=new_type(FUNCTION);
+  nt->next=new_type(INT);
+  add_var("readInt",clone_type(nt));
+  add_var("writeInt",clone_type(nt));
+  add_var("writeChar",clone_type(nt));
+  add_var("readChar",clone_type(nt));
+  add_var("writeReal",nt);
+  nt=new_type(FUNCTION);
+  nt->next=new_type(REAL);
+  add_var("readReal",nt);
+
+  stackalign=l2zm(0L);
+  if(!init_cg()) exit(EXIT_FAILURE);
+  if(zmeqto(stackalign,l2zm(0L)))
+    stackalign=maxalign; 
+  for(i=0;i<EMIT_BUF_DEPTH;i++)
+    emit_buffer[i]=mymalloc(EMIT_BUF_LEN);
+  emit_p=emit_buffer[0];
+
+  multiple_ccs=0;
+  optflags=-1;
+  maxoptpasses=100;
+
+  yyparse();
+
+  raus();
+}
+
+yyerror(char *s)
+{
+  error(1,s);
+}
+
+void error(int n,...)
+{
+  if(n==170||n==172) return;
+  errors++;
+  fprintf(stderr,"error %d\n",n);
+  raus();
+}
+
+void *getmem(size_t s)
+{
+  void *p=malloc(s);
+  if(!p){
+    error(2,"out of memory");
+  }
+  return p;
+}
+
+#define LABELNESTING 1024
+static int labelstack[LABELNESTING],labelidx;
+
+void push_int(int l)
+{
+  labelstack[labelidx++]=l;
+}
+
+int pop_int()
+{
+  return labelstack[--labelidx];
+}
+
+#define NAMENESTING 1024
+static char *namestack[NAMENESTING],nameidx;
+
+void push_ptr(void *ptr)
+{
+  namestack[nameidx++]=ptr;
+}
+
+void *pop_ptr()
+{
+  return namestack[--nameidx];
+}
+
+
+char *typename[]={"    ","int","real","array","function"};
+
+
+type *new_type(int t)
+{
+  type *new=new_typ();
+  new->flags=t;
+  new->next=0;
+  return new;
+}
+
+type *new_array(type *t,node *p)
+{
+  type *new=new_typ();
+  simplify_tree(p);
+  if(p->flags!=NNUMBER)
+    error(3,"array size not a constant");
+  if(p->type->flags!=INT)
+    error(4,"array size not an integer");
+  new->flags=ARRAY;
+  new->next=t;
+  new->size=l2zm((long)p->ivalue);
+  free_tree(p);
+  return new;
+}
+
+int nesting;
+int local_offset,parm_offset,framesize;
+
+#define MAXNESTING 128
+var *first_var[128];
+
+void free_varlist(var *v)
+{
+  var *m;
+  while(v){
+    free_var(v->vbccvar);
+    m=v->next;
+    free(v);
+    v=m;
+  }
+}
+
+void enter_block()
+{
+  nesting++;
+  first_var[nesting]=0;
+  push_int(local_offset);
+}
+
+void leave_block()
+{
+  if(first_var[nesting]){
+    var *p=first_var[nesting];
+    while(p->next)
+      p=p->next;
+    p->next=store_locals;
+    p->vbccvar->next=merk_varf;
+    store_locals=first_var[nesting];
+    merk_varf=store_locals->vbccvar;
+  }
+  nesting--;
+  local_offset=pop_int();
+}
+
+void gen_func(var *v,icode *first,int framesize)
+{
+  pric(stdout,get_first_icode());
+  vl1=first_var[0]?first_var[0]->vbccvar:0;
+  vl2=first_var[1]?first_var[1]->vbccvar:0;
+  vl3=merk_varf;
+  optimize(optflags,v->vbccvar);
+  memset(regs_modified,0,RSIZE);
+  pric(stdout,get_first_icode());
+  gen_code(out,get_first_icode(),v->vbccvar,max_offset);
+}
+
+void enter_func(char *name,type *p)
+{
+  type *t=new_type(FUNCTION);
+  var *v;
+  t->next=p;
+  t->exact=getmem(sizeof(*t->exact));
+  t->exact->count=0;
+  v=add_var(name,t);
+  local_offset=parm_offset=framesize=0;
+  push_ptr(v);
+  enter_block();
+}
+
+void leave_func()
+{
+  icode *p,*merk;
+  leave_block();
+  gen_func(pop_ptr(),get_first_icode(),framesize);
+  free_all_icode();
+  first_ic=last_ic=0;
+  free_varlist(store_locals);
+  merk_varf=0;
+  store_locals=0;
+}
+
+var *find_var(char *p,int minnest)
+{
+  var *v;
+  int i;
+
+  for(i=nesting;i>=minnest;i--){
+    for(v=first_var[i];v;v=v->next)
+      if(!strcmp(v->name,p))
+	return v;
+  }
+  return 0;
+}
+
+var *add_var(char *name,type *t)
+{
+  var *new=getmem(sizeof(*new));
+  struct Var *vv;
+  /*FIXME: add vbccvar */  
+  if(find_var(name,nesting))
+    error(5,"var %s already defined",name);
+  new->nesting=nesting;
+  new->name=add_string(name);
+  new->type=t;
+  if(*name==0){
+    new->next=store_locals;
+  }else{
+    new->next=first_var[nesting];
+  }
+  if(nesting==1){
+    /* parameter */
+    new->offset=parm_offset;
+    parm_offset+=szof(t);
+  }
+  if(nesting>1){
+    /* local variable */
+    new->offset=local_offset;
+    local_offset+=szof(t);
+    if(local_offset>framesize)
+      framesize=local_offset;
+  }    
+  /* attach vbcc variable */
+  vv=new_var();
+  vv->vtyp=clone_typ(new->type);
+  vv->identifier=add_string(name);
+  vv->nesting=(*name!=0?nesting:2);
+  vv->storage_class=(vv->nesting==0?EXTERN:AUTO);
+  if(nesting==1)
+    vv->offset=zmsub(l2zm(0L),zmadd(maxalign,l2zm(new->offset)));
+  else
+    vv->offset=l2zm((long)local_offset);
+  new->vbccvar=vv;
+
+  if(*name==0){
+    store_locals=new;
+    vv->next=merk_varf;
+    merk_varf=vv;
+  }else{
+    vv->next=first_var[nesting]?first_var[nesting]->vbccvar:0;
+    first_var[nesting]=new;
+  }
+  return new;
+}
+
+var *new_temp(int tflags)
+{
+  char tname[16];
+  static int itmps,rtmps,ptmps;
+  if(tflags==INT)
+    sprintf(tname,"\0 itmp%d",++itmps);
+  else if(tflags==REAL)
+    sprintf(tname,"\0 rtmp%d",++rtmps);
+  else if(tflags==POINTER)
+    sprintf(tname,"\0 rtmp%d",++ptmps);
+  else
+    error(16,"internal");
+  return add_var(tname,new_type(tflags));
+}
+
+struct Var *add_tmp_var(struct Typ *t)
+{
+  
+  return new_temp(t->flags)->vbccvar;
+}
+
+char *add_string(char *s)
+{
+  char *new=getmem(strlen(s)+1);
+  strcpy(new,s);
+  return new;
+}
+
+char *nodename[]={
+  "var","number","add","mul","sub","div","index","equals",
+  "lt","gt","leq","geq","neq","and","or",
+  "int2real","real2int","assign","call","argument"
+};
+
+node *number_node(void)
+{
+  node *new=getmem(sizeof(*new));
+  new->flags=NNUMBER;
+  if(strstr(tkname,".")){
+    double rval;
+    sscanf(tkname,"%lf",&rval);
+    new->rvalue=rval;
+    new->type=new_type(REAL);
+    new->left=new->right=0;
+  }else{
+    new->ivalue=atoi(tkname);
+    new->type=new_type(INT);
+    new->left=new->right=0;
+  }
+  return new;
+}
+
+node *var_node(void)
+{
+  var *v=find_var(tkname,0);
+  node *new;
+  if(!v){
+    error(6,"unknown identifier: %s",tkname);
+  }
+  new=getmem(sizeof(*new));
+  new->flags=NVARIABLE;
+  new->var=v;
+  new->type=clone_type(v->type);
+  new->left=new->right=0;
+  return new;
+}
+
+
+node *binary_node(enum nodeflags flags,node *left,node *right)
+{
+  node *new=getmem(sizeof(*new));
+  new->flags=flags;
+  new->left=left;
+  new->right=right;
+  new->type=0;
+  if(!left||(flags!=NCALL&&!right))
+    error(7,"internal error");
+  if(flags==NINDEX){
+    if(left->type->flags!=ARRAY)
+      error(8,"operand of [] must be array");
+    new->type=clone_type(left->type->next);
+  }else if(flags==NARG){
+    /* nothing to do? */
+  }else if(flags==NCALL){
+    if(left->type->flags!=FUNCTION)
+      error(9,"only functions can be called");
+    new->type=clone_type(left->type->next);
+  }else{
+    if(left->type->flags==ARRAY||right->type->flags==ARRAY)
+      error(10,"both operands must be real or int");
+    if(left->type->flags==REAL||right->type->flags==REAL){
+      new->type=new_type(REAL);
+      if(left->type->flags==INT){
+	new->left=conv_tree(left,REAL);
+      }
+      if(right->type->flags==INT){
+	new->right=conv_tree(right,REAL);
+      }      
+    }else
+      new->type=new_type(INT);
+  }
+  return new;
+}
+
+void print_tree(node *p)
+{
+  printf("%s(",nodename[p->flags]);
+  if(p->left)
+    print_tree(p->left);
+  if(p->right){
+    printf(",");
+    print_tree(p->right);
+  }
+  if(p->flags==NNUMBER){
+    if(p->type->flags==INT)
+      printf("%d[int]",p->ivalue);
+    else
+      printf("%g[real]",p->rvalue);
+  }
+  if(p->flags==NVARIABLE)
+    printf("%s[%s]",p->var->name,typename[p->var->type->flags]);
+  printf(")");
+}
+
+node *conv_tree(node *p,int tflags)
+{
+  node *new;
+  if(p->type->flags==tflags)
+    return p;
+  new=getmem(sizeof(*new));
+  if(tflags==REAL)
+    new->flags=NI2R;
+  else
+    new->flags=NR2I;
+  new->type=new_type(p->type->flags);
+  new->left=p;
+  new->right=0;
+  return new;
+}
+
+void free_tree(node *p)
+{
+  if(p->left)
+    free_tree(p->left);
+  if(p->right)
+    free_tree(p->right);
+  if(p->type)
+    free_type(p->type);
+  free(p);
+}
+
+
+static void const_node(node *p,int val)
+{
+  p->flags=NNUMBER;
+  p->ivalue=val;
+  if(p->left)
+    free_tree(p->left);
+  if(p->right)
+    free_tree(p->right);
+  p->left=p->right=0;
+}
+
+void simplify_tree(node *p)
+{
+  if(p->left)
+    simplify_tree(p->left);
+  if(p->right)
+    simplify_tree(p->right);
+  if(p->type&&p->type->flags==INT&&p->left&&p->left->flags==NNUMBER&&p->right&&p->right->flags==NNUMBER){
+    switch(p->flags){
+    case NADD: const_node(p,p->left->ivalue+p->right->ivalue); break;
+    case NMUL: const_node(p,p->left->ivalue*p->right->ivalue); break;
+    case NSUB: const_node(p,p->left->ivalue-p->right->ivalue); break;
+    case NDIV: 
+      if(p->right->ivalue!=0)
+	const_node(p,p->left->ivalue/p->right->ivalue); break;
+    }
+  }
+}
+
+void assign_statement(node *left,node *right)
+{
+  if(left->type->flags==ARRAY||right->type->flags==ARRAY)
+    error(11,"array type in assignment");
+  if(left->type->flags==FUNCTION||right->type->flags==FUNCTION)
+    error(12,"function type in assignment");
+
+  right=conv_tree(right,left->type->flags);
+  simplify_tree(left);
+  simplify_tree(right);
+  if(left->flags==NINDEX){
+    icode *n1,*n2,*n3;
+    n1=new_icode();
+    n1->code=MULT;
+    n1->typf=INT;
+    n1->q1=*gen_tree(left->right);
+    n1->q2.flags=KONST;
+    n1->q2.val.vint=zm2zi(sizetab[INT]);
+    n1->z.flags=VAR;
+    n1->z.v=new_temp(INT)->vbccvar;
+    n1->z.val.vmax=l2zm(0L);
+    n2=new_icode();
+    n2->code=ADDI2P;
+    n2->typf=INT;
+    n2->typf2=POINTER;
+    n2->q1=*gen_tree(left->left);
+    n2->q2=n1->z;
+    n2->z.flags=VAR;
+    n2->z.v=new_temp(POINTER)->vbccvar;
+    n2->z.val.vmax=l2zm(0L);
+    n3=new_icode();
+    n3->code=ASSIGN;
+    n3->typf=left->type->flags;
+    n3->q1=*gen_tree(right);
+    n3->z=n2->z;
+    n3->z.flags|=DREFOBJ;
+    n3->z.dtyp=POINTER;
+    n3->q2.val.vmax=szof(left->type);
+    add_icode(n1);
+    add_icode(n2);
+    add_icode(n3);
+#if 0    
+    /* leicht anderes Format */
+    new->flags=CSTORE;
+    new->op1=*gen_tree(right);
+    new->op2=*gen_tree(left->left);
+    new->dest=*gen_tree(left->right);
+#endif
+  }else{
+    icode *new=new_icode();
+    new->code=ASSIGN;
+    new->q1=*gen_tree(right);
+    new->z=*gen_tree(left);
+    new->q2.val.vmax=szof(left->type);
+    new->typf=left->type->flags;
+    add_icode(new);
+  }
+  free_tree(left);
+  free_tree(right);
+}
+
+void return_statement(node *p)
+{
+  icode *new=new_icode();
+  p=conv_tree(p,INT); /*FIXME*/
+  simplify_tree(p);
+  new->code=SETRETURN;
+  new->typf=p->type->flags;
+  new->q1=*gen_tree(p);
+  new->z.reg=freturn(p->type);
+  add_icode(new);
+  free_tree(p);
+}
+
+void while_statement(node *p)
+{
+  int loop=++label,exit=++label;
+  simplify_tree(p);
+  gen_cond(p,loop,exit);
+  gen_label(loop);
+  last_ic->flags|=LOOP_COND_TRUE;
+  push_ptr(p);
+  push_int(loop);
+  push_int(exit);
+#if 0
+  gen_label(loop);
+  gen_cond(p,start,exit);
+  free_tree(p);
+  gen_label(start);
+  push_int(loop);
+  push_int(exit);
+#endif
+}
+
+void while_end()
+{
+  int loop,exit;
+  node *p;
+  exit=pop_int();
+  loop=pop_int();
+  p=pop_ptr();
+  gen_cond(p,loop,exit);
+  gen_label(exit);
+#if 0
+  new=new_icode();
+  new->code=BRA;
+  new->typf=loop;
+  add_icode(new);
+  gen_label(exit);
+#endif
+}
+
+void if_statement(node *p)
+{
+  int true=++label,false=++label;
+  simplify_tree(p);
+  gen_cond(p,true,false);
+  free_tree(p);
+  gen_label(true);
+  push_int(false);
+}
+
+void if_end()
+{
+  gen_label(pop_int());
+}
+
+void if_else()
+{
+  int endlabel=++label;
+  icode *new=new_icode();
+  new->code=BRA;
+  new->typf=++label;
+  add_icode(new);
+  gen_label(pop_int());
+  push_int(label);
+}
+
+int label;
+
+operand *gen_tree(node *p)
+{
+  icode *new;
+  static operand op;
+
+  if(p->flags==NVARIABLE){
+    if(p->var->type->flags==ARRAY){
+      if(p->var->nesting==0){
+	op.flags=VAR|VARADR;
+	op.v=p->var->vbccvar;
+	op.val.vmax=l2zm(0L);
+	return &op;
+      }else{
+	icode *new=new_icode();
+	new->flags=ADDRESS;
+	new->q1.flags=VAR;
+	new->q1.v=p->var->vbccvar;
+	new->q1.val.vmax=l2zm(0L);
+	new->z.flags=VAR;
+	new->z.v=new_temp(POINTER)->vbccvar;
+	new->z.val.vmax=l2zm(0L);
+	add_icode(new);
+	return &new->z;
+      }
+    }else{
+      op.flags=VAR;
+      op.v=p->var->vbccvar;
+      op.val.vmax=l2zm(0L);
+      return &op;
+    }
+  }
+
+  if(p->flags==NNUMBER){
+    op.flags=KONST;
+    if(p->type->flags==INT)
+      op.val.vint=p->ivalue;
+    else
+      op.val.vdouble=zld2zd(d2zld(p->rvalue));
+    return &op;
+  }
+
+  if(p->flags==NADD||p->flags==NMUL||p->flags==NSUB||p->flags==NDIV||p->flags==NI2R||p->flags==NR2I){
+    int ttyp=p->type->flags;
+    new=new_icode();
+    switch(p->flags){
+    case NADD: new->code=ADD;break;
+    case NMUL: new->code=MULT;break;
+    case NSUB: new->code=SUB;break;
+    case NDIV: new->code=DIV;break;
+    case NI2R: new->code=CONVERT;ttyp=REAL;new->typf2=INT;break;
+    case NR2I: new->code=CONVERT;ttyp=INT;new->typf2=REAL;break;
+    }
+    new->q1=*gen_tree(p->left);
+    if(p->right)
+      new->q2=*gen_tree(p->right);
+    new->z.flags=VAR;
+    new->z.v=new_temp(ttyp)->vbccvar;
+    new->z.val.vmax=l2zm(0L);
+    new->typf=ttyp;
+    add_icode(new);
+    return &new->z;
+  }
+
+  if(p->flags==NINDEX){
+    if(p->type->flags==ARRAY){
+      icode *merk,*new=new_icode();
+      new->flags=MULT;
+      new->typf=INT;
+      new->q1=*gen_tree(p->right);
+      new->q2.flags=KONST;
+      new->q2.val.vint=szof(p->type);
+      new->z.flags=VAR;
+      new->z.v=new_temp(INT)->vbccvar;
+      new->z.val.vmax=l2zm(0L);
+      add_icode(new);
+      merk=new;
+      new=new_icode();
+      new->flags=ADDI2P;
+      new->typf=INT;
+      new->typf2=POINTER;
+      new->q1=*gen_tree(p->left);
+      new->q2=merk->z;
+      new->z.flags=VAR;
+      new->z.v=new_temp(POINTER)->vbccvar;
+      new->z.val.vmax=l2zm(0L);
+      op=new->z;
+      add_icode(new);
+      return &new->z;
+    }else{
+      icode *merk,*new=new_icode();
+      new->code=MULT;
+      new->typf=INT;
+      new->q1=*gen_tree(p->right);
+      new->q2.flags=KONST;
+      new->q2.val.vint=zm2zi(sizetab[INT]);
+      new->z.flags=VAR;
+      new->z.v=new_temp(INT)->vbccvar;
+      new->z.val.vmax=l2zm(0L);
+      add_icode(new);
+      merk=new;
+      new=new_icode();
+      new->code=ADDI2P;
+      new->q1=*gen_tree(p->left);
+      new->q2=merk->z;
+      new->typf=INT;
+      new->typf2=POINTER;
+      new->z.flags=VAR;
+      new->z.v=new_temp(POINTER)->vbccvar;
+      new->z.val.vmax=l2zm(0L);
+      op=new->z;
+      op.flags|=DREFOBJ;
+      op.dtyp=POINTER;
+      add_icode(new);
+      return &op;
+    }
+  }
+
+  if(p->flags==NCALL){
+    icode *new=new_icode();
+    new->code=CALL;
+    new->typf=FUNKT;
+    if(p->right)
+      new->q2.val.vmax=l2zm(push_arg(p->right));
+    else
+      new->q2.val.vmax=l2zm(0L);
+    new->q1=*gen_tree(p->left);
+    add_icode(new);
+    new=new_icode();
+    new->code=GETRETURN;
+    new->z.flags=VAR;
+    new->typf=p->type->flags;
+    new->z.v=new_temp(p->type->flags)->vbccvar;
+    new->z.val.vmax=l2zm(0L);
+    new->q1.reg=freturn(p->type);
+    add_icode(new);
+    return &new->z;
+  }
+
+  error(13,"operation not yet supported");
+}
+
+void gen_label(int l)
+{
+  icode *new=new_icode();
+  new->code=LABEL;
+  new->typf=l;
+  add_icode(new);
+}
+
+void gen_cond(node *p,int true_label,int false_label)
+{
+  icode *new;
+  if(p->flags==NAND){
+    int tmp=++label;
+    gen_cond(p->left,tmp,false_label);
+    gen_label(tmp);
+    gen_cond(p->right,true_label,false_label);
+    return;
+  }
+  if(p->flags==NOR){
+    int tmp=++label;
+    gen_cond(p->left,true_label,tmp);
+    gen_label(tmp);
+    gen_cond(p->right,true_label,false_label);
+    return;
+  }
+  new=new_icode();
+  new->code=COMPARE;
+  new->typf=p->type->flags;
+  new->q1=*gen_tree(p->left);
+  new->q2=*gen_tree(p->right);
+  add_icode(new);
+  new=new_icode();
+  switch(p->flags){
+  case NEQUALS: new->code=BEQ;break;
+  case NNEQ: new->code=BNE;break;
+  case NLT: new->code=BLT;break;
+  case NGT: new->code=BGT;break;
+  case NLEQ: new->code=BLE;break;
+  case NGEQ: new->code=BGE;break;
+  default: error(14,"internal");
+  }
+  new->typf=true_label;
+  add_icode(new);
+
+  new=new_icode();
+  new->code=BRA;
+  new->typf=false_label;
+  add_icode(new);
+}
+
+int push_arg(node *p)
+{
+  if(p->flags==NARG){
+    int s;
+    s=push_arg(p->right);
+    return s+push_arg(p->left);
+  }else{
+    icode *new=new_icode();
+    if(p->type->flags==ARRAY)
+      error(15,"arrays cannot be passed");
+    new->code=PUSH;
+    new->q2.val.vmax=szof(p->type);
+    new->z.val.vmax=new->q2.val.vmax;
+    new->typf=p->type->flags;
+    new->q1=*gen_tree(p);
+    add_icode(new);
+    return szof(p->type);
+  }
+}
+
+void free_var(struct Var *v)
+{
+  free(v);
+  /*FIXME*/
+}
+
+void add_IC(icode *new)
+{
+  if(last_ic&&new->code==ASSIGN&&new->q1.flags==VAR&&last_ic->z.flags==VAR&&
+     new->q1.v==last_ic->z.v&&zmeqto(new->q1.val.vmax,last_ic->z.val.vmax)&&
+     *new->q1.v->identifier==0){
+    last_ic->z=new->z;
+    free(new);
+    return;
+  }
+  insert_IC(last_ic,new);
+}
diff --git a/minicomp.h b/minicomp.h
new file mode 100755
index 0000000..c47f0f7
--- /dev/null
+++ b/minicomp.h
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "supp.h"
+
+extern FILE *infile;
+#define MAXLEN 1024
+extern char tkname[MAXLEN];
+extern int label;
+extern int nesting;
+extern int local_offset,parm_offset,framesize;
+
+#define REAL DOUBLE
+#define FUNCTION FUNKT
+
+#define YYERROR_VERBOSE 1
+
+enum nodeflags {
+  NVARIABLE,NNUMBER,NADD,NMUL,NSUB,NDIV,NINDEX,
+  NEQUALS,NLT,NGT,NLEQ,NGEQ,NNEQ,NAND,NOR,
+  NI2R,NR2I,NASSGN,NCALL,NARG
+};
+
+extern char *nodename[];
+
+typedef struct Typ type;
+
+typedef struct obj operand;
+
+typedef struct var {
+  int nesting;
+  char *name;
+  struct Typ *type;
+  struct var *next;
+  int offset;
+  struct Var *vbccvar;
+} var;
+
+#define MAXNESTING 128
+extern var *first_var[128];
+
+typedef struct {
+  int flags;
+  char *name;
+} *stype;
+
+typedef struct mnode {
+  enum nodeflags flags;
+  struct mnode *left,*right;
+  type *type;
+  var *var;
+  int ivalue;
+  double rvalue;
+} node;
+
+void enter_block(void);
+void leave_block(void);
+void enter_func(char *,type *);
+void leave_func(void);
+var *find_var(char *,int);
+var *add_var(char *,type *);
+var *new_temp(int);
+char *add_string(char *);
+void error(int,...);
+void *getmem(size_t);
+node *number_node(void);
+node *var_node(void);
+node *conv_tree(node *,int);
+node *binary_node(enum nodeflags,node *,node *);
+void print_tree(node *);
+void simplify_tree(node *);
+void free_tree(node *);
+type *new_type(int);
+type *new_array(type *,node *);
+void return_statement(node *);
+void while_statement(node *);
+void while_end(void);
+void if_statement(node *);
+void if_end(void);
+void if_else(void);
+void assign_statement(node *,node *);
+void push_int(int);
+int pop_int(void);
+void push_name(char *);
+char *pop_name(void);
+operand *gen_tree(node *);
+void gen_cond(node *,int,int);
+void gen_label(int);
+int push_arg(node *);
+void gen_global(char *,int);
diff --git a/minicomp.tab.c b/minicomp.tab.c
new file mode 100755
index 0000000..f50de99
--- /dev/null
+++ b/minicomp.tab.c
@@ -0,0 +1,1189 @@
+
+/*  A Bison parser, made from minicomp.y
+ by  GNU Bison version 1.27
+  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define	TKNUMBER	257
+#define	TKIDENTIFIER	258
+#define	TKREAL	259
+#define	TKINT	260
+#define	TKLEQ	261
+#define	TKGEQ	262
+#define	TKNEQ	263
+#define	TKIF	264
+#define	TKELSE	265
+#define	TKWHILE	266
+#define	TKRETURN	267
+#define	TKASSIGN	268
+#define	TKAND	269
+#define	TKOR	270
+
+#line 18 "minicomp.y"
+
+#include "minicomp.h"
+
+typedef void *voidptr;
+#define YYSTYPE voidptr
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define	YYFINAL		123
+#define	YYFLAG		-32768
+#define	YYNTBASE	32
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 64)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    23,
+    24,    27,    25,    29,    26,     2,    28,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,    19,    21,
+    20,    22,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+    17,     2,    18,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,    30,     2,    31,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
+     7,     8,     9,    10,    11,    12,    13,    14,    15,    16
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     3,     5,     7,     9,    11,    13,    18,    21,    23,
+    27,    29,    33,    37,    39,    43,    47,    51,    55,    59,
+    63,    67,    71,    75,    77,    81,    85,    87,    91,    93,
+    98,   102,   104,   109,   111,   113,   117,   119,   122,   124,
+   126,   128,   130,   132,   134,   135,   139,   143,   146,   149,
+   151,   152,   160,   161,   162,   166,   167,   174,   179,   183,
+   186,   190,   194,   197,   201,   203
+};
+
+static const short yyrhs[] = {    32,
+    33,     0,    33,     0,    59,     0,    36,     0,     5,     0,
+     6,     0,    34,    17,    40,    18,     0,    35,    36,     0,
+    36,     0,    34,    37,    19,     0,     4,     0,    38,    15,
+    39,     0,    38,    16,    39,     0,    39,     0,    40,    20,
+    40,     0,    40,     9,    40,     0,    40,    21,    40,     0,
+    40,    22,    40,     0,    40,     7,    40,     0,    40,     8,
+    40,     0,    23,    38,    24,     0,    40,    25,    41,     0,
+    40,    26,    41,     0,    41,     0,    41,    27,    42,     0,
+    41,    28,    42,     0,    42,     0,    23,    40,    24,     0,
+     3,     0,    44,    23,    45,    24,     0,    44,    23,    24,
+     0,    43,     0,    42,    17,    40,    18,     0,    44,     0,
+     4,     0,    45,    29,    40,     0,    40,     0,    46,    47,
+     0,    47,     0,    51,     0,    55,     0,    57,     0,    58,
+     0,    48,     0,     0,    30,    49,    50,     0,    35,    46,
+    31,     0,    46,    31,     0,    35,    31,     0,    31,     0,
+     0,    10,    23,    38,    24,    52,    48,    53,     0,     0,
+     0,    11,    54,    48,     0,     0,    12,    23,    38,    24,
+    56,    48,     0,    43,    14,    40,    19,     0,    13,    40,
+    19,     0,    60,    61,     0,    34,    37,    23,     0,    62,
+    24,    48,     0,    24,    48,     0,    62,    29,    63,     0,
+    63,     0,    34,    37,     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+    27,    29,    32,    34,    37,    39,    40,    43,    45,    48,
+    52,    56,    58,    59,    62,    64,    65,    66,    67,    68,
+    69,    72,    73,    74,    77,    78,    79,    82,    84,    85,
+    86,    87,    90,    92,    95,    99,   101,   104,   106,   109,
+   111,   112,   113,   114,   117,   119,   121,   123,   124,   125,
+   129,   130,   133,   135,   135,   139,   140,   143,   147,   151,
+   155,   159,   161,   164,   166,   169
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","TKNUMBER",
+"TKIDENTIFIER","TKREAL","TKINT","TKLEQ","TKGEQ","TKNEQ","TKIF","TKELSE","TKWHILE",
+"TKRETURN","TKASSIGN","TKAND","TKOR","'['","']'","';'","'='","'<'","'>'","'('",
+"')'","'+'","'-'","'*'","'/'","','","'{'","'}'","glob_decl_list","glob_decl",
+"type","decl_list","decl","decl_id","cond_expr","ao_expr","arith_expr","term",
+"factor","lvalue","variable","arg_list","stmt_list","stmt","block","@1","block_end",
+"if_stmt","@2","else_part","@3","while_stmt","@4","assgn_stmt","return_stmt",
+"func_decl","func_decl_begin","func_decl_end","par_list","par_decl", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    32,    32,    33,    33,    34,    34,    34,    35,    35,    36,
+    37,    38,    38,    38,    39,    39,    39,    39,    39,    39,
+    39,    40,    40,    40,    41,    41,    41,    42,    42,    42,
+    42,    42,    43,    43,    44,    45,    45,    46,    46,    47,
+    47,    47,    47,    47,    49,    48,    50,    50,    50,    50,
+    52,    51,    53,    54,    53,    56,    55,    57,    58,    59,
+    60,    61,    61,    62,    62,    63
+};
+
+static const short yyr2[] = {     0,
+     2,     1,     1,     1,     1,     1,     4,     2,     1,     3,
+     1,     3,     3,     1,     3,     3,     3,     3,     3,     3,
+     3,     3,     3,     1,     3,     3,     1,     3,     1,     4,
+     3,     1,     4,     1,     1,     3,     1,     2,     1,     1,
+     1,     1,     1,     1,     0,     3,     3,     2,     2,     1,
+     0,     7,     0,     0,     3,     0,     6,     4,     3,     2,
+     3,     3,     2,     3,     1,     2
+};
+
+static const short yydefact[] = {     0,
+     5,     6,     0,     2,     0,     4,     3,     0,     1,    11,
+     0,     0,     0,     0,    60,     0,    65,    29,    35,     0,
+     0,    24,    27,    32,    34,    10,    61,    45,    63,    66,
+     0,     0,     0,     7,     0,     0,     0,     0,     0,     0,
+     0,    62,    64,    28,    22,    23,    25,    26,     0,    31,
+    37,     0,     0,     0,     0,    50,     0,     0,     9,     0,
+    32,     0,    39,    44,    46,    40,    41,    42,    43,    33,
+    30,     0,     0,     0,     0,     0,    49,     8,     0,     0,
+    48,    38,    36,     0,     0,    14,     0,     0,    59,    47,
+     0,     0,     0,     0,     0,    51,     0,     0,     0,     0,
+     0,     0,    56,    58,    21,    12,    13,     0,    19,    20,
+    16,    15,    17,    18,     0,    53,    57,    54,    52,     0,
+    55,     0,     0
+};
+
+static const short yydefgoto[] = {     3,
+     4,     5,    58,     6,    12,    85,    86,    87,    22,    23,
+    24,    25,    52,    62,    63,    64,    41,    65,    66,   108,
+   119,   120,    67,   115,    68,    69,     7,     8,    15,    16,
+    17
+};
+
+static const short yypact[] = {    33,
+-32768,-32768,   148,-32768,    27,-32768,-32768,     0,-32768,-32768,
+    50,    75,   -21,    27,-32768,   128,-32768,-32768,-32768,    50,
+    25,   102,    -5,-32768,    32,-32768,-32768,-32768,-32768,-32768,
+   -21,    33,   137,-32768,    50,    50,    50,    50,    50,    44,
+    10,-32768,-32768,-32768,   102,   102,    -5,    -5,    46,-32768,
+   133,   131,    78,    81,    50,-32768,    27,    53,-32768,    -5,
+    55,    93,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,    50,    57,    57,    56,    60,-32768,-32768,   105,    50,
+-32768,-32768,   133,    57,    62,-32768,   125,    95,-32768,-32768,
+    74,    97,   118,    57,    57,-32768,    50,    50,    50,    50,
+    50,    50,-32768,-32768,-32768,-32768,-32768,   -21,   133,   133,
+   133,   133,   133,   133,   -21,   103,-32768,-32768,-32768,   -21,
+-32768,    85,-32768
+};
+
+static const short yypgoto[] = {-32768,
+   117,    -6,-32768,   -24,   -11,   -47,    70,   -10,   132,   -30,
+   -37,-32768,-32768,    64,   -43,   -13,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+    99
+};
+
+
+#define	YYLAST		168
+
+
+static const short yytable[] = {    29,
+    21,    14,    30,    61,     1,     2,    47,    48,    28,    33,
+    60,    39,    18,    19,     1,     2,    59,    42,    82,    53,
+    61,    54,    55,    13,    61,    14,    88,    60,    49,    51,
+    10,    60,    20,    78,    57,    82,    92,     1,     2,    28,
+    56,    61,    34,    11,    75,    76,    18,    19,    60,    35,
+    36,    57,    18,    19,    40,    18,    19,     1,     2,    18,
+    19,    83,    53,    70,    54,    55,    20,    50,    80,    91,
+    35,    36,    20,    93,    89,    20,    94,    95,    26,    84,
+    35,    36,    28,    77,   123,    96,   109,   110,   111,   112,
+   113,   114,   104,    26,   116,    18,    19,    27,    35,    36,
+    73,   117,    53,    74,    54,    55,   121,    18,    19,    94,
+    95,    94,    95,   118,    53,    20,    54,    55,   103,     9,
+   105,    79,    28,    81,    97,    98,    99,    20,    37,    38,
+    43,    97,    98,    99,    28,    90,     0,   100,   101,   102,
+     0,    44,    35,    36,   100,   101,   102,   122,     0,    35,
+    36,    31,     1,     2,    71,     0,    32,    35,    36,    72,
+    44,    35,    36,   106,   107,     0,    45,    46
+};
+
+static const short yycheck[] = {    13,
+    11,     8,    14,    41,     5,     6,    37,    38,    30,    20,
+    41,    17,     3,     4,     5,     6,    41,    31,    62,    10,
+    58,    12,    13,    24,    62,    32,    74,    58,    39,    40,
+     4,    62,    23,    58,    41,    79,    84,     5,     6,    30,
+    31,    79,    18,    17,    55,    57,     3,     4,    79,    25,
+    26,    58,     3,     4,    23,     3,     4,     5,     6,     3,
+     4,    72,    10,    18,    12,    13,    23,    24,    14,    80,
+    25,    26,    23,    84,    19,    23,    15,    16,    19,    23,
+    25,    26,    30,    31,     0,    24,    97,    98,    99,   100,
+   101,   102,    19,    19,   108,     3,     4,    23,    25,    26,
+    23,   115,    10,    23,    12,    13,   120,     3,     4,    15,
+    16,    15,    16,    11,    10,    23,    12,    13,    24,     3,
+    24,    58,    30,    31,     7,     8,     9,    23,    27,    28,
+    32,     7,     8,     9,    30,    31,    -1,    20,    21,    22,
+    -1,    24,    25,    26,    20,    21,    22,     0,    -1,    25,
+    26,    24,     5,     6,    24,    -1,    29,    25,    26,    29,
+    24,    25,    26,    94,    95,    -1,    35,    36
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.27.  */
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C.  */
+/* This used to test MSDOS, but that is a bad idea
+   since that symbol is in the user namespace.  */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+	 instead, just don't use alloca.  */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+   So I turned it off.   rms, 2 May 1997.  */
+/* #include <malloc.h>  */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+		 and on HPUX 10.  Eventually we can turn this on.  */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    { yychar = (token), yylval = (value);			\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+#ifndef YYPURE
+#define YYLEX		yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int	yychar;			/*  the lookahead symbol		*/
+YYSTYPE	yylval;			/*  the semantic value of the		*/
+				/*  lookahead symbol			*/
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;			/*  location data for the lookahead	*/
+				/*  symbol				*/
+#endif
+
+int yynerrs;			/*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;			/*  nonzero means print parse trace	*/
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/
+
+#ifndef	YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy.  Note that the size argument
+   should be passed with type unsigned int, because that is what the non-GCC
+   definitions require.  With GCC, __builtin_memcpy takes an arg
+   of type size_t, but it can handle unsigned int.  */
+
+#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
+#else				/* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     unsigned int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+  register char *t = to;
+  register char *f = from;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 216 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */
+
+  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
+  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/
+
+  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+  int yyfree_stacks = 0;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;		/*  the variable used to return		*/
+				/*  semantic values from the action	*/
+				/*  routines				*/
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+	 the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+	 but that might be undefined if yyoverflow is a macro.  */
+
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yyls1, size * sizeof (*yylsp),
+		 &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	{
+	  yyerror("parser stack overflow");
+	  if (yyfree_stacks)
+	    {
+	      free (yyss);
+	      free (yyvs);
+#ifdef YYLSP_NEEDED
+	      free (yyls);
+#endif
+	    }
+	  return 2;
+	}
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+      yyfree_stacks = 1;
+#endif
+      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1,
+		   size * (unsigned int) sizeof (*yyssp));
+      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+		   size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1,
+		   size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+	{
+	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise meaning
+	     of a token, for further debugging info.  */
+#ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+#endif
+	  fprintf (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+	       yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 5:
+#line 38 "minicomp.y"
+{yyval=new_type(DOUBLE);;
+    break;}
+case 6:
+#line 39 "minicomp.y"
+{yyval=new_type(INT);;
+    break;}
+case 7:
+#line 40 "minicomp.y"
+{yyval=new_array(yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 10:
+#line 49 "minicomp.y"
+{add_var(yyvsp[-1],yyvsp[-2]);;
+    break;}
+case 11:
+#line 53 "minicomp.y"
+{yyval=add_string(tkname);;
+    break;}
+case 12:
+#line 57 "minicomp.y"
+{yyval=binary_node(NAND,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 13:
+#line 58 "minicomp.y"
+{yyval=binary_node(NOR,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 15:
+#line 63 "minicomp.y"
+{yyval=binary_node(NEQUALS,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 16:
+#line 64 "minicomp.y"
+{yyval=binary_node(NNEQ,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 17:
+#line 65 "minicomp.y"
+{yyval=binary_node(NLT,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 18:
+#line 66 "minicomp.y"
+{yyval=binary_node(NGT,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 19:
+#line 67 "minicomp.y"
+{yyval=binary_node(NLEQ,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 20:
+#line 68 "minicomp.y"
+{yyval=binary_node(NGEQ,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 21:
+#line 69 "minicomp.y"
+{yyval=yyvsp[-1];
+    break;}
+case 22:
+#line 72 "minicomp.y"
+{yyval=binary_node(NADD,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 23:
+#line 73 "minicomp.y"
+{yyval=binary_node(NSUB,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 25:
+#line 77 "minicomp.y"
+{yyval=binary_node(NMUL,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 26:
+#line 78 "minicomp.y"
+{yyval=binary_node(NDIV,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 28:
+#line 83 "minicomp.y"
+{yyval=yyvsp[-1];;
+    break;}
+case 29:
+#line 84 "minicomp.y"
+{yyval=number_node();;
+    break;}
+case 30:
+#line 85 "minicomp.y"
+{yyval=binary_node(NCALL,yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 31:
+#line 86 "minicomp.y"
+{yyval=binary_node(NCALL,yyvsp[-2],0);;
+    break;}
+case 33:
+#line 91 "minicomp.y"
+{yyval=binary_node(NINDEX,yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 35:
+#line 96 "minicomp.y"
+{yyval=var_node();;
+    break;}
+case 36:
+#line 100 "minicomp.y"
+{yyval=binary_node(NARG,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 45:
+#line 118 "minicomp.y"
+{enter_block();;
+    break;}
+case 47:
+#line 122 "minicomp.y"
+{leave_block();;
+    break;}
+case 48:
+#line 123 "minicomp.y"
+{leave_block();;
+    break;}
+case 49:
+#line 124 "minicomp.y"
+{leave_block();;
+    break;}
+case 50:
+#line 125 "minicomp.y"
+{leave_block();;
+    break;}
+case 51:
+#line 130 "minicomp.y"
+{if_statement(yyvsp[-1]);;
+    break;}
+case 53:
+#line 134 "minicomp.y"
+{if_end();;
+    break;}
+case 54:
+#line 135 "minicomp.y"
+{if_else();;
+    break;}
+case 55:
+#line 135 "minicomp.y"
+{if_end();;
+    break;}
+case 56:
+#line 140 "minicomp.y"
+{while_statement(yyvsp[-1]);;
+    break;}
+case 57:
+#line 140 "minicomp.y"
+{while_end();;
+    break;}
+case 58:
+#line 144 "minicomp.y"
+{assign_statement(yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 59:
+#line 148 "minicomp.y"
+{return_statement(yyvsp[-1]);;
+    break;}
+case 61:
+#line 156 "minicomp.y"
+{enter_func(yyvsp[-1],yyvsp[-2]);;
+    break;}
+case 62:
+#line 160 "minicomp.y"
+{leave_func();;
+    break;}
+case 63:
+#line 161 "minicomp.y"
+{leave_func();;
+    break;}
+case 66:
+#line 170 "minicomp.y"
+{add_var(yyvsp[0],yyvsp[-1]);;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 542 "/usr/share/bison.simple"
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  int size = 0;
+	  char *msg;
+	  int x, count;
+
+	  count = 0;
+	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+	  for (x = (yyn < 0 ? -yyn : 0);
+	       x < (sizeof(yytname) / sizeof(char *)); x++)
+	    if (yycheck[x + yyn] == x)
+	      size += strlen(yytname[x]) + 15, count++;
+	  msg = (char *) malloc(size + 15);
+	  if (msg != 0)
+	    {
+	      strcpy(msg, "parse error");
+
+	      if (count < 5)
+		{
+		  count = 0;
+		  for (x = (yyn < 0 ? -yyn : 0);
+		       x < (sizeof(yytname) / sizeof(char *)); x++)
+		    if (yycheck[x + yyn] == x)
+		      {
+			strcat(msg, count == 0 ? ", expecting `" : " or `");
+			strcat(msg, yytname[x]);
+			strcat(msg, "'");
+			count++;
+		      }
+		}
+	      yyerror(msg);
+	      free(msg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exceeded");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+ yyacceptlab:
+  /* YYACCEPT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 0;
+
+ yyabortlab:
+  /* YYABORT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 1;
+}
+#line 173 "minicomp.y"
+
+
+#include "minicomplexer.c"
+
diff --git a/minicompg.tab.c b/minicompg.tab.c
new file mode 100755
index 0000000..b27bae0
--- /dev/null
+++ b/minicompg.tab.c
@@ -0,0 +1,1187 @@
+
+/*  A Bison parser, made from minicompg.y
+ by  GNU Bison version 1.27
+  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define	TKNUMBER	257
+#define	TKIDENTIFIER	258
+#define	TKREAL	259
+#define	TKINT	260
+#define	TKLEQ	261
+#define	TKGEQ	262
+#define	TKNEQ	263
+#define	TKIF	264
+#define	TKELSE	265
+#define	TKWHILE	266
+#define	TKRETURN	267
+#define	TKASSIGN	268
+#define	TKAND	269
+#define	TKOR	270
+
+#line 18 "minicompg.y"
+
+#include "minicomp.h"
+
+typedef void *voidptr;
+#define YYSTYPE voidptr
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define	YYFINAL		123
+#define	YYFLAG		-32768
+#define	YYNTBASE	32
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 64)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    23,
+    24,    27,    25,    29,    26,     2,    28,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,    19,    21,
+    20,    22,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+    17,     2,    18,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,    30,     2,    31,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
+     7,     8,     9,    10,    11,    12,    13,    14,    15,    16
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     3,     5,     7,     9,    11,    13,    18,    21,    23,
+    27,    29,    33,    37,    39,    43,    47,    51,    55,    59,
+    63,    67,    71,    75,    77,    81,    85,    87,    91,    93,
+    98,   102,   104,   109,   111,   113,   117,   119,   122,   124,
+   126,   128,   130,   132,   134,   135,   139,   143,   146,   149,
+   151,   152,   160,   161,   162,   166,   167,   174,   179,   183,
+   186,   190,   194,   197,   201,   203
+};
+
+static const short yyrhs[] = {    32,
+    33,     0,    33,     0,    59,     0,    36,     0,     5,     0,
+     6,     0,    34,    17,    40,    18,     0,    35,    36,     0,
+    36,     0,    34,    37,    19,     0,     4,     0,    38,    15,
+    39,     0,    38,    16,    39,     0,    39,     0,    40,    20,
+    40,     0,    40,     9,    40,     0,    40,    21,    40,     0,
+    40,    22,    40,     0,    40,     7,    40,     0,    40,     8,
+    40,     0,    23,    38,    24,     0,    40,    25,    41,     0,
+    40,    26,    41,     0,    41,     0,    41,    27,    42,     0,
+    41,    28,    42,     0,    42,     0,    23,    40,    24,     0,
+     3,     0,    44,    23,    45,    24,     0,    44,    23,    24,
+     0,    43,     0,    42,    17,    40,    18,     0,    44,     0,
+     4,     0,    45,    29,    40,     0,    40,     0,    46,    47,
+     0,    47,     0,    51,     0,    55,     0,    57,     0,    58,
+     0,    48,     0,     0,    30,    49,    50,     0,    35,    46,
+    31,     0,    46,    31,     0,    35,    31,     0,    31,     0,
+     0,    10,    23,    38,    24,    52,    48,    53,     0,     0,
+     0,    11,    54,    48,     0,     0,    12,    23,    38,    24,
+    56,    48,     0,    43,    14,    40,    19,     0,    13,    40,
+    19,     0,    60,    61,     0,    34,    37,    23,     0,    62,
+    24,    48,     0,    24,    48,     0,    62,    29,    63,     0,
+    63,     0,    34,    37,     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+    27,    29,    32,    34,    37,    39,    40,    43,    45,    48,
+    52,    56,    58,    59,    62,    64,    65,    66,    67,    68,
+    69,    72,    73,    74,    77,    78,    79,    82,    84,    85,
+    86,    87,    90,    92,    95,    99,   101,   104,   106,   109,
+   111,   112,   113,   114,   117,   119,   121,   123,   124,   125,
+   129,   130,   133,   135,   135,   139,   140,   143,   147,   151,
+   155,   159,   161,   164,   166,   169
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","TKNUMBER",
+"TKIDENTIFIER","TKREAL","TKINT","TKLEQ","TKGEQ","TKNEQ","TKIF","TKELSE","TKWHILE",
+"TKRETURN","TKASSIGN","TKAND","TKOR","'['","']'","';'","'='","'<'","'>'","'('",
+"')'","'+'","'-'","'*'","'/'","','","'{'","'}'","glob_decl_list","glob_decl",
+"type","decl_list","decl","decl_id","cond_expr","ao_expr","arith_expr","term",
+"factor","lvalue","variable","arg_list","stmt_list","stmt","block","@1","block_end",
+"if_stmt","@2","else_part","@3","while_stmt","@4","assgn_stmt","return_stmt",
+"func_decl","func_decl_begin","func_decl_end","par_list","par_decl", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    32,    32,    33,    33,    34,    34,    34,    35,    35,    36,
+    37,    38,    38,    38,    39,    39,    39,    39,    39,    39,
+    39,    40,    40,    40,    41,    41,    41,    42,    42,    42,
+    42,    42,    43,    43,    44,    45,    45,    46,    46,    47,
+    47,    47,    47,    47,    49,    48,    50,    50,    50,    50,
+    52,    51,    53,    54,    53,    56,    55,    57,    58,    59,
+    60,    61,    61,    62,    62,    63
+};
+
+static const short yyr2[] = {     0,
+     2,     1,     1,     1,     1,     1,     4,     2,     1,     3,
+     1,     3,     3,     1,     3,     3,     3,     3,     3,     3,
+     3,     3,     3,     1,     3,     3,     1,     3,     1,     4,
+     3,     1,     4,     1,     1,     3,     1,     2,     1,     1,
+     1,     1,     1,     1,     0,     3,     3,     2,     2,     1,
+     0,     7,     0,     0,     3,     0,     6,     4,     3,     2,
+     3,     3,     2,     3,     1,     2
+};
+
+static const short yydefact[] = {     0,
+     5,     6,     0,     2,     0,     4,     3,     0,     1,    11,
+     0,     0,     0,     0,    60,     0,    65,    29,    35,     0,
+     0,    24,    27,    32,    34,    10,    61,    45,    63,    66,
+     0,     0,     0,     7,     0,     0,     0,     0,     0,     0,
+     0,    62,    64,    28,    22,    23,    25,    26,     0,    31,
+    37,     0,     0,     0,     0,    50,     0,     0,     9,     0,
+    32,     0,    39,    44,    46,    40,    41,    42,    43,    33,
+    30,     0,     0,     0,     0,     0,    49,     8,     0,     0,
+    48,    38,    36,     0,     0,    14,     0,     0,    59,    47,
+     0,     0,     0,     0,     0,    51,     0,     0,     0,     0,
+     0,     0,    56,    58,    21,    12,    13,     0,    19,    20,
+    16,    15,    17,    18,     0,    53,    57,    54,    52,     0,
+    55,     0,     0
+};
+
+static const short yydefgoto[] = {     3,
+     4,     5,    58,     6,    12,    85,    86,    87,    22,    23,
+    24,    25,    52,    62,    63,    64,    41,    65,    66,   108,
+   119,   120,    67,   115,    68,    69,     7,     8,    15,    16,
+    17
+};
+
+static const short yypact[] = {    33,
+-32768,-32768,   148,-32768,    27,-32768,-32768,     0,-32768,-32768,
+    50,    75,   -21,    27,-32768,   128,-32768,-32768,-32768,    50,
+    25,   102,    -5,-32768,    32,-32768,-32768,-32768,-32768,-32768,
+   -21,    33,   137,-32768,    50,    50,    50,    50,    50,    44,
+    10,-32768,-32768,-32768,   102,   102,    -5,    -5,    46,-32768,
+   133,   131,    78,    81,    50,-32768,    27,    53,-32768,    -5,
+    55,    93,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,    50,    57,    57,    56,    60,-32768,-32768,   105,    50,
+-32768,-32768,   133,    57,    62,-32768,   125,    95,-32768,-32768,
+    74,    97,   118,    57,    57,-32768,    50,    50,    50,    50,
+    50,    50,-32768,-32768,-32768,-32768,-32768,   -21,   133,   133,
+   133,   133,   133,   133,   -21,   103,-32768,-32768,-32768,   -21,
+-32768,    85,-32768
+};
+
+static const short yypgoto[] = {-32768,
+   117,    -6,-32768,   -24,   -11,   -47,    70,   -10,   132,   -30,
+   -37,-32768,-32768,    64,   -43,   -13,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+    99
+};
+
+
+#define	YYLAST		168
+
+
+static const short yytable[] = {    29,
+    21,    14,    30,    61,     1,     2,    47,    48,    28,    33,
+    60,    39,    18,    19,     1,     2,    59,    42,    82,    53,
+    61,    54,    55,    13,    61,    14,    88,    60,    49,    51,
+    10,    60,    20,    78,    57,    82,    92,     1,     2,    28,
+    56,    61,    34,    11,    75,    76,    18,    19,    60,    35,
+    36,    57,    18,    19,    40,    18,    19,     1,     2,    18,
+    19,    83,    53,    70,    54,    55,    20,    50,    80,    91,
+    35,    36,    20,    93,    89,    20,    94,    95,    26,    84,
+    35,    36,    28,    77,   123,    96,   109,   110,   111,   112,
+   113,   114,   104,    26,   116,    18,    19,    27,    35,    36,
+    73,   117,    53,    74,    54,    55,   121,    18,    19,    94,
+    95,    94,    95,   118,    53,    20,    54,    55,   103,     9,
+   105,    79,    28,    81,    97,    98,    99,    20,    37,    38,
+    43,    97,    98,    99,    28,    90,     0,   100,   101,   102,
+     0,    44,    35,    36,   100,   101,   102,   122,     0,    35,
+    36,    31,     1,     2,    71,     0,    32,    35,    36,    72,
+    44,    35,    36,   106,   107,     0,    45,    46
+};
+
+static const short yycheck[] = {    13,
+    11,     8,    14,    41,     5,     6,    37,    38,    30,    20,
+    41,    17,     3,     4,     5,     6,    41,    31,    62,    10,
+    58,    12,    13,    24,    62,    32,    74,    58,    39,    40,
+     4,    62,    23,    58,    41,    79,    84,     5,     6,    30,
+    31,    79,    18,    17,    55,    57,     3,     4,    79,    25,
+    26,    58,     3,     4,    23,     3,     4,     5,     6,     3,
+     4,    72,    10,    18,    12,    13,    23,    24,    14,    80,
+    25,    26,    23,    84,    19,    23,    15,    16,    19,    23,
+    25,    26,    30,    31,     0,    24,    97,    98,    99,   100,
+   101,   102,    19,    19,   108,     3,     4,    23,    25,    26,
+    23,   115,    10,    23,    12,    13,   120,     3,     4,    15,
+    16,    15,    16,    11,    10,    23,    12,    13,    24,     3,
+    24,    58,    30,    31,     7,     8,     9,    23,    27,    28,
+    32,     7,     8,     9,    30,    31,    -1,    20,    21,    22,
+    -1,    24,    25,    26,    20,    21,    22,     0,    -1,    25,
+    26,    24,     5,     6,    24,    -1,    29,    25,    26,    29,
+    24,    25,    26,    94,    95,    -1,    35,    36
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.27.  */
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C.  */
+/* This used to test MSDOS, but that is a bad idea
+   since that symbol is in the user namespace.  */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+	 instead, just don't use alloca.  */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+   So I turned it off.   rms, 2 May 1997.  */
+/* #include <malloc.h>  */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+		 and on HPUX 10.  Eventually we can turn this on.  */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    { yychar = (token), yylval = (value);			\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+#ifndef YYPURE
+#define YYLEX		yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int	yychar;			/*  the lookahead symbol		*/
+YYSTYPE	yylval;			/*  the semantic value of the		*/
+				/*  lookahead symbol			*/
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;			/*  location data for the lookahead	*/
+				/*  symbol				*/
+#endif
+
+int yynerrs;			/*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;			/*  nonzero means print parse trace	*/
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/
+
+#ifndef	YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy.  Note that the size argument
+   should be passed with type unsigned int, because that is what the non-GCC
+   definitions require.  With GCC, __builtin_memcpy takes an arg
+   of type size_t, but it can handle unsigned int.  */
+
+#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
+#else				/* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     unsigned int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+  register char *t = to;
+  register char *f = from;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 216 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */
+
+  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
+  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/
+
+  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+  int yyfree_stacks = 0;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;		/*  the variable used to return		*/
+				/*  semantic values from the action	*/
+				/*  routines				*/
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+	 the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+	 but that might be undefined if yyoverflow is a macro.  */
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yyls1, size * sizeof (*yylsp),
+		 &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	{
+	  yyerror("parser stack overflow");
+	  if (yyfree_stacks)
+	    {
+	      free (yyss);
+	      free (yyvs);
+#ifdef YYLSP_NEEDED
+	      free (yyls);
+#endif
+	    }
+	  return 2;
+	}
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+      yyfree_stacks = 1;
+#endif
+      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1,
+		   size * (unsigned int) sizeof (*yyssp));
+      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+		   size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1,
+		   size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+	{
+	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise meaning
+	     of a token, for further debugging info.  */
+#ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+#endif
+	  fprintf (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+	       yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 5:
+#line 38 "minicompg.y"
+{yyval=new_type(DOUBLE);;
+    break;}
+case 6:
+#line 39 "minicompg.y"
+{yyval=new_type(INT);;
+    break;}
+case 7:
+#line 40 "minicompg.y"
+{yyval=new_array(yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 10:
+#line 49 "minicompg.y"
+{add_var(yyvsp[-1],yyvsp[-2]);;
+    break;}
+case 11:
+#line 53 "minicompg.y"
+{yyval=add_string(tkname);;
+    break;}
+case 12:
+#line 57 "minicompg.y"
+{yyval=binary_node(NAND,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 13:
+#line 58 "minicompg.y"
+{yyval=binary_node(NOR,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 15:
+#line 63 "minicompg.y"
+{yyval=binary_node(NEQUALS,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 16:
+#line 64 "minicompg.y"
+{yyval=binary_node(NNEQ,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 17:
+#line 65 "minicompg.y"
+{yyval=binary_node(NLT,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 18:
+#line 66 "minicompg.y"
+{yyval=binary_node(NGT,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 19:
+#line 67 "minicompg.y"
+{yyval=binary_node(NLEQ,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 20:
+#line 68 "minicompg.y"
+{yyval=binary_node(NGEQ,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 21:
+#line 69 "minicompg.y"
+{yyval=yyvsp[-1];
+    break;}
+case 22:
+#line 72 "minicompg.y"
+{yyval=binary_node(NADD,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 23:
+#line 73 "minicompg.y"
+{yyval=binary_node(NSUB,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 25:
+#line 77 "minicompg.y"
+{yyval=binary_node(NMUL,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 26:
+#line 78 "minicompg.y"
+{yyval=binary_node(NDIV,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 28:
+#line 83 "minicompg.y"
+{yyval=yyvsp[-1];;
+    break;}
+case 29:
+#line 84 "minicompg.y"
+{yyval=number_node();;
+    break;}
+case 30:
+#line 85 "minicompg.y"
+{yyval=binary_node(NCALL,yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 31:
+#line 86 "minicompg.y"
+{yyval=binary_node(NCALL,yyvsp[-2],0);;
+    break;}
+case 33:
+#line 91 "minicompg.y"
+{yyval=binary_node(NINDEX,yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 35:
+#line 96 "minicompg.y"
+{yyval=var_node();;
+    break;}
+case 36:
+#line 100 "minicompg.y"
+{yyval=binary_node(NARG,yyvsp[-2],yyvsp[0]);;
+    break;}
+case 45:
+#line 118 "minicompg.y"
+{enter_block();;
+    break;}
+case 47:
+#line 122 "minicompg.y"
+{leave_block();;
+    break;}
+case 48:
+#line 123 "minicompg.y"
+{leave_block();;
+    break;}
+case 49:
+#line 124 "minicompg.y"
+{leave_block();;
+    break;}
+case 50:
+#line 125 "minicompg.y"
+{leave_block();;
+    break;}
+case 51:
+#line 130 "minicompg.y"
+{if_statement(yyvsp[-1]);;
+    break;}
+case 53:
+#line 134 "minicompg.y"
+{if_end();;
+    break;}
+case 54:
+#line 135 "minicompg.y"
+{if_else();;
+    break;}
+case 55:
+#line 135 "minicompg.y"
+{if_end();;
+    break;}
+case 56:
+#line 140 "minicompg.y"
+{while_statement(yyvsp[-1]);;
+    break;}
+case 57:
+#line 140 "minicompg.y"
+{while_end();;
+    break;}
+case 58:
+#line 144 "minicompg.y"
+{assign_statement(yyvsp[-3],yyvsp[-1]);;
+    break;}
+case 59:
+#line 148 "minicompg.y"
+{return_statement(yyvsp[-1]);;
+    break;}
+case 61:
+#line 156 "minicompg.y"
+{enter_func(yyvsp[-1],yyvsp[-2]);;
+    break;}
+case 62:
+#line 160 "minicompg.y"
+{leave_func();;
+    break;}
+case 63:
+#line 161 "minicompg.y"
+{leave_func();;
+    break;}
+case 66:
+#line 170 "minicompg.y"
+{add_var(yyvsp[0],yyvsp[-1]);;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 542 "/usr/share/bison.simple"
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  int size = 0;
+	  char *msg;
+	  int x, count;
+
+	  count = 0;
+	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+	  for (x = (yyn < 0 ? -yyn : 0);
+	       x < (sizeof(yytname) / sizeof(char *)); x++)
+	    if (yycheck[x + yyn] == x)
+	      size += strlen(yytname[x]) + 15, count++;
+	  msg = (char *) malloc(size + 15);
+	  if (msg != 0)
+	    {
+	      strcpy(msg, "parse error");
+
+	      if (count < 5)
+		{
+		  count = 0;
+		  for (x = (yyn < 0 ? -yyn : 0);
+		       x < (sizeof(yytname) / sizeof(char *)); x++)
+		    if (yycheck[x + yyn] == x)
+		      {
+			strcat(msg, count == 0 ? ", expecting `" : " or `");
+			strcat(msg, yytname[x]);
+			strcat(msg, "'");
+			count++;
+		      }
+		}
+	      yyerror(msg);
+	      free(msg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exceeded");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+ yyacceptlab:
+  /* YYACCEPT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 0;
+
+ yyabortlab:
+  /* YYABORT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 1;
+}
+#line 173 "minicompg.y"
+
+
+#include "minicomplexer.c"
+
diff --git a/minicomplexer.c b/minicomplexer.c
new file mode 100755
index 0000000..b337995
--- /dev/null
+++ b/minicomplexer.c
@@ -0,0 +1,79 @@
+
+FILE *infile;
+static int cur_char=' ';
+
+char tkname[MAXLEN];
+
+int yylex()
+{
+  char *p=tkname;
+  int tmp;
+
+  while(isspace(cur_char))
+    cur_char=getc(infile);
+
+  if(isdigit(cur_char)){
+    do{
+      *p++=cur_char;
+      cur_char=getc(infile);
+    }while(isdigit(cur_char));
+    if(cur_char=='.'){
+      *p++=cur_char;
+      cur_char=getc(infile);
+      while(isdigit(cur_char)){
+	*p++=cur_char;
+	cur_char=getc(infile);
+      }
+    }
+    *p++=0;
+    return TKNUMBER;
+  }
+  if(isalpha(cur_char)){
+    do{
+      *p++=cur_char;
+      cur_char=getc(infile);
+    }while(isalnum(cur_char));
+    *p++=0;
+    if(!strcmp(tkname,"int"))
+      return TKINT;
+    if(!strcmp(tkname,"real"))
+      return TKREAL;
+    if(!strcmp(tkname,"if"))
+      return TKIF;
+    if(!strcmp(tkname,"else"))
+      return TKELSE;
+    if(!strcmp(tkname,"while"))
+      return TKWHILE;
+    if(!strcmp(tkname,"return"))
+      return TKRETURN;
+    return TKIDENTIFIER;
+  }
+  tmp=cur_char;
+  cur_char=getc(infile);
+  if(tmp=='!'&&cur_char=='='){
+    cur_char=getc(infile);
+    return TKNEQ;
+  }
+  if(tmp=='<'&&cur_char=='='){
+    cur_char=getc(infile);
+    return TKLEQ;
+  }
+  if(tmp=='>'&&cur_char=='='){
+    cur_char=getc(infile);
+    return TKGEQ;
+  }
+  if(tmp=='&'&&cur_char=='&'){
+    cur_char=getc(infile);
+    return TKAND;
+  }
+  if(tmp=='|'&&cur_char=='|'){
+    cur_char=getc(infile);
+    return TKOR;
+  }
+  if(tmp==':'&&cur_char=='='){
+    cur_char=getc(infile);
+    return TKASSIGN;
+  }
+  return tmp;
+}
+
diff --git a/misra_errors.h b/misra_errors.h
new file mode 100755
index 0000000..d9a128e
--- /dev/null
+++ b/misra_errors.h
@@ -0,0 +1,380 @@
+/* Kapitel 1 */
+1,1,"All code shall conform to ISO 9899:1990 \"Programming languages - Câ\", amended and "
+"corrected by ISO/IEC 9899/COR1:1995, ISO/IEC 9899/AMD1:1995, and ISO/IEC 9899/COR2:1996.",MISRA|MISRA_2004,
+
+1,2,"No reliance shall be placed on undefined or unspecified behaviour.",MISRA|MISRA_2004,
+
+1,3,"Multiple compilers and/or languages shall only be used if there is a common defined "
+"interface standard for object code to which the languages/compilers/assembler conforms",MISRA|MISRA_2004,
+
+1,4,"The compiler/linker shall be checked to ensure that 31 character significance and "
+"case sensitivity are supported for external identifiers",MISRA|MISRA_2004,
+
+1,5,"Floating point implementations should comply with a defined floating-point standard",MISRA|MISRA_2004,
+
+/* Kapitel 2 */
+2,1,"Assembly language shall be encapsulated and isolated",MISRA|MISRA_2004,
+
+2,2,"Source code shall only use /* ... */ style comments",MISRA|MISRA_2004,
+
+2,3,"The character sequence /* shall not be used within a comment",MISRA|MISRA_2004,
+
+2,4,"Sections of code should not be \"commented out\"",MISRA|MISRA_2004,
+
+
+/* Kapitel 3 */
+3,1,"All usage of implementation-defined behaviour shall be documented ",MISRA|MISRA_2004,
+
+3,2,"The character set and corresponding encoding shall be documented",MISRA|MISRA_2004,
+
+3,3,"The implementation of integer division in the chosen compiler should "
+"be determined, documented and taken into account",MISRA|MISRA_2004,
+
+3,4,"All use of the #pragma directive shall be documented and explained",MISRA|MISRA_2004,
+
+3,5,"If it is being relied upon, the implementation-defined behaviour and "
+"packing of bitfields shall be documented",MISRA|MISRA_2004,
+
+3,6,"All libraries used in production code shall be written to comply with "
+"the provisions of this document, and shall have been subject to appropriate validation",MISRA|MISRA_2004,
+
+
+/* Kapitel 4 */
+4,1,"Only those escape sequences that are defined in the ISO C standard shall be used",MISRA|MISRA_2004|MISRA_PREPROC,
+
+4,2,"Trigraphs shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 5*/
+5,1,"Identifiers (internal and external) shall not rely on the significance "
+"of more than 31 characters",MISRA|MISRA_2004,
+
+5,2,"Identifiers in an inner scope shall not use the same name as an identifier "
+"in an outer scope, and therefor hide that identifier",MISRA|MISRA_2004,
+
+5,3,"A typedef name shall be a unique identifier",MISRA|MISRA_2004,
+
+5,4,"A tag name shall be a unique identifier",MISRA|MISRA_2004,
+
+5,5,"No object or function identifier with static storage duration should be reused",MISRA|MISRA_2004,
+
+5,6,"No identifier in one name space should have the same spelling as an identifier "
+"in another name space, with the exception of structure and union member names",MISRA|MISRA_2004,
+
+5,7,"No identifier name should be reused",MISRA|MISRA_2004,
+
+
+/* Kapitel 6 */
+6,1,"The plain char type shall be used only for the storage and use of character values",MISRA|MISRA_2004,
+
+6,2,"signed and unsigned char type shall be used only for the storage and use of numeric values",MISRA|MISRA_2004,
+
+6,3,"typedefs that indicate size and signedness should be used in place of the basic types",MISRA|MISRA_2004,
+
+6,4,"Bit fields shall only be defined to be of type unsigned int or signed int",MISRA|MISRA_2004,
+
+6,5,"Bit fields of type signed int shall be at least 2 bit long",MISRA|MISRA_2004,
+
+
+/* Kapitel 7 */
+7,1,"Octal constants (other than zero) and octal escape sequences shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 8 */
+8,1,"Functions shall have prototype declaration and the prototype shall "
+"be visible at both the function definition and call",MISRA|MISRA_2004,
+
+8,2,"Whenever an object or function is declared or defined, its type shall "
+"be explicitly stated",MISRA|MISRA_2004,
+
+8,3,"For each function parameter the type given in the declaration and "
+"definition shall be identical, and the return type shall also be identical",MISRA|MISRA_2004,
+
+8,4,"If objects or functions are declared more than once their type shall be compatible",MISRA|MISRA_2004,
+
+8,5,"There shall be no definition of objects or functions in a header file",MISRA|MISRA_2004,
+
+8,6,"Functions shall be declared at file scope",MISRA|MISRA_2004,
+
+8,7,"Objects shall be defined at block scope if they are only accessed from "
+"within a single function",MISRA|MISRA_2004,
+
+8,8,"An external object or function shall be declared in one and only one file",MISRA|MISRA_2004,
+
+8,9,"An identifier with external linkage shall have excactly one external definition",MISRA|MISRA_2004,
+
+8,10,"All declarations and definitions of objects and functions at file scope shall "
+"have internal linkage  unless external linkage is required",MISRA|MISRA_2004,
+
+8,11,"The static storage class specifier shall be used in definitions and declarations "
+"of objects and functions that have internal linkage",MISRA|MISRA_2004,
+
+8,12,"When an array is declared with external linkage, its size shall be stated "
+"or defined implicitly be initialisation",MISRA|MISRA_2004,
+
+
+/* Kapitel 9 */
+9,1,"All automatic variables shall have been assigned a value before being used",MISRA|MISRA_2004,
+
+9,2,"Braces shall be used to indicate and match the structure in the non-zero "
+"initialisation of arrays and structures",MISRA|MISRA_2004,
+
+9,3,"In an enumerator list, the \"=\" construct shall not be used to explicitly "
+"initialise members other than the first, unless all items are explicitly initialised",MISRA|MISRA_2004,
+
+
+/* Kapitel 10 */
+10,1,"The value of an expression of integer type shall not be implicitly converted to a different underlying type if: \n"
+"  a) it is not a conversion to a wider integer type of the same signedness, or\n"
+"  b) the expression is complex, or\n"
+"  c) the expression is not constant and is a function argument, or\n"
+"  d) the expression is not constant and is a return expression",MISRA|MISRA_2004,
+
+10,2,"The value of an expression of floating type shall not be implicitly converted to a different type if:\n"
+"  a) it is not a conversion to a wider floating type, or\n"
+"  b) the expression is complex, or\n"
+"  c) the expression is a function argument, or\n"
+"  d) the expression is a return expression\n",MISRA|MISRA_2004,
+
+10,3,"The value of a complex expression of integer type may only be cast "
+"to a atype that is narrower and of the same signedness as the "
+"underlying type of the expression",MISRA|MISRA_2004,
+
+10,4,"The value of a complex expression of floating type may only be cast "
+"to a narrower floating type",MISRA|MISRA_2004,
+
+10,5,"If the bitwise operators ~ and << are applied to an operand of "
+"underlying type unsigned char or unsigned short, the result "
+"shall be immediately cast to the underlying type of the operand",MISRA|MISRA_2004,
+
+10,6,"A \"U\" suffix shall be applied to all constants of unsigned type",MISRA|MISRA_2004,
+
+/* Kapitel 11 */
+11,1,"Conversions shall not be performed between a pointer to a function and any type "
+"other than an integral type",MISRA|MISRA_2004,
+
+11,2,"Conversions shall not be performed between a pointer to object and any type "
+"other than an integral type, another pointer to object type or a pointer to void",MISRA|MISRA_2004,
+
+11,3,"A cast should not be performed between a pointer type and an integral type",MISRA|MISRA_2004,
+
+11,4,"A cast should not be performed between a pointer to object type and a "
+"different pointer to object type.",MISRA|MISRA_2004,
+
+11,5,"A cast shall not be performed that removes any const or volatile qualification "
+"from the type addresses by a pointer",MISRA|MISRA_2004,
+
+
+/* Kapitel 12 */
+12,1,"Limited dependence should be placed on C's operator precedence rules in expressions",MISRA|MISRA_2004,
+
+12,2,"The value of an expression shall be the same under any order of "
+"evaluation that the standard permits",MISRA|MISRA_2004,
+
+12,3,"The sizeof operator shall not be used on expressions that contain side effects",MISRA|MISRA_2004,
+
+12,4,"The right-hand operand of a logical && or || operator shall not "
+"contain side effects",MISRA|MISRA_2004,
+
+12,5,"The operands of a logical && or || shall be primary-expressions",MISRA|MISRA_2004,
+
+12,6,"The operands of logical operators (&&, || and !) should be effectively Boolean, "
+"Expressions that are effectively Booleand should not be used as operands to "
+"eperators other than(&&, || and !)",MISRA|MISRA_2004,
+
+12,7,"Bitweise operators shall not be applied to operands whose underlying type is signed",MISRA|MISRA_2004,
+
+12,8,"The right-hand operand of a shift operator shall lie between zero and one less "
+"than the width in bits of ther underlying type of the left-hand operand.",MISRA|MISRA_2004,
+
+12,9,"The unary minus operator shall not be applied to an expression whose underlying type is unsigned",MISRA|MISRA_2004,
+
+12,10,"The comma operator shall not be used",MISRA|MISRA_2004,
+
+12,11,"Evaluation of constant unsigned integer expressions should not lead to wrap-around",MISRA|MISRA_2004,
+
+12,12,"The underlying bit representation of floating-point values shall not be used",MISRA|MISRA_2004,
+
+12,13,"The increment (++) and decrement (--) operators should not be mixed with other "
+"operators in an expression",MISRA|MISRA_2004,
+
+
+/* Kapitel 13 */
+13,1,"Assignment opetaors shall not be used in expressions that yield a Boolean value",MISRA|MISRA_2004,
+
+13,2,"Tests of a value against zero should be made explicit, unless the operand is effectively Boolean",MISRA|MISRA_2004,
+
+13,3,"Floating-point expressions shall not be tested for equality or inequality",MISRA|MISRA_2004,
+
+13,4,"The controlling expression of a for statement shall not contain any objects of floating type.",MISRA|MISRA_2004,
+
+13,5,"The three expressions of a for statement shall be concerned only with loop control",MISRA|MISRA_2004,
+
+13,6,"Numeric variables being used within a for loop for iteration counting shall not be modified in the body of the loop",MISRA|MISRA_2004,
+
+13,7,"Boolean operations whose results are invariant shall not be permitted",MISRA|MISRA_2004,
+
+
+/* Kapitel 14 */
+14,1,"There shall be no unreachable code",MISRA|MISRA_2004,
+
+14,2,"All non-null statements shall either:\n"
+"  a) have at least one side-effect however executed, or\n"
+"  b) cause control flow to change",MISRA|MISRA_2004,
+
+14,3,"Before preprocessing, a null statement shall only occur on a line by itself; it may be "
+"followed by a comment provided that the first character following the null statement "
+"is a white-space character.",MISRA|MISRA_2004,
+
+14,4,"The goto statement shall not be used",MISRA|MISRA_2004,
+
+14,5,"The continue statement shall not be used",MISRA|MISRA_2004,
+
+14,6,"For any interation statement there shall be at most one braek statement used for loop termination",MISRA|MISRA_2004,
+
+14,7,"A function shall have a single point of exit at the end of the function",MISRA|MISRA_2004,
+
+14,8,"The statement forming the body of a switch, while, do ... while or for statement "
+"shall be a compound statement",MISRA|MISRA_2004,
+
+14,9,"An if (expression) construct shall be followed by a compound statement. The else "
+"keyword shall be followed by either a compound statement, or another if statement",MISRA|MISRA_2004,
+
+14,10,"All if ... else if constructs shall be terminated with an else clause",MISRA|MISRA_2004,
+
+
+/* Kapitel 15 */
+15,1,"A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement",MISRA|MISRA_2004,
+
+15,2,"An unconditional break statement shall terminate every non-empty switch clause",MISRA|MISRA_2004,
+
+15,3,"The final clause of a switch statement shall be the default clause",MISRA|MISRA_2004,
+
+15,4,"A Switch expression shall not represent a value that is effectively Boolean",MISRA|MISRA_2004,
+
+15,5,"Every switch statement shall have at least one case clause",MISRA|MISRA_2004,
+
+
+/* Kapitel 16 */
+16,1,"Functions shall not be defined with a variable number of arguments",MISRA|MISRA_2004,
+
+16,2,"Functions shall not call themselves, either directly or indirectly",MISRA|MISRA_2004,
+
+16,3,"Identifiers shall be given for all of the parameters in a function prototype declaration",MISRA|MISRA_2004,
+
+16,4,"The identifiers used in the declaration and definition of a function shall be identical",MISRA|MISRA_2004,
+
+16,5,"Functions with no parameters shall be declared with parameter type void",MISRA|MISRA_2004,
+
+16,6,"The number of arguments passed to a function shall match the number of parameters",MISRA|MISRA_2004,
+
+16,7,"A pointer parameter in a function prototype should be declared as pointer to  const "
+"if the pointer is not used to modify the addressed object",MISRA|MISRA_2004,
+
+16,8,"All exit paths from a function with non-void return type shall have an explicit "
+"return statement with an expression",MISRA|MISRA_2004,
+
+16,9,"A function identifier shall only be used with either a preceding &, or with a "
+"parenthesised parameter list, which may be empty",MISRA|MISRA_2004,
+
+16,10,"If a function returns error information, then that error information shall be tested",MISRA|MISRA_2004,
+
+
+/* Kapitel 17 */
+17,1,"Pointer arithmetic shall only be applied to pointers that address an array or array element",MISRA|MISRA_2004,
+
+17,2,"Pointer subtraction shall only be apllied to pointers that address elements of the same array",MISRA|MISRA_2004,
+
+17,3,">, >=, <, <= shall not be applied to pointer types except where they point to the same array",MISRA|MISRA_2004,
+
+17,4,"Array indexing shall be the only allowed form of pointer arithmetic",MISRA|MISRA_2004,
+
+17,5,"The declaration of objects should contain no more than 2 levels of pointer indirection",MISRA|MISRA_2004,
+
+17,6,"The address of an object with automatic storage shall not be assigned to an other "
+"object that may persist after the first object has ceased to exist",MISRA|MISRA_2004,
+
+
+/* Kapitel 18 */
+18,1,"All structure and union types shall be complete at the end of a translation unit",MISRA|MISRA_2004,
+
+18,2,"An object shall not be assigned to an overlapping object",MISRA|MISRA_2004,
+
+18,3,"An area of memory shall not be reused for unrelated purposes",MISRA|MISRA_2004,
+
+18,4,"Unions shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 19 */
+19,1,"#include statements in a file should only be preceded by other preprocessor directives or comments",MISRA|MISRA_2004,
+
+19,2,"Non-standard characters should not occur in header file names in #include directives",MISRA|MISRA_2004,
+
+19,3,"The #include directive shall be followed by either a <filename> or \"filename\" sequence",MISRA|MISRA_2004,
+
+19,4,"C macros shall only expand to a braced initialiser, a constant, a parenthesised "
+"expression, a type qualifier, a storage class specifier, or a do-while-zero construct",MISRA|MISRA_2004,
+
+19,5,"Macros shall not be #defined'd or #undef'd within a block",MISRA|MISRA_2004,
+
+19,6,"#undef shall not be used",MISRA|MISRA_2004,
+
+19,7,"A function should be used in preference to a function-like macro",MISRA|MISRA_2004,
+
+19,8,"A function-like macro shall not be invoked without all of its arguments",MISRA|MISRA_2004,
+
+19,9,"Arguments to a function-like macro shall not contain tokens that look like preprocessing directives",MISRA|MISRA_2004,
+
+19,10,"In the definition of a function-like macro each instance of a parameter shall be enclosed "
+"in parentheses unless it is used as the operand of # or ##",MISRA|MISRA_2004,
+
+19,11,"All macro identifiers in preprocessor directives shall be defined before use, except "
+"in #ifdef and #ifndef preprocessor directives and the defined() operator",MISRA|MISRA_2004,
+
+19,12,"There shall be at most one occurrence of the # or ## preprocessor operators in a "
+"single macro definition",MISRA|MISRA_2004,
+
+19,13,"The # and ## preprocessor operators should not be used",MISRA|MISRA_2004,
+
+19,14,"The defined preprocessor operator shall only be used in one of the two standard forms",MISRA|MISRA_2004,
+
+19,15,"Precautions shall be taken in order to prevent the contents of a header file being included twice",MISRA|MISRA_2004,
+
+19,16,"Preprocessing directives shall be syntactically meaningful even when excluded by the preprocessor",MISRA|MISRA_2004,
+
+19,17,"All #else, #elif and #endif preprocessor directives shall reside in the same file as "
+"the #if or #ifdef directive to which they are related",MISRA|MISRA_2004,
+
+
+/* Kapitel 20 */
+20,1,"Reserved  identifiers, macros and functions in the standard library, shall not "
+"be defined, redefined or undefined",MISRA|MISRA_2004,
+
+20,2,"The names of standard library macros, objects and functions shall not be reused",MISRA|MISRA_2004,
+
+20,3,"The validity of values passed to library functions shall be checked",MISRA|MISRA_2004,
+
+20,4,"Dynamic heap memory allocation shall not be used",MISRA|MISRA_2004,
+
+20,5,"The error indicator errno shall not be used",MISRA|MISRA_2004,
+
+20,6,"The macro offsetof, in library <stddef.h>, shall not be used",MISRA|MISRA_2004,
+
+20,7,"The setjmp macro and the longjmp function shall not be used",MISRA|MISRA_2004,
+
+20,8,"The signal handling facilities of <signal.h> shall not be used",MISRA|MISRA_2004,
+
+20,9,"The input/output library <stdio.h> shall not be used in production code",MISRA|MISRA_2004,
+
+20,10,"The library functions atof, atoi and atol from library <stdlib.h> shall not be used",MISRA|MISRA_2004,
+
+20,11,"The library functions abort, exit, getenv and system from library <stdlib.h> shall not be used.",MISRA|MISRA_2004,
+
+20,12,"The time handling functions of library <time.h> shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 21 */
+21,1,"Minimisation of run-time failures shall be ensured by the use of at least one of:\n"
+"  a) static analysis tools/techniques\n"
+"  b) dynamic analysis tools/techniques\n"
+"  c) explicit coding of checks to handle run-time faults",MISRA|MISRA_2004,
diff --git a/opt.c b/opt.c
new file mode 100644
index 0000000..c3cec77
--- /dev/null
+++ b/opt.c
@@ -0,0 +1,2300 @@
+/*  $VER: vbcc (opt.c) $Revision: 1.52 $    */
+/*  allgemeine Routinen fuer den Optimizer und Steuerung der einzelnen  */
+/*  Laeufe                                                              */
+
+#include "opt.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+/*  die naechsten Funktionen sollten evtl. in ic.c                  */
+
+/*  Sind use/change-Listen initialisiert?   */
+int have_alias;
+
+int static_cse=1,dref_cse=1;
+int no_eff_ics,early_eff_ics;
+
+#ifdef ALEX_REG
+extern flowgraph *pFg;
+#endif
+
+void insert_IC(IC *p,IC *new)
+/*  fuegt new hinter p ein; p darf 0 sein                           */
+{
+  if((new->code==ADDI2P||new->code==SUBIFP||new->code==SUBPFP)&&!ISPOINTER(new->typf2))
+    ierror(0);
+  new->prev=p;
+  if(p){
+    new->next=p->next; p->next=new;
+  }else{
+    new->next=first_ic; first_ic=new; 
+  }
+  if(new->next) 
+    new->next->prev=new; 
+  else 
+    last_ic=new;
+  new->q1.am=new->q2.am=new->z.am=0;
+}
+
+#ifndef NO_OPTIMIZER
+
+int gchanged;   /*  Merker, ob Optimierungslauf etwas geaendert hat */
+int norek;      /*  diese Funktion wird nicht rekursiv auf          */
+int nocall;     /*  diese Funktion kehrt nicht zum Caller zurueck   */
+
+void fix_shortop(flowgraph *fg,IC *p)
+{
+  if((p->typf&NQ)<INT&&!shortcut(p->code,p->typf)){
+    static type ta;
+    type *t;
+    IC *new;
+    if(DEBUG&1024){puts("fix shortop");pric2(stdout,p);puts("to;");}
+    ta.flags=int_erw(p->typf);
+    t=arith_typ(&ta,&ta);
+    new=new_IC();
+    new->code=CONVERT;
+    new->q1=p->q1;
+    new->z.flags=VAR;
+    new->z.v=add_tmp_var(clone_typ(t));
+    new->typf2=p->typf|UNSIGNED;
+    new->typf=t->flags|UNSIGNED;
+    p->q1=new->z;
+    insert_IC_fg(fg,p->prev,new);
+    new=new_IC();
+    new->code=CONVERT;
+    new->q1=p->q2;
+    new->z.flags=VAR;
+    new->z.v=add_tmp_var(clone_typ(t));
+    new->typf2=p->typf|UNSIGNED;
+    new->typf=t->flags|UNSIGNED;
+    p->q2=new->z;
+    insert_IC_fg(fg,p->prev,new);
+    new=new_IC();
+    new->code=CONVERT;
+    new->z=p->z;
+    new->q1.flags=VAR;
+    new->q1.v=add_tmp_var(t);
+    new->typf=p->typf|UNSIGNED;
+    new->typf2=t->flags|UNSIGNED;
+    p->z=new->q1;
+    insert_IC_fg(fg,p,new);   
+    p->typf=t->flags|UNSIGNED;
+    if(DEBUG&1024){
+      pric2(stdout,p->prev->prev);
+      pric2(stdout,p->prev);
+      pric2(stdout,p);
+      pric2(stdout,p->next);
+    }
+  }
+}
+
+#if HAVE_LIBCALLS
+extern np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2);
+
+
+/* insert libcalls just before register allocation */
+static int insert_libcalls(flowgraph *fg)
+{
+  IC *p,*next,*add;
+  int replaced=0;
+  static node n,nl,nr;
+  static type t,tl,tr;
+  if(DEBUG&1024) printf("insert_libcalls\n");
+  while(fg){
+    for(p=fg->start;p;p=next){
+      int c=p->code,end=0;
+      char *libname;
+      next=p->next;
+      if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST){
+	if(libname=use_libcall(c,p->typf,p->typf2)){
+	  IC *merk_first,*merk_last;
+	  static node n1,n2;
+	  static type t1,t2;
+	  if(DEBUG&1024){
+	    printf("converting IC to libcall:\n");
+	    pric2(stdout,p);
+	  }
+#if FIXED_SP
+	  {
+	    /* move nested pushs */
+	    IC *m;flowgraph *g=fg;int fd=0,i;
+	    for(i=0;i<p->arg_cnt;i++){
+	      m=p->arg_list[i];
+	      if(m->code==PUSH){
+		Var *v;type *t;IC *new;
+		fd=1;
+		if(DEBUG&1024){
+		  printf("moving push\n");
+		  pric2(stdout,m);
+		}
+		if((m->typf&NQ)==STRUCT) ierror(0);
+		if((m->typf&NQ)==CHAR&&!zmeqto(m->q2.val.vmax,Z1)) ierror(0);
+		t=new_typ();
+		t->flags=m->typf;
+		v=add_tmp_var(t);
+		new=new_IC();
+		new->code=PUSH;
+		new->q2.val.vmax=m->q2.val.vmax;
+		new->typf=m->typf;
+		new->q1.flags=VAR;
+		new->q1.v=v;
+		new->q1.val.vmax=Z0;
+		m->z=new->q1;
+		m->code=ASSIGN;
+		insert_IC_fg(g,p,new);
+		if(DEBUG&1024){
+		  pric2(stdout,m);
+		  pric2(stdout,new);
+		}
+		p->arg_list[i]=new;
+	      }
+	    }
+	  }
+#endif	  
+	  replaced=1;
+	  merk_last=last_ic;
+	  merk_first=first_ic;
+	  first_ic=last_ic=0;
+	  n1.flags=REINTERPRET;
+	  n1.o=p->q1;
+	  n1.ntyp=&t1;
+	  t1.flags=q1typ(p);
+	  if(p->q2.flags){
+	    n2.flags=REINTERPRET;
+	    n2.o=p->q2;
+	    n2.ntyp=&t2;
+	    t2.flags=q2typ(p);
+	    gen_libcall(libname,&n1,&t1,&n2,&t2);
+	  }else
+	    gen_libcall(libname,&n1,&t1,0,0);
+	  if(!last_ic||last_ic->code!=GETRETURN) ierror(0);
+	  last_ic->z=p->z;
+	  add=first_ic;
+	  last_ic=merk_last;
+	  first_ic=merk_first;
+	  for(;add;add=next){
+	    next=add->next;
+	    insert_IC_fg(fg,p->prev,add);
+	  }
+	  next=p->next;
+	  if(fg->end==p) end=1;
+	  if(p->z.flags){
+	    remove_IC_fg(fg,p);
+	  }else{
+	    type *t=new_typ();
+	    t->flags=LIBCALL_CMPTYPE;
+	    p->code=COMPARE;
+	    p->q2.flags=KONST;
+	    gval.vmax=Z0;
+	    eval_const(&gval,MAXINT);
+	    insert_const(&p->q2.val,LIBCALL_CMPTYPE);
+	    p->typf=LIBCALL_CMPTYPE;
+	    p->q1.flags=VAR;
+	    p->q1.v=add_tmp_var(t);
+	    p->q1.val.vmax=l2zm(0L);
+	    p->prev->z=p->q1;
+	    p->z.flags=0;
+	  }
+	}
+      }
+      if(end||p==fg->end) break;
+    }
+    fg=fg->normalout;
+  }
+  return replaced;
+}
+#endif
+
+/*  temporary fuer verschiedene Bitvektoren */
+bvtype *tmp;
+
+int in_varlist(varlist *vl,int cnt,Var *v,int flags)
+{
+  int i;
+  /*FIXME: slow */
+  for(i=0;i<cnt;i++){
+    if(vl[i].v==v&&vl[i].flags==flags) return 1;
+  }
+  return 0;
+}
+
+static void add_call_list(void)
+{
+  IC *p;
+  for(p=first_ic;p;p=p->next){
+    if(p->code==CALL&&p->call_cnt==0){
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+	p->call_cnt=1;
+	p->call_list=mymalloc(sizeof(*p->call_list));
+	p->call_list[0].v=p->q1.v;
+	p->call_list[0].flags=0;
+      }
+    }
+  }
+}
+
+void calc_finfo(Var *v,int flags)
+{
+  IC *p;int i,known,maxtyp,t,c;
+  /* 128 types should be enough for everyone :-) */
+  #define TSIZE BVSIZE(128)
+  static bvtype tf[TSIZE];
+  if(!v->fi) ierror(0);
+  if(flags&CALC_USES){
+    if(v->fi->flags&ALL_USES) return;
+    free(v->fi->use_list);
+    v->fi->use_cnt=0;
+    v->fi->use_list=0;
+    memset(tf,0,TSIZE);
+    known=1;maxtyp=-1;
+    for(p=first_ic;p;p=p->next){
+      c=p->code;
+      if(p->q1.flags&DREFOBJ){
+	t=(q1typ(p)&NQ);
+	if(t>maxtyp) maxtyp=t;
+	BSET(tf,t);
+      }
+      if(p->q2.flags&DREFOBJ){
+	t=(q2typ(p)&NQ);
+	if(t>maxtyp) maxtyp=t;
+	BSET(tf,t);
+      }
+      if(c==CALL){
+	if((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&ALL_USES)){
+	  free(v->fi->use_list);
+	  v->fi->use_cnt=0;
+	  v->fi->use_list=0;
+	  known=0;
+	  break;
+	}else{
+	  for(i=0;i<p->q1.v->fi->use_cnt;i++){
+	    if(p->q1.v->fi->use_list[i].v){
+	      if(!in_varlist(v->fi->use_list,v->fi->use_cnt,p->q1.v->fi->use_list[i].v,p->q1.v->fi->use_list[i].flags)){
+		v->fi->use_cnt++;
+		v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+		v->fi->use_list[v->fi->use_cnt-1]=p->q1.v->fi->use_list[i];
+	      }
+	    }else{
+	      BSET(tf,p->q1.v->fi->use_list[i].flags&NQ);
+	    }
+	  }
+	}
+      }else{
+	for(i=0;i<p->use_cnt;i++){
+	  if(p->use_list[i].v->nesting!=0) continue;
+	  if(!in_varlist(v->fi->use_list,v->fi->use_cnt,p->use_list[i].v,p->use_list[i].flags)){
+	    v->fi->use_cnt++;
+	    v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+	    v->fi->use_list[v->fi->use_cnt-1]=p->use_list[i];
+	  }
+	}
+      }
+    }
+    for(c=0;c<=maxtyp;c++){
+      if(BTST(tf,c)){
+	v->fi->use_cnt++;
+	v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+	v->fi->use_list[v->fi->use_cnt-1].v=0;
+	v->fi->use_list[v->fi->use_cnt-1].flags=c;
+      }
+    }
+    if(known) v->fi->flags|=ALL_USES;
+  }
+  if(flags&CALC_CHANGES){
+    if(v->fi->flags&ALL_MODS) return;
+    free(v->fi->change_list);
+    v->fi->change_cnt=0;
+    v->fi->change_list=0;
+    memset(tf,0,TSIZE);
+    known=1;maxtyp=-1;
+    for(p=first_ic;p;p=p->next){
+      c=p->code;
+      if(p->z.flags&DREFOBJ){
+	t=(ztyp(p)&NQ);
+	if(t>maxtyp) maxtyp=t;
+	BSET(tf,t);
+      }
+      if(c==CALL){
+	if((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&ALL_MODS)){
+	  free(v->fi->change_list);
+	  v->fi->change_cnt=0;	  
+	  v->fi->change_list=0;
+	  known=0;
+	  break;
+	}else{
+	  for(i=0;i<p->q1.v->fi->change_cnt;i++){
+	    if(p->q1.v->fi->change_list[i].v){
+	      if(!in_varlist(v->fi->change_list,v->fi->change_cnt,p->q1.v->fi->change_list[i].v,p->q1.v->fi->change_list[i].flags)){
+		v->fi->change_cnt++;
+		v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+		v->fi->change_list[v->fi->change_cnt-1]=p->q1.v->fi->change_list[i];
+	      }
+	    }else{
+	      BSET(tf,p->q1.v->fi->change_list[i].flags&NQ);
+	    }
+	  }
+	}
+      }else{
+	for(i=0;i<p->change_cnt;i++){
+	  if(p->change_list[i].v->nesting!=0) continue;
+	  if(!in_varlist(v->fi->change_list,v->fi->change_cnt,p->change_list[i].v,p->change_list[i].flags)){
+	    v->fi->change_cnt++;
+	    v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+	    v->fi->change_list[v->fi->change_cnt-1]=p->change_list[i];
+	  }
+	}
+      }
+    }
+    for(c=0;c<=maxtyp;c++){
+      if(BTST(tf,c)){
+	v->fi->change_cnt++;
+	v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+	v->fi->change_list[v->fi->change_cnt-1].v=0;
+	v->fi->change_list[v->fi->change_cnt-1].flags=c;
+      }
+    }
+    if(known) v->fi->flags|=ALL_MODS;
+  }
+  if(flags&CALC_CALLS){
+    if(v->fi->flags&ALL_CALLS) return;
+    free(v->fi->call_list);
+    v->fi->call_list=0;
+    v->fi->call_cnt=0;
+    p=v->fi->opt_ic;
+    if(!p)
+      p=v->fi->first_ic;
+    for(;p;p=p->next){
+      if(p->code==CALL){
+	if(p->q1.flags&DREFOBJ) return;
+	if(!in_varlist(v->fi->call_list,v->fi->call_cnt,p->q1.v,0)){
+	  v->fi->call_cnt++;
+	  v->fi->call_list=myrealloc(v->fi->call_list,v->fi->call_cnt*sizeof(varlist));
+	  v->fi->call_list[v->fi->call_cnt-1].v=p->q1.v;
+	  v->fi->call_list[v->fi->call_cnt-1].flags=0;
+	}
+      }
+    }
+    v->fi->flags|=ALL_CALLS;
+  }
+}
+
+void used_clist(type *t,const_list *cl)
+{
+  int i;zmax l;
+
+  if(ISARRAY(t->flags)){
+    for(l=l2zm(0L);!zmleq(t->size,l)&&cl;l=zmadd(l,l2zm(1L)),cl=cl->next){
+      if(!cl->other){ierror(0);return;}
+      used_clist(t->next,cl->other);
+    }
+    return;
+  }
+  if(ISUNION(t->flags)&&!cl->tree){
+    used_clist((*t->exact->sl)[zm2l(cl->idx)].styp,cl->other);
+    return;
+  }
+  if(ISSTRUCT(t->flags)){
+    type *st;
+    if(!cl||!cl->tree){
+      for(i=0;i<t->exact->count&&cl;i++){
+	st=(*t->exact->sl)[i].styp;
+	if(!(*t->exact->sl)[i].identifier) ierror(0);
+	if(zmeqto(l2zm((long)i),cl->idx)){
+	  if((*t->exact->sl)[i].identifier[0]){
+	    if(cl->other) used_clist(st,cl->other);
+	    cl=cl->next;
+	  }
+	}
+      }
+    }
+    return;
+  }
+  if(cl->tree&&(cl->tree->o.flags&VAR))
+    used_objects(cl->tree->o.v);
+  return;
+}
+
+void used_objects(Var *v)
+{
+  int i;
+  if(v->flags&REFERENCED) return;
+  v->flags|=REFERENCED;
+  if(ISFUNC(v->vtyp->flags)){
+    IC *p;
+    if(!(v->flags&DEFINED)) return;
+    if(!v->fi) ierror(0);
+    for(i=0;i<v->fi->call_cnt;i++){
+      if(v->fi->call_list[i].v->flags&DEFINED)
+	used_objects(v->fi->call_list[i].v);
+    }
+    /*FIXME: use/change aus fi */
+    for(p=v->fi->opt_ic;p;p=p->next){
+      if(p->q1.flags&VAR) used_objects(p->q1.v);
+      if(p->q2.flags&VAR) used_objects(p->q2.v);
+      if(p->z.flags&VAR) used_objects(p->z.v);
+    }
+  }else{
+    if(v->clist) used_clist(v->vtyp,v->clist);
+  }
+}
+
+zmax recalc_start_offset;
+
+static void mark_na(bvtype *tmp,int r,int *eqto)
+{
+  int i;
+  if(r<0||r>=vcount-rcount||BTST(tmp,r)) return;
+  /*if(DEBUG&1024) printf("mark_na %s(%p):\n",vilist[r]->identifier,(void*)vilist[r]);*/
+  BSET(tmp,r);
+  for(i=0;i<vcount-rcount;i++){
+    if(eqto[i]!=r&&eqto[r]!=i) continue;
+    /*if((DEBUG&1024)&&!BTST(tmp,i)) printf("  mark_na %s(%p)\n",vilist[i]->identifier,(void*)vilist[i]);*/
+    mark_na(tmp,i,eqto);
+  }
+}
+
+/* TODO: remove ugly hack by decent exit criteria */
+static int reccheck_maxcnt;
+
+/* check if function v can not call callee */
+static int check_nonrecursive(Var *v,Var *callee)
+{
+  int i;
+  Var *f;
+  if(--reccheck_maxcnt==0) return 0;
+  if(v->fi&&(v->fi->flags&ALL_CALLS)){
+    for(i=0;i<v->fi->call_cnt;i++){
+      f=v->fi->call_list[i].v;
+      if(f==v)
+	return 0;
+      if(!check_nonrecursive(f,callee))
+	return 0;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+static void cnv_static(Var *v)
+{
+  if((v->storage_class==AUTO||v->storage_class==REGISTER)&&zmleq(Z0,v->offset)&&v->reg==0/*&&!(v->flags&CONVPARAMETER)*/){
+    v->storage_class=STATIC;
+    v->offset=++label;
+    v->flags|=(USEDASSOURCE|USEDASDEST|DEFINED|STATICAUTO);
+    if(v->clist){free_clist(v->clist);v->clist=0;}
+    if(DEBUG&1024) printf("changing %s(%p) to static (L%ld)\n",v->identifier,v,zm2l(v->offset));
+  }
+}
+
+/* replace auto variables by statics if possible */
+void replace_statics(Var *v)
+{
+  IC *p;
+  if(DEBUG&1024) printf("replace_statics()\n");
+  if(force_statics||(v->fi&&(v->fi->flags&ALL_CALLS))){
+    if(!force_statics){
+      reccheck_maxcnt=100;
+      if(!check_nonrecursive(v,v))
+	return;
+      if(DEBUG&1024) printf("non-recursive\n");
+    }
+
+    for(p=first_ic;p;p=p->next){
+      if((p->q1.flags&(VAR|REG))==VAR) cnv_static(p->q1.v);
+      if((p->q2.flags&(VAR|REG))==VAR) cnv_static(p->q2.v);
+      if((p->z.flags&(VAR|REG))==VAR) cnv_static(p->z.v);
+
+      if(p->code==ADDRESS&&p->q1.v->storage_class==STATIC){
+	p->code=ASSIGN;
+	p->q1.flags|=VARADR;
+	p->q2.val.vmax=sizetab[p->typf2&NQ];
+	p->typf=p->typf2;
+      }
+    }
+  }
+}
+
+
+void recalc_offsets(flowgraph *g)
+/*  berechnet Offsets fuer auto-Variablen neu und versucht, fuer Variablen, */
+/*  die nicht gleichzeitig aktiv sind, den gleichen Platz zu belegen        */
+{
+  int i,j,b,bcnt,r,*eqto,pass;size_t bsize,vsize;zmax *al,*sz;
+  bvtype **used,*tmp,*empty,*vtmp,*vpos;
+  IC *p;
+  flowgraph *fg;
+
+  if(DEBUG&1024) printf("recalculating offsets\n");
+  if(DEBUG&1024) printf("setting up arrays\n");
+  /*bsize=(basic_blocks+CHAR_BIT-1)/CHAR_BIT; /* we don's use fg->index but count from 0 */
+  bsize=BVSIZE(basic_blocks);
+  if(DEBUG&1024) printf("bsize=%lu\n",(unsigned long)bsize);
+  tmp=mymalloc(bsize);
+  al=mymalloc(sizeof(*al)*(vcount-rcount));
+  eqto=mymalloc(sizeof(int)*(vcount-rcount));
+  sz=mymalloc(sizeof(*sz)*(vcount-rcount));
+  empty=mymalloc(bsize);
+  memset(empty,0,bsize);
+  used=mymalloc(sizeof(bvtype *)*(vcount-rcount));
+  /*  Tabelle, welche Variable in welchem Block belegt ist, aufbauen  */
+  for(i=0;i<vcount-rcount;i++){
+    if((vilist[i]->storage_class==AUTO||vilist[i]->storage_class==REGISTER)&&zmleq(l2zm(0L),vilist[i]->offset)){
+      if(DEBUG&2048) printf("setting up for %s,%ld\n",vilist[i]->identifier,zm2l(vilist[i]->offset));
+      used[i]=mymalloc(bsize);
+      memset(used[i],0,bsize);
+    }else{
+      used[i]=0;
+    }
+    sz[i]=szof(vilist[i]->vtyp);
+    al[i]=falign(vilist[i]->vtyp);
+    eqto[i]=-1;
+  }
+  b=0; fg=g;
+  while(fg){
+    if(b>=basic_blocks) ierror(0);
+    for(i=0;i<vcount-rcount;i++){
+      if(used[i]&&(BTST(fg->av_in,i)||BTST(fg->av_out,i))){
+	BSET(used[i],b);
+	for(r=1;r<=MAXR;r++)
+	  if(fg->regv[r]&&fg->regv[r]->index==i) BCLR(used[i],b);
+      }
+    }
+    for(p=fg->start;p;p=p->next){
+      if((p->q1.flags&(VAR|REG))==VAR){
+	i=p->q1.v->index;
+	if(i!=-1&&i<vcount-rcount){
+	  if(i<0||i>=vcount) ierror(0);
+	  if(i>=0&&used[i]){
+	    BSET(used[i],b);
+	  }
+	}
+      }
+      if((p->q2.flags&(VAR|REG))==VAR){
+	i=p->q2.v->index;
+	if(i!=-1&&i<vcount-rcount){
+	  if(i<0||i>=vcount) ierror(0);
+	  if(i>=0&&used[i]){
+	    BSET(used[i],b);
+	  }
+	}
+      }
+      if((p->z.flags&(VAR|REG))==VAR){
+	i=p->z.v->index;
+	if(i!=-1){
+	  if(i<0||i>=vcount) ierror(0);
+	  if(i>=0&&used[i]){
+	    BSET(used[i],b);
+	  }
+	}
+      }
+      if(p==fg->end) break;
+    }
+    fg=fg->normalout;
+    b++;
+  }
+  bcnt=b;
+
+  if(DEBUG&1024) printf("local recalc\n");
+  vsize=BVSIZE(vcount-rcount);
+  vtmp=mymalloc(vsize);
+  vpos=mymalloc(vsize);
+  j=0;
+  for(fg=g;fg;fg=fg->normalout){
+    bvcopy(vtmp,fg->av_in,vsize);
+    bvunite(vtmp,fg->av_out,vsize);
+    for(r=1;r<=MAXR;r++)
+      if(fg->regv[r]&&fg->regv[r]->index<vcount-rcount) BSET(vtmp,fg->regv[r]->index);
+    for(i=0;i<vcount-rcount;i++){
+      if(!BTST(vtmp,i)){
+	if(!used[i]||!BTST(used[i],j)||(vilist[i]->storage_class!=AUTO&&vilist[i]->storage_class!=REGISTER))
+	  BSET(vtmp,i);
+	else{
+	  for(r=0;r<bcnt;r++)
+	    if(r!=j&&BTST(used[i],r))
+	      BSET(vtmp,i);
+	}
+      }
+    }
+#if 1
+    if(DEBUG&1024){
+      printf("possible for local recalc block %d (%d):\n",j,fg->index);
+      for(i=0;i<vcount-rcount;i++)
+	if(!BTST(vtmp,i))
+	  printf("  %s(%p)\n",vilist[i]->identifier,(void*)vilist[i]);
+    }
+#endif
+    for(p=fg->start;p;p=p->next){
+      if((p->z.flags&(VAR|DREFOBJ))==VAR){
+	b=p->z.v->index;
+	if(b>=0&&b<vcount-rcount&&eqto[b]<0&&!BTST(vtmp,b)){
+	  /* imprecise, but should do the job */
+	  IC *m;
+	  /*if(DEBUG&1024) printf("checking %s(%p)\n",vilist[b]->identifier,(void*)vilist[b]);*/
+	  bvcopy(vpos,vtmp,vsize);
+	  for(m=p->next;m;m=m->next){
+	    if(m->q1.flags&VAR) mark_na(vpos,m->q1.v->index,eqto);
+	    if(m->q2.flags&VAR) mark_na(vpos,m->q2.v->index,eqto);
+	    if(m->z.flags&VAR){
+	      mark_na(vpos,m->z.v->index,eqto);
+	      if(m->z.v->index==b) BSET(vtmp,b);
+	    }
+	    if(m==fg->end) break;
+	  }
+	  for(i=vcount-rcount-1;i>=0;i--){
+	    if(!BTST(vpos,i)&&i!=b){
+	      if(DEBUG&1024) printf("local memory for %s(%p) and %s(%p) equal",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);
+	      eqto[b]=i;
+	      if(!zmleq(al[b],al[i])) al[i]=al[b];
+	      if(!zmleq(sz[b],sz[i])) sz[i]=sz[b];
+	      if(!zmleq(al[i],al[b])) al[b]=al[i];
+	      if(!zmleq(sz[i],sz[b])) sz[b]=sz[i];
+	      if(DEBUG&1024) printf(" sz=%ld al=%ld\n",(long)zm2l(al[i]),(long)zm2l(sz[i]));
+	      BSET(vtmp,i);
+	      /*bvunite(used[i],used[b],bsize);*/
+	      break;
+	    }
+	  }
+	}
+      }
+      if(p==fg->end) break;
+    }
+    j++;
+  }
+  free(vtmp);
+  free(vpos);
+
+
+  /*  schauen, ob Variablen in gleichen Speicher koennen  */
+  if(DEBUG&1024) printf("looking for distinct variables\n");
+  for(i=0;i<vcount-rcount;i++){
+
+    if(!used[i]||eqto[i]>=0) continue;
+    if(!memcmp(used[i],empty,bsize)){ free(used[i]);used[i]=0;continue;}
+    for(b=i+1;b<vcount-rcount;b++){
+      if(!used[b]||eqto[b]>=0) continue;
+      if(!memcmp(used[b],empty,bsize)){ free(used[b]);used[b]=0;continue;}
+      if(DEBUG&2048) printf("comparing %s(%p) and %s(%p)\n",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);
+      
+      memcpy(tmp,used[i],bsize);
+      bvintersect(tmp,used[b],bsize);
+      if(!memcmp(tmp,empty,bsize)){
+	if(DEBUG&1024) printf("memory for %s(%p) and %s(%p) equal\n",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);
+	eqto[b]=i;
+	if(!zmleq(al[b],al[i])) al[i]=al[b];
+	if(!zmleq(sz[b],sz[i])) sz[i]=sz[b];
+	if(!zmleq(al[i],al[b])) al[b]=al[i];
+	if(!zmleq(sz[i],sz[b])) sz[b]=sz[i];
+	bvunite(used[i],used[b],bsize);
+      }
+    }
+  }
+
+  if(DEBUG&1024) printf("propagating sz/al\n");
+  do{
+    if(DEBUG&1024) printf("ppass\n");
+    b=0;
+    for(i=0;i<vcount-rcount;i++){
+      j=i;
+      while((j=eqto[j])>=0){
+	if(!zmleq(sz[j],sz[i])){sz[i]=sz[j];b=1;j=i;if(DEBUG&1024) printf("lmset %d(%p) to sz %ld\n",i,vilist[i],zm2l(sz[i]));}
+	if(!zmleq(sz[i],sz[j])){sz[j]=sz[i];b=1;if(DEBUG&1024) printf("lmset %d(%p) to sz %ld\n",j,vilist[j],zm2l(sz[j]));}
+	if(!zmleq(al[j],al[i])){al[i]=al[j];b=1;j=i;if(DEBUG&1024) printf("lmset %d(%p) to al %ld\n",i,vilist[i],zm2l(al[i]));}
+	if(!zmleq(al[i],al[j])){al[j]=al[i];b=1;if(DEBUG&1024) printf("lmset %d(%p) to al %ld\n",j,vilist[j],zm2l(al[j]));}
+
+      }
+    }
+  }while(b);
+
+  if(DEBUG&1024) printf("final recalculating\n");
+  max_offset=recalc_start_offset;
+  for(pass=0;pass<3;pass++){
+    zmax a;
+    for(a=maxalign;!zmeqto(a,Z0);a=zmsub(a,Z1)){
+      for(i=0;i<vcount-rcount;i++){
+	if(!used[i]) continue;
+	if(!zmeqto(a,al[i])) continue;
+	if(eqto[i]>=0&&pass<2) continue;
+
+	if(pass==0){
+	  if(!zmleq(sz[i],sizetab[MAXINT])&&!zmleq(sz[i],sizetab[LDOUBLE])) continue;
+	}
+	free(used[i]);
+	used[i]=0;
+	if(DEBUG&2048) printf("adjusting offset for %s,%ld(%p)\n",vilist[i]->identifier,zm2l(vilist[i]->offset),(void*)vilist[i]);
+	if(eqto[i]>=0){
+	  j=eqto[i];
+	  do{
+	  }while(used[j]&&(j=eqto[j])>=0);
+	  if(j<0) ierror(0);
+	  if(!zmleq(sz[i],sz[j])) 
+	    {printf("%d(%p) %d(%p) %ld %ld\n",i,vilist[i],j,vilist[j],zm2l(sz[i]),zm2l(sz[j]));ierror(0);}
+	  if(!zmleq(al[i],al[j]))
+	    {printf("%d(%p) %d(%p) %ld %ld\n",i,vilist[i],j,vilist[j],zm2l(al[i]),zm2l(al[j]));ierror(0);}
+	  vilist[i]->offset=vilist[j]->offset;
+	  if(DEBUG&2048) printf("set to %ld (eqto)\n",(long)zm2l(vilist[i]->offset));
+	  continue;
+	}
+	vilist[i]->offset=zmmult(zmdiv(zmadd(max_offset,zmsub(al[i],l2zm(1L))),al[i]),al[i]);
+	max_offset=zmadd(vilist[i]->offset,sz[i]);
+	if(DEBUG&2048) printf("set to %ld (std)\n",(long)zm2l(vilist[i]->offset));
+      }
+    }
+  }
+  recalc_start_offset=l2zm(0L);
+  free(used);
+  free(sz);
+  free(al);
+  free(tmp);
+  free(empty);
+  free(eqto);
+}
+void remove_IC_fg(flowgraph *g,IC *p)
+/*  Entfernt IC p und beachtet Flussgraph. Ausserdem werden             */
+/*  use/change-Listen freigegeben.                                      */
+{
+  if(p->q1.am||p->q2.am||p->z.am) ierror(0);
+  if(have_alias){
+    free(p->use_list);
+    free(p->change_list);
+  }
+  if(g->start==g->end){
+    g->start=g->end=0;
+  }else{
+    if(p==g->end) g->end=p->prev;
+    if(p==g->start) g->start=p->next;
+  }
+  remove_IC(p);
+}
+
+/* function to decide whether a possible const memcpy shall
+   be implemented using typ t; if noptr is non-zero decide
+   if not introducing a pointer is preferable */
+int decide_const_memcpy(IC *p,int typ,int noptr)
+{
+  zmax cnt;
+
+  /* usually int is the most efficient */
+  if(typ==CHAR){
+  }else if(typ==BESTCOPYT){
+    if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+      return 0;
+    if(!zmleq(align[typ],falign(p->z.v->vtyp)))
+      return 0;
+    if(!zmeqto(zmmod(p->z.val.vmax,align[typ]),Z0))
+      return 0;
+  }else
+    return 0;
+  
+  cnt=zmdiv(p->q2.val.vmax,sizetab[typ]);
+
+  if((p->z.flags&(DREFOBJ|KONST))!=DREFOBJ){
+    int sc;
+    if(p->z.flags&DREFOBJ)
+      sc=STATIC;
+    else
+      sc=p->z.v->storage_class;
+    if(sc==AUTO||sc==REGISTER){
+      /* we assume that writes on the stack can be combined */
+      if(typ==CHAR&&noptr)
+	if(zmleq(cnt,zmmult(clist_copy_pointer,sizetab[BESTCOPYT])))
+	  return 1;
+      if(zmleq(cnt,l2zm(clist_copy_stack)))
+	return 1;
+    }else{
+      if(zmleq(cnt,l2zm(clist_copy_static)))
+	return 1;
+    }
+  }
+
+  if(noptr==0&&zmleq(cnt,l2zm(clist_copy_pointer)))
+    return 1;
+
+  return 0;
+}
+
+int insert_const_memcpy(flowgraph *fg)
+{
+  int changed =0;
+  flowgraph *g;
+  for(g=fg;g;g=g->normalout){
+    IC *p;
+    for(p=g->start;p;p=p->next){
+      int c=p->code;
+      
+      /* TODO: finish support for PUSH */
+      if((c==ASSIGN/*||c==PUSH*/)&&(p->q1.flags&(VAR|VARADR|DREFOBJ))==VAR&&p->q1.v->clist&&is_const(p->q1.v->vtyp)){
+	zmax i,sz=p->q2.val.vmax;
+	zuchar zuc;
+	Var *v=p->q1.v;
+	type *t=v->vtyp;
+	int ok=1;
+
+	for(i=Z0;zmleq(i,sz);i=zmadd(i,Z1)){
+	  if(!get_clist_byte(t,v->clist,i,&zuc))
+	    ok=0;
+	}
+	
+	if(ok==1){
+	  int typ=0,noptr=1;
+	  int a1,a2;
+	  if(DEBUG&1024) {printf("can replace const memcpy:\n");pric2(stdout,p);}
+	  
+	  if(c==ASSIGN&&(p->z.flags&(DREFOBJ|KONST))!=DREFOBJ){
+	    if(decide_const_memcpy(p,BESTCOPYT,noptr))
+	      typ=BESTCOPYT;
+	    else if(decide_const_memcpy(p,CHAR,noptr))
+	      typ=CHAR;
+	  }
+	  if(typ==0){
+	    noptr=0;
+	    if(decide_const_memcpy(p,BESTCOPYT,noptr))
+	      typ=BESTCOPYT;
+	    else if(decide_const_memcpy(p,CHAR,noptr))
+	      typ=CHAR;
+	  }
+	  
+	  if(typ){
+	    Var *ptr;
+	    IC *new;
+
+	    if(DEBUG&1024) printf("will do it (typ=%d noptr=%d)\n",typ,noptr);
+	    if(!noptr){
+	      type *pt;
+	      if(p->z.flags&VAR){
+		if(p->z.flags&DREFOBJ){
+		  type *new=new_typ();
+		  new->flags=p->z.dtyp&NQ;
+		  new->next=new_typ();
+		  new->next->flags=typ;
+		  pt=new;
+		}else{
+		  pt=new_typ();
+		  pt->flags=POINTER_TYPE(p->z.v->vtyp);
+		  pt->next=clone_typ(p->z.v->vtyp);
+		}
+	      }else{
+		static type ct={CHAR};
+		type *new;
+		ct.flags=typ;
+		new=new_typ();
+		new->flags=POINTER_TYPE(&ct);
+		new->next=new_typ();
+		new->next->flags=typ;
+		pt=new;
+	      }
+
+	      ptr=add_tmp_var(pt);
+	      new=new_IC();
+	      new->z.flags=VAR;
+	      new->z.v=ptr;
+	      new->q1=p->z;
+	      if(p->z.flags&DREFOBJ){
+		new->code=ASSIGN;
+		new->q1.flags&=~DREFOBJ;
+		new->typf=ptr->vtyp->flags;
+	      }else if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN){
+		new->code=ASSIGN;
+		new->q1.flags|=VARADR;
+		new->typf=ptr->vtyp->flags;
+	      }else if(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER){
+		new->code=ADDRESS;
+		new->typf=p->z.v->vtyp->flags;
+		new->typf2=ptr->vtyp->flags;
+	      }else
+		ierror(0);
+	      new->q2.val.vmax=sizetab[new->typf];
+	      insert_IC_fg(g,p->prev,new);
+	    }
+	    i=Z0;
+	    while(!zmleq(sz,i)){
+	      /* use CHAR for possibly remaining bytes */
+	      if(!zmleq(zmadd(sizetab[typ],i),sz))
+		typ=CHAR;
+	      new=new_IC();
+	      new->code=p->code;
+	      new->typf=typ;
+	      new->q1.flags=KONST;
+	      if(typ==CHAR){
+		if(!get_clist_byte(t,v->clist,zmadd(i,p->q1.val.vmax),&zuc))
+		  ierror(0);
+		new->q1.val.vuchar=zuc;
+	      }else{
+		int state;
+		gval.vmax=get_clist_int(t,v->clist,zmadd(i,p->q1.val.vmax),zm2l(sizetab[typ]),&state);
+		if(!state) ierror(0);
+		eval_const(&gval,MAXINT);
+		insert_const(&new->q1.val,typ);
+	      }
+	      new->q2.val.vmax=sizetab[new->typf];
+	      if(new->code==ASSIGN){
+		if(noptr){
+		  new->z=p->z;
+		  new->z.val.vmax=zmadd(new->z.val.vmax,i);
+		}else{
+		  new->z.flags=VAR|DREFOBJ;
+		  new->z.v=ptr;
+		  new->z.dtyp=ptr->vtyp->flags;
+		}
+	      }else
+		ierror(0); /* TODO: PUSH */
+	      insert_IC_fg(g,p->prev,new);
+	      if(!noptr){
+		new=new_IC();
+		new->code=ADDI2P;
+		new->q1.flags=VAR;
+		new->q1.v=ptr;
+		new->z=new->q1;
+		new->q2.flags=KONST;
+		new->q2.val.vint=zm2zi(sizetab[typ]);
+		new->typf=INT;
+		new->typf2=ptr->vtyp->flags;
+		insert_IC_fg(g,p->prev,new);
+	      }	
+	      i=zmadd(i,sizetab[typ]);
+		
+	    }
+	    remove_IC_fg(g,p);
+	    p=new;
+	    changed=1;
+	  }
+	}
+      }
+      
+      if(p==g->end) break;
+    }
+  }
+  return changed;
+}
+
+/* combines assignments of constants into a larger type */
+void combine_const_assigns(void)
+{
+  static int ctype[BESTCOPYT],i,j;
+  IC *p=first_ic;
+
+  /* calculate table of combine types */
+  for(i=CHAR;i<BESTCOPYT;i++){
+    ctype[i]=0;
+    for(j=BESTCOPYT;j>CHAR;j--){
+      if(zmeqto(sizetab[j],zmadd(sizetab[i],sizetab[i]))){
+	if(DEBUG&1024) printf("possible combine type %s=>%s\n",typname[i],typname[j]);
+	ctype[i]=j;
+	break;
+      }
+    }
+  }
+  while(p){
+    if(p->code==ASSIGN&&(p->q1.flags&(KONST|DREFOBJ))==KONST&&(p->z.flags&(DREFOBJ|VAR))==VAR){
+      IC *p2=p->next;
+      if(p2&&p2->code==ASSIGN&&(p2->q1.flags&(KONST|DREFOBJ))==KONST&&(p2->z.flags&(DREFOBJ|VAR))==VAR&&p->z.v==p2->z.v&&p->typf==p2->typf&&zmeqto(p->q2.val.vmax,p2->q2.val.vmax)&&zmeqto(p2->z.val.vmax,zmadd(p->z.val.vmax,sizetab[p->typf&NQ]))){
+	int dt,t=p->typf&NQ,sc=p->z.v->storage_class;
+	if(t<BESTCOPYT&&(dt=ctype[t])){
+	  zmax os;
+	  /* for stack variables we can use the actual offset, for statics
+	     we rely on the type alignment */
+	  if(sc==AUTO||sc==REGISTER)
+	    os=zmadd(p->z.v->offset,p->z.val.vmax);
+	  else{
+	    if(zmeqto(zmmod(falign(p->z.v->vtyp),align[dt]),Z0))
+	      os=p->z.val.vmax;
+	    else
+	      os=Z1;
+	  }
+	  if(zmeqto(zmmod(os,align[dt]),Z0)){
+	    zumax v1,v2;
+	    if(DEBUG&1024){
+	      printf("combine const assignment:\n");
+	      pric2(stdout,p);
+	      pric2(stdout,p2);
+	    }
+	    p->typf=dt;
+	    p->q2.val.vmax=sizetab[dt];
+	    eval_const(&p->q1.val,t|UNSIGNED);
+	    v1=vmax;
+	    eval_const(&p2->q1.val,t|UNSIGNED);
+	    v2=vmax;
+	    if(BIGENDIAN)
+	      v1=zmlshift(v1,zmmult(sizetab[t],char_bit));
+	    else
+	      v2=zmlshift(v2,zmmult(sizetab[t],char_bit));
+	    gval.vmax=zmor(v1,v2);
+	    eval_const(&gval,MAXINT);
+	    insert_const(&p->q1.val,dt);
+	    if(DEBUG&1024){printf("to:\n"); pric2(stdout,p);}
+	    remove_IC(p2);
+	    if(p->prev) p=p->prev; /* retry for more combining */
+	    continue;
+	  }
+	}
+      }
+    }
+    p=p->next;
+  }
+}
+      
+
+/* allowed to create new variables */
+int early_peephole(void)
+{
+  IC *p;
+  int changed,gchanged=0,c,t;
+  do{
+    changed=0;
+    p=first_ic;
+    while(p){
+      c=p->code;
+      t=p->typf;
+     if(c==COMPARE&&(p->q2.flags&KONST)&&ISINT(p->typf)){
+	case_table *ct;
+	/* TODO: support multiple_ccs */
+	if(!multiple_ccs&&(ct=calc_case_table(p,JUMP_TABLE_DENSITY))&&ct->num>1&&ct->density==1){
+	  int i;
+	  for(i=0;i<ct->num;i++){
+	    if(ct->labels[i]!=ct->labels[0])
+	      break;
+	  }
+	  if(i>=ct->num){
+	    IC *new;
+	    static type ityp;
+	    if(DEBUG&1024) printf("converting cases to range-check\n");
+	    if(multiple_ccs) ierror(0);
+	    new=new_IC();
+	    new->code=SUB;
+	    new->typf=ct->typf;
+	    new->q1=p->q1;
+	    new->q2.flags=KONST;
+	    if(ct->typf&UNSIGNED)
+	      eval_const(&ct->min,UNSIGNED|MAXINT);
+	    else
+	      eval_const(&ct->min,MAXINT);
+	    insert_const(&new->q2.val,ct->typf);
+	    new->z.flags=VAR;
+	    ityp.flags=ct->typf;
+	    new->z.v=add_tmp_var(clone_typ(&ityp));
+	    new->z.val.vmax=l2zm(0L);
+	    insert_IC(p->prev,new);
+	    new=new_IC();
+	    new->code=COMPARE;
+	    new->q1=p->prev->z;
+	    new->z.flags=0;
+	    new->q2.flags=KONST;
+	    new->typf=(ct->typf|UNSIGNED);
+	    gval.vumax=ct->diff;
+	    eval_const(&gval,UNSIGNED|MAXINT);
+	    insert_const(&new->q2.val,new->typf);
+	    insert_IC(p->prev,new);
+	    new=new_IC();
+	    new->code=BLE;
+	    new->typf=ct->labels[0];
+	    insert_IC(p->prev,new);
+ 	    while(p!=ct->next_ic){
+	      IC *m=p->next;
+	      remove_IC(p);
+	      p=m;
+	    }
+	    changed=1;
+	    continue;
+	  }
+	}
+      }
+      p=p->next;
+    }
+    gchanged|=changed;
+  }while(changed);
+  return gchanged;
+}
+
+int peephole()
+/*  macht alle moeglichen Vereinfachungen/Vereinheitlichungen   */
+{
+  IC *p;obj o;int t,c,null,eins,changed,done=0;
+  function_calls=0;
+  do{
+    if(DEBUG&1024) printf("searching for peephole optimizations\n");
+    changed=0;ic_count=0;
+    p=first_ic;
+    while(p){
+      c=p->code;
+      t=p->typf;
+      if(c==NOP&&!p->q1.flags&&!p->q2.flags&&!p->z.flags){
+	IC *m;
+	if(DEBUG&1024) printf("removing nop\n");
+	m=p;p=p->next;
+	remove_IC(m);
+	continue;
+      }
+      ic_count++;
+      if(c==LABEL&&report_suspicious_loops&&p->next&&p->next->code==BRA&&p->next->typf==t){
+	error(208);report_suspicious_loops=0;
+      }
+      if(c==COMPARE&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+	eval_const(&p->q2.val,t);
+	if(ISINT(t)&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
+	  IC *p2=p->next;
+	  if(p2->code==BGE){
+	    vmax=l2zm(0L);insert_const(&gval,MAXINT);
+	    p->q2.val=gval;p2->code=BGT;changed=1;
+	    if(DEBUG&1024) printf("cmp #1 replaced by cmp #0(1)\n");
+	  }else if(p2->code==BLT){
+	    vmax=l2zm(0L);insert_const(&gval,MAXINT);
+	    p->q2.val=gval;p2->code=BLE;changed=1;
+	    if(DEBUG&1024) printf("cmp #1 replaced by cmp #0(2)\n");
+	  }
+	}else if(ISINT(t)&&!(t&UNSIGNED)&&zmeqto(vmax,l2zm(-1L))){
+	  IC *p2=p->next;
+	  if(p2->code==BGT){
+	    vmax=l2zm(0L);insert_const(&gval,MAXINT);
+	    p->q2.val=gval;p2->code=BGE;changed=1;
+	    if(DEBUG&1024) printf("cmp #-1 replaced by cmp #0(1)\n");
+	  }else if(p2->code==BLE){
+	    vmax=l2zm(0L);insert_const(&gval,MAXINT);
+	    p->q2.val=gval;p2->code=BLT;changed=1;
+	    if(DEBUG&1024) printf("cmp #-1 replaced by cmp #0\n(2)");
+	  }
+	}else if((t&UNSIGNED)&&zmeqto(vmax,Z0)){
+	  IC *p2=p->next;
+	  if(p2->code==BLT){
+	    if(DEBUG&1024){printf("cmp uns,#0; blt eliminated\n");pric2(stdout,p);}
+	    remove_IC(p);
+	    p=p2->next;
+	    remove_IC(p2);
+	    continue;
+	  }
+	  if(p2->code==BGE){
+	    if(DEBUG&1024){printf("cmp uns,#0; bge to bra\n");pric2(stdout,p);}
+	    remove_IC(p);
+	    p2->code=BRA;
+	    p=p2;
+	    continue;
+	  }
+	  if(p2->code==BLE){
+	    if(DEBUG&1024){printf("cmp uns,#0; ble to beq\n");pric2(stdout,p);}
+	    p2->code=BEQ;
+	  }else if(p2->code==BGT){
+	    if(DEBUG&1024){printf("cmp uns,#0; bgt to bne\n");pric2(stdout,p);}
+	    p2->code=BNE;
+	  }
+	}else if((t&UNSIGNED)&&zmeqto(vmax,Z1)){
+	  IC *p2=p->next;
+	  if(p2->code==BLT){
+	    if(DEBUG&1024){printf("cmp uns,#1; blt to cmp #0;beq\n");pric2(stdout,p);}
+	    gval.vmax=Z0;
+	    eval_const(&gval,MAXINT);
+	    insert_const(&p->q2.val,p->typf);
+	    p2->code=BEQ;
+	  }else if(p2->code==BGE){
+	    if(DEBUG&1024){printf("cmp uns,#1; bge to cmp #0;bne\n");pric2(stdout,p);}
+	    gval.vmax=Z0;
+	    eval_const(&gval,MAXINT);
+	    insert_const(&p->q2.val,p->typf);
+	    p2->code=BNE;
+	  }
+	}
+      }
+      if(c>=BEQ&&c<BRA&&p->next&&p->next->code==BRA&&p->typf==p->next->typf){
+	IC *p2,*m;
+	if(DEBUG&1024){
+	  printf("removing bcc followed by bra\n");
+	  pric2(stdout,p);
+	}
+	m=p->next;
+	p2=p->prev;
+	remove_IC(p);
+	if(p2&&(p2->code==TEST||p2->code==COMPARE)&&p2->z.flags==0){
+	  if(DEBUG&1024){
+	    printf("removing comparison:\n");
+	    pric2(stdout,p2);
+	  }
+	  remove_IC(p2);
+	}
+	p=m;
+	changed=1;
+	continue;
+      }
+      if(c==CALL) function_calls++;
+      if(p->code==COMPARE&&(p->q1.flags&(VAR|VARADR))==(VAR|VARADR)&&(p->q2.flags&(VAR|VARADR))==(VAR|VARADR)&&p->q1.v==p->q2.v){
+	IC *old=p->prev;
+	if(fold(p)){ changed=1; p=old;continue;}
+	p=p->next;continue;
+      }
+      if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+	if(((p->q2.flags&(KONST|DREFOBJ))==KONST)||!p->q2.flags){
+	  IC *old=p->prev;
+	  if(fold(p)){ changed=1; p=old;continue;}
+	  p=p->next;continue;
+	}else{
+	  if(c==ADD||c==MULT||(c>=OR&&c<=AND)||(c==COMPARE&&!(p->z.flags)&&p->next&&p->next->code>=BEQ&&p->next->code<BRA)){ /*  const nach rechts   */
+	    if(DEBUG&1024){ printf("swapped commutative op:\n");pric2(stdout,p);}
+	    o=p->q1;p->q1=p->q2;p->q2=o;
+	    if(c==COMPARE){
+	      IC *br=p->next;
+	      if(br->code==BLT) br->code=BGT;
+	      else if(br->code==BLE) br->code=BGE;
+	      else if(br->code==BGT) br->code=BLT;
+	      else if(br->code==BGE) br->code=BLE;
+	    }
+	  }
+	}
+      }
+      if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+	/*  algebraische Optimierungen  */
+	eval_const(&p->q2.val,q2typ(p));
+	if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))) null=1; else null=0;
+	if(zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))&&zldeqto(vldouble,d2zld(1.0))) eins=1; else eins=0;
+	if(zmeqto(vmax,l2zm(-1L))&&zldeqto(vldouble,d2zld(-1.0))) eins=-1;
+	if(eins<0&&(c==MULT||c==DIV)){
+	  if(DEBUG&1024){ printf("MULT/DIV with (-1) converted to MINUS:\n");pric2(stdout,p);}
+	  p->code=c=MINUS;p->q2.flags=0;
+	  changed=1;
+	}
+#if HAVE_POF2OPT
+	if(((c==MULT)||((c==DIV||c==MOD)&&(t&UNSIGNED)))&&ISINT(t)){
+	  /*  ersetzt mul etc. mit Zweierpotenzen     */
+	  long ln;
+	  if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+	    if(ln=get_pof2(vumax)){
+	      if(c==MOD){
+		vmax=zmsub(vmax,l2zm(1L));
+		p->code=c=AND;
+	      }else{
+		if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+		vmax=l2zm(ln-1);
+	      }
+	      gval.vmax=vmax;
+	      eval_const(&gval,MAXINT);
+	      insert_const(&p->q2.val,t);
+	      p->typf2=p->typf;
+	      changed=1;
+	    }
+	  }
+	}
+#endif
+	if(c==LSHIFT||c==RSHIFT){
+	  zmax size;
+	  size=zmmult(sizetab[q1typ(p)&NQ],char_bit);
+	  if(zmleq(size,vmax)){
+	    if(c==LSHIFT||(q1typ(p)&UNSIGNED)){
+	      if(DEBUG&1024){ printf("lshift converted to ASSIGN 0:\n");pric2(stdout,p);}
+	      o.val.vmax=l2zm(0L);eval_const(&o.val,MAXINT);
+	      insert_const(&p->q1.val,t);p->q1.flags=KONST;
+	      p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+	      changed=1;
+	    }else{
+	      if(DEBUG&1024){ printf("rshift changed to maxlength:\n");pric2(stdout,p);}
+	      o.val.vmax=zmsub(size,l2zm(1L));eval_const(&o.val,MAXINT);
+	      insert_const(&p->q2.val,t);
+	      changed=1;	      
+	    }
+	  }
+	}
+
+	if((c==SUB||c==ADD||c==ADDI2P||c==SUBIFP)&&!(q2typ(p)&UNSIGNED)&&zmleq(vmax,l2zm(0L))&&zldleq(vldouble,d2zld(0.0))){
+	  obj o;int ct=q2typ(p);
+	  o=p->q2;
+	  calc(MINUS,ct,&o.val,0,&o.val,0);
+	  eval_const(&o.val,ct);
+	  if(!zmleq(vmax,l2zm(0L))&&!zldleq(vldouble,d2zld(0.0))){
+	    calc(MINUS,ct,&o.val,0,&o.val,0);
+	    if(!compare_objs(&p->q2,&o,ct)){
+	      if(DEBUG&1024){ printf("SUB converted to ADD:\n");pric2(stdout,p);}
+	      calc(MINUS,ct,&p->q2.val,0,&p->q2.val,0);
+	      if(p->code==ADD) p->code=SUB;
+	      else if(p->code==SUB) p->code=ADD;
+	      else if(p->code==ADDI2P) p->code=SUBIFP;
+	      else if(p->code==SUBIFP) p->code=ADDI2P;
+	      c=p->code;
+	      changed=1;
+	    }
+	  }
+	}
+	if((eins>0&&(c==MULT||c==DIV))||(null&&(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==LSHIFT||c==RSHIFT||c==OR||c==XOR))){
+	  if(DEBUG&1024){ printf("operation converted to simple assignment:\n");pric2(stdout,p);}
+	  if(c==ADDI2P||c==SUBIFP) p->typf=t=p->typf2;
+	  p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+	  changed=1;
+	}
+	if(null&&(c==MULT||c==DIV||c==MOD||c==AND)){
+	  if(c==DIV||c==MOD){ err_ic=p;error(210);err_ic=0;}
+	  if(DEBUG&1024){ printf("operation converted to ASSIGN 0:\n");pric2(stdout,p);}
+	  o.val.vmax=l2zm(0L);eval_const(&o.val,MAXINT);
+	  insert_const(&p->q1.val,t);p->q1.flags=KONST;
+	  p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+	  changed=1;
+	}
+	if((ISINT(t)||fp_assoc)&&(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==MULT||c==LSHIFT||c==RSHIFT||c==OR||c==AND)){
+	  /*  assoziative Operatoren  */
+	  IC *n=p->next;
+	  int nc,tp,tn;
+	  tp=q2typ(p);
+	  if(n){
+	    nc=n->code;
+	    tn=q2typ(n);
+	    if(c==ADD&&nc==SUB) nc=ADD;
+	    if(c==ADDI2P&&nc==SUBIFP) nc=ADDI2P;
+	    if(c==SUB&&nc==ADD) nc=SUB;
+	    if(c==SUBIFP&&nc==ADDI2P) nc=SUBIFP;
+	  }
+	  if(n&&nc==c&&(n->q2.flags&KONST)&&tn==tp&&(!(tn&VOLATILE))&&(p->z.flags&VAR)&&n->q1.flags==p->z.flags&&n->q1.v==p->z.v&&zmeqto(n->q1.val.vmax,p->z.val.vmax)&&!is_volatile_obj(&n->q1)&&!is_volatile_obj(&p->z)){
+	    if(p->q1.flags==p->z.flags&&p->q1.v==p->z.v&&zmeqto(p->q1.val.vmax,p->z.val.vmax)&&!is_volatile_obj(&p->q1)){
+	      if(n->q1.flags==n->z.flags&&n->q1.v==n->z.v&&zmeqto(n->q1.val.vmax,n->z.val.vmax)){
+		if(DEBUG&1024){ printf("using associativity(1) with:\n");pric2(stdout,p);pric2(stdout,p->next);}
+		n->q1=p->q1;
+		if(nc!=n->code){
+		  gval.vmax=l2zm(0L);
+		  eval_const(&gval,MAXINT);
+		  insert_const(&gval,t);
+		  calc(SUB,tn,&gval,&n->q2.val,&n->q2.val,0);
+		  n->code=nc;
+		}
+		if(c==LSHIFT||c==RSHIFT||c==ADDI2P||c==SUB||c==SUBIFP)
+		  calc(ADD,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+		else
+		  calc(c,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+		changed=1;
+		if(DEBUG&1024) printf("must remove first operation\n");
+		n=p;p=p->next;
+		if(have_alias){ free(n->use_list); free(n->change_list); }
+		remove_IC(n);
+		continue;
+	      }
+	    }else{
+	      if(DEBUG&1024){ printf("using associativity(2) with:\n");pric2(stdout,p);pric2(stdout,p->next);}
+	      n->q1=p->q1;
+	      if(nc!=n->code){
+		gval.vmax=l2zm(0L);
+		eval_const(&gval,MAXINT);
+		insert_const(&gval,t);
+		calc(SUB,tn,&gval,&n->q2.val,&n->q2.val,0);
+		n->code=nc;
+	      }
+	      if(c==LSHIFT||c==RSHIFT||c==ADDI2P||c==SUB||c==SUBIFP)
+		calc(ADD,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+	      else
+		calc(c,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+	      changed=1;
+	    }
+	  }
+	}
+	if((c==ADDI2P||c==SUBIFP)&&(p->q1.flags&VARADR)){
+	  /*  add #var,#const -> move #var+const      */
+	  union atyps val;
+	  if(DEBUG&1024){printf("add/sub #var,#const changed to assign:\n");pric2(stdout,p);}
+	  eval_const(&p->q2.val,t);
+	  insert_const(&val,MAXINT);
+	  if(c==ADDI2P)
+	    calc(ADD,MAXINT,&p->q1.val,&val,&p->q1.val,0);
+	  else
+	    calc(SUB,MAXINT,&p->q1.val,&val,&p->q1.val,0);
+	  p->code=c=ASSIGN;
+	  p->q2.flags=0;
+	  p->typf=t=p->typf2;
+	  p->q2.val.vmax=sizetab[t&NQ];
+	  changed=1;
+	}
+	if((c==ADD||c==SUB)&&ISINT(t)&&p->next&&p->next->next){
+	  /*FIXME: using SCRATCH is not nice */
+	  IC *p1=p->next,*p2=p1->next;
+	  if(p1->code==MULT&&p2->code==ADDI2P&&
+	     p1->typf==t&&p2->typf==t&&
+	     (p1->q2.flags&KONST)&&(p->z.flags&(SCRATCH|DREFOBJ))==SCRATCH&&(p1->z.flags&(SCRATCH|DREFOBJ))==SCRATCH&&
+	     !compare_objs(&p->z,&p1->q1,t)&&
+	     !compare_objs(&p1->z,&p2->q2,t)){
+
+	    if(DEBUG&1024){ printf("rearranging array-access(1):\n");pric2(stdout,p);pric2(stdout,p1);pric2(stdout,p2);}
+	    p1->q1=p->q1;
+	    p->q1=p2->q1;
+	    p2->q1=p2->z;
+	    p->z=p2->z;
+	    calc(MULT,t,&p->q2.val,&p1->q2.val,&p->q2.val,0);
+	    if(c==ADD) p->code=ADDI2P; else p->code=SUBIFP;
+	    p->typf2=p2->typf2;
+	    if(!(p->q1.flags&VARADR)){
+	      /* for static addresses it is best to add the constant
+		 part of the offset first (can be folded); for others
+		 the constant part might better be the last, as it can
+		 frequentlz be reduced bz addressing-modes */
+	      if(DEBUG&1024) printf("reversing\n");
+	      p2->q1=p->q1;
+	      p->q1=p->z;
+	      if(p->prev) p->prev->next=p1;
+	      p1->prev=p->prev;
+	      if(p==first_ic) first_ic=p1;
+	      p->next=p2->next;
+	      if(p->next) p->next->prev=p;
+	      p->prev=p2;
+	      p2->next=p;
+	      p=p1;
+	    }
+	    changed=1;continue;
+	  }
+	}
+      }
+      if(p->q1.flags&KONST){
+	/*  algebraische Optimierungen  */
+	eval_const(&p->q1.val,t);
+	if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))) null=1; else null=0;
+	if(null&&(c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)){
+	  if(DEBUG&1024){ printf("operation converted to ASSIGN 0:\n");pric2(stdout,p);}
+	  o.val.vmax=l2zm(0L);eval_const(&o.val,MAXINT);
+	  insert_const(&p->q1.val,t);p->q1.flags=KONST;
+	  p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+	  changed=1;
+	}
+      }
+      if(!USEQ2ASZ&&p->z.flags&&!compare_objs(&p->q2,&p->z,p->typf)){
+	if(c==ADD||c==MULT||(c>=OR&&c<=AND)){
+	  obj o;
+	  if(DEBUG&1024){printf("swapping objs because USEQ2ASZ\n");pric2(stdout,p);}
+	  o=p->q2;p->q2=p->q1;p->q1=o;
+	  /*  kein changed hier!  */
+	}else{pric2(stdout,p); ierror(0);}
+      }
+      if((c==ADD||c==SUB)&&p->next){
+	/*FIXME: using SCRATCH is not nice */
+	IC *p1=p->next;
+	if(p1->code==ADDI2P&&p1->typf==t&&(p->z.flags&(SCRATCH|DREFOBJ))==SCRATCH&&!compare_objs(&p->z,&p1->q2,t)&&zmleq(sizetab[p1->typf2&NQ],sizetab[p1->typf&NQ])){
+	  if(DEBUG&1024){ printf("rearranging array-access(2):\n");pric2(stdout,p);pric2(stdout,p1);}
+	  p1->q2=p->q1;
+	  p->q1=p1->q1;
+	  p->z=p1->z;
+	  p1->q1=p1->z;
+	  if(c==ADD) p->code=c=ADDI2P; else p->code=c=SUBIFP;
+	  p->typf2=p1->typf2;
+	  changed=1;continue;
+	}
+      }
+      if((c==SUB||c==DIV||c==MOD)&&!compare_objs(&p->q1,&p->q2,p->typf)){
+	/*  x-x=0, x/x=1, x%x=0 */
+	if(DEBUG&1024){ printf("i-i, i/i, i%%i converted to ASSIGN 0/1:\n");pric2(stdout,p);}
+	if(c==DIV) o.val.vmax=l2zm(1L); else o.val.vmax=l2zm(0L);
+	eval_const(&o.val,MAXINT);insert_const(&p->q1.val,t);p->q1.flags=KONST;
+	p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+	changed=1;
+      }
+      if(c==ASSIGN&&(p->z.flags&VAR)&&p->z.flags==p->q1.flags&&p->z.v==p->q1.v&&zmeqto(p->z.val.vmax,p->q1.val.vmax)){
+	IC *d;
+	if(DEBUG&1024){ printf("removing redundant move:\n");pric2(stdout,p);}
+	changed=1;
+	d=p; p=p->next;
+	if(have_alias){ free(d->use_list); free(d->change_list);}
+	remove_IC(d); continue;
+      }
+#if 1
+      /* TODO: better decision when to use for which targets? */
+      if(c==CONVERT&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&(p->z.flags&(VAR|DREFOBJ))==VAR&&!is_volatile_ic(p)){
+	IC *p1=p->next;
+	if(p1&&p1->code==CONVERT&&(p->typf2&NQ)==(p1->typf&NQ)&&(p->typf&NQ)==(p1->typf2&NQ)&&zmleq(sizetab[p->typf2&NQ],sizetab[p->typf&NQ])&&!compare_objs(&p->z,&p1->q1,p->typf2)&&!is_volatile_ic(p1)&&ISFLOAT(p->typf)==ISFLOAT(p->typf2)){
+	  if(DEBUG&1024){printf("propagating CONVERTS:\n");pric2(stdout,p);pric2(stdout,p1);}
+	  p1->q1=p->q1;
+	  p1->code=ASSIGN;
+	  p1->q2.val.vmax=sizetab[p1->typf&NQ];
+	  continue;
+	}
+	/* TODO: better decision when to use for which targets? */
+	if(p1&&(p1->code==ADDI2P||p1->code==SUBIFP)&&(p1->typf&NU)==(p->typf&NU)&&!compare_objs(&p->z,&p1->q2,p1->typf)&&!is_volatile_ic(p1)&&(p->typf2&NQ)>=MINADDI2P&&(p->typf2&NQ)<=MAXADDI2P&&zmleq(sizetab[p->typf2&NQ],sizetab[p->typf&NQ])){
+	  if((p->typf2&UNSIGNED)&&(p->typf2&NU)>=MINADDUI2P){
+	    if(DEBUG&1024){printf("propagating CONVERT/ADDI2P:\n");pric2(stdout,p);pric2(stdout,p1);}
+	    p1->q2=p->q1;
+	    p1->typf=p->typf2;
+	    continue;
+	  }
+	}
+      }
+#endif
+      if(c>=BEQ&&c<=BGT){
+	IC *p2=p->prev;
+	if(p2&&p2->code==COMPARE&&!compare_objs(&p->q1,&p2->z,0)){
+	  IC *p3=p2->prev;
+	  if(p3&&p3->code==c){
+	    IC *p4=p3->prev;
+	    if(p4->code==COMPARE&&!compare_objs(&p3->q1,&p4->z,0)
+	       &&!compare_objs(&p2->q1,&p4->q1,p4->typf)&&!compare_objs(&p2->q2,&p4->q2,p4->typf)){
+	      if(DEBUG&1024){printf("removing redundant compare\n");pric2(stdout,p2);pric2(stdout,p);}
+	      p->code=NOP;
+	      p->q1.flags=p->q2.flags=p->z.flags=0;
+	      p->typf=0;
+	      p2->code=NOP;
+	      p2->typf=0;
+	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+	      changed=1;
+	    }
+	  }
+	}
+      }
+
+      if((c==ADDI2P||c==SUBIFP)&&(p->q1.flags&(VARADR|DREFOBJ))==VARADR){
+	IC *p2=p->next;
+	if(p2->code==ADDI2P&&p->typf2==p2->typf2&&!compare_objs(&p->z,&p2->q1,p->typf2)&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+	  if(DEBUG&1024){printf("rearranging ADDI2P to fold VARADR+const\n");pric2(stdout,p);pric2(stdout,p2);}
+	  eval_const(&p2->q2.val,p2->typf);
+	  p->q1.val.vmax=zmadd(p->q1.val.vmax,vmax);
+	  p2->code=ASSIGN;
+	  p2->typf=p2->typf2;
+	  p2->q2.val.vmax=sizetab[p2->typf&NQ];
+	}
+      }
+
+      p=p->next;
+    }
+    if(changed) done|=changed;
+    gchanged|=changed;
+  }while(changed);
+  return done;
+}
+
+void insert_loads()
+/*  Laedt Speicher in temporaere Variablen */
+{
+  IC *p,*new;
+  type t={0},v={VOID};
+  int c;
+  if(DEBUG&1024) printf("insert_loads()\n");
+  for(p=first_ic;p;p=p->next){
+    c=p->code;
+    if(p->typf&VOLATILE) continue;
+    if(p->typf2&VOLATILE) continue;
+    if(p->q2.flags||c==PUSH){
+      if((dref_cse&&(p->q1.flags&DREFOBJ)&&!(p->q1.dtyp&(PVOLATILE|VOLATILE)))||(static_cse&&(p->q1.flags&(VAR|VARADR))==VAR&&(p->q1.v->storage_class==EXTERN||p->q1.v->storage_class==STATIC))){
+        new=new_IC();
+        new->code=ASSIGN;
+	new->typf=q1typ(p);
+	if(ISSCALAR(new->typf)){
+	  new->q1.am=new->q2.am=new->z.am;
+	  new->q1=p->q1;
+	  new->q2.flags=0;
+	  new->q2.val.vmax=sizetab[new->typf&NQ];
+	  new->z.flags=VAR;
+	  new->z.val.vmax=l2zm(0L);
+	  t.flags=new->typf;
+	  if(ISPOINTER(new->typf)) t.next=&v; else t.next=0;
+	  new->z.v=add_tmp_var(clone_typ(&t));
+	  insert_IC(p->prev,new);
+	  p->q1=new->z;
+	}else
+	  free(new);
+      }
+      if((dref_cse&&(p->q2.flags&DREFOBJ)&&!(p->q2.dtyp&(PVOLATILE|VOLATILE)))||(static_cse&&(p->q2.flags&(VAR|VARADR))==VAR&&(p->q2.v->storage_class==EXTERN||p->q2.v->storage_class==STATIC))){
+        new=new_IC();
+        new->code=ASSIGN;
+	new->typf=q2typ(p);
+	if(ISSCALAR(new->typf)){
+	  new->q1.am=new->q2.am=new->z.am;
+	  new->q1=p->q2;
+	  new->q2.flags=0;
+	  new->q2.val.vmax=sizetab[new->typf&NQ];
+	  new->z.flags=VAR;
+	  new->z.val.vmax=l2zm(0L);
+	  t.flags=new->typf;
+	  if(ISPOINTER(new->typf)) t.next=&v; else t.next=0;
+	  new->z.v=add_tmp_var(clone_typ(&t));
+	  insert_IC(p->prev,new);
+	  p->q2=new->z;
+	}else
+	  free(new);
+      }
+      if(p->q2.flags&&((dref_cse&&(p->z.flags&DREFOBJ)&&!(p->z.dtyp&(PVOLATILE|VOLATILE)))||(static_cse&&(p->z.flags&(VAR|VARADR))==VAR&&(p->z.v->storage_class==EXTERN||p->z.v->storage_class==STATIC)))){
+	/* translate x op y -> mem to x op y -> tmp; move tmp -> mem */
+        new=new_IC();
+        new->code=ASSIGN;
+	new->typf=ztyp(p);
+	if(ISSCALAR(new->typf)){
+	  new->q1.am=new->q2.am=new->z.am;
+	  new->z=p->z;
+	  new->q2.flags=0;
+	  new->q2.val.vmax=sizetab[new->typf&NQ];
+	  new->q1.flags=VAR;
+	  new->q1.val.vmax=l2zm(0L);
+	  t.flags=new->typf;
+	  if(ISPOINTER(new->typf)) t.next=&v; else t.next=0;
+	  new->q1.v=add_tmp_var(clone_typ(&t));
+	  insert_IC(p,new);
+	  p->z=new->q1;
+	}else
+	  free(new);
+      }
+    }
+  }
+}
+
+void insert_ccs(void)
+/*  Fuegt Variablen fuer ccs ein.   */
+{
+    IC *p; Var *v; type *t;
+    if(DEBUG&1024) printf("insert_ccs()\n");
+    for(p=first_ic;p;p=p->next){
+        if(p->code==COMPARE||p->code==TEST){
+            p->z.flags=VAR;
+            p->z.val.vmax=l2zm(0L);
+            t=new_typ();
+            t->flags=0;
+            v=add_tmp_var(t);
+            p->z.v=v;
+            p=p->next;
+            if(p->code<BEQ||p->code>BGT){
+                p=p->prev;
+                p->code=NOP;
+                p->q1.flags=p->q2.flags=p->z.flags=0;
+		p->typf=0;
+            }else{
+                p->q1.flags=VAR;
+                p->q1.val.vmax=l2zm(0L);
+                p->q1.v=v;
+            }
+        }
+    }
+}
+
+static int to_be_inlined(Var *v)
+{
+  /* decide whether function should be inlined */
+  int c;IC *p;
+  /* no code available */
+  if(!v->fi||!v->fi->first_ic) return 0;
+  /* marked as noinline */
+  if(v->fi->flags&NO_INLINE) return 0;
+  /* returns something not in a register (FIXME) */
+  if(!ffreturn(v->vtyp->next)&&(v->vtyp->next->flags&NQ)!=VOID) return 0;
+  /* varargs function */
+  if((c=v->vtyp->exact->count)!=0&&(*v->vtyp->exact->sl)[c-1].styp->flags!=VOID)
+    return 0;
+  /* uses variable length arrays */
+  if(v->fi->flags&USES_VLA) return 0;
+  if(v->fi->inline_size>=0){
+    c=v->fi->inline_size;
+  }else{
+    for(c=0,p=v->fi->first_ic;p;p=p->next) c++;
+  }
+  /* try to always inline functions specified as inline */
+  if(v->flags&INLINEFUNC)
+    return 1;
+  if(c>inline_size) return 0;
+  /* we assume that inlining saves size if the number of arguments
+     is larger than the number of ICs + CALL +SETRETURN  */
+  if(optsize&&c-2>(v->vtyp->exact->count)) return 0;
+  return 1;
+}
+
+static int depth_reached;
+
+static int cross_module_inline(int only_full)
+{
+  IC *p,*np,*new,*ip,*cp,*getreturn;
+  Var *v,*vp;
+  int i,c,firstl,lastl,more_passes=0;
+  if(DEBUG&1024) printf("cross_module_inline(only_full=%d)\n",only_full);
+  for(p=first_ic;p;){
+    np=p->next;
+    if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&to_be_inlined(p->q1.v)){
+      zmax pushed=p->q2.val.vmax;
+      IC *gr;
+      v=p->q1.v;
+      if(only_full&&((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&FULL_INLINE))){
+	depth_reached=1;
+      }else{
+	more_passes=1;
+	if(DEBUG&1024){
+	  printf("inlining call to %s\n",p->q1.v->identifier);
+	  for(vp=v->fi->vars;vp;vp=vp->next)
+	    printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);
+	}
+	gr=p->next;
+	while(gr&&gr->code==NOP) gr=gr->next;
+	if(gr&&gr->code==GETRETURN){
+	  getreturn=gr;
+	  np=getreturn->next;
+	}else{
+	  getreturn=0;
+	}
+	/*  Kopien der Variablen erzeugen   */
+	for(vp=v->fi->vars;vp;vp=vp->next){
+	  vp->inline_copy=0;
+	}
+	cp=p;
+	/* find first and last label used */
+	firstl=lastl=0;
+	for(ip=v->fi->first_ic;ip;ip=ip->next){
+	  if(ip->code>=LABEL&&ip->code<=BRA){
+	    if(firstl==0||ip->typf<firstl) firstl=ip->typf;
+	    if(lastl==0||ip->typf>lastl) lastl=ip->typf;
+	  }
+	}
+	/* Argumente einfuegen */
+	vp=v->fi->vars;
+	for(i=0;i<p->arg_cnt;i++){
+	  while(vp&&(!*vp->identifier||(zmleq(l2zm(0L),vp->offset)&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next;
+	  if(!vp)
+	    continue;
+	  if(DEBUG&1024) printf("arg nr. %d to var <%s>\n",i,vp->identifier);
+	  vp->inline_copy=add_tmp_var(clone_typ(vp->vtyp));
+	  ip=p->arg_list[i];
+	  if(ip->code==ASSIGN){
+	    /* find and delete nop for register passing */
+	    IC *nop;
+	    if(!(ip->z.flags&VAR)||ip->z.v->reg==0) ierror(0);
+	    for(nop=ip->next;nop;nop=nop->next){
+	      if(nop->code==NOP&&(nop->q1.flags&(VAR|DREFOBJ))==VAR&&nop->q1.v==ip->z.v)
+		break;
+	    }
+	    if(!nop) ierror(0);
+	    if(np==nop) np=nop->next;
+	    remove_IC(nop);
+	  }else if(ip->code==PUSH){
+	    ip->code=ASSIGN;
+	    pushed=zmsub(pushed,ip->q2.val.vmax);
+	  }else{
+	    pric2(stdout,ip);
+	    ierror(0);
+	  }
+	  ip->typf&=~VOLATILE;
+	  ip->z.flags=VAR;
+	  ip->z.v=vp->inline_copy;
+	  if((ip->z.v->vtyp->flags&NU)!=(ip->typf&NU)){
+	    /* have to convert */
+	    ip->typf2=ip->typf;
+	    ip->typf=ip->z.v->vtyp->flags;
+	    ip->code=CONVERT;
+	  }	  
+	  ip->z.val.vmax=l2zm(0L);
+	  vp=vp->next;
+	}
+	
+	if(!zmeqto(pushed,l2zm(0L))){
+	  /* ueberfluessige PUSHs entfernen */
+	  IC *m;
+	  ip=p->prev;
+	  while(1){
+	    m=ip->prev;
+	    if(ip->code==PUSH){
+	      if(0/*!(c_flags[26]&USEDFLAG)&&ip->q1.flags*/) ierror(0);
+	      if(!zmleq(ip->q2.val.vmax,pushed)) ierror(0);
+	      pushed=zmsub(pushed,ip->q2.val.vmax);
+	      if(np==ip) np=np->next;
+	      remove_IC(ip);
+	      if(zmeqto(pushed,l2zm(0L))) break;
+	    }
+	    if(!m) ierror(0);
+	    ip=m;
+	  }
+	}
+	
+	/*  Code einfuegen und Labels umschreiben   */
+	ip=v->fi->first_ic;
+	while(ip){
+	  Var *iv;
+	  int c;
+	  if(ip->code==CONVERT&&(ip->q1.flags&(VAR|DREFOBJ))==VAR&&(ip->q1.v->flags&CONVPARAMETER)&&(ip->z.flags&(VAR|DREFOBJ))==VAR&&ip->q1.v==ip->z.v){
+	    if(DEBUG&1024) {printf("eliminate oldstyle CONVERT:\n");pric2(stdout,ip);}
+	    ip=ip->next;
+	    continue;
+	  }
+	  new=new_IC();
+	  *new=*ip;
+	  ip->copy=new;
+	  c=ip->code;
+	  /*  evtl. ist ein IC praktisch ein SETRETURN, falls das */
+	  /*  Rueckgabeziel ueber Parameterzeiger angespr. wird   */
+	  if(ip->z.flags&VAR){
+	    iv=ip->z.v;
+	    if(iv->storage_class==AUTO||iv->storage_class==REGISTER||(iv->flags&STATICAUTO)){
+	      if(0/*!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))*/){
+		if(getreturn){
+		  new->z=getreturn->z;
+		}else{
+		  new->code=NOP;
+		  new->q1.flags=new->q2.flags=new->z.flags=0;
+		  new->typf=0;
+		}
+	      }else{
+		if(!iv->inline_copy){
+		  iv->inline_copy=add_tmp_var(clone_typ(iv->vtyp));
+		  iv->inline_copy->reg=iv->reg;
+		}
+		new->z.v=iv->inline_copy;
+	      }/*else if(iv->inline_copy) ierror(0);*/
+	    }
+	  }
+	  /* recreate ADDRESS when inlining STATICAUTO */
+	  if((new->q1.flags&(VAR|VARADR))==(VAR|VARADR)&&(new->q1.v->flags&STATICAUTO)){
+	    if(new->code!=ASSIGN) ierror(0);
+	    if(DEBUG&1024) printf("recreating ADDRESS from STATICAUTO:\n");
+	    if(DEBUG&1024) pric2(stdout,new);
+	    new->code=ADDRESS;
+	    new->q1.flags&=~VARADR;
+	    new->typf2=new->typf;
+	    new->typf=CHAR; /* TODO: Do we restore the old type? */
+	    if(DEBUG&1024) pric2(stdout,new);
+	  }
+	  /*  Kopien aller auto/register Variablen erzeugen   */
+	  if(ip->q1.flags&VAR){
+	    iv=ip->q1.v;
+	    if(iv->storage_class==AUTO||iv->storage_class==REGISTER||(iv->flags&STATICAUTO)){
+	      if(!iv->inline_copy){
+		iv->inline_copy=add_tmp_var(clone_typ(iv->vtyp));
+		iv->inline_copy->reg=iv->reg;
+	      }
+	      new->q1.v=iv->inline_copy;
+	      if(c==ADDRESS) new->q1.v->flags|=USEDASADR;
+	    }/*else if(iv->inline_copy) ierror(0);*/
+	  }
+	  if(ip->q2.flags&VAR){
+	    iv=ip->q2.v;
+	    if(iv->storage_class==AUTO||iv->storage_class==REGISTER||(iv->flags&STATICAUTO)){
+	      if(!iv->inline_copy){
+		iv->inline_copy=add_tmp_var(clone_typ(iv->vtyp));
+		iv->inline_copy->reg=iv->reg;
+	      }
+	      new->q2.v=iv->inline_copy;
+	    }/*else if(iv->inline_copy) ierror(0);*/
+	  }
+	  if(c==CALL){
+	    int i;
+	    function_calls+=1;
+	    new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+	    for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy;
+	  }
+	  if(c>=LABEL&&c<=BRA){
+	    new->typf+=label+1-firstl;
+	  }
+	  if(c==SETRETURN){
+	    if(getreturn){
+	      new->code=ASSIGN;
+	      new->z=getreturn->z;
+	    }else{
+	      new->code=NOP;
+	      new->q1.flags=new->q2.flags=new->z.flags=0;
+	      new->typf=0;
+	    }
+	  }
+	  new->q1.flags&=~SCRATCH;
+	  new->q2.flags&=~SCRATCH;
+	  new->z.flags&=~SCRATCH;
+	  if(new->code==ASSIGN&&!new->q1.flags) ierror(0);
+	  insert_IC(cp,new);
+	  cp=new;
+	  ip=ip->next;
+	}
+	
+	label+=lastl-firstl+1;
+	remove_IC(p);
+	if(getreturn) remove_IC(getreturn);
+      }
+    }
+    p=np;
+  }
+  
+  return more_passes;
+}
+
+#endif
+#define FREEAV free(av_globals);free(av_statics);free(av_drefs);free(av_address);
+void optimize(long flags,Var *function)
+/*  flags:   1=Register, 2=optimize, 4=cse/cp, 8=constant_propagation,  */
+/*          16=dead_assignments, 32=global-optimizations                */
+/*          64=blockweise Registervergabe, 128=loop_optimizations (nur  */
+/*             in Verbindung mit 32), 256=recalc_offsets                */
+{
+#ifndef NO_OPTIMIZER
+  flowgraph *g,*fg=0;
+  int r,i,pass=0,mustrepeat,intask;
+  int lc_freed,lc_done=0;
+  if(!function) ierror(0);
+  norek=nocall=0;
+  report_suspicious_loops=report_weird_code=1;
+  if(!strcmp(function->identifier,"main")){norek=1;nocall=1;}
+  /*  falls main() rekursiv aufgerufen werden kann, muss nomain==0 sein   */
+
+  intask=(function->vattr&&strstr(function->vattr,"taskprio("));
+
+  
+#else
+
+  flags&=1;
+
+#endif
+
+
+  if(flags&2){
+#ifndef NO_OPTIMIZER
+    if(DEBUG&1024) printf("\nOptimizing function %s\n",function->identifier);
+    /*  Variablen fuer ccs einsetzen.   */
+    if(cross_module&&(flags&4096)){
+      int i,notdone=1;
+      for(i=0;notdone;i++){
+	depth_reached=0;
+	notdone=cross_module_inline(i>=inline_depth);
+      }
+      if(!depth_reached){
+	if(!function->fi) function->fi=new_fi();
+	function->fi->flags|=FULL_INLINE;
+	if(DEBUG&1024) printf("function %s set to full-inline\n",function->identifier);
+      }
+    }
+    if(multiple_ccs) insert_ccs();
+    /*  Speicherzugriffe in extra tmp-Vars umleiten, wegen cse */
+    if(flags&4) insert_loads();
+    /*  nur ein pass, wenn nur lokale Optimierungen */
+    if(!(flags&32)) maxoptpasses=1;
+    do{
+      gchanged=0;pass++;
+      av_globals=av_statics=av_address=av_drefs=0;
+      ae_globals=ae_statics=ae_address=ae_drefs=0;
+      cp_globals=cp_statics=cp_address=cp_drefs=0;
+      dlist=0;vilist=0;elist=0;
+      
+      if(DEBUG&1024) printf("\noptimizer (function %s) pass %d\n",function->identifier,pass);
+      early_peephole();
+      num_vars();
+      peephole();
+      fg=jump_optimization();
+      create_alias(fg);
+      if(DEBUG&2048) print_vi();
+
+#if 0
+      if(DEBUG&1024) printf("range analysis\n");
+      range_analysis(fg);
+      myfree(rangebuf);
+      rangebuf=0;
+#endif
+
+      if(flags&8){
+#if 0
+	do{
+	  num_defs();
+	  if(flags&32){
+	    reaching_definitions(fg);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    r=constant_propagation(fg,1);
+	  }else{
+	    r=constant_propagation(fg,0);
+	  }
+	  if(DEBUG&1024) {printf("constant_propagation returned %d\n",r);print_flowgraph(fg);}
+	  if(r){
+	    if(peephole()){free_flowgraph(fg);fg=jump_optimization();}
+	  }
+	  if(r&2){
+	    if(DEBUG&1024) printf("must repeat num_vars\n");
+	    free(vilist);
+	    FREEAV;
+	    num_vars();
+	  }
+	}while(r);
+#endif
+	num_defs();
+	mustrepeat=0;
+
+
+	if(DEBUG&1024) printf("trying constant propagation\n");
+	if(DEBUG&1024) print_flowgraph(fg);
+	if((flags&32)&&!(disable&4))
+	  reaching_definitions(fg);
+	for(g=fg;g;g=g->normalout){
+	  do{
+	    r=constant_propagation(g,(flags&32)&&!(disable&4));
+	    gchanged|=r;
+	    if(r){
+	      IC *p;
+	      if(r&2) mustrepeat=1;
+	      r=0;
+	      for(p=g->start;p;p=p->next){
+		if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(!p->q2.flags||(p->q2.flags&(KONST|DREFOBJ))==KONST)){
+		  if(p->code!=TEST&&p->code!=COMPARE&&fold(p)) r=1;
+		}
+		if(p==g->end) break;
+	      }
+	    }
+	  }while(r);
+	}
+	if(DEBUG&1024) print_flowgraph(fg);
+	free(rd_matrix);
+	free(var_defs);
+	free(defs_kill);
+	free(defs_gen);
+	free(dlist);
+	free_flowgraph(fg);
+	if(mustrepeat){
+	  if(DEBUG&1024) printf("must repeat num_vars()\n");
+	  free(vilist);
+	  FREEAV;
+	  early_peephole();
+	  num_vars();
+	}
+	peephole();
+	fg=jump_optimization();
+      }
+      if(flags&4){
+	int repeat;
+
+	if(early_eff_ics&&!no_eff_ics)
+	  mark_eff_ics();
+
+	do{
+	  do{
+	    num_exp();
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    if(disable&32)
+	      repeat=r=0;
+	    else
+	      repeat=r=cse(fg,0);    /*  local cse   */
+	    if(DEBUG&1024) printf("local cse returned %d\n",r);
+	    gchanged|=r;
+	    if(r){  /*  neue Variablen eingefuegt   */
+	      if(DEBUG&1024) printf("must repeat num_vars\n");
+	      free(vilist);
+	      FREEAV;
+	      num_vars();
+	    }
+	    do{
+	      num_copies();
+	      if(DEBUG&1024) print_flowgraph(fg);
+	      if(disable&128)
+		r=0;
+	      else
+		r=copy_propagation(fg,0);   /*  copy propagation    */
+	      if(DEBUG&1024) printf("local copy propagation returned %d\n",r);
+	      if(r&2){
+		if(DEBUG&1024) printf("must repeat num_vars\n");
+		free(vilist);
+		FREEAV;
+		num_vars();
+	      }
+	      gchanged|=r;repeat|=r;
+	    }while(r);
+	  }while(repeat);
+	  repeat=0;
+	  if(flags&32){
+	    num_exp();
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    available_expressions(fg);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    if(disable&48)
+	      r=0;
+	    else
+	      r=cse(fg,1);
+	    gchanged|=r;repeat|=r;
+	    if(DEBUG&1024) printf("global cse returned %d\n",r);
+	    if(r){  /*  neue Variablen eingefuegt   */
+	      if(DEBUG&1024) printf("must repeat num_vars\n");
+	      free(vilist);
+	      FREEAV;
+	      num_vars();
+	      gchanged|=r;repeat|=r;
+	      do{
+		num_copies();
+		if(DEBUG&1024) print_flowgraph(fg);
+		if(disable&128)
+		  r=0;
+		else
+		  r=copy_propagation(fg,0);   /*  copy propagation    */
+		if(DEBUG&1024) printf("local copy propagation returned %d\n",r);
+		if(r&2){
+		  if(DEBUG&1024) printf("must repeat num_vars\n");
+		  free(vilist);
+		  FREEAV;
+		  num_vars();
+		}
+		gchanged|=r;repeat|=r;
+	      }while(r);
+	    }
+	    num_copies();
+	    available_copies(fg);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    if(disable&192)
+	      r=0;
+	    else
+	      r=copy_propagation(fg,1);   /*  copy propagation    */
+	    if(DEBUG&1024) printf("global copy propagation returned %d\n",r);
+	    if(r&2){
+	      if(DEBUG&1024) printf("must repeat num_vars\n");
+	      free(vilist);
+	      FREEAV;
+	      num_vars();
+	    }
+	    gchanged|=r;repeat|=r;
+	  }
+	}while(0/*repeat*/);
+      }
+      if((flags&160)==160){
+	if(!no_eff_ics)
+	  mark_eff_ics();
+
+	r=loop_optimizations(fg);
+	gchanged|=r;
+	fg=jump_optimization();
+      }
+      if((flags&16)||((flags&1)&&pass>=maxoptpasses)){
+	/*                num_vars();*/
+	free_alias(fg);
+	create_alias(fg);
+	active_vars(fg);
+	if(DEBUG&1024) print_flowgraph(fg);
+	if((flags&16)&&pass<=maxoptpasses){
+	  r=dead_assignments(fg);
+	  if(DEBUG&1024) printf("dead_assignments returned %d\n",r);
+	  gchanged|=r;
+	}
+      }
+
+      if(!gchanged){
+	int r;
+	r=insert_const_memcpy(fg);
+	if(r){
+	  gchanged|=1;
+	  pass--;
+	}
+      }      
+
+#if HAVE_LIBCALLS
+      /* if no further optimizations are found, insert libcalls
+	 and look some more */
+      if(!lc_done&&(!gchanged||pass>=maxoptpasses)){
+	int r;
+	r=insert_libcalls(fg);
+	lc_done=1;
+	if(r){
+	  gchanged|=1;
+	  pass--;
+	}
+      }
+#endif
+      
+      if((!gchanged||pass>=maxoptpasses)){
+	/*  Funktion evtl. fuer inlining vorbereiten und    */
+	/*  Registervergabe                                 */
+	int varargs=0,c;
+	if((c=function->vtyp->exact->count)!=0&&(*function->vtyp->exact->sl)[c-1].styp->flags!=VOID)
+	  varargs=1;
+	
+	/*  default-Wert fuer inline-Entscheidung   */
+	if(!cross_module&&!varargs&&(flags&4096)&&(only_inline||ic_count<=inline_size)){
+	  /*  fuer function inlining vorbereiten   */
+	  IC *p,*new;
+	  if(DEBUG&1024) printf("function <%s> prepared for inlining(ic_count=%d)\n",function->identifier,ic_count);
+	  if(!function->fi) function->fi=new_fi();
+	  function->fi->first_ic=first_ic;
+	  function->fi->last_ic=last_ic;
+	  first_ic=last_ic=0;
+	  p=function->fi->first_ic;
+	  while(p){
+	    new=new_IC();
+	    memcpy(new,p,ICS);
+	    p->copy=new;
+	    if((p->code>=BEQ&&p->code<=BRA)||p->code==LABEL)
+	      new->typf-=lastlabel;
+	    new->q1.flags&=~SCRATCH;
+	    new->q2.flags&=~SCRATCH;
+	    new->z.flags&=~SCRATCH;
+	    add_IC(new);
+	    new->file=p->file;
+	    new->line=p->line;
+	    if(new->code==CALL){
+	      int i;
+	      new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+	      for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=p->arg_list[i]->copy;
+	    }
+	    p=p->next;
+	  }
+	  p=first_ic;first_ic=function->fi->first_ic;function->fi->first_ic=p;
+	  p=last_ic;last_ic=function->fi->last_ic;function->fi->last_ic=p;
+	  function->fi->vars=0;
+	}
+	
+	if(cross_module) calc_finfo(function,CALC_USES|CALC_CHANGES|(prefer_statics?CALC_CALLS:0));
+       
+
+	if(flags&1){
+	  local_combine(fg);
+	  if(DEBUG&1024) print_flowgraph(fg);
+	  if(coloring){
+#ifdef ALEX_REG
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    loops(fg,1);
+	    num_defs();
+	    reaching_definitions(fg);
+	    GCAssignRegs(fg,function->identifier);
+	    { 
+	      int stack_used;IC *p;
+#if 1
+	      for(p=pFg->start;p;p=p->next){
+		if((p->q1.flags&(REG|VAR))==VAR&&zmleq(l2zm(0L),p->q1.v->offset))
+		  break;
+		if((p->q2.flags&(REG|VAR))==VAR&&zmleq(l2zm(0L),p->q2.v->offset))
+		  break;
+		if((p->z.flags&(REG|VAR))==VAR&&zmleq(l2zm(0L),p->z.v->offset))
+		  break;
+	      }
+	      if(!p) max_offset=l2zm(0L);
+#endif
+	    }
+	      
+	    fg = pFg;
+#else
+	    ierror(0);
+#endif
+	  }else{
+	    local_regs(fg);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    loops(fg,1);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    fg=create_loop_headers(fg,1);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    fg=create_loop_footers(fg,1);
+	    if(DEBUG&1024) print_flowgraph(fg);
+	    if(!(disable&8192))
+	      create_const_vars(fg);
+	    loop_regs(fg,intask);
+	    if(DEBUG&1024) print_flowgraph(fg);
+#if 0
+	    if(flags&64){
+	      block_regs(fg);
+	      if(DEBUG&1024) print_flowgraph(fg);
+	    }
+#endif
+	    /* calculate optimized size for cross-module-inlining */
+	    {
+	      IC *p;
+	      if(!function->fi) function->fi=new_fi();
+	      function->fi->inline_size=0;
+	      for(p=first_ic;p;p=p->next) function->fi->inline_size++;
+	      if(DEBUG&1024) printf("inline_size=%ld\n",function->fi->inline_size);
+	    }
+
+	    insert_regs(fg);
+	    insert_saves(fg);
+	    if(prefer_statics||force_statics) replace_statics(function);
+	    
+	    if(flags&256) recalc_offsets(fg);
+	    free_const_vars();
+	  }
+	}
+      }
+
+      free_alias(fg);
+      free_flowgraph(fg);
+      free(vilist);
+      FREEAV;
+
+      if((flags&32)&&gchanged&&pass>=maxoptpasses) error(172,maxoptpasses);
+
+    }while(gchanged&&pass<maxoptpasses);
+    /*  nur, um nochmal ueberfluessige Labels zu entfernen  */
+    fg=construct_flowgraph();
+    free_flowgraph(fg);
+    combine_const_assigns();
+    
+#endif
+
+  }else{
+    /*  keine Optimierungen     */
+    if(flags&1) simple_regs();
+    load_simple_reg_parms();
+  }
+#ifndef NO_OPTIMIZER
+  add_call_list();
+#endif
+
+  lastlabel=label;
+}
+
+
+
diff --git a/opt.h b/opt.h
new file mode 100644
index 0000000..528efdf
--- /dev/null
+++ b/opt.h
@@ -0,0 +1,171 @@
+/*  $VER: vbcc (opt.h) $Revision: 1.4 $    */
+
+#include "supp.h"
+
+extern int gchanged;   /*  Merker, ob Optimierungslauf etwas geaendert hat */
+extern int norek;      /*  diese Funktion wird nicht rekursiv auf          */
+extern int nocall;     /*  diese Funktion kehrt nicht zum Caller zurueck   */
+extern int inr;        /*  number of num_Vars iteration */
+
+/*  temporary fuer verschiedene Bitvektoren */
+extern bvtype *tmp;
+
+/*  fuer aktive Variablen   */
+extern Var **vilist;
+extern unsigned int vcount;    /*  0..vcount-rcount-1: vars, vcount-rcount..vcount: DREFOBJs */
+extern unsigned int rcount;
+extern size_t vsize;
+extern bvtype *av_globals,*av_address,*av_statics,*av_drefs;
+extern int report_dead_statements;
+
+/*  fuer verfuegbare Definitionen   */
+extern unsigned int dcount;
+extern size_t dsize;
+extern IC **dlist;
+extern bvtype **var_defs,**var_undefs;
+extern bvtype **defs_kill,**defs_gen;
+extern bvtype *rd_defs,*rd_tmp;
+extern bvtype *rd_matrix;
+#define UNDEF(x) (x+dcount)
+
+/*  fuer verfuegbare Ausdruecke */
+extern IC **elist;
+extern unsigned int ecount;
+extern size_t esize;
+extern bvtype *ae_globals,*ae_address,*ae_statics,*ae_drefs;
+
+/*  fuer verfuegbare Kopien */
+extern unsigned int ccount;
+extern size_t csize;
+extern IC **clist;
+
+/*  fuer frequency-reduction    */
+extern bvtype *inloop,*invariant;
+
+/*  alle Assignments, globaler oder Adr. fuer propagation etc.         */
+extern bvtype *cp_globals,*cp_address,*cp_statics,*cp_drefs,*cp_act,*cp_dest;
+/*  alle Kopieranweisungen, die eine best. Variable als Quelle haben    */
+extern bvtype **copies;
+
+extern int have_alias;
+extern int static_cse,dref_cse;
+
+typedef struct {
+  union atyps min,max;
+} range;
+
+extern range *rangebuf;
+
+typedef struct flowgraph{
+  IC *start,*end;
+  struct flowgraph *normalout,*branchout;
+  struct flowlist *in;
+  int index;
+  /*  Letzter Block der Schleife, falls Block Start einer Schleife ist    */
+  struct flowgraph *loopend;
+  /*  Anzahl Funktionsaufrufe im Block/der Schleife   */
+  int calls,loop_calls;
+  /*  Bitvektoren fuer aktive Variablen, reaching-definitions,
+      available-expressions und available-copies */
+  bvtype *av_in,*av_out,*av_gen,*av_kill;
+  bvtype *rd_in,*rd_out,*rd_gen,*rd_kill;
+  bvtype *ae_in,*ae_out,*ae_gen,*ae_kill;
+  bvtype *cp_in,*cp_out,*cp_gen,*cp_kill;
+  /* points-to-info */
+  bvtype **pt;
+  /* range-info */
+  range *ra_normalout,*ra_branchout;
+  /*  Registervariablen   */
+  Var *regv[MAXR+1];
+  /*  Merker, ob Register gebraucht wurde; MACR+1 Bits    */
+  bvtype regused[RSIZE/sizeof(bvtype)];
+#ifdef ALEX_REG
+  int loop_depth; /* schleifentiefe des blocks. Wird nur fuer echte Schleifen gezaehlt. */
+#endif
+} flowgraph;
+
+extern unsigned int basic_blocks;
+
+typedef struct flowlist{
+    flowgraph *graph;
+    struct flowlist *next;
+} flowlist;
+
+int compare_const(union atyps *q1,union atyps *q2,int t);
+int compare_objs(obj *o1,obj *o2,int t);
+void simple_regs(void);
+void load_simple_reg_parms(void);
+void remove_IC_fg(flowgraph *g,IC *p);
+
+extern int lastlabel;
+
+flowgraph *new_flowgraph(void);
+flowgraph *construct_flowgraph(void);
+void print_av(bvtype *bitvector);
+void print_rd(bvtype *bitvector);
+void print_ae(bvtype *bitvector);
+void print_cp(bvtype *bitvector);
+void print_flowgraph(flowgraph *g);
+void free_flowgraph(flowgraph *g);
+void num_vars(void);
+void print_vi(void);
+void av_change(IC *p,bvtype *use,bvtype *def);
+void av_update(IC *,bvtype *);
+void active_vars(flowgraph *fg);
+int dead_assignments(flowgraph *fg);
+void insert_IC(IC *p,IC *new);
+void insert_IC_fg(flowgraph *fg,IC *p,IC *new);
+void insert_allocreg(flowgraph *fg,IC *p,int code,int reg);
+void used_objects(Var *);
+void used_clist(type *,const_list *);
+void fix_shortop(flowgraph *,IC *);
+
+extern Var *lregv[MAXR+1],*first_const,*last_const;
+extern flowgraph *lfg;
+
+extern int report_weird_code,report_suspicious_loops,pointer_call;
+
+int replace_local_reg(obj *);
+void local_regs(flowgraph *);
+void local_combine(flowgraph *);
+void create_const_vars(flowgraph *);
+void free_const_vars(void);
+void loop_regs(flowgraph *,int);
+void block_regs(flowgraph *);
+void insert_saves(flowgraph *);
+flowgraph *jump_optimization(void);
+void num_defs(void);
+void reaching_definitions(flowgraph *);
+void rd_change(IC *);
+void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p);
+int fold(IC *p);
+int peephole(void);
+int propagate(IC *p,obj *o,int replace,int global);
+int constant_propagation(flowgraph *fg,int global);
+int compare_exp(const void *a1,const void *a2);
+void num_exp(void);
+void available_expressions(flowgraph *fg);
+void available_copies(flowgraph *fg);
+int cse(flowgraph *fg,int global);
+void num_copies(void);
+int copy_propagation(flowgraph *fg,int global);
+int loops(flowgraph *fg,int mode);
+flowgraph *create_loop_headers(flowgraph *fg,int av);
+flowgraph *create_loop_footers(flowgraph *fg,int av);
+void insert_regs(flowgraph *fg);
+void recalc_offsets(flowgraph *fg);
+void optimize(long flags,Var *function);
+int loop_optimizations(flowgraph *fg);
+int decide_reverse(zmax);
+void range_analysis(flowgraph *fg);
+void ic_uses(IC *p,bvtype *result);
+void ic_changes(IC *p,bvtype *result);
+void create_alias(flowgraph *fg);
+void free_alias(flowgraph *fg);
+void update_alias(Var *old,Var *new);
+void print_pt(bvtype **);
+void free_pt(bvtype **);
+#define CALC_CALLS 1
+#define CALC_USES  2
+#define CALC_CHANGES 4
+void calc_finfo(Var *,int);
diff --git a/osek_supp.h b/osek_supp.h
new file mode 100755
index 0000000..bda8d32
--- /dev/null
+++ b/osek_supp.h
@@ -0,0 +1,13 @@
+/* used for special operating system support */
+extern bvtype task_preempt_regs[],task_schedule_regs[];
+typedef struct tasklist {
+  struct Var *v;
+  int prio;
+  int taskid;
+  enum {NON_PREEMPTIVE=1,DOES_BLOCK=2,CALLS_SCHED=4,ISR=8} flags;
+  bvtype context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+  bvtype preempt_context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+  bvtype schedule_context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+  bvtype unsaved_context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+} tasklist;
+
diff --git a/osekrm.c b/osekrm.c
new file mode 100644
index 0000000..62c5528
--- /dev/null
+++ b/osekrm.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BSIZE 4196
+char buf[BSIZE];
+
+int main()
+{
+  int nest=0;
+  while(fgets(buf,BSIZE,stdin)){
+    if(nest==0){
+      fputs(buf,stdout);
+      if(!strncmp(buf,"#if HAVE_OSEK",12)||!strncmp(buf,"#ifdef HAVE_MISRA",17)||!strncmp(buf,"#ifdef HAVE_ECPP",16))
+	nest++;
+    }else{
+      if(!strncmp(buf,"#endif",6))
+	nest--;
+      if(!strncmp(buf,"#if",3))
+	nest++;
+      if(nest==1&&!strncmp(buf,"#else",5))
+	fputs("illegal #else found",stderr);
+      if(nest==1&&!strncmp(buf,"#elif",5))
+	fputs("illegal #elif found",stderr);
+      if(nest==0)
+	fputs(buf,stdout);
+      else
+	puts("/* removed */");
+    }
+  }
+  return 0;
+}
+
diff --git a/parse_expr.c b/parse_expr.c
new file mode 100644
index 0000000..5669c07
--- /dev/null
+++ b/parse_expr.c
@@ -0,0 +1,1050 @@
+/*  $VER: vbcc (parse_expr.c) $Revision: 1.22 $  */
+
+#include "vbcc_cpp.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+np new_node(void)
+{
+  np p=mymalloc(NODES);
+  p->flags=0;
+  p->lvalue=0;
+  p->sidefx=0;
+  p->ntyp=0;
+  p->left=0;
+  p->right=0;
+  p->alist=0;
+  p->identifier=0;
+  p->o.flags=0;
+  return p;
+}
+
+np expression(void)
+/*  Komma-Ausdruecke  */
+{
+  np left,right,new;
+  left=assignment_expression();
+  if(!left->flags) return 0;
+  killsp();
+  while(ctok->type==COMMA){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    next_token();
+    killsp();
+    right=assignment_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->ntyp=0;
+    new->flags=KOMMA;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np assignment_expression(void)
+/*  Zuweisungsausdruecke  */
+{
+  np left,new;int c=ASSIGNOP,op;
+  left=conditional_expression();
+  killsp();
+  switch(ctok->type){
+  case ASGN: c=ASSIGN;break;
+  case ASSTAR: op=MULT;break;
+  case ASSLASH: op=DIV;break;
+  case ASPCT: op=MOD;break;
+  case ASPLUS: op=ADD;break;
+  case ASMINUS: op=SUB;break;
+  case ASAND: op=AND;break;
+  case ASCIRC: op=XOR;break;
+  case ASOR: op=OR;break;
+  case ASLSH: op=LSHIFT;break;
+  case ASRSH: op=RSHIFT;break;
+  default:
+    return left;
+  }
+  next_token();
+  new=new_node();
+  new->left=left;
+  new->ntyp=0;
+  if(c==ASSIGN){
+    new->right=assignment_expression();
+    new->flags=ASSIGN;
+  }else{
+    /*  ASSIGNOP(a,b)->ASSIGN(a,OP(a,b))    */
+    new->flags=ASSIGNOP;    /* nur um zum Merken, dass nur einmal */
+                            /* ausgewertet werden darf            */
+    new->right=new_node();
+    new->right->left=left;
+    new->right->right=assignment_expression();
+    new->right->ntyp=0;
+    new->right->flags=op;
+  }
+  return new;
+}
+np conditional_expression(void)
+/*  Erledigt ? :   */
+{
+  np left,new;
+  left=logical_or_expression();
+  killsp();
+  if(ctok->type==QUEST){   
+    next_token();killsp();
+    new=new_node();
+    new->flags=COND;
+    new->ntyp=0;
+    new->left=left;
+    new->right=new_node();
+    new->right->flags=COLON;
+    new->right->ntyp=0;
+    new->right->left=expression();
+    killsp();
+    if(ctok->type==T_COLON){next_token();killsp();} else error(70);
+    new->right->right=conditional_expression();
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np logical_or_expression(void)
+/*  Erledigt ||  */
+{
+  np left,right,new;int bra;
+  if(ctok->type==LPAR) bra=1; else bra=0;
+  left=logical_and_expression();
+  killsp();
+  while(ctok->type==T_LOR){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    next_token();
+    killsp();
+    if(ctok->type==LPAR) bra=1; else bra=0;
+    right=logical_and_expression();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=LOR;
+    new->ntyp=0;
+    left=new;
+    killsp();
+    if(ctok->type==T_LAND) error(222);
+  }
+  return left;
+}
+np logical_and_expression(void)
+/*  Erledigt &&  */
+{
+  np left,right,new;int bra;
+  if(ctok->type==LPAR) bra=1; else bra=0;
+  left=inclusive_or_expression();
+  killsp();
+  while(ctok->type==T_LAND){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    next_token();
+    killsp();
+    if(ctok->type==LPAR) bra=1; else bra=0;
+    right=inclusive_or_expression();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=LAND;
+    new->ntyp=0;
+    left=new;
+    killsp();
+    if(ctok->type==T_LOR) error(222);
+  }
+  return left;
+}
+np inclusive_or_expression(void)
+/*  Erledigt |  */
+{
+  np left,right,new;
+  left=exclusive_or_expression();
+  killsp();
+  while(ctok->type==T_OR){
+    next_token();
+    killsp();
+    right=exclusive_or_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=OR;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np exclusive_or_expression(void)
+/*  Erledigt ^  */
+{
+  np left,right,new;
+  left=and_expression();
+  killsp();
+  while(ctok->type==CIRC){
+    next_token();
+    killsp();
+    right=and_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=XOR;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np and_expression(void)
+
+/*  Erledigt &  */
+{
+  np left,right,new;
+  left=equality_expression();
+  killsp();
+  while(ctok->type==T_AND){
+    next_token();
+    killsp();
+    right=equality_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=AND;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np equality_expression(void)
+/*  Erledigt == und !=  */
+{
+  np left,right,new;int c;
+  left=relational_expression();
+  killsp();
+  while(ctok->type==SAME||ctok->type==NEQ){
+    if(ctok->type==NEQ) c=INEQUAL; else c=EQUAL;
+    next_token();
+    killsp();
+    right=relational_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=c;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np relational_expression(void)
+/*  Erledigt <,>,<=,>=  */
+{
+  np left,right,new;int c;
+  left=shift_expression();
+  killsp();
+  while(ctok->type==LT||ctok->type==GT||ctok->type==LEQ||ctok->type==GEQ){
+    if(ctok->type==LT) c=LESS;
+    else if(ctok->type==GT) c=GREATER;
+    else if(ctok->type==LEQ) c=LESSEQ;
+    else c=GREATEREQ;
+    next_token();
+    killsp();
+    right=shift_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=c;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np shift_expression(void)
+/*  Erledigt <<,>>  */
+{
+  np left,right,new;int c;
+  left=additive_expression();
+  killsp();
+  while(ctok->type==LSH||ctok->type==RSH){
+    if(ctok->type==LSH)
+      c=LSHIFT; 
+    else
+      c=RSHIFT;
+    next_token();
+    killsp();
+    right=additive_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=c;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np additive_expression(void)
+/*  Erledigt +,-  */
+{
+  np left,right,new;int c;
+  left=multiplicative_expression();
+  killsp();
+  while(ctok->type==PLUS||ctok->type==T_MINUS){
+    if(ctok->type==PLUS) c=ADD; else c=SUB;
+    next_token();killsp();
+    right=multiplicative_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=c;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np multiplicative_expression(void)
+/*  Erledigt *,/,%  */
+{
+  np left,right,new;int c;
+  left=cast_expression();
+  killsp();
+  while(ctok->type==STAR||ctok->type==SLASH||ctok->type==PCT){
+    if(ctok->type==STAR) c=MULT; 
+    else if(ctok->type==SLASH) c=DIV; 
+    else c=MOD;
+    next_token();killsp();
+    right=cast_expression();
+    new=new_node();
+    new->left=left;
+    new->right=right;
+    new->flags=c;
+    new->ntyp=0;
+    left=new;
+    killsp();
+  }
+  return left;
+}
+np cast_expression(void)
+/*  Erledigt (typ)  */
+{
+  np new;char *imerk,buff[MAXI];
+  killsp();
+  if(ctok->type!=LPAR||!declaration(1)) return unary_expression();
+  next_token();killsp();
+  new=new_node();
+  new->right=0;
+  buff[0]=0;
+  imerk=ident;ident=buff;
+  new->ntyp=declarator(declaration_specifiers());
+  ident=imerk;
+  if(buff[0]) error(356);
+  killsp();
+  if(ctok->type!=RPAR) error(59); else next_token();
+  killsp();
+  if(c99&&ctok->type==LBRA){
+    /* compund literals */
+    init_dyn_cnt=0;
+    new->cl=initialization(new->ntyp,nesting!=0,0,0,0,0);
+    killsp();
+    if(new->cl){
+      if(ISARRAY(new->ntyp->flags)&&zmeqto(new->ntyp->size,l2zm(0L))){
+	const_list *p=new->cl;
+	while(p){new->ntyp->size=zmadd(p->idx,l2zm(1L));p=p->next;}
+      }
+    }
+    new->flags=LITERAL;
+    new->left=0;
+    new->val.vmax=l2zm((long)init_dyn_cnt);
+  }else{
+    new->flags=CAST;
+    new->left=cast_expression();
+  }
+  return new;
+}
+np unary_expression(void)
+/*  Erledigt !,~,++,--,+,-,*,&,sizeof,__typeof  */
+{
+  np new;char *merk;
+  killsp();
+  if(ctok->type!=NAME&&ctok->type!=PLUS&&ctok->type!=PPLUS&&ctok->type!=T_MINUS&&ctok->type!=MMINUS&&ctok->type!=T_AND&&ctok->type!=STAR&&ctok->type!=NOT&&ctok->type!=LNOT)
+    return postfix_expression();
+  if(ctok->type==NAME){
+    enum {SIZEOF,TYPEOF,ALIGNOF,OFFSETOF} op;
+    if(strcmp("sizeof",ctok->name)&&strcmp("__typeof",ctok->name)&&strcmp("__alignof",ctok->name)&&strcmp("__offsetof",ctok->name)){
+      return postfix_expression();
+    }else{
+      if(*ctok->name=='s') 
+	op=SIZEOF; 
+      else if(ctok->name[2]=='a') 
+	op=ALIGNOF;
+      else if(ctok->name[2]=='t')
+	op=TYPEOF;
+      else
+	op=OFFSETOF;
+      next_token();
+      killsp();
+      new=new_node();
+      new->flags=CEXPR;
+      new->ntyp=new_typ();
+      if(op==SIZEOF||op==OFFSETOF){
+	if(HAVE_INT_SIZET)
+	  new->ntyp->flags=(UNSIGNED|INT);
+	else
+	  new->ntyp->flags=(UNSIGNED|LONG);
+      }else
+	new->ntyp->flags=INT;
+      new->right=0;
+      new->left=0;
+      
+      if(ctok->type==LPAR&&declaration(1)){
+	type *t;
+	next_token();killsp();
+	buff[0]=0;
+	merk=ident;ident=buff;
+	t=declarator(declaration_specifiers());
+	if(type_uncomplete(t)) error(176);
+	ident=merk;
+	if(buff[0]) error(356);
+	if(op==OFFSETOF){
+	  if(ctok->type==COMMA)
+	    next_token();
+	  else
+	    error(57);
+	  if(ctok->type!=NAME) error(76);
+	  if(t->flags!=STRUCT){
+	    error(310);
+	    vumax=ul2zum(0UL);
+	  }else
+	    vumax=zm2zum(struct_offset(t->exact,ctok->name));
+	  next_token();
+	  if(HAVE_INT_SIZET)
+	    new->val.vuint=zum2zui(vumax);
+	  else
+	    new->val.vulong=zum2zul(vumax);
+	}else if(op==SIZEOF){
+	  if(is_vlength(t)){
+	    new->dsize=vlength_szof(t);
+	    new->flags=IDENTIFIER;
+	    new->val.vmax=l2zm(0L);
+	    new->sidefx=0;
+	    new->identifier=empty;
+	  }else{
+	    if(HAVE_INT_SIZET)
+	      new->val.vuint=zum2zui(zm2zum(szof(t)));
+	    else
+	      new->val.vulong=zum2zul(zm2zum(szof(t)));
+	  }
+	}else if(op==ALIGNOF){
+	  new->val.vint=zm2zi(falign(t));
+	}else if(op==TYPEOF){
+	  new->val.vint=zm2zi(l2zm(t->flags));
+	}
+	freetyp(t);
+	killsp();
+	if(ctok->type!=RPAR) error(59); else next_token();
+      }else{
+	np tree;
+	if(op==OFFSETOF) error(0);
+	killsp();
+	tree=unary_expression();
+	if(!tree||!type_expression(tree,0)){
+	  if(op==SIZEOF){
+	    if(HAVE_INT_SIZET)
+	      new->val.vuint=zum2zui(ul2zum(0UL));
+	    else
+	      new->val.vulong=zum2zul(ul2zum(0UL));
+	    error(73);
+	  }else{
+	    new->val.vint=zm2zi(l2zm(-1L));
+	  }
+	}else{
+	  if(op==SIZEOF){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+		if(type_uncomplete(tree->ntyp)) error(176);
+	    if(is_vlength(tree->ntyp)){
+	      new->dsize=vlength_szof(tree->ntyp);
+	      new->flags=IDENTIFIER;
+	      new->val.vmax=l2zm(0L);
+	      new->sidefx=0;
+	      new->identifier=empty;
+	    }else{
+	      if(HAVE_INT_SIZET)
+		new->val.vuint=zum2zui(zm2zum(szof(tree->ntyp)));
+	      else
+		new->val.vulong=zum2zul(zm2zum(szof(tree->ntyp)));
+	    }
+	  }else{
+	    if(op==ALIGNOF)
+	      new->val.vint=zm2zi(falign(tree->ntyp));
+	    else
+	      new->val.vint=zm2zi(l2zm(tree->ntyp->flags));
+	  }
+	}
+	if(tree) free_expression(tree);killsp();
+      }
+      return new;
+    }
+  }
+  new=new_node();
+  new->right=0;
+  new->ntyp=0;
+  if(ctok->type==PLUS){
+    next_token();
+    free(new);
+    return cast_expression();
+  }else if(ctok->type==T_MINUS){
+    next_token();
+    new->left=cast_expression();
+    new->flags=MINUS;    
+  }else if(ctok->type==PPLUS){
+    next_token();
+    new->left=unary_expression();
+    new->flags=PREINC;
+  }else if(ctok->type==MMINUS){
+    next_token();
+    new->left=unary_expression();
+    new->flags=PREDEC;
+  }else if(ctok->type==T_AND){
+    next_token();
+    new->left=cast_expression();
+    new->flags=ADDRESS;
+  }else if(ctok->type==STAR){
+    next_token();
+    new->left=cast_expression();
+    new->flags=CONTENT;
+  }else if(ctok->type==NOT){
+    next_token();
+    new->left=cast_expression();
+    new->flags=KOMPLEMENT;
+  }else if(ctok->type==LNOT){
+    next_token();
+    new->left=cast_expression();
+    new->flags=NEGATION;
+  }
+  new->right=0;
+  new->ntyp=0;
+  return new;
+}
+np postfix_expression(void)
+/*  Erledigt [],(),.,->,++,--  */
+{
+  np new,left;
+  left=primary_expression();
+  killsp();
+  while(ctok->type==LBRK||ctok->type==LPAR||ctok->type==DOT||ctok->type==ARROW||ctok->type==PPLUS||ctok->type==MMINUS){
+    new=new_node();
+    new->ntyp=0;
+    new->right=0;
+    new->left=left;
+    if(ctok->type==MMINUS){
+      next_token();
+      new->flags=POSTDEC;
+    }else if(ctok->type==ARROW){
+      next_token(); killsp();
+      new->flags=DSTRUCT;
+      new->right=identifier_expression();
+      new->right->flags=MEMBER;
+      new->left=new_node();
+      new->left->ntyp=0;
+      new->left->left=left;
+      new->left->right=0;
+      new->left->flags=CONTENT;
+    }else if(ctok->type==LBRK){
+      next_token(); killsp();
+      new->flags=CONTENT;
+      new->left=new_node();
+      new->left->flags=ADD;
+      new->left->ntyp=0;
+      new->left->left=left;
+      new->left->right=expression();
+      killsp();
+      if(ctok->type!=RBRK) error(62); else next_token();
+    }else if(ctok->type==PPLUS){
+      next_token();
+      new->flags=POSTINC;
+    }else if(ctok->type==DOT){
+      next_token();killsp();
+      new->right=identifier_expression();
+      new->flags=DSTRUCT;
+      new->right->flags=MEMBER;
+    }else if(ctok->type==LPAR){
+      argument_list *al,*first_alist=0,*last_alist=0;np n;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+      new->left=left;
+      new->flags=CALL;
+      new->right=0;
+      new->alist=argument_list_expression();
+    }
+    left=new;
+    killsp();
+  }
+  return left;
+}
+argument_list *argument_list_expression(void)
+/* returns CALL node with alist attached, but without identifier */
+{
+  argument_list *al,*first_alist=0,*last_alist=0;np n;
+  if(ctok->type!=LPAR)ierror(0);
+  next_token();killsp();
+  while(ctok->type!=RPAR){
+    n=assignment_expression();
+    al=mymalloc(sizeof(argument_list));
+    al->arg=n;al->next=0;
+    if(last_alist){
+      last_alist->next=al;
+      last_alist=al;
+    }else{
+      last_alist=first_alist=al;
+    }
+    killsp();
+    if(ctok->type==COMMA){
+      next_token();killsp();
+      if(ctok->type==RPAR) error(59);
+    }else if(ctok->type!=RPAR) error(57);
+  }
+  if(ctok->type!=RPAR) error(59); else next_token();
+  return first_alist;
+}
+np primary_expression(void)
+/*  primary-expressions (Konstanten,Strings,(expr),Identifier)  */
+{
+  np new;token mtok;
+  if(ctok->type==NUMBER) return constant_expression();
+  if(ctok->type==T_STRING||ctok->type==T_CHAR) return string_expression();
+  if(ctok->type==LPAR){
+    next_token();killsp();
+    new=expression();
+    killsp();
+    if(ctok->type!=RPAR) error(59); else next_token();
+    return new;
+  }
+  return identifier_expression();
+}
+
+const_list *cl_from_string(char *start, char *end)
+{
+  const_list *r,*cl,**prev;int i;
+  prev=&r;
+  for(i=0;i<end-start+1;i++){
+    cl=mymalloc(CLS);
+    cl->next=0;
+    cl->tree=0;
+    cl->idx=l2zm((long)i);
+    cl->val.vmax=l2zm(0L);
+    cl->other=mymalloc(CLS);
+    cl->other->next=cl->other->other=0;
+    cl->other->tree=0;
+    cl->other->idx=l2zm(0L);
+    cl->other->val.vchar=zm2zc(l2zm((long)start[i]));
+    *prev=cl;
+    prev=&cl->next;
+  }
+  return r;
+}
+
+np string_expression(void)
+/*  Gibt Zeiger auf string oder Zeichenkonstante zurueck  */
+{
+  np new; char f,*s,*p;int flag,val;
+  zmax zm;zumax zum;
+  static char *string;
+  static size_t slen;
+  p=string;
+  while(1){
+    s=ctok->name;
+    if(*s=='L') {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+		s++;}    /*  Noch keine erweiterten Zeichen  */
+    if(ctok->type==T_STRING&&*s!='\"') ierror(0);
+    if(ctok->type==T_CHAR&&*s!='\'') ierror(0);
+    f=*s++;
+    while(*s!=f&&*s!=0){
+      size_t pos=p-string;
+      if(slen<=pos+1){
+	slen+=128;
+	string=myrealloc(string,slen);
+	p=string+pos;
+      }
+      if(*s=='\\'){
+	s++;
+	if(*s=='\\'){*p++=CHARCONV('\\');s++;continue;}
+	if(*s=='n'){*p++=CHARCONV('\n');s++;continue;}
+	if(*s=='t'){*p++=CHARCONV('\t');s++;continue;}
+	if(*s=='r'){*p++=CHARCONV('\r');s++;continue;}
+	if(*s=='v'){*p++=CHARCONV('\v');s++;continue;}
+	if(*s=='b'){*p++=CHARCONV('\b');s++;continue;}
+	if(*s=='f'){*p++=CHARCONV('\f');s++;continue;}
+	if(*s=='a'){*p++=CHARCONV('\a');s++;continue;}
+	if(*s=='\?'){*p++=CHARCONV('\?');s++;continue;}
+	if(*s=='\''){*p++=CHARCONV('\'');s++;continue;}
+	if(*s=='\"'){*p++=CHARCONV('\"');s++;continue;}
+	flag=val=0;
+	while(*s>='0'&&*s<='7'&&flag<3){
+	  val=val*8+*s-'0';
+	  s++;flag++;
+	}
+	if(flag){*p++=val;continue;}
+	if(*s=='x'){
+	  int warned=0;
+	  s++;val=0;
+	  while((*s>='0'&&*s<='9')||(*s>='a'&&*s<='f')||(*s>='A'&&*s<='F')){
+	    val=val*16;
+	    if(*s>='0'&&*s<='9') val+=*s-'0';
+	    if(*s>='a'&&*s<='f') val+=*s-'a'+10;
+	    if(*s>='A'&&*s<='F') val+=*s-'A'+10;
+	    if(!warned&&((unsigned long)val)>zum2ul(tu_max[CHAR])){
+	      error(364);
+	      warned=1;
+	    }
+	    s++;
+	  }
+	  *p++=val;continue;
+	}
+	error(71);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      }
+      *p++=CHARCONV(*s);
+      s++;
+    }
+    if(*s!=f) error(74);
+    next_token();
+    killsp();
+    if(f!='\"'||ctok->type!=T_STRING) break;
+  }
+  if(!string){
+    slen+=128;
+    string=myrealloc(string,slen);
+    p=string;
+  }
+  *p=0;
+  new=new_node();
+  new->ntyp=new_typ();
+  if(f=='\"'){
+    new->ntyp->flags=ARRAY;
+    new->ntyp->size=l2zm((long)(p-string)+1);
+    new->ntyp->next=new_typ();
+    new->ntyp->next->flags=STRINGCONST|CHAR;
+    new->ntyp->next->next=0;
+    new->flags=STRING;
+    new->cl=cl_from_string(string,p);
+    /*        new->identifier=add_identifier(string,p-string);*/
+    new->val.vmax=l2zm(0L);
+  }else{
+    char *l;
+    if(ecpp)new->ntyp->flags=CONST|CHAR;
+    else new->ntyp->flags=CONST|INT;
+    new->ntyp->next=0;
+    new->flags=CEXPR;
+		/* TODO: Hier eventuell was mitspeichern das char */
+    zm=l2zm(0L);zum=ul2zum(0UL);
+    p--;
+    if(p>string){ error(72);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	} 
+    for(BIGENDIAN?(l=string):(l=p);BIGENDIAN?(l<=p):(l>=string);BIGENDIAN?(l++):(l--)){
+      /*  zm=zm<<CHAR_BIT+*p  */
+      if(default_unsigned){
+	zum=zumlshift(zum,char_bit);
+	zum=zmadd(zum,ul2zum(*(unsigned char *)l));
+	new->val.vint=zm2zi(zum2zm(zum));
+      }else{
+	zm=zmlshift(zm,char_bit);
+	zm=zmadd(zm,l2zm((long)*l));
+	new->val.vint=zm2zi(zm);
+      }
+    }
+  }
+  new->left=new->right=0;
+  return new;
+}
+np constant_expression(void)
+/*  Gibt Zeiger auf erzeugt Struktur fuer Konstante zurueck */
+{
+  np new; zldouble db;
+  zumax value,zbase,digit;unsigned long base=10,t;
+  char *s,*merk;int warned=0,tm=0;
+  merk=s=ctok->name;
+  value=ul2zum(0L);
+  new=new_node();
+  new->ntyp=new_typ();
+  new->ntyp->flags=0;
+  new->flags=CEXPR;
+  new->left=new->right=0;
+  new->sidefx=0;
+  if(*s=='0'){
+    s++;
+    if(*s=='x'||*s=='X'){s++;base=16;} else base=8;
+  }
+  zbase=ul2zum(base);
+  if(*s>='0'&&*s<='9') t=*s-'0'; 
+  else if(*s>='a'&&*s<='f') t=*s-'a'+10; 
+  else if(*s>='A'&&*s<='F') t=*s-'A'+10;
+  else t=20;
+  while(t<base){
+    digit=ul2zum(t);
+    if(!warned){
+      if(!c99&&!zumleq(value,zumdiv(zumsub(t_max(UNSIGNED|LONG),digit),zbase)))
+	warned=1;
+      if(c99&&!zumleq(value,zumdiv(zumsub(t_max(UNSIGNED|LLONG),digit),zbase)))
+	warned=1;      
+    }
+    value=zumadd(zummult(value,zbase),digit);
+    s++;
+    if(*s>='0'&&*s<='9') t=*s-'0'; 
+    else if(*s>='a'&&*s<='f') t=*s-'a'+10; 
+    else if(*s>='A'&&*s<='F') t=*s-'A'+10; 
+    else t=20;
+  }
+  while((!(tm&UNSIGNED)&&(*s=='u'||*s=='U'))||((tm&NQ)==0&&(*s=='l'||*s=='L'))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    if(!(tm&UNSIGNED)&&(*s=='u'||*s=='U')){
+      if((tm&NQ)==LONG){
+	if(!c99||zumleq(value,t_max(UNSIGNED|LONG)))
+	  new->ntyp->flags=(UNSIGNED|LONG);
+	else
+	  new->ntyp->flags=(UNSIGNED|LLONG);
+      }else if((tm&NQ)==LLONG)
+	new->ntyp->flags=(UNSIGNED|LLONG);
+      else if(zumleq(value,t_max(UNSIGNED|INT)))
+	new->ntyp->flags=UNSIGNED|INT;
+      else if(!c99||zumleq(value,t_max(UNSIGNED|LONG)))
+	new->ntyp->flags=UNSIGNED|LONG;
+      else
+	new->ntyp->flags=UNSIGNED|LLONG;
+      tm|=UNSIGNED;
+    }else{
+      if(c99&&s[1]==s[0]){
+	s++;
+	if(tm&UNSIGNED)
+	  new->ntyp->flags=(UNSIGNED|LLONG);
+	else if(base==10||zumleq(value,t_max(LLONG)))
+	  new->ntyp->flags=LLONG;
+	else
+	  new->ntyp->flags=UNSIGNED|LLONG;
+	tm|=LLONG;
+      }else{
+	if(tm&UNSIGNED){
+	  if(!c99||zumleq(value,t_max(UNSIGNED|LONG)))
+	    new->ntyp->flags=(UNSIGNED|LONG);
+	  else
+	    new->ntyp->flags=(UNSIGNED|LLONG);
+	}else{
+	  if(!c99){
+	    if(base==10||zumleq(value,t_max(LONG)))
+	      new->ntyp->flags=LONG;
+	    else
+	      new->ntyp->flags=UNSIGNED|LONG;
+	  }else{ 
+	    if(zumleq(value,t_max(LONG)))
+	      new->ntyp->flags=LONG;
+	    else if(base!=10&&zumleq(value,t_max(UNSIGNED|LONG)))
+	      new->ntyp->flags=UNSIGNED|LONG;
+	    else if(base==10||zumleq(value,t_max(LLONG)))
+	      new->ntyp->flags=LLONG;
+	    else
+	      new->ntyp->flags=UNSIGNED|LLONG;
+	  }
+	}
+	tm|=LONG;
+      }	
+    }
+    s++;
+  }
+  if(*s=='.'||*s=='e'||*s=='E'){
+    /*  Fliesskommakonstante, ignoriert vorher berechneten Wert, falls er   */
+    /*  nicht dezimal und nicht 0 war (da er dann oktal war)                */
+    if(*merk=='0'&&!zumeqto(value,ul2zum(0UL))){
+      value=ul2zum(0UL);zbase=ul2zum(10UL);
+      while(*merk>='0'&&*merk<='9'){
+	digit=ul2zum((unsigned long)(*merk-'0'));
+	value=zumadd(zummult(value,zbase),digit);
+	merk++;
+      }
+      if(merk!=s) error(75);
+    }
+    db=zum2zld(value);
+    if(*s=='.'){
+      /*  Teil hinter Kommastellen    */
+      zldouble zdiv,zbased,zsum,digit;
+      int cnt=0;
+      s++;
+      zbased=d2zld(10.0);zdiv=d2zld(1.0);zsum=d2zld(0.0);
+      while(*s>='0'&&*s<='9'){
+        if (cnt<35){
+	  cnt++;
+          digit=d2zld((double)(*s-'0'));
+          zsum=zldadd(zldmult(zsum,zbased),digit);
+          zdiv=zldmult(zdiv,zbased);
+        }
+        s++;
+      }
+      db=zldadd(db,zlddiv(zsum,zdiv));
+      
+    }
+    if(*s=='e'||*s=='E'){
+      /*  Exponentialdarstellung  */
+      int exp,vorz,i;zldouble zbased;
+      zbased=d2zld((double)10);
+      s++;
+      if(*s=='-'){
+	s++;vorz=-1;
+      }else{
+	vorz=1;if(*s=='+') s++;
+      }
+      exp=0;
+      while(*s>='0'&&*s<='9') exp=exp*10+*s++-'0';
+      for(i=0;i<exp;i++){
+	if(vorz>0) db=zldmult(db,zbased);
+	else   db=zlddiv(db,zbased);
+      }
+    }
+    new->ntyp->flags=DOUBLE;
+    if(*s=='f'||*s=='F'){
+      new->ntyp->flags=FLOAT;s++;
+    }else if(*s=='l'||*s=='L'){
+      new->ntyp->flags=LDOUBLE;s++;
+    }
+  }else{
+    if(warned) error(211);
+    if(new->ntyp->flags==0){
+      if(base==10){
+	if(zumleq(value,t_max(INT))) 
+	  new->ntyp->flags=INT;
+	else if(!c99||zumleq(value,t_max(LONG)))
+	  new->ntyp->flags=LONG; 
+        else
+	  new->ntyp->flags=LLONG;
+      }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	if(zumleq(value,t_max(INT)))
+	  new->ntyp->flags=INT; 
+	else 
+	  if(zumleq(value,t_max(UNSIGNED|INT)))
+	    new->ntyp->flags=UNSIGNED|INT;
+	else if(zumleq(value,t_max(LONG)))
+	  new->ntyp->flags=LONG;
+	else if(!c99||zumleq(value,t_max(UNSIGNED|LONG))){
+	  new->ntyp->flags=UNSIGNED|LONG;error(212);
+	}else if(zumleq(value,t_max(LLONG)))
+	  new->ntyp->flags=LLONG;
+	else
+	  new->ntyp->flags=UNSIGNED|LLONG;
+      }
+    }
+  }
+
+  if(*s) error(232);
+  
+  if(new->ntyp->flags==FLOAT) new->val.vfloat=zld2zf(db);
+  else if(new->ntyp->flags==DOUBLE) new->val.vdouble=zld2zd(db);
+  else if(new->ntyp->flags==LDOUBLE) new->val.vldouble=db;
+  else if(new->ntyp->flags==INT) new->val.vint=zm2zi(zum2zm(value));
+  else if(new->ntyp->flags==(UNSIGNED|INT)) new->val.vuint=zum2zui(value);
+  else if(new->ntyp->flags==LONG) new->val.vlong=zm2zl(zum2zm(value));
+  else if(new->ntyp->flags==(UNSIGNED|LONG)) new->val.vulong=zum2zul(value);
+  else if(new->ntyp->flags==LLONG) new->val.vllong=zm2zll(zum2zm(value));
+  else if(new->ntyp->flags==(UNSIGNED|LLONG)) new->val.vullong=zum2zull(value);
+  else ierror(0);
+  next_token();
+  return new;
+}
+np identifier_expression(void)
+/*  Erzeugt Identifier mit Knoten  */
+{
+  np new;char buff[MAXI];
+  killsp();
+  if(ctok->type==NAME){
+    if(is_keyword(ctok->name)) error(216,ctok->name);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    new=new_node();
+    new->flags=IDENTIFIER;
+    new->left=new->right=0;
+    new->identifier=add_identifier(ctok->name,strlen(ctok->name));
+    if(!strncmp(ctok->name,"__maskm_",8)){
+      unsigned long mask;
+      if(sscanf(ctok->name,"__maskm_%lu_%s",&mask,new->identifier)!=2) ierror(0);
+      sprintf(new->identifier+strlen(new->identifier),".%lu",mask);
+    }
+    new->ntyp=0;
+    new->sidefx=0;
+    new->val.vmax=l2zm(0L);
+    new->o.v=0;
+    next_token();
+  }else{
+    error(76);
+    new=0;
+  }
+  return new;
+}
+void free_alist(argument_list *p)
+/*  Gibt argument_list inkl. expressions frei  */
+{
+  argument_list *merk;
+  while(p){
+    merk=p->next;
+    if(p->arg) free_expression(p->arg);
+    free(p);
+    p=merk;
+  }
+}
+void free_expression(np p)
+/*  Gibt expression mit allen Typen etc. frei  */
+{
+  if(!p) return;
+  if(p->flags==ASSIGNOP){
+    if(!p->right){ierror(0);return;}
+    if(p->right->left==p->left)  p->left=0;
+    if(p->right->right==p->left) p->left=0;
+  }
+  if(p->flags==CALL&&p->alist) free_alist(p->alist);
+  if(p->ntyp) freetyp(p->ntyp);
+  if(p->left) free_expression(p->left);
+  if(p->right) free_expression(p->right);
+  free(p);
+}
+
diff --git a/pp.c b/pp.c
new file mode 100755
index 0000000..385cb1d
--- /dev/null
+++ b/pp.c
@@ -0,0 +1,975 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+FILE *infile;
+int line=1;
+
+#define INCSIZE 16
+FILE **incfile;
+char **incname;
+int *incline;
+int incn,incsize;
+
+#define PP_TSIZE 1024
+
+/*FIXME*/
+#define ierror(x) abort();
+#define mymalloc(x) malloc(x)
+#define myrealloc(x,y) realloc(x,y)
+
+/* must not collide with source character-set */
+enum {
+  TKKEYWORD=-32,
+  TKMARG,
+  TKIDENTIFIER,
+  TKNUMBER,
+  TKPLUSPLUS,
+  TKMINMIN,
+  TKEOL,
+  TKLTLT,
+  TKGTGT,
+  TKSREF,
+  TKLE,
+  TKGE,
+  TKEQ,
+  TKNE,
+  TKLAND,
+  TKLOR,
+  TKMULEQ,
+  TKDIVEQ,
+  TKMODEQ,
+  TKPLUSEQ,
+  TKMINEQ,
+  TKLTLTEQ,
+  TKGTGTEQ,
+  TKANDEQ,
+  TKOREQ,
+  TKXOREQ,
+  TKDDD,
+  TKNUMNUM
+};
+
+static char *tokout[]={"err","err","err","err","++","--","","<<",">>","->","<=",">=","==",
+		       "!=","&&","||","*=","/=","%=","+=","-=","<<=",">>=","&=",
+		       "|=","^=","...","##"
+};
+
+static char *desc[]={
+  "TKKEYWORD",
+  "TKMARG",
+  "TKIDENTIFIER",
+  "TKNUMBER",
+  "TKPLUSPLUS",
+  "TKMINMIN",
+  "TKEOL",
+  "TKLTLT",
+  "TKGTGT",
+  "TKSREF",
+  "TKLE",
+  "TKGE",
+  "TKEQ",
+  "TKNE",
+  "TKLAND",
+  "TKLOR",
+  "TKMULEQ",
+  "TKDIVEQ",
+  "TKMODEQ",
+  "TKPLUSEQ",
+  "TKMINEQ",
+  "TKLTLTEQ",
+  "TKGTGTEQ",
+  "TKANDEQ",
+  "TKOREQ",
+  "TKXOREQ",
+  "TKDDD",
+  "TKNUMNUM"
+};
+
+typedef struct {
+  int size;
+  int next;
+  int *tokens;
+} tokenlist;
+
+#ifndef OBFUSCATOR
+
+#define VARARG_MACRO  1
+#define BUILTIN_MACRO 2
+#define NEED_PAREN    4
+
+typedef struct {
+  char *name;
+  int flags;
+  int nargs;
+  tokenlist repl;
+} macro;
+
+#define PP_HSIZE 16384
+static int **hash_table;
+
+#define PP_MSIZE 128
+static macro *macro_table;
+static int macro_cnt=1,macro_size;
+
+void print_tokenlist(FILE *,tokenlist *);
+
+static void copy_tokenlist(tokenlist *new,tokenlist *old)
+{
+  if(new->size<old->next+new->next){
+    new->size=old->next+new->next;
+    new->tokens=myrealloc(new->tokens,new->size*sizeof(*new->tokens));
+  }
+  memcpy(new->tokens+new->next,old->tokens,old->next*sizeof(*new->tokens));
+  new->next+=old->next;
+}
+
+static int new_macro(char *name,int flags,int nargs,tokenlist *repl)
+{
+  int i,*p;
+  if(macro_cnt>=macro_size){
+    macro_size+=PP_MSIZE;
+    macro_table=myrealloc(macro_table,macro_size*sizeof(*macro_table));
+    macro_table[0].name=0; /* dummy */
+  }
+  macro_table[macro_cnt].name=mymalloc(strlen(name)+1);
+  strcpy(macro_table[macro_cnt].name,name);
+  macro_table[macro_cnt].flags=flags;
+  macro_table[macro_cnt].nargs=nargs;
+  macro_table[macro_cnt].repl.size=0;
+  macro_table[macro_cnt].repl.next=0;
+  macro_table[macro_cnt].repl.tokens=0;  
+  copy_tokenlist(&macro_table[macro_cnt].repl,repl);
+  return macro_cnt++;
+}
+
+static void free_macro(int n)
+{
+  free(macro_table[n].name);
+  free(macro_table[n].repl.tokens);
+  macro_table[n].name=0;
+}
+
+static int hash(char *p)
+{
+  int s=0;
+  while(*p)
+    s+=*p++;
+  return s%PP_HSIZE;
+}
+
+static int find_macro(char *name)
+{
+  int i=hash(name),n,*p;
+  if(!(p=hash_table[i])) return 0;
+  n=p[0];
+  for(i=1;i<=n;i++)
+    if(macro_table[p[i]].name&&!strcmp(macro_table[p[i]].name,name))
+      return p[i];
+  return 0;
+}
+
+static void add_macro(int n)
+{
+  int i=hash(macro_table[n].name),*p;
+  if(!(p=hash_table[i])){
+    hash_table[i]=p=mymalloc(2*sizeof(*hash_table[i]));
+    p[0]=1;
+    p[1]=n;
+  }else{
+    p=hash_table[i]=myrealloc(p,(p[0]+1)*sizeof(*p));
+    p[0]++;
+    p[p[0]]=n;
+printf("hash_collisio, depth=%d\n",p[0]);
+  }
+}
+
+#endif /* OBFUSCATOR */
+
+static FILE *include_file(const char *name)
+{
+    if(incn>=incsize){
+	incsize+=INCSIZE;
+	incfile=myrealloc(incfile,incsize*sizeof(*incfile));
+	incname=myrealloc(incname,incsize*sizeof(*incname));
+	incline=myrealloc(incline,incsize*sizeof(*incline));
+    }
+    if(!name){
+	incfile[incn]=stdin;
+	name="<stdin>";
+    }else{
+	incfile[incn]=fopen(name,"r");
+    }
+printf("include file %s\n",name);
+    incname[incn]=mymalloc(strlen(name)+1);
+    strcpy(incname[incn],name);
+    incn++;
+    return incfile[incn-1];
+}
+
+static FILE *close_file(void)
+{
+    --incn;
+    free(incname[incn]);
+    if(incfile[incn])
+      fclose(incfile[incn]);
+    if(incn<=0)
+	return 0;
+    return incfile[incn-1];
+}
+
+static void add_token(tokenlist *p,int c)
+{
+  if(p->next>=p->size){
+    p->size+=PP_TSIZE;
+    p->tokens=myrealloc(p->tokens,p->size*sizeof(*p->tokens));
+  }
+  p->tokens[p->next]=c;
+  p->next++;
+}
+
+int read_char(void)
+/* Read next input character. Counts line numbers. */
+{
+  int tmp=getc(infile);
+  if(tmp=='\n') line++;
+  return tmp;
+}
+
+static int push_back=EOF;
+
+static int get_next_char(void)
+/* Read next character. Handles trigraphs and line-concatenation. */
+{
+  static int buf[2],inbuf;
+  int tmp,tmp2;
+  if(push_back!=EOF){
+    tmp=push_back;
+    push_back=EOF;
+    return tmp;
+  }
+  if(inbuf==0){
+    tmp=read_char();
+    if(tmp!='\\'&&tmp!='?'){
+      return tmp;
+    }else{
+      buf[0]=tmp;
+      inbuf=1;
+      /* fall through */
+    }
+  }
+  if(inbuf==1){
+    if(buf[0]!='?'&&buf[0]!='\\'){
+      inbuf=0;
+      return buf[0];
+    }else{
+      tmp=read_char();
+      if(buf[0]=='\\'){
+	if(tmp=='\n'){
+	  inbuf=0;
+	  return get_next_char();
+	}else{
+	  buf[0]=tmp;
+	  return '\\';
+	}
+      }else{
+	if(tmp=='?'){
+	  buf[1]='?';
+	  inbuf=2;
+	  /* fall through */
+	}else{
+	  buf[0]=tmp;
+	  return '?';
+	}
+      }
+    }
+  }
+  if(inbuf==2){
+    if(buf[0]!='?') ierror(0);
+    if(buf[1]!='?'){
+      inbuf=1;
+      tmp=buf[0];
+      buf[0]=buf[1];
+      return tmp;
+    }else{
+      tmp2=tmp=read_char();;
+      /* FIXME: only if on */
+      if(tmp=='=') tmp2='#';
+      else if(tmp=='(') tmp2='[';
+      else if(tmp=='/') tmp2='\\';
+      else if(tmp==')') tmp2=']';
+      else if(tmp=='\'') tmp2='^';
+      else if(tmp=='<') tmp2='{';
+      else if(tmp=='!') tmp2='|';
+      else if(tmp=='>') tmp2='}';
+      else if(tmp=='-') tmp2='~';
+      if(tmp!=tmp2){
+	/* FIXME: warning */
+	if(tmp2!='\\'){
+	  inbuf=0;
+	  return tmp2;
+	}else{
+	  inbuf=1;
+	  buf[0]=tmp2;
+	  return get_next_char();
+	}
+      }else{
+	tmp=buf[0];
+	buf[0]=buf[1];
+	buf[1]=tmp2;
+	return tmp;
+      }
+    }
+  }
+  ierror(0);
+}
+
+static int get_next_token(tokenlist *p)
+{
+  int c,z,tmp,*cnt;
+  while(1){
+    c=get_next_char();
+    if(c=='"'||c=='\''){
+      int term=c,escape=0;
+      add_token(p,c);      
+      z=p->next;
+      add_token(p,0);
+      while(1){
+	c=get_next_char();
+	/* FIXME */
+	if(c==EOF||c=='\n'){
+	  puts("unterminated string");
+	  return 0;
+	}
+	if(c==term&&!escape) return 0;
+	if(escape&&c=='\\')
+	    escape=0;
+	else
+	    escape=(c=='\\');
+	add_token(p,c);
+	p->tokens[z]++;
+      }
+    }else if(c=='_'||isalpha((unsigned char)c)){
+      add_token(p,TKIDENTIFIER);
+      z=p->next;
+      add_token(p,1);
+      add_token(p,c);
+      while((c=get_next_char())=='_'||isalnum((unsigned char)c)){
+	add_token(p,c);
+	p->tokens[z]++;
+      }
+      push_back=c;
+      return 0;
+    }else if(isdigit((unsigned char)c)){
+      tmp=c;
+      c=TKNUMBER;
+    }else if(c=='.'){
+      tmp=get_next_char();
+      if(isdigit((unsigned char)tmp)){
+	push_back=tmp;
+	tmp='.';
+	c=TKNUMBER;
+      }else if(tmp=='.'){
+	c=get_next_char();
+	if(c!='.'){puts("..x-token");return 0;}/*FIXME*/
+	add_token(p,TKDDD);
+	return 0;
+      }else
+	push_back=tmp;
+      /* fall through */
+    }else if(c=='+'){
+      c=get_next_char();
+      if(c=='+'){
+	add_token(p,TKPLUSPLUS);
+      }else if(c=='='){
+	add_token(p,TKPLUSEQ);
+      }else{
+	add_token(p,'+');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='-'){
+      c=get_next_char();
+      if(c=='-'){
+	add_token(p,TKMINMIN);
+      }else if(c=='='){
+	add_token(p,TKMINEQ);
+      }else if(c=='>'){
+	add_token(p,TKSREF);
+      }else{
+	add_token(p,'-');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='|'){
+      c=get_next_char();
+      if(c=='|'){
+	add_token(p,TKLOR);
+      }else if(c=='='){
+	add_token(p,TKOREQ);
+      }else{
+	add_token(p,'|');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='&'){
+      c=get_next_char();
+      if(c=='&'){
+	add_token(p,TKLAND);
+      }else if(c=='='){
+	add_token(p,TKANDEQ);
+      }else{
+	add_token(p,'&');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='<'){
+      c=get_next_char();
+      if(c=='<'){
+	c=get_next_char();
+	if(c=='='){
+	  add_token(p,TKLTLTEQ);
+	}else{
+	  add_token(p,TKLTLT);
+	  push_back=c;
+	}
+      }else if(c=='='){
+	add_token(p,TKLE);
+      }else{
+	add_token(p,'<');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='>'){
+      c=get_next_char();
+      if(c=='>'){
+	c=get_next_char();
+	if(c=='=')
+	  add_token(p,TKGTGTEQ);
+	else{
+	  add_token(p,TKGTGT);
+	  push_back=c;
+	}
+      }else if(c=='='){
+	add_token(p,TKGE);
+      }else{
+	add_token(p,'>');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='!'){
+      c=get_next_char();
+      if(c=='='){
+	add_token(p,TKNE);
+      }else{
+	add_token(p,'!');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='*'){
+      c=get_next_char();
+      if(c=='='){
+	add_token(p,TKMULEQ);
+      }else{
+	add_token(p,'*');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='%'){
+      c=get_next_char();
+      if(c=='='){
+	add_token(p,TKMODEQ);
+      }else{
+	add_token(p,'%');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='#'){
+      c=get_next_char();
+      if(c=='#'){
+	add_token(p,TKNUMNUM);
+      }else{
+	add_token(p,'#');
+	push_back=c;
+      }
+      return 0;
+    }else if(c=='/'){
+      /*FIXME*/
+      c=get_next_char();
+      if(c=='*'){
+	int cstate=0;
+	while(1){
+	  c=get_next_char();
+	  if(c=='*'){
+	    if(cstate==2) /*FIXME*/;
+	    cstate=1;
+	  }else if(c=='/'){
+	    if(cstate==1) break;
+	    cstate=2;
+	  }else cstate=0;
+	}
+	if(p->next>=1&&p->tokens[p->next-1]!=' '){
+	    add_token(p,' ');
+	    return 0;
+	}else
+	    continue;
+      }else if(c=='/'/*FIXME*/){
+	while((c=get_next_char())!=EOF&&c!='\n');
+	if(c==EOF) ierror(0); /*FIXME*/
+	add_token(p,'\n');
+	return 0;
+      }else if(c=='='){
+	add_token(p,TKDIVEQ);
+	return 0;
+      }
+      push_back=c;
+      c='/';
+      /* fall through */
+    }
+    if(c==TKNUMBER){
+      add_token(p,TKNUMBER);
+      z=p->next;
+      add_token(p,1);
+      add_token(p,tmp);
+      while(1){
+	c=get_next_char();
+	if(c=='e'||c=='E'||/*FIXME?*/c=='p'||c=='P'){
+	  add_token(p,c);
+	  p->tokens[z]++;
+	  tmp=get_next_char();
+	  if(tmp=='+'||tmp=='-'){
+	    add_token(p,tmp);
+	    p->tokens[z]++;
+	  }else{
+	    push_back=tmp;
+	  }
+	}else if(c=='.'||c=='_'||isalnum((unsigned char)c)){
+	  add_token(p,c);
+	  p->tokens[z]++;
+	}else{
+	  push_back=c;
+	  break;
+	}
+      }
+      return 0;
+    }
+    if(c==EOF||c=='\n'){
+      add_token(p,c);
+      return c;
+    }
+    if(!isspace((unsigned char)c)){
+      add_token(p,c);
+      return 0;
+    }else{
+      if(p->next>=1&&p->tokens[p->next-1]!=' ')
+	add_token(p,' ');
+      return 0;
+    }
+  }
+}
+
+void print_tokenlist(FILE *f,tokenlist *p)
+{
+  int i,*tr=p->tokens,*end=tr+p->next;
+  while(tr<end){
+    if(*tr=='"'||*tr=='\''||*tr==TKIDENTIFIER||*tr==TKNUMBER){
+      int n;
+      if(*tr=='"')
+	fprintf(f,"STRING: ");
+      else if(*tr=='\'')
+	fprintf(f,"CCONST: ");
+      else if(*tr==TKNUMBER)
+	fprintf(f,"NUMBER: ");
+      else
+	fprintf(f,"IDENT: ");
+      tr++;
+      n=*tr++;
+      for(i=0;i<n;i++)
+	fprintf(f,"%c",*tr++);
+      fprintf(f,"\n");
+      continue;
+    }
+    if(*tr==TKMARG){
+      fprintf(f,"ARG %d\n",tr[1]);
+      tr+=2; continue;
+    }
+    if(*tr==EOF){
+      fprintf(f,"EOF\n");
+      tr++; continue;
+    }
+    if(*tr=='\n'){
+      fprintf(f,"NEWLINE\n");
+      tr++; continue;
+    }
+    if(*tr>=TKPLUSPLUS&&*tr<=TKNUMNUM){
+      fprintf(f,"%s\n",desc[*tr-TKKEYWORD]);
+      tr++; continue;
+    }
+    fprintf(f,"OTHER: %d(%c)\n",*tr,*tr);
+    tr++;
+  }
+}
+
+void print_code(FILE *f,tokenlist *p)
+{
+  int i,*tr=p->tokens,*end=tr+p->next;
+  while(tr<end){
+    if(*tr=='"'||*tr=='\''||*tr==TKIDENTIFIER||*tr==TKNUMBER){
+      int n,c;
+      if(*tr==TKIDENTIFIER||*tr==TKNUMBER)
+	c=0;
+      else
+	c=*tr;
+      tr++;
+      if(c)
+	  fprintf(f,"%c",c);
+      n=*tr++;
+      for(i=0;i<n;i++)
+	fprintf(f,"%c",*tr++);
+      if(c)
+	fprintf(f,"%c",c);
+      continue;
+    }
+    if(*tr==EOF){
+	return;
+    }
+    if(*tr=='\n'){
+      fprintf(f,"\n");
+      tr++; continue;
+    }
+    if(*tr>=TKPLUSPLUS&&*tr<=TKNUMNUM){
+      fprintf(f,"%s",tokout[*tr-TKKEYWORD]);
+      tr++; continue;
+    }
+    fprintf(f,"%c",*tr);
+    tr++;
+  }
+}
+
+char *token2string(int *p)
+{
+  int n=p[1];char *s;
+  static char *buf,len;
+  if(n+1>len){
+    len=n+1;
+    buf=mymalloc(len);
+  }
+  s=buf;
+  p+=2;
+  while(--n>=0) *s++=*p++;
+  *s=0;
+  return buf;
+}
+
+#ifndef OBFUSCATOR
+
+static int *get_macro_arg(tokenlist *arg,int *p,int vararg)
+{
+  int par=0;
+  while(1){
+    if(*p==EOF||*p=='\n') puts("unterminated macro invocation"); /*FIXME*/
+    if(*p==','&&par==0&&!vararg) return p;
+    if(*p==')'){
+      if(par>0){
+	add_token(arg,*p++);
+	par--;
+	continue;
+      }else
+	return p;
+    }
+    if(*p==TKIDENTIFIER||*p==TKNUMBER||*p=='"'||*p=='\''){
+      int n;
+      add_token(arg,*p++);
+      n=*p;
+      add_token(arg,*p++);
+      while(--n>=0) add_token(arg,*p++);
+      continue;
+    }
+    if(*p=='(') par++;
+    add_token(arg,*p++);
+  }
+}
+
+void stringize(tokenlist *new,tokenlist *src)
+{
+  int z,f,n;
+  int *p=src->tokens,*end=p+src->next;
+puts("1");
+  add_token(new,'"');
+  z=new->next;
+  add_token(new,0);
+  while(p<end){
+puts("2");
+    f=*p;
+    if(f==TKIDENTIFIER||f==TKNUMBER||f=='"'||f=='\''){
+      if(f=='"'){
+	add_token(new,'\\');
+	add_token(new,'"');
+	new->tokens[z]+=2;
+      }else if(f=='\''){
+	add_token(new,'\'');
+	new->tokens[z]++;
+      }
+      p++;
+      n=*p++;
+      while(--n>=0){
+	if((f=='"'||f=='\'')&&(*p=='\\'||*p=='"')){
+	  add_token(new,'\\');
+	  new->tokens[z]++;
+	}
+	add_token(new,*p++);
+	new->tokens[z]++;
+      }
+      continue;
+    }
+puts("3b");
+    add_token(new,*p++);
+    new->tokens[z]++;
+  }
+}
+
+int expand(tokenlist *dest,tokenlist *old,tokenlist *scratch1,tokenlist *scratch2)
+{
+  int n,i,*p,*end;
+  int did_replace=0,notdone;
+  tokenlist *new=scratch1,*src=old,t1={0},t2={0};
+  do{
+puts("starting expand iteration");
+    notdone=0;
+    p=src->tokens;
+    end=p+src->next;
+    while(p<end){
+      if(*p==TKIDENTIFIER||*p==TKNUMBER||*p=='"'||*p=='\''){
+	if(*p==TKIDENTIFIER&&(n=find_macro(token2string(p)))!=0){
+	  tokenlist *repl=&macro_table[n].repl;
+	  if(!(macro_table[n].flags&NEED_PAREN)){
+	    n=repl->next;
+	    for(i=0;i<n;i++) add_token(new,repl->tokens[i]);
+	    p+=p[1]+2;
+	    did_replace=notdone=1;
+	    continue;
+	  }else if(p[p[1]+2]=='('){
+	    tokenlist **args=mymalloc((macro_table[n].nargs+1)*sizeof(*args));
+	    /*	  tokenlist *scratch=mymalloc(sizeof(*scratch));*/
+	    int *r,*end;
+	    p+=p[1]+3;
+	    for(i=0;i<macro_table[n].nargs;i++){
+	      if(i!=0){
+		if(*p==',') p++; else puts(", expect");/*FIXME*/
+	      }
+	      args[i]=mymalloc(sizeof(**args));
+	      args[i]->size=0;
+	      args[i]->next=0;
+	      args[i]->tokens=0;
+	      p=get_macro_arg(args[i],p,0);
+	      printf("arg %d:\n",i);
+	      print_tokenlist(stdout,args[i]);
+	    }
+	    if(macro_table[n].flags&VARARG_MACRO){
+	      args[i]=mymalloc(sizeof(**args));
+	      args[i]->size=0;
+	      args[i]->next=0;
+	      args[i]->tokens=0;
+	      if(*p==',') p++; else puts(", expect");/*FIXME*/
+	      p=get_macro_arg(args[i],p,1);
+	      printf("vararg:\n");
+	      print_tokenlist(stdout,args[i]);
+	    }
+	    if(*p==')') p++; else puts(") expect");/*FIXME*/
+	    
+	    r=macro_table[n].repl.tokens;
+	    end=r+macro_table[n].repl.next;
+	    while(r<end){
+	      if(*r==TKIDENTIFIER||*r==TKNUMBER||*r=='"'||*r=='\''){
+		n=r[1];
+		puts("insert idnt");
+		r+=2;
+		while(--n>=0) add_token(new,*r++);
+		continue;
+	      }
+	      if(*r=='#'){
+		r++;
+		if(*r!=TKMARG) {puts("huch?");ierror(0);/*FIXME*/}
+		r++;
+		n=*r++;
+		stringize(new,args[n]);
+		continue;
+	      }
+	      if(*r==TKMARG){
+		t1.next=t2.next=0;
+		expand(new,args[r[1]],&t1,&t2);
+		r+=2;
+		continue;
+	      }
+	      puts("insert other");
+	      add_token(new,*r++);
+	    }
+	    
+	    for(i=0;i<macro_table[n].nargs;i++) free(args[i]);
+	    if(macro_table[n].flags&VARARG_MACRO) free(args[i]);
+	    free(args);
+	    did_replace=notdone=1;
+	    continue;
+	  }
+	}
+	add_token(new,*p++);
+	n=*p++;
+	add_token(new,n);
+	for(i=0;i<n;i++) add_token(new,*p++);
+      }else
+	add_token(new,*p++);
+    }
+    if(!notdone){
+puts("expand done, copying");
+print_tokenlist(stdout,new);
+      copy_tokenlist(dest,new);
+puts("copy done");
+    }else{
+puts("need another iteration");
+      src=new;
+      if(new==scratch1)
+	new=scratch2;
+      else
+	new=scratch1;
+      new->next=0;
+    }
+  }while(notdone);
+  return did_replace;
+}
+
+#endif /* OBFUSCATOR */
+
+main()
+{
+  int i,lastline=line,*p;
+  tokenlist tl={0},t2={0},t3={0},t4={0};
+  infile=include_file(0);
+#ifndef OBFUSCATOR  
+  hash_table=mymalloc(PP_HSIZE*sizeof(*hash_table));
+  for(i=0;i<PP_HSIZE;i++) hash_table[i]=0;
+#endif  
+  while(1){
+    tl.next=0;
+    while(!(i=get_next_token(&tl)));
+    add_token(&tl,TKEOL);
+    print_code(stdout,&tl);
+    if(i==EOF){
+	infile=close_file();
+	if(!infile) exit(0);
+    }
+#ifndef OBFUSCATOR
+    p=&tl.tokens[0];
+    while(*p==' ') p++;
+    if(*p=='#'&&(p[1]==TKIDENTIFIER||(p[1]==' '&&p[2]==TKIDENTIFIER))){
+      char *s;
+      p++;
+      if(*p!=TKIDENTIFIER) p++;
+      s=token2string(p);
+      if(!strcmp(s,"include")){
+	puts("include found");
+	*p=TKNUMBER; /* prevent expansion */
+	p+=2+p[1];
+	i=p-&tl.tokens[0];
+	t2.next=0;
+	t3.next=0;
+	t4.next=0;
+	expand(&t2,&tl,&t3,&t4);
+	p=&t2.tokens[i];
+	while(*p==' ') p++;
+printf("*p=%d\n",*p);
+	if(*p=='\"'){
+	  s=token2string(p);
+	  infile=include_file(s);
+	  if(!infile) infile=close_file();
+	  if(!infile) {exit(EXIT_FAILURE);/*FIXME*/}
+	}
+	
+	continue;
+      }else if(!strcmp(s,"define")){
+	puts("define found");
+	p+=2+p[1];
+	while(*p==' ') p++;
+	if(*p!=TKIDENTIFIER){
+	  puts("#define needs ID");
+	}else{
+	  char *mname;
+	  int flags=0,nargs=0;
+	  static char **pnames;
+	  static int pnsize;
+
+	  s=token2string(p);
+	  p+=2+p[1];
+	  mname=mymalloc(strlen(s)+1);
+	  strcpy(mname,s);
+	  printf("id=%s\n",mname);
+	  while(*p==' ') p++;
+	  if(*p=='('){
+	    puts("function-like");
+	    p++;
+	    while(*p==' ') p++;
+	    while(*p==TKIDENTIFIER){
+	      flags=0;
+	      s=token2string(p);
+	      p+=p[1]+2;
+	      printf("parameter %s\n",s);
+	      if(nargs>=pnsize){
+		pnsize+=PP_MSIZE;
+		pnames=myrealloc(pnames,pnsize*sizeof(*pnames));
+	      }
+	      for(i=0;i<nargs;i++)
+		if(!strcmp(pnames[i],s)) puts("double parameter");
+	      pnames[nargs]=mymalloc(strlen(s)+1);
+	      strcpy(pnames[nargs],s);
+	      nargs++;
+	      while(*p==' ') p++;
+	      if(*p==','){ p++;flags=1;}
+	      while(*p==' ') p++;
+	    }
+	    if(flags){
+	      flags=NEED_PAREN;
+	      if(*p==TKDDD){p++;flags|=VARARG_MACRO;}else puts(".../,");/*FIXME*/
+	      while(*p==' ') p++;
+	      if(*p==')') p++; else puts(") expect");/*FIXME*/
+	    }else{
+	      flags=NEED_PAREN;
+	      if(*p==')') p++; else puts(") expect");/*FIXME*/
+	    }
+	  }
+	  /*FIXME: # must be followed by parameter */
+	  t2.next=0;
+	  while(*p==' ') p++;
+	  while(p<tl.tokens+tl.next&&*p!='\n'){
+	    if(*p==TKIDENTIFIER){
+	      s=token2string(p);
+	      for(i=0;i<nargs;i++){
+		if(!strcmp(pnames[i],s)) break;
+	      }
+	      if(i<nargs||((flags&VARARG_MACRO)&&!strcmp("__VA_ARGS__",s))){
+		p+=p[1]+2;
+		add_token(&t2,TKMARG);
+		add_token(&t2,i);
+		continue;
+	      }
+	    }
+	    add_token(&t2,*p++);
+	  }
+	  for(i=0;i<nargs;i++) free(pnames[i]);
+	  i=new_macro(mname,flags,nargs,&t2);
+	  add_macro(i);
+	  printf("replacement-list for %s\n",mname);
+	  print_tokenlist(stdout,&t2);
+	}
+      }
+    }else{
+      t2.next=0;
+      t3.next=0;
+      t4.next=0;
+      expand(&t2,&tl,&t3,&t4);
+      /*      print_tokenlist(stdout,&t2);*/
+      print_code(stdout,&t2);
+    }
+#endif /* OBFUSCATOR */    
+  }
+}
diff --git a/pptst.h b/pptst.h
new file mode 100755
index 0000000..788fb45
--- /dev/null
+++ b/pptst.h
@@ -0,0 +1,34 @@
+test
+hello
+con\
+catenated
+not\ 
+concatenated
+??= 
+??( 
+??/ 
+??) 
+??' 
+??< 
+??! 
+??> 
+??- 
+From standard: printf("Eh???/n");
+con??/
+catenated with trigraph
+
+# /*   */ define fail succeed
+fail
+#undef fail
+ #define fail succeed
+fail
+
+#define x(a,b) a+b
+
+x(12
+23
+,
+34
+45
+)
+
diff --git a/preproc.c b/preproc.c
new file mode 100755
index 0000000..54f6701
--- /dev/null
+++ b/preproc.c
@@ -0,0 +1,2506 @@
+/* TODO:
+
+   ---- HIGHEST PRIORITY ----
+
+   * #ifndef
+
+   * #if/#elif - Bearbeitung
+
+   * leere argument-/tokenlists erlauben
+
+   * Anzahl der Argumente checken (auch zuviele ergeben einen Error)
+
+   * bei REDEFINING und allowredefinition=0 tokenlist genau ueberpruefen
+
+   * Aufteilen in mehrere Sourcen main.c pplists.c etc.
+   * Einige Variablen umbenennen (x,y,i,j,l,n etc =8)
+
+   -----------------------------------------------------------------
+
+   * Verbesserungen:
+   * - Nach malloc()/vor free() ueberpruefen ob NULL-Pointer
+   * - Statt per dlen per Ptr2EOL abfragen..
+
+   * Fragen an Volker:
+   * - _ alleine ein Identifier ? Ja
+
+   ---- LOWEST PRIORITY ----
+
+   * - Token loeschen, wenn nur noch TokenList benutzt wird.
+
+   * - ParseIdent.. optimieren
+
+   * - Rest optimieren =8)
+
+   * - PreParsing umschreiben.. __LINE__ muss mit der echten
+   *    Zeilennummer uebereinstimmen (die LFs drinlassen)
+ */
+
+/*
+ * PreProcessor
+ * $VER: VBPP V0.00 (19 Sep 1995)
+ * (w) 1995 by Thorsten Schaaps
+ */
+
+#include <time.h>
+
+#include "vbc.h"
+#include "vbpp.h"
+
+/*vb:   */
+static char FILE_[]=__FILE__;
+
+/*vb:   */
+char pp_version[] = "vbpp V0.00 (w) 1995 by Thorsten Schaaps";
+
+                                /* #define MAXIFNESTING 1024 *//*vb: ifnesting==incnesting */
+
+FILE *in[MAXINCNESTING];        /*  Sourcefiles     */
+int zn[MAXINCNESTING];          /*  Zeilennummern   */
+char *filenames[MAXINCNESTING];  /*  Filenamen   */
+int incnesting;                 /*  aktuelle Verschachtelungstiefe  */
+unsigned long linenr;           /*  Zeilennummer */
+
+char *incpath[MAXINCPATHS] =
+{"vinclude:"};                  /*  Includepfade    */
+
+int incpathc = 1;               /*  Anzahl der Includepfade     */
+
+char ppstring[MAXPPINPUT];
+
+int cmtnesting = 0;             /*  aktuelle Kommentar-Versch.-Tiefe */
+
+                                          /*int ifnesting; *//*vb: *//*  aktuelle IF-Tiefe */
+/*vb: ifnesting==incnesting */
+short ifstatus[MAXINCNESTING];  /* Array fuer Status-Verschachtelung */
+int if_cnt;                     /* Zaehler fuer #if's waehrend do_output=0 */
+int abs_if_cnt;                 /* zaehlt auch waehrend do_output */
+
+int do_output = 1;              /* Flag zur Erzeugung eines Outputs */
+
+struct strnode *strlist;
+
+struct mnode *mlist;
+
+int did_expand;
+
+/* Temporaere Debugging-Routinen */
+void PrintSN(struct strnode *tl)
+{
+    switch (tl->type) {
+    case NORMAL:
+        printf(" Normal........:");
+        break;
+    case PP_IDENT:
+        printf(" Identifier....:");
+        break;
+    case ARGUMENT:
+        printf(" Argument Nr.%2d:", tl->number);
+        break;
+    case NUMBER:
+        printf(" Number........:");
+        break;
+    case PP_STR:
+        printf(" String........:");
+        break;
+    case SPACE:
+        printf(" Space.........:");
+        break;
+    case SPECIAL:
+        printf(" Special..Nr.%2d:", tl->flags);
+        break;
+    default:
+        printf(" unknown..Nr.%2d:", tl->type);
+        break;
+    }
+    printf(" %s\n", tl->str);
+}
+void PrintTL(struct strnode *tl)
+{
+
+#ifdef bla
+
+    if (tl) {
+        printf("TokenList:\n");
+        while (tl) {
+            PrintSN(tl);
+            tl = tl->next;
+        }
+    }
+#endif
+
+}
+
+
+/* ******* Listen-Funktionen ******* */
+
+/* AddMakroNode - Fuegt eine Node an den Anfang einer Liste ein */
+void AddMakroNode(struct mnode **list, struct mnode *node)
+{
+
+    if (DEBUG & 32)
+        puts("AddMakroNode");
+
+    if (node) {
+        node->prev = NULL;
+        node->next = *list;
+        *list = node;
+        if (node->next)
+            node->next->prev = node;
+    }
+}
+
+
+/* AddStrNode - Fuegt eine Node in die Liste ein */
+void AddStrNode(struct strnode **list, struct strnode *node, char *str)
+{
+
+    if (DEBUG & 32)
+        puts("AddStrNode");
+
+
+    if (node || str) {
+        if (!node)
+            node = (struct strnode *) malloc(sizeof(struct strnode));
+        /* HIER: Rueckgabewert wegen Fehler ! */
+        if (!node) {
+            error(196);
+        } else {
+            node->prev = NULL;
+            node->next = *list;
+            if (str)
+                node->str = str;
+            *list = node;
+            if (node->next)
+                node->next->prev = node;
+        }
+    }
+}
+
+
+/* AddStrNodeBehind - Fuegt eine Node ans Ende der Liste ein */
+void AddStrNodeBehind(struct strnode **list, struct strnode *node, char *str)
+{
+    struct strnode *listnode;
+
+    if (DEBUG & 32)
+        puts("AddStrNodeBehind");
+
+
+    if (node || str) {
+        if (!node)
+            node = (struct strnode *) malloc(sizeof(struct strnode));
+        if (!node) {
+            error(196);
+        } else {
+            if (!*list) {
+                node->prev = NULL;
+                node->next = NULL;
+                *list = node;
+            } else {
+                listnode = *list;
+                while (listnode->next) {
+                    listnode = listnode->next;
+                }
+                node->prev = listnode;
+                node->next = NULL;
+                listnode->next = node;
+            }
+            if (str)
+                node->str = str;
+        }
+    }
+}
+
+
+/* RemMakroNode - Entfernt eine Node aus der Liste ohne sie zu loeschen */
+void RemMakroNode(struct mnode **list, struct mnode *node)
+{
+
+    if (DEBUG & 32)
+        puts("RemMakroNode");
+
+
+    if (node->prev) {
+        if (node->next)
+            node->next->prev = node->prev;
+        node->prev->next = node->next;
+    } else {
+        if (node->next)
+            node->next->prev = NULL;
+        *list = node->next;
+    }
+    node->next = node->prev = NULL;
+}
+
+/* InsertMakroNode - Setzt eine Node hinter einer anderen ein */
+void InsertMakroNode(struct mnode **list, struct mnode *node, struct mnode *behind)
+{
+
+    if (DEBUG & 32)
+        puts("InsertMakroNode");
+
+
+    if (behind) {
+        node->prev = behind;
+        node->next = behind->next;
+        behind->next = node;
+        if (node->next)
+            node->next->prev = node;
+    } else
+        AddMakroNode(list, node);
+}
+
+/* RemStrNode - Entfernt eine Node aus der Liste ohne sie zu loeschen */
+void RemStrNode(struct strnode **list, struct strnode *node)
+{
+
+    if (DEBUG & 32)
+        puts("RemStrNode");
+
+
+    if (node->prev) {
+        if (node->next)
+            node->next->prev = node->prev;
+        node->prev->next = node->next;
+    } else {
+        if (node->next)
+            node->next->prev = NULL;
+        *list = node->next;
+    }
+    node->next = node->prev = NULL;
+}
+
+
+/* FindMakroNode - sucht den passenden Eintrag in der Liste
+ *                 len=0 - der gesamte String muss uebereinstimmen
+ *                 len>0 - die ersten len Zeichen muessen stimmen
+ */
+struct mnode *FindMakroNode(struct mnode *list, char *str, int len)
+{
+
+    if (DEBUG & 32)
+        puts("FindMakroNode");
+
+    while (list) {
+        if (len) {
+            if ((strlen(list->name) == len) && (!strncmp(list->name, str, len)))
+                return (list);
+        } else {
+            if (!strcmp(list->name, str))
+                return (list);
+        }
+        list = list->next;
+    }
+    return (0);
+}
+
+
+/* DelMakroNode - gibt den gesamten Speicher einer Node frei, ist list#NULL
+ *                wird die Node vorher aus der Liste entfernt
+ */
+void DelMakroNode(struct mnode **list, struct mnode *node)
+{
+
+    if (DEBUG & 32)
+        puts("DelMakroNode");
+
+
+    if (node) {
+        if (list && *list)
+            RemMakroNode(list, node);
+        if (node->name)
+            free(node->name);
+        if (node->args)
+            free(node->args);
+        if (node->token)
+            free(node->token);
+        if (node->tokenlist)
+            DelStrList(&node->tokenlist);
+        free(node);
+    }
+}
+
+
+/* DelStrNode - gibt den gesamten Speicher einer Node frei, ist list#NULL
+ *              wird die Node vorher aus der Liste entfernt
+ */
+void DelStrNode(struct strnode **list, struct strnode *node)
+{
+
+    if (DEBUG & 32)
+        puts("DelStrNode");
+
+
+    if (node) {
+        if (list && *list)
+            RemStrNode(list, node);
+        if (node->str)
+            free(node->str);
+        free(node);
+    }
+}
+
+void MergeStrNodes(struct strnode *prev, struct strnode *next)
+{
+    /* next will now be deleted and prev->str will be */
+    /* the joined strings from prev&next */
+    char *newstr;
+/*vb:   */
+    char c, *s, *d;
+
+    if (DEBUG & 32)
+        puts("MergeStrNodes");
+
+
+    newstr = (char *) malloc(prev->len + next->len + 1);
+/*vb: string-Routinen ersetzt (hoffentlich schneller)
+   strcpy(newstr,prev->str);
+   strcat(newstr,next->str);
+ */
+    d = newstr;
+    s = prev->str;
+    do {
+        c = *s++;
+        *d++ = c;
+    } while (c);
+    d--;
+    s = next->str;
+    do {
+        c = *s++;
+        *d++ = c;
+    } while (c);
+
+    if (prev->str)
+        free(prev->str);        /*vb: wenn prev->str==0 knallts doch schon oben? */
+    prev->str = newstr;
+    prev->len += next->len;
+    DelStrNode(NULL, next);
+}
+
+/* DelMakroList - loescht eine gesamte Liste */
+void DelMakroList(struct mnode **list)
+{
+
+    if (DEBUG & 32)
+        puts("DelMakroList");
+
+
+    while (*list)
+        DelMakroNode(list, *list);
+    /*  *list=NULL; *//*vb: *list==0 */
+}
+
+
+/* DelStrList - loescht eine gesamte Liste samt der Nodes/Strings */
+void DelStrList(struct strnode **list)
+{
+
+    if (DEBUG & 32)
+        puts("DelStrList");
+
+
+    while (*list)
+        DelStrNode(list, *list);
+    /*  *list=NULL; *//*vb: *list==0 */
+}
+
+/* AllocSpace - erzeugt eine StrNode vom Typ Space */
+struct strnode *AllocSpace()
+{
+    struct strnode *newnode;
+    char *newstr;
+
+
+    if (DEBUG & 32)
+        puts("AllocSpace");
+
+
+    newstr = (char *) malloc(2);
+    if (newstr) {
+        newstr[0] = ' ';
+        newstr[1] = 0;
+        newnode = (struct strnode *) malloc(sizeof(struct strnode));
+        if (newnode) {
+            newnode->str = newstr;
+            newnode->type = SPACE;
+            newnode->len = 1;
+            newnode->next = newnode->prev = NULL;
+            newnode->flags = newnode->number = 0;
+            return (newnode);
+        }
+    }
+    return (NULL);
+}
+
+
+/* CloneStrList - erstellt eine exakte Kopie der Liste oder eines Ausschnittes */
+/*                wenn listend#NULL */
+struct strnode *CloneStrList(struct strnode *list, struct strnode *listend)
+{
+    struct strnode *prevnode = NULL, *newnode, *newlist = NULL;
+    char *newstr;
+
+    if (DEBUG & 32)
+        puts("CloneStrList");
+
+
+    while (list) {
+        newnode = (struct strnode *) malloc(sizeof(struct strnode));
+        if (!newnode) {
+            DelStrList(&newlist);
+            return (NULL);
+        }
+        newstr = (char *) malloc(list->len + 1);
+        if (!newstr) {
+            free(newnode);
+            DelStrList(&newlist);
+            return (NULL);
+        }
+        strcpy(newstr, list->str);
+        newnode->str = newstr;
+        newnode->len = list->len;
+        newnode->flags = list->flags;
+        newnode->type = list->type;
+        newnode->number = list->number;
+        newnode->next = NULL;
+        newnode->prev = prevnode;
+
+        if (prevnode)
+            prevnode->next = newnode;
+        else
+            newlist = newnode;
+        prevnode = newnode;
+
+        if (listend && list == listend)
+            list = NULL;
+        else
+            list = list->next;
+    }
+    return (newlist);
+}
+
+
+/* DoMakroFunction - erstellt eine StrList entsprechend des Function-Makros */
+struct strnode *DoMakroFunction(struct mnode *makro)
+{
+    struct strnode *result = NULL;
+    char *newstr = NULL, *timestr = NULL;
+    int len, type;
+    time_t timevalue;
+
+    if (DEBUG & 32)
+        puts("DoMakroFunction");
+
+
+    if (makro->flags & FUNCTION) {
+        switch (makro->funcnum) {
+        case FUNCLINE:
+            newstr = (char *) malloc(11);
+            if (!newstr)
+                return (NULL);
+            sprintf(newstr, "%lu", linenr);
+            len = strlen(newstr);
+            type = NUMBER;
+            break;
+        case FUNCFILE:
+            len = strlen(filenames[incnesting]);
+            newstr = (char *) malloc(len + 1 + 2);
+            if (!newstr)
+                return (NULL);
+            *newstr = '\"';
+            strcpy((newstr + 1), filenames[incnesting]);
+            strcat(newstr, "\"");
+            type = PP_STR;
+            break;
+        case FUNCDATE:
+            type = PP_STR;
+            newstr = (char *) malloc(14);
+            if (!newstr)
+                return (NULL);
+            timevalue = time(0);
+            timestr = ctime(&timevalue);
+            newstr[0] = '\"';
+            strncpy(newstr + 1, timestr + 4, 7);        /* copy 'Mmm dd ' */
+            strcpy(newstr + 8, timestr + 20);   /* copy 'yyyy' */
+            newstr[12] = '\"';
+            newstr[13] = 0;
+            len = 13;
+            break;
+        case FUNCTIME:
+            type = PP_STR;
+            newstr = (char *) malloc(11);
+            if (!newstr)
+                return (NULL);
+            timevalue = time(0);
+            timestr = ctime(&timevalue);
+            newstr[0] = '\"';
+            strncpy(newstr + 1, timestr + 11, 8);       /* copy 'hh:mm:ss' */
+            newstr[9] = '\"';
+            newstr[10] = 0;
+            len = 10;
+            break;
+        default:
+            return (NULL);
+            break;
+        }
+        result = (struct strnode *) malloc(sizeof(struct strnode));
+        if (!result) {
+            if (newstr)
+                free(newstr);
+            return (NULL);
+        }
+        result->prev = result->next = NULL;
+        result->str = newstr;
+        result->len = len;
+        result->number = result->flags = 0;
+        result->type = type;
+    }
+    return (result);
+}
+
+
+/* *******  String-Funktionen ****** */
+
+/* Str2List - parsed einen String in eine StrList */
+struct strnode *Str2List(char *str)
+{
+    struct strnode *newlist = NULL, *newnode = NULL;
+    char *temp, *string;
+    int length, type, flags;
+
+    if (DEBUG & 32)
+        puts("Str2List");
+
+    while (*str) {
+        flags = 0;
+/*vb: casts eingefuegt   */
+        if (isspace((unsigned char) *str)) {    /* Spaces parsen */
+            temp = str + 1;
+            length = 1;
+            while (*temp && isspace((unsigned char) *temp)) {
+                temp++;
+                length++;
+            }
+            type = SPACE;
+        } else if (*str == '\"') {      /* String parsen */
+            temp = str + 1;
+            length = 2;
+            while (*temp && *temp != '\"')
+                if (*temp == '\\') {
+                    temp += 2;
+                    length += 2;
+                } else {
+                    temp++;
+                    length++;
+                }
+            type = PP_STR;
+        } else if (*str == '\'') {      /* String parsen */
+            temp = str + 1;
+            length = 2;
+            while (*temp && *temp != '\'')
+                if (*temp == '\\') {
+                    temp += 2;
+                    length += 2;
+                } else {
+                    temp++;
+                    length++;
+                }
+            type = PP_STR;
+        } else if (isdigit((unsigned char) *str) || (*str == '.' && isdigit((unsigned char) *(str + 1)))) {
+            /* Zahlen parsen */
+            temp = str;
+            length = 0;
+            while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+                temp++;
+                length++;
+            }
+            if (*temp == '.') {
+                temp++;
+                length++;
+                if (isdigit((unsigned char) *temp) || *temp == 'e' || *temp == 'E')
+                    while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+                        temp++;
+                        length++;
+                    }
+            }
+            if (*(temp - 1) == 'e' || *(temp - 1) == 'E')
+                if (isdigit((unsigned char) *temp) || *temp == '+' || *temp == '-') {
+                    temp++;
+                    length++;
+                    while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+                        temp++;
+                        length++;
+                    }
+                }
+            type = NUMBER;
+        } else if (isalpha((unsigned char) *str) || *str == '_') {      /* moegl. Identifier parsen */
+            temp = str + 1;
+            length = 1;
+            while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+                temp++;
+                length++;
+            }
+            type = PP_IDENT;
+        } else if (*str) {      /* alles andere als einzelne Zeichen */
+            length = 1;
+            type = NORMAL;
+        }
+        string = (char *) malloc(length + 1);
+        if (!string) {
+            error(196);
+            DelStrList(&newlist);
+            return (NULL);
+        }
+        strncpy(string, str, length);
+        string[length] = 0;
+        str += length;
+
+        newnode = (struct strnode *) malloc(sizeof(struct strnode));
+        if (!newnode) {
+            error(196);
+            if (string)
+                free(string);
+            return (NULL);
+        }
+        newnode->str = string;
+        newnode->len = length;
+        newnode->flags = flags;
+        newnode->type = type;
+
+        AddStrNodeBehind(&newlist, newnode, NULL);
+    }
+    return (newlist);
+}
+
+/* List2Str - schreibt eine Liste als String zurueck */
+int List2Str(struct strnode *list, char *str, int maxchars)
+{
+    int len = 0;
+    char c, *p;
+
+    if (DEBUG & 32)
+        puts("List2Str");
+
+
+    *str = 0;
+    if (list) {
+        while (list) {
+            if ((len + (list->len)) > (maxchars - 1)) {
+                error(177);
+                return (0);
+            } else {
+                /*vb:   */
+                p = list->str;
+                do {
+                    c = *p++;
+                    *str++ = c;
+                } while (c);
+                str--;
+/*        strcat(str,list->str); */
+                len += list->len;
+            }
+            list = list->next;
+        }
+        return (len + 1);
+    } else {
+        *str = 0;
+        return (1);
+    }
+}
+
+/* ListLen - ermittelt die Laenge einer Str-Liste (in Zeichen) */
+int ListLen(struct strnode *list)
+{
+    int len = 0;
+    while (list) {
+        len += list->len;
+        list = list->next;
+    }
+    return (len);
+}
+
+/* ListStrLen - ermittelt die Laenge einer Str-List als String   */
+/*              d.h. mit " am Anfang und Ende, sowie einem \ vor */
+/*              jedem \ und "                                    */
+int ListStrLen(struct strnode *list)
+{
+    int len = 2;
+    while (list) {
+        if (list->type == SPACE)
+            len++;
+        else {
+            len += list->len;
+            if (list->type == PP_STR && list->str[0] == '\"')
+                len += 2;
+            else if (list->type == NORMAL && list->str[0] == '\\')
+                len++;
+        }
+        list = list->next;
+    }
+    return (len);
+}
+
+/* CopyList2StrStr - kopiert eine Str-List als String um         */
+/*              d.h. mit " am Anfang und Ende, sowie einem \ vor */
+/*              jedem \ und "                                    */
+CopyList2StrStr(struct strnode * list, char *str)
+{
+    int len;
+
+    if (DEBUG & 32)
+        puts("CopyList2StrStr");
+
+
+    str[0] = 0;
+    if (list) {
+        strcpy(str, "\"");
+        len = 1;
+        while (list) {
+            if (list->type == SPACE) {
+                len++;
+                strcat(str, " ");
+            } else {
+                len += list->len;
+                if (list->type == PP_STR && list->str[0] == '\"') {
+                    strcat(str, "\\");
+                    strncat(str, list->str, list->len - 1);
+                    strcat(str, "\\\"");
+                } else if (list->type == NORMAL && list->str[0] == '\\') {
+                    strcat(str, "\\");
+                    strcat(str, list->str);
+                } else
+                    strcat(str, list->str);
+            }
+            list = list->next;
+        }
+        strcat(str, "\"");
+        len++;
+    }
+    return (len);
+}
+
+/* NextToSpecial - checked, ob die StrNode neben einem # oder ## steht */
+int NextToSpecial(struct strnode *node)
+{
+    struct strnode *search;
+
+    if (DEBUG & 32)
+        puts("NextToSpecial");
+
+
+    if (node->prev) {
+        search = node->prev;
+        while (search && search->type == SPACE)
+            search = search->prev;
+        if (search && search->type == SPECIAL)
+            return (search->flags);
+    }
+    if (node->next) {
+        search = node->next;
+        while (search && search->type == SPACE)
+            search = search->next;
+        /* Hinter der Node ist ein # (ToString) ohne Bedeutung */
+        if (search && search->type == SPECIAL
+            && search->flags == KILLSPACES)
+            return (KILLSPACES);
+    }
+    return (NONE);
+}
+
+/* FindBracket - sucht das passende Gegenstueck zu der (, auf die Node zeigt */
+/*               dabei werden verschachtelte Klammern beachtet               */
+struct strnode *FindBracket(struct strnode *node)
+{
+
+    if (DEBUG & 32)
+        puts("FindBracket");
+
+
+    if (node && node->next && node->type == NORMAL && node->str[0] == '(') {
+        do {
+            node = node->next;
+            if (node && node->type == NORMAL) {
+                if (node->str[0] == ')')
+                    return (node);
+                if (node->str[0] == '(')
+                    node = FindBracket(node);
+            }
+        } while (node);
+        return (NULL);
+    } else
+        return (NULL);
+}
+
+/* CloneArg - gibt eine Liste zurueck, die das n. Argument des Makros enthaelt */
+struct strnode *CloneArg(struct strnode *list, int n, int *error)
+{
+    int argnum = 0;
+    struct strnode *start;
+
+    if (error)
+        *error = OK;
+
+    if (list) {
+        if (DEBUG & 32)
+            printf("CloneArg\n");
+        if (list->type == PP_IDENT)
+            list = list->next;
+        while (list && list->type == SPACE)
+            list = list->next;
+
+        if (list && list->type == NORMAL && list->str[0] == '(') {
+            list = list->next;  /* Skip ( */
+
+            if (DEBUG & 32)
+                printf("- IDENT skipped, ( found\n");
+
+            while (list && (argnum < n)) {
+                if (list->type == NORMAL) {
+                    if (list->str[0] == ')')
+                        list = NULL;
+                    if (list && list->str[0] == '(')
+                        list = (FindBracket(list))->next;
+                    if (list && list->str[0] == ',')
+                        argnum++;
+                }
+                if (list)
+                    list = list->next;
+            }
+
+            while (list && list->type == SPACE)
+                list = list->next;
+
+            if (list) {
+                if (list->type == NORMAL && (list->str[0] == ')' || list->str[0] == ',')) {     /* HIER evtl. ein Space erzeugen */
+                    return (NULL);
+                }
+                start = list;
+            } else {
+                if (error)
+                    *error = ARG_EXPECTED;
+                return (NULL);
+            }
+
+            if (DEBUG & 32)
+                printf("- Okay, Arg-Start found: %s\n", start->str);
+
+            while (list && (argnum == n)) {
+                if (list->type == NORMAL) {
+                    switch (list->str[0]) {
+                    case ')':
+                    case ',':
+                        argnum++;
+                        list = list->prev;
+                        break;
+                    case '(':
+                        list = FindBracket(list);
+                    default:
+                        if (list)
+                            list = list->next;
+                        break;
+                    }
+                } else if (list)
+                    list = list->next;
+            }
+
+            while (list && list->type == SPACE)
+                list = list->prev;
+
+            if (DEBUG & 32)
+                printf("- Okay, Arg-End found: %s\n", list->str);
+            return (CloneStrList(start, list));
+
+        } else {
+            if (error)
+                *error = ARG_EXPECTED;
+            return (NULL);
+        }
+    } else
+        return (NULL);
+}
+
+/* ExpandArgMakro - ersetzt ein Makro mit Argumenten */
+int ExpandArgMakro(struct mnode *makro, struct strnode **list,
+                   struct strnode **pos)
+{
+    struct strnode *clone, *temp, *temp1, *arg, *new;
+    struct strnode *prev, *next;
+    struct mnode *prevmakro;
+    char *newstr;
+    int spec, len, x;
+
+    clone = CloneStrList(makro->tokenlist, NULL);
+    if (!clone)
+        return (OUT_OF_MEM);
+
+    if (DEBUG & 32)
+        printf("ExpandArgMakro - Clone build.\n");
+
+    temp = clone;
+    while (temp) {
+        if (temp->type == ARGUMENT) {
+            arg = CloneArg(*pos, temp->number, &x);
+            if (!arg) {
+                DelStrList(&clone);
+                return (x);
+            }
+            if (DEBUG & 32) {
+                printf("ARGUMENT:\n");
+                PrintTL(arg);
+                printf("Argument found - ");
+            }
+            if (spec = NextToSpecial(temp)) {
+                /* nicht expandieren, nur einsetzen */
+                if (spec == TOSTRING) {
+
+                    if (DEBUG & 32)
+                        printf("next to #\n");
+                    /* als String einsetzen */
+                    new = (struct strnode *) malloc(sizeof(struct strnode));
+                    if (!new) {
+                        DelStrList(&clone);
+                        DelStrList(&arg);
+                        return (OUT_OF_MEM);
+                    }
+                    len = ListStrLen(arg);
+                    newstr = (char *) malloc(len + 1);
+                    if (!newstr) {
+                        DelStrList(&clone);
+                        DelStrList(&arg);
+                        if (new)
+                            free(new);
+                        return (OUT_OF_MEM);
+                    }
+                    CopyList2StrStr(arg, newstr);
+                    DelStrList(&arg);
+                    new->len = len + 2;
+                    new->flags = new->number = 0;
+                    new->type = PP_STR;
+                    new->str = newstr;
+
+                    prev = temp->prev;
+                    next = temp->next;
+                    DelStrNode(NULL, temp);     /* Argument */
+
+                    while (prev && prev->type == SPACE) {
+                        temp = prev->prev;
+                        DelStrNode(&clone, prev);
+                        prev = temp;
+                    }
+
+                    if (prev && prev->type == SPECIAL && prev->flags == TOSTRING) {
+                        temp = prev->prev;
+                        DelStrNode(&clone, prev);
+                        prev = temp;
+                    } else
+                        ierror(0);
+
+                    new->prev = prev;
+                    if (prev)
+                        prev->next = new;
+                    else
+                        clone = new;
+                    new->next = next;
+                    if (next)
+                        next->prev = new;
+                    temp = new;
+                } else {
+                    /* Einfach nur einsetzen */
+                    if (DEBUG & 32)
+                        printf("next to ##\n");
+                    prev = temp->prev;
+                    next = temp->next;
+                    DelStrNode(NULL, temp);
+                    arg->prev = prev;
+                    if (prev)
+                        prev->next = arg;
+                    else
+                        clone = arg;
+                    while (arg->next)
+                        arg = arg->next;
+                    arg->next = next;
+                    if (next)
+                        next->prev = arg;
+                    temp = arg;
+                }
+            } else {
+                /* expandieren und einsetzen */
+                if (DEBUG & 32)
+                    printf("normal arg\n");
+                if (x = ExpandList(&arg)) {
+                    DelStrList(&clone);
+                    DelStrList(&arg);
+                    return (x);
+                }
+                if (DEBUG & 32) {
+                    printf("expanded arg:\n");
+                    PrintTL(arg);
+                }
+                prev = temp->prev;
+                next = temp->next;
+                DelStrNode(NULL, temp);
+                arg->prev = prev;
+                if (prev)
+                    prev->next = arg;
+                else
+                    clone = arg;
+                while (arg->next)
+                    arg = arg->next;
+                arg->next = next;
+                if (next)
+                    next->prev = arg;
+                temp = arg;
+            }                   /* of N2Special */
+        }
+        if (temp)
+            temp = temp->next;
+    }
+
+    if (DEBUG & 32)
+        printf("Arguments expanded.\n");
+
+    temp = clone;
+    while (temp) {
+        if (temp->type == SPECIAL && temp->flags == KILLSPACES) {
+            prev = temp->prev;
+            next = temp->next;
+            if ((prev->type == PP_IDENT || prev->type == NUMBER)) {
+                switch (next->type) {
+                case NUMBER:    /* merge -> ident */
+                case PP_IDENT:
+                    RemStrNode(&clone, next);
+                    MergeStrNodes(prev, next);
+                    next = temp->next;
+                    /* next will now be deleted and prev->str will be */
+                    /* the joined strings from prev&next */
+                default:        /* no merge / del ## */
+                    DelStrNode(&clone, temp);
+                    temp = next;
+                    break;
+                }               /* of switch */
+            } else {
+                DelStrNode(&clone, temp);
+                temp = next;
+            }
+        }
+        if (temp)
+            temp = temp->next;
+    }
+
+    /* 'makro' aus mlist ausklinken */
+    prevmakro = makro->prev;
+    RemMakroNode(&mlist, makro);
+
+    /* alles expandieren */
+    if (!(x = ExpandList(&clone))) {
+        /* akt. StrNode durch clone-Liste ersetzen */
+
+        if (DEBUG & 32) {
+            printf("Complete Makro expanded\n");
+            PrintTL(clone);
+        }
+        /* clone anstelle von pos in list einsetzen */
+        prev = (*pos)->prev;
+        next = (*pos)->next;
+
+        DelStrNode(NULL, *pos);
+
+#ifdef bla
+        while (next && next->type == SPACE) {
+            temp = next->next;
+            DelStrNode(NULL, next);     /* SPACE zwischen Makro und Args loeschen */
+            next = temp;
+        }
+#endif
+        while (next && next->type == SPACE)
+            next = next->next;
+        /* SPACE hinter Makro ueberspringen */
+
+        if (next && next->type == NORMAL && next->str[0] == '(') {
+            temp = next;
+            next = FindBracket(temp);
+            if (next)
+                next = next->next;
+            do {
+                temp1 = temp->next;
+                DelStrNode(NULL, temp);         /* ARG-List hinter Makro loeschen */
+                temp = temp1;
+            } while (temp != next);
+        } else {
+            ierror(0);
+        }
+
+
+        /* vor clone ein SPACE einsetzen, wenn nicht PREV==SPACE */
+/*vb:   hier !prev|| wegen Enforcerhit eingesetzt; waere prev&& besser? */
+        if (!prev || prev->type != SPACE) {
+            if (temp = AllocSpace()) {
+                temp->next = clone;
+                if (clone)
+                    clone->prev = temp;
+                clone = temp;
+            }
+        }
+        clone->prev = prev;
+        if (prev)
+            prev->next = clone;
+        else
+            *list = clone;
+
+        while (clone->next)
+            clone = clone->next;
+        /* nach clone ein SPACE einsetzen, wenn nicht NEXT==SPACE */
+/*vb:   hier !next|| wegen Enforcerhit eingesetzt; waere next&& besser? */
+        if (!next || next->type != SPACE) {
+            if (temp = AllocSpace()) {
+                temp->prev = clone;
+                if (clone)
+                    clone->next = temp;
+                clone = temp;
+            }
+        }
+        *pos = clone;
+        clone->next = next;
+        if (next)
+            next->prev = clone;
+
+        /* 'makro' wieder einsetzen */
+        InsertMakroNode(&mlist, makro, prevmakro);
+        return (OK);
+    } else {
+        InsertMakroNode(&mlist, makro, prevmakro);
+        return (x);
+    }
+
+}
+
+/* ExpandList - ersetzt alle Makros in der Liste */
+int ExpandList(struct strnode **list)
+{
+    struct mnode *found, *before;
+    struct strnode *clone, *beforestr, *afterstr, *listtemp, *temp2,
+    *temp3;
+    int result = OK;
+
+    if (DEBUG & 32)
+        puts("ExpandList");
+
+
+    listtemp = *list;
+    while (listtemp) {
+
+        if (listtemp->type == PP_IDENT) {
+
+            found = FindMakroNode(mlist, listtemp->str, 0);
+            if (found) {
+/*vb: merken, ob mind. ein Makro expandiert wurde   */
+                did_expand = 1;
+                if (found->flags & PARAMETER) {
+                    /* Makro mit Argument(en) */
+                    if (DEBUG & 32)
+                        printf("Makro with args\n");
+
+                    temp2 = listtemp->next;
+                    while (temp2 && temp2->type == SPACE)
+                        temp2 = temp2->next;
+
+                    if (temp2 && temp2->type == NORMAL && temp2->str[0] == '(')
+                        if (result = ExpandArgMakro(found, list, &listtemp))
+                            return (result);
+
+                } else {
+
+                    /* Makro ohne Argument */
+
+                    /* ExpandNormMakro - expandiert ein Makro ohne Argumente */
+                    /* Parameter: s.o. */
+
+                    if (found->flags & FUNCTION) {
+                        clone = DoMakroFunction(found);
+                    } else {
+                        clone = CloneStrList(found->tokenlist, NULL);
+                    }
+                    if (!clone)
+                        return (OUT_OF_MEM);
+                    /* akt. MakroNode ausklinken um rekursive Exp. zu verhindern */
+                    before = found->prev;
+                    RemMakroNode(&mlist, found);
+                    if (!(result = ExpandList(&clone))) {
+                        /* akt. StrNode durch clone-Liste ersetzen */
+                        beforestr = listtemp->prev;
+                        afterstr = listtemp->next;
+                        DelStrNode(NULL, listtemp);
+                        listtemp = afterstr;
+                        clone->prev = beforestr;
+                        if (beforestr)
+                            beforestr->next = clone;
+                        else
+                            *list = clone;
+                        while (clone->next)
+                            clone = clone->next;
+                        clone->next = afterstr;
+                        if (afterstr)
+                            afterstr->prev = clone;
+                        /* akt. Makronode wieder einsetzen */
+                        InsertMakroNode(&mlist, found, before);
+                    } else {
+                        /* akt. Makronode wieder einsetzen */
+                        InsertMakroNode(&mlist, found, before);
+                        return (result);
+                    }
+                }
+            }
+        }
+        if (listtemp)
+            listtemp = listtemp->next;
+    }
+
+    return (OK);
+}
+
+
+/* ParseIdentifier - parsed den Input-Define-String und haengt das Makro */
+/*                   in die Liste */
+
+struct mnode *ParseIdentifier(char *str)
+{
+    int x, numargs = 0, flags = 0, len = 0;
+    char *name = NULL, *args = NULL, *token = NULL, *temp, *temp2, *argtemp;
+    struct mnode *newmakro, *found;
+    struct strnode *tokenlist = NULL, *templist, *arglist = NULL, *templist2;
+    struct strnode *next, *prev;
+
+    if (DEBUG & 32)
+        puts("ParseIdentifier");
+
+/*vb: casts eingefuegt  */
+    while (isspace((unsigned char) *str)) {
+        str++;
+    }
+    if (!(isalpha((unsigned char) *str) || *str == '_')) {
+        error(178);
+        return (0);
+    }
+    temp = str;
+    while (isalnum((unsigned char) *temp) || (*temp == '_')) {
+        temp++;
+        len++;
+    }
+
+    /* auf schon vorhandene (evtl. FESTE) Definition suchen */
+    found = FindMakroNode(mlist, str, len);
+    if (found && (found->flags & NOREDEF)) {
+        error(179);
+        return (0);
+    }
+/*vb:   */
+    if (1) {
+        /* Okay, ist egal, wie das alte Makro aussah */
+
+/*vb:   */
+        if (found && !(c_flags[15] & USEDFLAG)) {
+            error(197);
+        }
+        temp = name = (char *) malloc(len + 1);         /* Speicher fuer Name-String belegen */
+        if (!name) {
+            error(196);
+            return (0);
+        }
+        for (x = 0; x < len; x++) {
+            *temp++ = *str++;
+        }                       /* Namen kopieren */
+        *temp = 0;
+
+        if (*str == '(') {
+            flags |= PARAMETER;
+            str++;              /* jump over '(' */
+            temp = str;
+            len = 0;
+/*vb: casts eingefuegt  */
+            while (*temp && (*temp != ')'))
+                if (!(isspace((unsigned char) *temp))) {
+                    len++;
+                    temp++;
+                } else {
+                    temp++;
+                }
+            if (*temp == 0) {
+                error(180);
+                if (name)
+                    free(name);
+                return (0);
+            }
+            args = temp = (char *) malloc(len + 1);
+            if (!args) {
+                error(196);
+                if (name)
+                    free(name);
+                return (0);
+            }
+            for (x = 0; x < len;)
+                if (!(isspace((unsigned char) *str))) {
+                    x++;
+                    *temp++ = *str++;
+                } else {
+                    str++;
+                }
+            *temp = 0;
+            str++;              /* jump over ')' */
+
+            /* Argumentliste parsen und auf Fehler pruefen */
+            temp = args;
+            while (*temp && (isalpha((unsigned char) *temp) || *temp == '_')) {
+                temp++;
+                while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+                    temp++;
+                }
+                if (!(*temp) || *temp == ',') {
+                    numargs++;
+                    if ((*temp == ',') && (isalpha((unsigned char) *(temp + 1)) || *(temp + 1) == '_'))
+                        temp++;
+                }
+            }
+            if (*temp) {
+                if (args)
+                    free(args);
+                if (name)
+                    free(name);
+                if (*temp == ',') {
+                    error(181);
+                } else {
+                    error(182);
+                }
+                return (0);
+            }
+        }
+        while (isspace((unsigned char) *str))
+            str++;              /* Skip Spaces */
+        /* HIER: pruefen, ob tokenlist erstellt werden konnte (leere tokenlist->ok) */
+        tokenlist = Str2List(str);
+        if (DEBUG & 32)
+            printf(" - build TokenList\n");
+        templist = tokenlist;
+        while (templist) {
+            if ((templist->type == NORMAL) && (!strcmp(templist->str, "#"))) {
+
+                if ((templist->next) && (templist->next->type == NORMAL)
+                    && (!strcmp(templist->next->str, "#"))) {
+                    /* ## KILLSPACES */
+                    if ((templist->prev) && (templist->next->next)) {
+                        templist->type = SPECIAL;
+                        templist->flags = KILLSPACES;
+                        DelStrNode(&tokenlist, templist->next);
+                    } else {
+                        error(183);
+                        if (name)
+                            free(name);
+                        if (args)
+                            free(args);
+                        if (tokenlist)
+                            DelStrList(&tokenlist);
+                        return (0);
+                    }
+                }
+            }
+            templist = templist->next;
+        }
+
+        /* Token parsen/kopieren */
+        if ((flags & PARAMETER)) {      /* Argumente parsen */
+            arglist = NULL;
+            temp = temp2 = args;
+            while (*temp) {
+                len = 0;
+                while (*temp && *temp != ',') {
+                    temp++;
+                    len++;
+                }
+                if (*temp == ',')
+                    temp++;
+                argtemp = (char *) malloc(len + 1);
+                if (!argtemp) {
+                    error(196);
+                    if (name)
+                        free(name);
+                    if (args)
+                        free(args);
+                    if (arglist)
+                        DelStrList(&arglist);
+                    if (tokenlist)
+                        DelStrList(&tokenlist);
+                    return (0);
+                }
+                strncpy(argtemp, temp2, len);
+                temp2 = temp;
+                *(argtemp + len) = 0;
+                AddStrNodeBehind(&arglist, NULL, argtemp);
+            }
+            templist = tokenlist;
+            while (templist) {
+                if (templist->type == PP_IDENT) {
+                    x = 0;
+                    templist2 = arglist;
+                    while (templist2) {
+                        if (!strcmp(templist->str, templist2->str)) {
+                            templist->type = ARGUMENT;
+                            templist->number = x;
+                        }
+                        x++;
+                        templist2 = templist2->next;
+                    }
+                }
+                templist = templist->next;
+            }
+            DelStrList(&arglist);
+            if (DEBUG & 32)
+                printf(" - Arguments found.\n");
+            /* #-Specials korrigieren, nachdem die Argumente erkannt wurden */
+            templist = tokenlist;
+            while (templist) {
+                if ((templist->type == NORMAL) && (!strcmp(templist->str, "#"))) {
+                    if ((templist->next) && (templist->next->type == ARGUMENT)) {
+                        templist->type = SPECIAL;
+                        templist->flags = TOSTRING;
+                    } else {
+                        error(184);
+                        if (name)
+                            free(name);
+                        if (args)
+                            free(args);
+                        if (arglist)
+                            DelStrList(&arglist);
+                        if (tokenlist)
+                            DelStrList(&tokenlist);
+                        return (0);
+                    }
+                }
+                templist = templist->next;
+            }
+            if (DEBUG & 32)
+                printf(" - Special-# corrected.\n");
+        } else {                /* Token kopieren */
+            temp = str;
+            len = 0;
+            while ((*temp) && (*temp != '\n')) {
+                temp++;
+                len++;
+            }
+            temp = token = (char *) malloc(len + 1);
+            if (!token) {
+                error(196);
+                if (name)
+                    free(name);
+                if (args)
+                    free(args);
+                if (tokenlist)
+                    DelStrList(&tokenlist);
+                return (0);
+            }
+            for (x = 0; x < len; x++) {
+                *temp++ = *str++;
+            }
+            *temp = 0;
+        }
+
+
+        templist = tokenlist;
+        while (templist) {
+            if (templist->type == SPECIAL && templist->flags == KILLSPACES) {
+                next = templist->next;
+                prev = templist->prev;
+
+                /* Kill Spaces before/after ## */
+                while (prev && prev->type == SPACE) {
+                    templist2 = prev->prev;
+                    DelStrNode(&tokenlist, prev);
+                    prev = templist2;
+                }
+                while (next && next->type == SPACE) {
+                    templist2 = next->next;
+                    DelStrNode(&tokenlist, next);
+                    next = templist2;
+                }
+                if ((!next) || (!prev))
+                    ierror(0);
+
+                if (next->type != ARGUMENT && prev->type != ARGUMENT) {
+                    if ((prev->type == PP_IDENT || prev->type == NUMBER)) {
+                        switch (next->type) {
+                        case NUMBER:    /* merge -> ident */
+                        case PP_IDENT:
+                            RemStrNode(&tokenlist, next);
+                            MergeStrNodes(prev, next);
+                            next = templist->next;
+                            /* next will now be deleted and prev->str will be */
+                            /* the joined strings from prev&next */
+                        default:        /* no merge / del ## */
+                            DelStrNode(&tokenlist, templist);
+                            templist = next;
+                            break;
+                        }       /* of switch */
+                    } else {
+                        DelStrNode(&tokenlist, templist);
+                        templist = next;
+                    }
+                }
+            }
+            if (templist)
+                templist = templist->next;
+        }
+
+
+/* erst HIER bei allowredefinition=0 abfragen ?? */
+
+        if (newmakro = (struct mnode *) malloc(sizeof(struct mnode))) {
+            newmakro->name = name;
+            newmakro->args = args;
+            newmakro->token = token;
+            newmakro->tokenlist = tokenlist;
+            newmakro->flags = flags;
+            newmakro->funcnum = 0;
+            AddMakroNode(&mlist, newmakro);
+        } else {
+            error(196);
+            if (name)
+                free(name);
+            if (token)
+                free(token);
+            if (args)
+                free(args);
+            if (tokenlist)
+                DelStrList(&tokenlist);
+        }
+        return (newmakro);
+
+    } else {
+/*vb:   das ist irgendwie Unsinn hier, glaube ich   */
+        ierror(0);
+        /* HIER: ueberpruefen, ob Macrodefinitionen uebereinstimmen, sonst Error */
+        if (*temp == '(') {
+            if (found->flags & PARAMETER) {
+                temp++;         /* skip ( */
+
+
+
+            } else {
+                error(185);
+                return (NULL);
+            }
+        }
+        /* HIER nur noch tokenlisten vergleichen */
+
+    }
+    if (DEBUG & 32)
+        printf("ParseIdent falls of\n");
+}
+
+
+/* PreParse - 3-Zeichen-Folgen ersetzen, \+CR Zeilen anhaengen, usw.. */
+
+int PreParse()
+{
+    char *src, *dest, *dest2;
+    int slen, dlen = 0;
+    int cat = 0;                /*vb: um zu merken, ob Zeilen mit \ verbunden werden */
+    dest2 = string;
+
+    if (DEBUG & 32)
+        puts("PreParse");
+
+
+    if (!fgets(ppstring, MAXPPINPUT, in[incnesting])) {
+        if (cmtnesting)
+            error(186);
+/*vb:   */
+/*      if(ifstatus[incnesting]) error(186); */
+/*      ifnesting--; */
+        if (DEBUG & 32)
+            printf("-- end of file  ifnesting-1:%d\n\n", incnesting);
+        if (incnesting) {
+            fclose(in[incnesting]);
+            incnesting--;
+            return (pp_nextline());
+        } else
+            return (0);
+    } else if (DEBUG & 32)
+        printf("gets1:%s\n", ppstring);         /*vb: */
+
+    if ((strlen(ppstring) == (MAXPPINPUT - 1)) && (ppstring[MAXPPINPUT - 2] != '\n')) {
+        error(177);
+        return (0);
+    }
+    zn[incnesting]++;
+    linenr = zn[incnesting];
+
+    do {
+        /* Zeilen einlesen, bis kein Kommentar mehr */
+
+        /* Zeilen einlesen bis kein \ mehr am Ende */
+        do {
+            /* Source-String an Dest-String anhaengen und ??x-Folgen ersetzen */
+/*vb: das killt sonst das angehaengte wieder   */
+            if (cat == 0) {
+                dest = src = ppstring;
+                slen = 0;
+            }
+            do {
+                if (*src != '\n') {
+
+                    if ((*src == '?') && (*(src + 1) == '?') && !(c_flags[16] & USEDFLAG)) {
+                        switch (*(src + 2)) {
+                        case '=':
+                            *dest++ = '#';
+                            src += 2;
+                            break;
+                        case '/':
+                            *dest++ = '\\';
+                            src += 2;
+                            break;
+                        case '\'':
+                            *dest++ = '^';
+                            src += 2;
+                            break;
+                        case '(':
+                            *dest++ = '[';
+                            src += 2;
+                            break;
+                        case ')':
+                            *dest++ = ']';
+                            src += 2;
+                            break;
+                        case '!':
+                            *dest++ = '|';
+                            src += 2;
+                            break;
+                        case '<':
+                            *dest++ = '{';
+                            src += 2;
+                            break;
+                        case '>':
+                            *dest++ = '}';
+                            src += 2;
+                            break;
+                        case '-':
+                            *dest++ = '~';
+                            src += 2;
+                            break;
+                        default:
+                            *dest++ = *src;
+                            break;
+                        }       /* of switch */
+                    } else {
+                        *dest++ = *src;
+                    }
+
+                    if (slen < MAXPPINPUT) {
+                        slen++;
+                    } else {
+                        error(177);
+                        return (0);
+                    }
+                }
+            } while (*src++);
+
+            src = dest;
+            /* dest->lastchar+2/NULL+1 (dest-1)-> 0 (dest-2)->lastchar */
+            if (*(dest - 2) == '\\') {
+                /*vb: sollte das slen statt dlen sein?  */
+                if (fgets(src, MAXPPINPUT - dlen, in[incnesting])) {
+                    if (DEBUG & 32)
+                        printf("gets2:%s\n", src);      /*vb:  */
+/* Hier auf LF+0 abfragen */
+                    dest -= 2;
+                    zn[incnesting]++;
+                    cat = 1;    /*vb: merken, dass Zeilen verbunden wurden */
+                }
+            }
+        } while (*dest == '\\');
+
+        src = ppstring;
+        while (*src) {
+            /* ' Strings ueberlesen */
+            if ((*src == '\'') && (!cmtnesting)) {
+                if (dlen < MAXINPUT) {
+                    *dest2++ = *src++;
+                    dlen++;
+                } else {
+                    error(177);
+                    return (0);
+                }
+                while (*src && *src != '\'') {
+                    if (*src == '\\') {
+                        *dest2++ = *src++;
+                        dlen++;
+                    };
+                    if (dlen < MAXINPUT) {
+                        *dest2++ = *src++;
+                        dlen++;
+                    } else {
+                        error(177);
+                        return (0);
+                    }
+                }
+                if (dlen < MAXINPUT) {
+                    *dest2++ = *src++;
+                    dlen++;
+                } else {
+                    error(177);
+                    return (0);
+                }
+            }
+            /* " Strings ueberlesen */
+            if ((*src == '\"') && (!cmtnesting)) {
+                *dest2++ = *src++;
+                dlen++;
+                while (*src && *src != '\"') {
+                    if (*src == '\\') {
+                        *dest2++ = *src++;
+                        dlen++;
+                    };
+                    if (dlen < MAXINPUT) {
+                        *dest2++ = *src++;
+                        dlen++;
+                    } else {
+                        error(177);
+                        return (0);
+                    }
+                }
+                if (dlen < MAXINPUT) {
+                    *dest2++ = *src++;
+                    dlen++;
+                } else {
+                    error(177);
+                    return (0);
+                }
+            }
+            /* Kommentare weglassen */
+            if ((*src == '/') && (*(src + 1) == '*')) {
+                src += 2;
+                if (dlen < MAXINPUT) {
+                    *dest2++ = ' ';
+                    dlen++;
+                } else {
+                    error(177);
+                    return (0);
+                }
+                if ((cmtnesting && (c_flags[13] & USEDFLAG)) || (!cmtnesting))
+                    cmtnesting++;
+                else
+                    error(198);
+            } else {
+                if ((*src == '*') && (*(src + 1) == '/') && cmtnesting) {
+                    src += 2;
+                    cmtnesting--;
+                }
+            }
+
+            /* C++-Comment weglassen */
+            if ((!cmtnesting) && (*src == '/') && (*(src + 1) == '/') && (c_flags[14] & USEDFLAG))
+                *src = 0;
+
+            if (!cmtnesting) {
+                if (*src) {
+                    *dest2++ = *src++;
+                }
+                if (dlen < MAXINPUT) {
+                    dlen++;
+                } else {
+                    error(177);
+                    return (0);
+                }
+            } else {
+                if (*src)
+                    src++;
+            }
+        }
+
+        if (cmtnesting) {
+            if (!fgets(ppstring, MAXPPINPUT, in[incnesting])) {
+                if (cmtnesting)
+                    error(186);
+                if (incnesting) {
+                    fclose(in[incnesting]);
+                    incnesting--;
+                    return (pp_nextline());
+                } else
+                    return (0);
+            } else if (DEBUG & 32)
+                printf("gets2:%s\n", ppstring);         /*vb:   */
+
+            if ((strlen(ppstring) == (MAXPPINPUT - 1)) && (ppstring[MAXPPINPUT - 2] != '\n')) {
+                error(177);
+                return (0);
+            }
+            zn[incnesting]++;
+        }
+    } while (cmtnesting);
+
+/*vb: das ueberschreibt den Speicher */
+#if 0
+    *dest2-- = 0;
+    while (isspace(*dest2))
+        *dest2-- = 0;           /* Spaces killen */
+#endif
+
+/*vb: hoffe, das ist besser */
+    *dest2 = 0;
+    while (dest2 > string && isspace((unsigned char) *--dest2))
+        *dest2 = 0;
+
+
+    return (1);
+}
+
+/* **************** PreProcessor ***************** */
+
+int pp_init(void)
+{
+    char *macroname;
+    struct mnode *macronode;
+
+    if (!(c_flags[6] & USEDFLAG))
+        printf("%s\n", pp_version);
+
+    incnesting = /*ifnesting= */ -1;    /*vb:  */
+    cmtnesting = if_cnt = abs_if_cnt = 0;
+    mlist = NULL;
+    strlist = NULL;
+
+    macroname = (char *) malloc(9);
+    if (!macroname)
+        return (0);
+    strcpy(macroname, "__LINE__");
+    macronode = (struct mnode *) malloc(sizeof(struct mnode));
+    if (!macronode) {
+        if (macroname)
+            free(macroname);
+        return (0);
+    }
+    macronode->name = macroname;
+    macronode->args = macronode->token = NULL;
+    macronode->tokenlist = NULL;
+    macronode->flags = FUNCTION | NODELETE | NOREDEF;
+    macronode->funcnum = FUNCLINE;
+    AddMakroNode(&mlist, macronode);
+
+    macroname = (char *) malloc(9);
+    if (!macroname)
+        return (0);
+    strcpy(macroname, "__FILE__");
+    macronode = (struct mnode *) malloc(sizeof(struct mnode));
+    if (!macronode) {
+        if (macroname)
+            free(macroname);
+        DelMakroList(&mlist);
+        return (0);
+    }
+    macronode->name = macroname;
+    macronode->args = macronode->token = NULL;
+    macronode->tokenlist = NULL;
+    macronode->flags = FUNCTION | NODELETE | NOREDEF;
+    macronode->funcnum = FUNCFILE;
+    AddMakroNode(&mlist, macronode);
+
+    macroname = (char *) malloc(9);
+    if (!macroname)
+        return (0);
+    strcpy(macroname, "__DATE__");
+    macronode = (struct mnode *) malloc(sizeof(struct mnode));
+    if (!macronode) {
+        if (macroname)
+            free(macroname);
+        DelMakroList(&mlist);
+        return (0);
+    }
+    macronode->name = macroname;
+    macronode->args = macronode->token = NULL;
+    macronode->tokenlist = NULL;
+    macronode->flags = FUNCTION | NODELETE | NOREDEF;
+    macronode->funcnum = FUNCDATE;
+    AddMakroNode(&mlist, macronode);
+
+    macroname = (char *) malloc(9);
+    if (!macroname)
+        return (0);
+    strcpy(macroname, "__TIME__");
+    macronode = (struct mnode *) malloc(sizeof(struct mnode));
+    if (!macronode) {
+        if (macroname)
+            free(macroname);
+        DelMakroList(&mlist);
+        return (0);
+    }
+    macronode->name = macroname;
+    macronode->args = macronode->token = NULL;
+    macronode->tokenlist = NULL;
+    macronode->flags = FUNCTION | NODELETE | NOREDEF;
+    macronode->funcnum = FUNCTIME;
+    AddMakroNode(&mlist, macronode);
+
+    macroname = (char *) malloc(9);
+    if (!macroname)
+        return (0);
+    strcpy(macroname, "__STDC__");
+    macronode = (struct mnode *) malloc(sizeof(struct mnode));
+    if (!macronode) {
+        if (macroname)
+            free(macroname);
+        DelMakroList(&mlist);
+        return (0);
+    }
+    macronode->name = macroname;
+    macronode->args = NULL;
+    macroname = (char *) malloc(2);
+    if (!macroname) {
+        if (macronode->name)
+            free(macronode->name);
+        if (macronode)
+            free(macronode);
+        DelMakroList(&mlist);
+        return (0);
+    }
+    strcpy(macroname, "1");
+    macronode->token = macroname;
+    macronode->tokenlist = Str2List(macroname);
+    if (!macronode->tokenlist) {
+        if (macronode->name)
+            free(macronode->name);
+        if (macronode->token)
+            free(macronode->token);
+        if (macronode)
+            free(macronode);
+        DelMakroList(&mlist);
+        return (0);
+    }
+    macronode->flags = NODELETE;
+    macronode->funcnum = 0;
+    AddMakroNode(&mlist, macronode);
+
+    return (1);
+}
+
+
+void pp_free(void)
+{
+    int i;
+
+    if (DEBUG & 32)
+        puts("pp_free");
+
+/*vb: Schleifenindex korrekt gesetzt    */
+    for (i = incnesting; i >= 0; i--)
+        if (in[i])
+            fclose(in[i]);
+    DelMakroList(&mlist);
+    DelStrList(&strlist);
+}
+
+int pp_include(char *f)
+{
+    if (DEBUG & 32)
+        printf("trying to include %s\n", f);    /*vb:  */
+
+    if (incnesting >= MAXINCNESTING - 1) {
+        error(187);
+        return (0);
+    }
+/*vb:   */
+/*    if(ifnesting>=MAXIFNESTING-1)   {error("Too many nested #ifs or #includes",0);return(0);} */
+    incnesting++;
+    /*    ifnesting++; *//*vb:   */
+    ifstatus[incnesting] = 0;   /*vb:   */
+
+    if (DEBUG & 32)
+        printf("-- include: ifnesting:%d ifstatus:0 \n\n", incnesting);
+
+    in[incnesting] = fopen(f, "r");
+    if (!in[incnesting]) {
+        incnesting--;
+        return (0);
+    }
+    filenames[incnesting] = f;
+    zn[incnesting] = linenr = 0;
+    return (1);
+}
+
+
+
+/* ********************** Main-Function ******************* */
+int pp_nextline(void)
+{
+    char *src, *dest, *temp;
+    int complete_len, len, i, result;
+    struct mnode *makro;
+    struct strnode *linelist, *inclinelist;
+
+    if (DEBUG & 32)
+        puts("pp_nextline");
+
+    dest = string;
+    dest[0] = 0;
+
+    /* String vorbereiten, 3ZF ersetzen, \-Zeilen anhaengen, Kommentare loeschen */
+    if (!PreParse())
+        return (0);
+
+    /* Ueberpruefung auf PreProcessor-Commands */
+    src = string;
+/*vb: casts eingefuegt  */
+    while (isspace((unsigned char) *src)) {
+        src++;
+    }                           /* SkipSpaces */
+
+    if (*src == '#') {          /* #-Direktive gefunden */
+        src++;                  /* # ueberlesen */
+
+        while (isspace((unsigned char) *src)) {
+            src++;
+        }                       /* SkipSpaces */
+
+/*vb:   Direktiven, die nichts mit #if etc. zu tun haben, nach hinten   */
+
+
+/* IFDEF */
+        if (!strncmp(src, "ifdef", 5)) {
+            src += 5;
+            abs_if_cnt++;       /*vb: */
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                /* identifier suchen */
+                if (do_output) {
+/*vb:   */
+/*            if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #if's",0); return(0);} */
+/*            ifnesting++; */
+                    temp = src;
+                    len = 0;
+                    while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
+                        temp++;
+                        len++;
+                    }
+                    makro = FindMakroNode(mlist, src, len);
+                    if (DEBUG & 32)
+                        printf("-- #ifdef found, ");
+                    if (makro) {
+/*vb:   */
+                        ifstatus[incnesting] = 1;       /* Bedingung == TRUE */
+                        if (DEBUG & 32)
+                            printf(" condition '%s' found     (TRUE)\n", makro->name);
+                    } else {
+/*vb:   */
+                        ifstatus[incnesting] = 2;       /* Bedingung == FALSE */
+                        do_output = 0;
+                        if (DEBUG & 32)
+                            printf(" condition not found (FALSE)\n\n");
+                    }
+                } else {
+                    if_cnt++;
+                    if (DEBUG & 32)
+                        printf("-- #ifdef found and if_cnt increased\n\n");
+                }
+                string[0] = 0;  /*vb: yo   */
+                return (1);
+            }
+        }                       /* EO IFDEF */
+        /* IFNDEF */
+        if (!strncmp(src, "ifndef", 6)) {
+            src += 6;
+            abs_if_cnt++;       /*vb: */
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+
+                /* identifier suchen */
+                if (do_output) {
+/*vb:   */
+/*            if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #if's",0); return(0);} */
+/*            ifnesting++; */
+                    temp = src;
+                    len = 0;
+                    while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
+                        temp++;
+                        len++;
+                    }
+                    if (DEBUG & 32)
+                        printf("-- FindMakroNode: len=%d temp=%p\n", len, (void*)temp);
+                    makro = FindMakroNode(mlist, src, len);
+                    if (DEBUG & 32)
+                        printf("-- #ifndef found, ");
+                    if (!makro) {
+/*vb:   */
+                        ifstatus[incnesting] = 1;       /* Bedingung == TRUE (Makro not existing) */
+                        if (DEBUG & 32)
+                            printf(" condition not found  (TRUE)\n\n");
+                    } else {
+/*vb:   */
+                        ifstatus[incnesting] = 2;       /* Bedingung == FALSE */
+                        do_output = 0;
+                        if (DEBUG & 32)
+                            printf(" condition '%s'     found (FALSE)\n\n", makro->name);
+                    }
+                    /* HIER: string[0]=0; */
+                } else {
+                    if_cnt++;
+                    if (DEBUG & 32)
+                        printf("-- #ifndef found and if_cnt increased\n\n");
+                }
+                string[0] = 0;  /*vb:   */
+                return (1);
+            }
+        }                       /* EO IFNDEF */
+        /* IF */
+        if (!strncmp(src, "if", 2)) {
+            src += 2;
+            abs_if_cnt++;       /*vb:   */
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                /* Bedingung auswerten */
+
+
+
+                printf("****** WARNING ******* #if is not yet implemented\n");
+
+
+                string[0] = 0;  /*vb:   */
+                return (1);
+            }
+        }                       /* EO IF */
+        /* ELIF */
+        if (!strncmp(src, "elif", 4)) {
+            src += 4;
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                /* Bedingung auswerten */
+
+
+
+
+
+                printf("****** WARNING ******* #elif is not yet implemented\n");
+
+
+
+
+                string[0] = 0;  /*vb:   */
+                return (1);
+            }
+        }                       /* EO ELIF */
+        /* ELSE */
+        if (!strncmp(src, "else", 4)) {
+            src += 4;
+            if (isspace((unsigned char) *src) || *src == 0) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+
+                if (!if_cnt) {
+                    switch (ifstatus[incnesting]) {     /*vb:   */
+                    case 0:
+                        error(188);
+                        return (0);
+                        break;
+                    case 1:
+                        do_output = 0;
+                        /* HIER: auf #endif suchen SearchENDIF(); */
+                        /* HIER: ifnesting--; do_output=1; */
+                        break;
+                    case 2:
+                        ifstatus[incnesting] = 3;       /*vb:   */
+                        do_output = 1;
+                        break;
+                    case 3:
+                        error(189);
+                        return (0);
+                        break;
+                    }
+                }
+                string[0] = 0;  /*vb:    */
+                return (1);
+            }
+        }                       /* EO ELSE */
+        /* ENDIF */
+        if (!strncmp(src, "endif", 5)) {
+            src += 5;
+            abs_if_cnt--;       /*vb:   */
+            if (isspace((unsigned char) *src) || *src == 0) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                /* HIER: Auf Zeilenende testen */
+
+                if (DEBUG & 32)
+                    printf("-- #endif found, ");
+
+                if (if_cnt) {
+                    if_cnt--;
+                    if (DEBUG & 32)
+                        printf("if_cnt decreased (to %d)\n", if_cnt);
+                } else {
+                    if (DEBUG & 32)
+                        printf("ifnesting: %d  ifstatus: %d\n", incnesting, ifstatus[incnesting]);
+                    if (abs_if_cnt < 0 /*(incnesting==-1)||ifstatus[incnesting]==0 */ ) {       /*vb:   */
+                        error(190);
+                        return (0);
+                    }
+                    /*            ifnesting--; *//*vb:   */
+                    /* HIER: evtl. do_output entsprechend ifstatus[] setzen */
+                    /*vb: natuerlich    */
+                    do_output = 1;
+                    ifstatus[incnesting] = abs_if_cnt > 0;      /*vb: 1 oder 0   */
+                }
+                string[0] = 0;  /*vb: ja */
+                return (1);
+            }
+        }                       /* EO ENDIF */
+        /*vb: andere Direktiven gegebenenfalls ueberspringen    */
+        if (!do_output) {
+            if (DEBUG & 32)
+                printf("do_output==0 => skipping: %s\n", src);
+            string[0] = 0;
+            return (1);
+        }
+/* DEFINE */
+        if ( /*(do_output)&& */ (!strncmp(src, "define", 6))) {         /*vb:   */
+            if (DEBUG & 32)
+                printf("#define found\n");
+            src += 6;
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                if (ParseIdentifier(src)) {
+                    string[0] = 0;
+                    return (1);
+                } else {
+                    if (DEBUG & 32)
+                        printf("ParseIdent returned 0\n");
+                    return (0);
+                }
+            }
+        }                       /* EO DEFINE */
+        /* UNDEF */
+        if ( /*(do_output)&& */ (!strncmp(src, "undef", 5))) {  /*vb:   */
+            src += 5;
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                temp = src;
+                len = 0;
+                while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
+                    temp++;
+                    len++;
+                }
+                makro = FindMakroNode(mlist, src, len);
+                if (makro->flags & NODELETE) {
+                    error(199);
+                } else {
+                    DelMakroNode(&mlist, makro);
+                }
+                while (isspace((unsigned char) *temp)) {
+                    temp++;
+                }
+                if (*temp != 0 && *temp != '\n') {
+                    error(200);
+                }
+                string[0] = 0;
+                return (1);
+            }
+        }                       /* EO UNDEF */
+        /* INCLUDE */
+        if ( /*(do_output)&& */ (!strncmp(src, "include", 7))) {        /*vb:   */
+            src += 7;
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+                if (*src != '<' && *src != '\"') {
+                    /* Versuchen den Rest zu expandieren */
+                    inclinelist = Str2List(src);
+                    if (!ExpandList(&inclinelist)) {
+                        if (List2Str(inclinelist, src, MAXINPUT - (src - string))) {
+                            /* HIER exit ? */
+                        }
+                    } else {
+                        error(191);     /* HIER exit ? */
+                    }
+                }
+/*vb: geaendert, so dass #include "..." auch noch im Standardpfad sucht */
+                if (DEBUG & 32)
+                    printf("includename=%s\n", src);
+                if (*src == '<' || *src == '\"') {
+                    char *m = src, c;
+                    if (*src == '<')
+                        c = '>';
+                    else
+                        c = '\"';
+                    if (*src == '\"') {
+                        /* im aktuellen Verzeichnis suchen und includen */
+                        src++;
+                        temp = src;
+                        len = 0;
+                        while (*temp != '\"') {
+                            temp++;
+                            len++;
+                        }
+                        temp++;
+                        while (isspace((unsigned char) *temp))
+                            temp++;
+                        if (*temp) {
+                            error(200);
+                        }
+                        temp = (char *) malloc(len + 1);
+                        if (temp) {
+                            strncpy(temp, src, len);
+                            *(temp + len) = 0;
+                            if (pp_include(temp)) {
+                                AddStrNode(&strlist, NULL, temp);
+                                string[0] = 0;
+                                return (1);
+                            } else {
+                                if (temp)
+                                    free(temp);
+/*vb:
+   error("pp: cannot open file to include",0);
+   return(0); */
+                            }
+                        } else {
+                            error(196);
+                        }       /* HIER: Exit? */
+                    }
+                    /* in den Standard-Verzeichnissen suchen und includen */
+                    src = m;
+                    src++;
+                    temp = src;
+                    len = 0;
+                    while (*temp != c && *temp != 0) {
+                        temp++;
+                        len++;
+                    }           /*vb: sicherer */
+                    temp++;
+                    while (isspace((unsigned char) *temp))
+                        temp++;
+                    if (*temp) {
+                        error(200);
+                    }
+                    temp = NULL;
+                    for (i = 0; i < incpathc; i++) {
+                        complete_len = strlen(incpath[i]) + len;
+                        temp = (char *) malloc(complete_len + 1);
+                        if (temp) {
+                            strcpy(temp, incpath[i]);
+                            strncat(temp, src, len);
+                            *(temp + complete_len) = 0;
+                            if (pp_include(temp)) {
+                                AddStrNode(&strlist, NULL, temp);
+                                if (DEBUG & 32)
+                                    printf("include <%s> found\n", temp);
+                                string[0] = 0;
+                                return (1);
+                            } else {
+                                if (temp)
+                                    free(temp);
+                            }
+                        } else {
+                            error(196);
+                        }       /* HIER: Exit ? */
+                    }           /* of FOR i */
+                    error(191);
+                    return (0);
+                } else {
+                    error(192);
+                    return (0);
+                }
+            } else {
+                error(193);
+                return (0);
+            }
+        }                       /* EO INCLUDE */
+        /* LINE */
+        if (!strncmp(src, "line", 4)) {
+            src += 4;
+            if (isspace((unsigned char) *src)) {
+                return (1);     /* Ignorieren und an Compiler weiterreichen */
+            }
+        }                       /* EO LINE */
+        /* ERROR */
+        if (!strncmp(src, "error", 5)) {
+            src += 5;
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+
+                return (1);
+            }
+        }                       /* EO ERROR */
+        /* PRAGMA */
+        if (!strncmp(src, "pragma", 6)) {
+            src += 6;
+            if (isspace((unsigned char) *src)) {
+                while (isspace((unsigned char) *src)) {
+                    src++;
+                }
+
+                return (1);
+            }
+        }                       /* EO PRAGMA */
+        /* Unknown */
+        /*    if(do_output){ */
+        /*vb:   */
+        error(193);
+        return (0);
+        /*    } *//*vb:   */
+    } else if (do_output) {
+        /* Normale Anweisung. Komplette Zeile expandieren */
+
+/*vb:   */
+
+        linelist = Str2List(string);
+
+        if (DEBUG & 32)
+            PrintTL(linelist);
+
+/*vb: */
+        did_expand = 0;
+
+        if (result = ExpandList(&linelist)) {
+            switch (result) {
+            case OUT_OF_MEM:
+                error(196);
+                break;
+            case NUM_OF_ARGS:
+                error(194);
+                break;
+            case ARG_EXPECTED:
+                error(195);
+                break;
+            default:
+                ierror(0);
+                break;
+            }
+            DelStrList(&linelist);
+            return (0);
+        }
+        if (DEBUG & 32)
+            PrintTL(linelist);
+
+/*vb: List2Str nur aufrufen, falls etwas expandiert wurde   */
+        if (did_expand && !List2Str(linelist, string, MAXINPUT)) {
+            DelStrList(&linelist);
+            return (0);
+        }
+        DelStrList(&linelist);
+
+/*vb:   */
+    } else
+        string[0] = 0;
+    return (1);
+}
diff --git a/range.c b/range.c
new file mode 100644
index 0000000..6696f95
--- /dev/null
+++ b/range.c
@@ -0,0 +1,322 @@
+/*  $VER: vbcc (range.c) $Revision: 1.1 $    */
+/*  range analysis and related optimizations */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+
+#define RANGESIZE (sizeof(range)*(vcount+1))
+
+range *rangebuf;
+
+static void clear_range(range *p,int i)
+{
+  Var *v;
+  int t;
+
+  v=vilist[i];
+  t=v->vtyp->flags;
+  if(ISINT(t)){
+    if(t&UNSIGNED){
+      p[i].min.vumax=Z0;
+      p[i].max.vumax=tu_max[t&NQ];
+    }else{
+      p[i].min.vmax=t_min[t&NQ];
+      p[i].max.vmax=t_max[t&NQ];
+    }
+  }
+}
+
+void print_ranges(FILE *f,range *p)
+{
+  int i,t;
+  Var *v;
+  for(i=0;i<vcount-rcount;i++){
+    v=vilist[i];
+    t=v->vtyp->flags;
+    if(ISINT(t)){
+      fprintf(f,"%03d %s (%p): ",i,v->identifier,v);
+      if(t&UNSIGNED){
+	printzum(f,p[i].min.vumax);
+	fprintf(f,"...");
+	printzum(f,p[i].max.vumax);
+      }else{
+	printzm(f,p[i].min.vmax);
+	fprintf(f,"...");
+	printzm(f,p[i].max.vmax);
+      }
+      fprintf(f,"\n");
+    }
+  }
+}
+
+static void combine_ranges(range *d,range *n)
+{
+  int i,t;
+  Var *v;
+  for(i=0;i<vcount-rcount;i++){
+    v=vilist[i];
+    t=v->vtyp->flags;
+    if(ISINT(t)){
+      if(t&UNSIGNED){
+	if(zumleq(n[i].min.vumax,d[i].min.vumax))
+	  d[i].min.vumax=n[i].min.vumax;
+	if(zumleq(d[i].max.vumax,n[i].max.vumax))
+	  d[i].max.vumax=n[i].max.vumax;
+      }else{
+	if(zmleq(n[i].min.vmax,d[i].min.vmax))
+	  d[i].min.vmax=n[i].min.vmax;
+	if(zmleq(d[i].max.vmax,n[i].max.vmax))
+	  d[i].max.vmax=n[i].max.vmax;
+      }
+    }
+  }
+}
+
+static int update_ranges(range *d,range *n)
+{
+  int i,t,change=0;
+  Var *v;
+  for(i=0;i<vcount-rcount;i++){
+    v=vilist[i];
+    t=v->vtyp->flags;
+    if(ISINT(t)){
+      if(t&UNSIGNED){
+	if(!zumeqto(n[i].min.vumax,d[i].min.vumax)){
+	  d[i].min.vumax=n[i].min.vumax;
+	  change=1;
+	}
+	if(!zumeqto(d[i].max.vumax,n[i].max.vumax)){
+	  d[i].max.vumax=n[i].max.vumax;
+	  change=1;
+	}
+      }else{
+	if(!zmeqto(n[i].min.vmax,d[i].min.vmax)){
+	  d[i].min.vmax=n[i].min.vmax;
+	  change=1;
+	}
+	if(!zmeqto(d[i].max.vmax,n[i].max.vmax)){
+	  d[i].max.vmax=n[i].max.vmax;
+	  change=1;
+	}
+      }
+    }
+  }
+  return change;
+}
+
+void do_ranges(range *d,IC *p)
+{
+  int i,j,t,c=p->code;
+  if((p->z.flags&(VAR|DREFOBJ))==VAR){
+    i=p->z.v->index;
+    t=p->z.v->vtyp->flags;
+    if(c==ASSIGN){
+      if((p->typf&NU)!=(t&NU)){
+	clear_range(d,i);
+      }else if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+	eval_const(&p->q1.val,t);
+	if(t&UNSIGNED)
+	  d[i].min.vumax=d[i].max.vumax=vumax; 
+	else
+	  d[i].min.vmax=d[i].max.vmax=vmax; 
+      }else if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(p->q1.v->vtyp->flags&NU)==(t&NU)){
+	j=p->q1.v->index;
+	d[i].min=d[j].min;
+	d[i].max=d[j].max;
+      }else
+	clear_range(d,i);
+    }else{
+      clear_range(d,i);
+    }
+  }else{
+    j=p->change_cnt;
+    for(i=0;i<j;i++){
+      if(!(p->change_list[i].flags&DREFOBJ))
+	clear_range(d,p->change_list[i].v->index);
+    }
+  }
+}
+
+static void insert_max(range *p,int t)
+{
+  if(t&UNSIGNED){
+    if(!zumleq(p->max.vumax,vumax))
+      p->max.vumax=vumax;
+    if(!zumleq(p->min.vumax,p->max.vumax))
+      p->min.vumax=vumax;
+  }else{
+    if(!zmleq(p->max.vmax,vmax))
+      p->max.vmax=vmax;
+    if(!zmleq(p->min.vmax,p->max.vmax))
+      p->min.vmax=vmax;
+  }
+}
+
+static void insert_min(range *p,int t)
+{
+  if(t&UNSIGNED){
+    if(!zumleq(vumax,p->min.vumax))
+      p->min.vumax=vumax;
+    if(!zumleq(p->min.vumax,p->max.vumax))
+      p->max.vumax=vumax;
+  }else{
+    if(!zmleq(vmax,p->min.vmax))
+      p->min.vmax=vmax;
+    if(!zmleq(p->min.vmax,p->max.vmax))
+      p->max.vmax=vmax;
+  }
+}
+
+static void inc_val(int t)
+{
+  if(t&UNSIGNED){
+    if(!zumeqto(vumax,tu_max[t&NU]))
+      vumax=zumadd(vumax,ZU1);
+  }else{
+    if(!zmeqto(vmax,t_max[t&NU]))
+      vmax=zmadd(vmax,Z1);
+  }
+}
+
+static void dec_val(int t)
+{
+  if(t&UNSIGNED){
+    if(!zumeqto(vumax,ZU0))
+      vumax=zumsub(vumax,ZU1);
+  }else{
+    if(!zmeqto(vmax,t_min[t&NU]))
+      vmax=zmsub(vmax,Z1);
+  }
+}
+
+void range_analysis(flowgraph *fg)
+{
+  flowgraph *g;
+  range *bp,*erange,*crange;
+  Var *v;
+  int i,t,done,pass;
+  rangebuf=mymalloc(RANGESIZE*(2*basic_blocks+3));
+  bp=rangebuf;
+  for(i=0;i<vcount-rcount;i++)
+    clear_range(bp,i);
+  erange=bp;
+  bp+=RANGESIZE;
+  for(g=fg;g;g=g->normalout){
+    g->ra_normalout=bp;
+    memcpy(bp,erange,RANGESIZE);
+    bp+=RANGESIZE;
+    g->ra_branchout=bp;
+    memcpy(bp,erange,RANGESIZE);
+    bp+=RANGESIZE;
+  }
+  crange=bp;
+
+  pass=1;
+  do{
+    if(DEBUG&1024) printf("range analysis pass %d\n",pass);
+    done=1;
+    for(g=fg;g;g=g->normalout){
+      flowlist *lp;
+      IC *p;
+      int c,first=1;
+      memcpy(crange,erange,RANGESIZE);
+      for(lp=g->in;lp;lp=lp->next){
+	if(lp->graph->normalout==g&&(!lp->graph->end||lp->graph->end->code!=BRA)){
+	  if(first){
+	    memcpy(crange,lp->graph->ra_normalout,RANGESIZE);
+	    first=0;
+	  }else
+	    combine_ranges(crange,lp->graph->ra_normalout);
+	}
+	if(lp->graph->branchout==g){
+	  if(first) {
+	    memcpy(crange,lp->graph->ra_branchout,RANGESIZE);
+	    first=0;
+	  }else
+	    combine_ranges(crange,lp->graph->ra_branchout);
+	}
+      }
+      if(DEBUG&131072){
+	printf("block %d, input:\n",g->index);
+	print_ranges(stdout,crange);
+      }
+      for(p=g->start;p;p=p->next){
+	do_ranges(crange,p);
+	if(p==g->end||p->code==TEST||p->code==COMPARE) break;
+      }
+      if(p) c=p->code; else c=0;
+      if(c==COMPARE||c==TEST){
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(c==TEST||(p->q2.flags&(KONST|DREFOBJ))==KONST)){
+	  IC *b=p->next;
+	  range tmp;
+	  while(b&&b->code<BEQ||b->code>BGT) b=b->next;
+	  if(!b) ierror(0);
+	  if(c==TEST){
+	    vmax=Z0;
+	    vumax=ZU0;
+	  }else
+	    eval_const(&p->q2.val,p->typf);
+	  i=p->q1.v->index;
+	  t=p->q1.v->vtyp->flags;
+	  if(b->code==BEQ){
+	    if(update_ranges(g->ra_normalout,crange)) done=0;
+	    if(t&UNSIGNED)
+	      crange[i].min.vumax=crange[i].max.vumax=vumax;
+	    else
+	      crange[i].min.vmax=crange[i].max.vmax=vmax;
+	    if(update_ranges(g->ra_branchout,crange)) done=0;
+	  }else if(b->code==BNE){
+	    if(update_ranges(g->ra_branchout,crange)) done=0;
+	    if(t&UNSIGNED)
+	      crange[i].min.vumax=crange[i].min.vumax=vumax;
+	    else
+	      crange[i].max.vumax=crange[i].max.vumax=vumax;
+	    if(update_ranges(g->ra_normalout,crange)) done=0;
+	  }else if(b->code==BLT||b->code==BLE){
+	    tmp=crange[i];
+	    if(b->code==BLT) dec_val(t);
+	    insert_max(&crange[i],t);
+	    if(update_ranges(g->ra_branchout,crange)) done=0;
+	    crange[i]=tmp;
+	    inc_val(t);
+	    insert_min(&crange[i],t);
+	    if(update_ranges(g->ra_normalout,crange)) done=0;
+	  }else if(b->code==BGE||b->code==BGT){
+	    tmp=crange[i];
+	    if(b->code==BGT) inc_val(t);
+	    insert_min(&crange[i],t);
+	    if(update_ranges(g->ra_branchout,crange)) done=0;
+	    crange[i]=tmp;
+	    dec_val(t);
+	    insert_max(&crange[i],t);
+	    if(update_ranges(g->ra_normalout,crange)) done=0;
+	  }else
+	    ierror(0);
+	}else{
+	  if(update_ranges(g->ra_branchout,crange)) done=0;
+	  if(update_ranges(g->ra_normalout,crange)) done=0;
+	}
+      }else{
+	if(g->branchout){
+	  /* must be BRA as we checked for COMPARE/TEST above */
+	  if(update_ranges(g->ra_branchout,crange))
+	    done=0;
+	}else{
+	  if(update_ranges(g->ra_normalout,crange))
+	    done=0;
+	}
+      }
+      if(DEBUG&131072){
+	printf("ra_branchout:\n");
+	print_ranges(stdout,g->ra_branchout);
+	printf("ra_normalout:\n");
+	print_ranges(stdout,g->ra_normalout);
+      }
+    }
+    pass++;
+  }while(!done);
+  
+  
+}
diff --git a/rd.c b/rd.c
new file mode 100644
index 0000000..79ad513
--- /dev/null
+++ b/rd.c
@@ -0,0 +1,645 @@
+/*  $VER: vbcc (rd.c) $Revision: 1.16 $    */
+/*  reaching definitions and constant propagation   */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+unsigned int dcount;
+size_t dsize;
+IC **dlist;
+bvtype *rd_defs;
+bvtype **defs_kill;    /* definitions killed */
+bvtype **defs_gen;     /* definitions undefined */
+bvtype **var_defs;     /* definitions of a variable */
+bvtype **var_undefs;   /* definitions which are undefined by writing to this var */
+bvtype *rd_matrix;
+
+int def_overwrites(IC *new,IC *old);
+#define NO_OVERWRITE 0
+#define FULL_OVERWRITE 1
+#define PARTIAL_OVERWRITE 2
+#define EXACT_OVERWRITE 3
+
+/*  compares two constants; -1, if q1<q2; 0, if q1==q1; 1 otherwise  */
+int compare_const(union atyps *q1,union atyps *q2,int t)
+{
+  zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+  t&=NU;
+  eval_const(q1,t);d1=vldouble;l1=vmax;u1=vumax;
+  eval_const(q2,t);d2=vldouble;l2=vmax;u2=vumax;
+  if(ISFLOAT(t)) return(zldleq(d2,d1)?!zldeqto(d1,d2):-1);
+  if(ISPOINTER(t)||(t&UNSIGNED)) return(zumleq(u2,u1)?!zumeqto(u1,u2):-1);
+  return(zmleq(l2,l1)?!zmeqto(l1,l2):-1);
+}
+
+/* prints definitions in a bitvector */
+void print_rd(bvtype *bitvector)
+{
+  unsigned int i;
+  if(!bitvector) {printf("reaching definitions not available\n");return;}
+  for(i=1;i<=dcount;i++){
+    if(BTST(bitvector,i)) {printf("%3u:",i);pric2(stdout,dlist[i]);}
+    if(BTST(bitvector,UNDEF(i))) {printf("%3u(ud):",i);pric2(stdout,dlist[i]);}
+  }
+}
+
+/* numbers all definitions and creates some bitvectors */
+void num_defs(void)
+{
+  int i,j;IC *p;
+  size_t matrix_size;
+  bvtype *bp;
+  unsigned long heapsize=0;
+  if(DEBUG&1024) printf("numerating definitions\n");
+  i=0;
+  for(p=first_ic;p;p=p->next){
+    if(!(p->z.flags&(VAR|DREFOBJ))&&p->code!=CALL){p->defindex=0;continue;}
+    p->defindex=++i;
+  }
+  dcount=i;
+  /*dsize=(2*dcount+1+CHAR_BIT)/CHAR_BIT;    /* +1, da bei 1 anfaengt */
+  dsize=BVSIZE(2*(dcount+1));
+  if(DEBUG&(16384|1024)) printf("%lu definitions, dsize=%lu\n",(unsigned long)dcount,(unsigned long)dsize);
+  
+  /* get big memory block to store defs_kill, defs_gen, vars, var_defs and var_undefs */
+  matrix_size=(2*(dcount+vcount)*dsize);
+  rd_matrix=bp=mymalloc(matrix_size);
+  memset(bp,0,matrix_size);
+  heapsize+=matrix_size;
+
+  /* calculate bit-vector which contains all definitions killed or */
+  /* undefined (=partially overwritten) by this definition         */
+  defs_kill=mymalloc(sizeof(*defs_kill)*(dcount+1));
+  defs_gen=mymalloc(sizeof(*defs_gen)*(dcount+1));
+  heapsize+=2*sizeof(*defs_kill)*(dcount+1);
+
+  for(i=1;i<=dcount;i++){
+    defs_kill[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+    defs_gen[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+  }
+  
+  /* calculate bit vector with all undefined definitions of each variable */
+  var_defs=mymalloc(sizeof(*var_defs)*vcount);
+  heapsize+=sizeof(*var_defs)*vcount;
+  var_undefs=mymalloc(sizeof(*var_undefs)*vcount);
+  heapsize+=sizeof(*var_undefs)*vcount;
+  for(i=0;i<vcount;i++){
+    var_defs[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+    var_undefs[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+  }
+  
+  /* calculate pointers to IC for every definition */
+  dlist=mymalloc((dcount+1)*sizeof(*dlist));
+  heapsize+=(dcount+1)*sizeof(*dlist);
+
+  for(p=first_ic;p;p=p->next){
+    if(p->defindex){
+      dlist[p->defindex]=p;
+      if(p->z.flags&VAR){
+        Var *v=p->z.v;
+        i=v->index;
+        if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+        BSET(var_defs[i],p->defindex);
+	BSET(var_defs[i],UNDEF(p->defindex));
+	if(i<rcount){
+	  BSET(var_defs[i+vcount-rcount],p->defindex);
+	  BSET(var_defs[i+vcount-rcount],UNDEF(p->defindex));
+	}
+        BSET(var_undefs[i],UNDEF(p->defindex));
+      }
+    }
+  }
+  
+  for(i=1;i<=dcount;i++){
+    p=dlist[i];
+    for(j=0;j<p->change_cnt;j++){
+      int idx;
+      idx=p->change_list[j].v->index;
+      if(p->change_list[j].flags&DREFOBJ) idx+=vcount-rcount;
+      if(idx>=vcount) continue;	
+      BSET(var_defs[idx],i);
+      bvunite(defs_gen[i],var_undefs[idx],dsize);
+    }
+    if(p->z.flags&VAR){
+      for(j=1;j<=dcount;j++){
+	int ow;
+	IC *p2;
+	if(i==j) continue;
+	p2=dlist[j];
+	if(!(p2->z.flags&VAR)||p->z.v!=p2->z.v||p->z.flags!=p2->z.flags)
+	  continue;
+	ow=def_overwrites(p,p2);
+	if(ow==FULL_OVERWRITE||ow==EXACT_OVERWRITE){
+	  BSET(defs_kill[i],j);
+	  BSET(defs_kill[i],UNDEF(j));
+	}
+	if(ow==EXACT_OVERWRITE||ow==NO_OVERWRITE){
+	  BCLR(defs_gen[i],j);
+	  BCLR(defs_gen[i],UNDEF(j));
+	}
+      }
+    }
+    /* every definition defines itself) */
+    BSET(defs_gen[i],i);
+    BCLR(defs_gen[i],UNDEF(i));
+    BSET(defs_kill[i],UNDEF(i));
+  }
+  
+  if(DEBUG&2048){
+    for(i=0;i<vcount;i++){
+      printf("var_defs for var %i %s(%p):\n",i,vilist[i]->identifier,vilist[i]);
+      print_rd(var_defs[i]);
+    }
+	
+    for(i=1;i<=dcount;i++){
+      printf("Def%3d: ",i);pric2(stdout,dlist[i]);
+      printf(" kills:\n");
+      for(j=1;j<=dcount;j++){
+	if(BTST(defs_kill[i],j)) {printf("  ");pric2(stdout,dlist[j]);}
+	if(BTST(defs_kill[i],UNDEF(j))) {printf("  (ud)");pric2(stdout,dlist[j]);}
+      }
+      printf(" gens:\n");
+      for(j=1;j<=dcount;j++){
+	if(BTST(defs_gen[i],j)) {printf("  ");pric2(stdout,dlist[j]);}
+	if(BTST(defs_gen[i],UNDEF(j))) {printf("  (ud)");pric2(stdout,dlist[j]);}
+      }
+    }
+  }
+
+  if(DEBUG&16384) printf("num_defs heapsize=%lu\n",heapsize);
+
+  free(var_undefs);
+}
+
+/* returns whether n overwrites the definition p */
+int def_overwrites(IC *n,IC *o)
+{
+  zmax nstart,nend,ostart,oend,nsize,osize;
+  if(!(n->z.flags&VAR)) ierror(0);
+  if(!(o->z.flags&VAR)) ierror(0);
+  if((n->z.flags&DREFOBJ)!=(o->z.flags&DREFOBJ)) ierror(0);
+  if(n->code==ASSIGN){
+    nsize=n->q2.val.vmax;
+  }else{
+    nsize=sizetab[ztyp(n)&NQ];
+  }
+  if(o->code==ASSIGN){
+    osize=o->q2.val.vmax;
+  }else{
+    osize=sizetab[ztyp(o)&NQ];
+  }
+  if(n->z.flags&DREFOBJ)
+    return zmleq(osize,nsize);
+
+  nstart=n->z.val.vmax;
+  nend=zmsub(zmadd(nstart,nsize),l2zm(1L));
+  ostart=o->z.val.vmax;
+  oend=zmsub(zmadd(ostart,osize),l2zm(1L));
+
+  if(zmeqto(nstart,ostart)&&zmeqto(nend,oend))
+    return EXACT_OVERWRITE;
+
+  if(zmleq(nstart,ostart)&&zmleq(oend,nend))
+    return FULL_OVERWRITE;
+
+  if(zmleq(ostart,nstart)&&zmleq(nstart,oend))
+    return PARTIAL_OVERWRITE;
+  if(zmleq(ostart,nend)&&zmleq(nend,oend))
+    return PARTIAL_OVERWRITE;
+
+  return NO_OVERWRITE;
+}
+
+/* performs data flow analysis for reaching definitions */
+void reaching_definitions(flowgraph *fg)
+{
+  flowgraph *g;IC *p;bvtype *tmp,*init;
+  int changed,pass,i,j;
+  unsigned long heapsize=0;
+  /*  rd_gen und rd_kill fuer jeden Block berechnen   */
+  if(DEBUG&1024) printf("analysing reaching definitions\n");
+  tmp=mymalloc(dsize);
+  init=mymalloc(dsize);
+  heapsize+=2*dsize;
+  memset(init,0,dsize);
+  for(i=1;i<=dcount;i++){
+    p=dlist[i];
+    if(p->z.flags&VAR){
+      Var *v=p->z.v;
+      if(v->storage_class==EXTERN||v->storage_class==STATIC||v->reg!=0||!zmleq(l2zm(0L),v->offset)){
+	BSET(init,UNDEF(i));
+      }
+    }
+  }
+  g=fg;
+  while(g){
+    g->rd_in=mymalloc(dsize);
+    memset(g->rd_in,0,dsize);
+    g->rd_out=mymalloc(dsize);
+    memset(g->rd_out,0,dsize);
+    g->rd_gen=mymalloc(dsize);
+    memset(g->rd_gen,0,dsize);
+    g->rd_kill=mymalloc(dsize);
+    memset(g->rd_kill,0,dsize);
+    heapsize+=4*dsize;
+    p=g->end;
+    while(p){
+      if(p->defindex){
+	bvunite(g->rd_gen,defs_gen[p->defindex],dsize);
+	bvdiff(g->rd_gen,g->rd_kill,dsize);
+	bvunite(g->rd_kill,defs_kill[p->defindex],dsize);
+	bvdiff(g->rd_kill,g->rd_gen,dsize);
+      }
+      if(p==g->start) break;
+      p=p->prev;
+    }
+    memcpy(g->rd_out,g->rd_gen,dsize);
+    g=g->normalout;
+  }
+
+  /*  rd_in und rd_out fuer jeden Block berechnen */
+  /*  out(b)=gen(B) vorinitialisiert              */
+  if(DEBUG&1024) {printf("pass:");pass=0;}
+  do{
+    if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+    changed=0;
+    g=fg;
+    while(g){
+      flowlist *lp;
+      /*  in(B)=U out(C) : C Vorgaenger von B */
+      if(g==fg)
+	memcpy(g->rd_in,init,dsize);
+      else
+	memset(g->rd_in,0,dsize);
+      lp=g->in;
+      while(lp){
+	if(!lp->graph) ierror(0);
+	if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA)
+	  bvunite(g->rd_in,lp->graph->rd_out,dsize);
+	lp=lp->next;
+      }
+      /*  out(b)=gen(B) U (in(B)-kill(B)  */
+      memcpy(tmp,g->rd_in,dsize);
+      bvdiff(tmp,g->rd_kill,dsize);
+      bvunite(tmp,g->rd_gen,dsize);
+      if(!bvcmp(tmp,g->rd_out,dsize)){changed=1;memcpy(g->rd_out,tmp,dsize);}
+      g=g->normalout;
+    }
+  }while(changed);
+  if(DEBUG&1024) printf("\n");
+  if(DEBUG&16384) printf("reaching_defs heapsize=%lu\n",heapsize);
+  free(tmp);
+  free(init);
+}
+
+/* calculates z:=q1 op q2 with constants */
+/* if p is non-zero q1typ,q2typ from p will be used */
+void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p)
+{
+  zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+  if(p) t=q1typ(p);
+  eval_const(q1,t);
+  d1=vldouble;l1=vmax;u1=vumax;
+  if(c!=MINUS&&c!=KOMPLEMENT){
+    if(p)
+      eval_const(q2,q2typ(p));
+    else
+      eval_const(q2,t);
+    d2=vldouble;l2=vmax;u2=vumax;
+  }
+  if(c==ADD){ vldouble=zldadd(d1,d2);vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+  if(c==SUB){ vldouble=zldsub(d1,d2);vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+  if(c==ADDI2P){ vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+  if(c==SUBIFP){ vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+  if(c==MULT){ vldouble=zldmult(d1,d2);vmax=zmmult(l1,l2);vumax=zummult(u1,u2);}
+  if(c==DIV||c==MOD){
+    if(zldeqto(d2,d2zld(0.0))&&zmeqto(l2,l2zm(0L))&&zumeqto(u2,ul2zum(0UL))){
+      err_ic=p;error(210);err_ic=0;
+      vmax=l2zm(0L);vumax=ul2zum(0L);vldouble=d2zld(0.0);
+    }else{
+      if(c==DIV){
+	vldouble=zlddiv(d1,d2);
+	if(!zmeqto(l2,l2zm(0L))) vmax=zmdiv(l1,l2);
+	if(!zumeqto(u2,ul2zum(0UL))) vumax=zumdiv(u1,u2);
+      }else{
+	if(!zmeqto(l2,l2zm(0L))) vmax=zmmod(l1,l2);
+	if(!zumeqto(u2,ul2zum(0UL))) vumax=zummod(u1,u2);
+      }
+    }
+  }
+  if(c==AND){ vmax=zmand(l1,l2);vumax=zumand(u1,u2);}
+  if(c==OR){ vmax=zmor(l1,l2);vumax=zumor(u1,u2);}
+  if(c==XOR){ vmax=zmxor(l1,l2);vumax=zumxor(u1,u2);}
+  if(c==LSHIFT){ vmax=zmlshift(l1,l2);vumax=zumlshift(u1,l2);}
+  if(c==RSHIFT){ vmax=zmrshift(l1,l2);vumax=zumrshift(u1,l2);}
+  if(c==MINUS){ vldouble=zldsub(d2zld(0.0),d1);vmax=zmsub(l2zm(0L),l1);vumax=zumsub(ul2zum(0UL),u1);}
+  if(c==KOMPLEMENT){ vmax=zmkompl(l1);vumax=zumkompl(u1);}
+
+  if(ISFLOAT(t)){
+    gval.vldouble=vldouble;
+    eval_const(&gval,LDOUBLE);
+  }else if(t&UNSIGNED){
+    gval.vumax=vumax;
+    eval_const(&gval,(UNSIGNED|MAXINT));
+  }else{
+    gval.vmax=vmax;
+    eval_const(&gval,MAXINT);
+  }
+  if(p) t=ztyp(p);
+  insert_const(z,t);
+}
+
+/* folds constant ICs */
+int fold(IC *p)
+{
+  int c;
+  if(!p) ierror(0);
+  c=p->code;
+  if(c==SUBPFP||c==ASSIGN||c==PUSH||c==SETRETURN) return 0;
+  if(DEBUG&1024) {printf("folding IC:\n");pric2(stdout,p);}
+  if(c==TEST||c==COMPARE){
+    union atyps val;int cc; /*  condition codes */
+    IC *bp;
+    if(c==TEST){
+      eval_const(&p->q1.val,p->typf);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+	cc=0; 
+      else
+	cc=1;
+    }else{
+      if(p->q1.flags&VARADR)
+	cc=compare_const(&p->q1.val,&p->q2.val,UNSIGNED|MAXINT);
+      else
+	cc=compare_const(&p->q1.val,&p->q2.val,p->typf);
+    }
+    bp=p->next;
+    if(bp->code>=BEQ&&bp->code<=BGT&&(!p->z.flags||p->z.v==bp->q1.v)){
+      if(DEBUG&1024) printf("(cc=%d; comparison eliminated)\n",cc);
+      if(have_alias){ free(p->use_list);free(p->change_list);}
+      remove_IC(p);
+      while(1){   /*  zugehoerigen Branch suchen  */
+	if(!bp||bp->code==LABEL||bp->code==BRA) ierror(0);
+	c=bp->code;
+	if(c>=BEQ&&c<=BGT) break;
+	bp=bp->next;
+      }
+      if((c==BEQ&&cc==0)||(c==BNE&&cc!=0)||(c==BLT&&cc<0)||(c==BGT&&cc>0)||(c==BLE&&cc<=0)||(c==BGE&&cc>=0)){
+	if(DEBUG&1024){ printf("changed following branch to BRA:\n");pric2(stdout,bp);}
+	bp->code=BRA;bp->q1.flags=0;
+      }else{
+	if(DEBUG&1024){ printf("removed following branch:\n");pric2(stdout,bp);}
+	if(have_alias){ free(bp->use_list);free(bp->change_list);}
+	remove_IC(bp);
+      }
+      return 1;
+    }
+    if(p->z.flags==0){
+      p->code=NOP;
+      p->q1.flags=p->q2.flags=p->z.flags=0;
+      return 1;
+    }else
+      return 0;
+  }
+  if(c==CONVERT){
+    eval_const(&p->q1.val,p->typf2);
+    insert_const(&p->q1.val,p->typf);
+  }else
+    calc(c,p->typf,&p->q1.val,&p->q2.val,&p->q1.val,p);
+  p->q2.flags=0;
+  if(p->code==ADDI2P||p->code==SUBIFP)
+    p->typf=p->typf2;
+  p->q2.val.vmax=sizetab[p->typf&NQ];
+  p->code=ASSIGN;
+  if(DEBUG&1024){printf("becomes\n");pric2(stdout,p);}
+  return 1;
+}
+
+/* tries to replace objects by constants and detects some uninitialized */
+/* variables; if cponly==0, address-constants will be replaced, */
+/* otherwise only real constants are replaced, sic points to the IC */
+/* containing the object pointed to by o */
+int propagate(IC *sic,obj *o,int cponly,int global)
+{
+  unsigned int i,j,t,found;union atyps *val=0;
+  Var *v,*vaddr=0;IC *p;
+  zmax voff;
+  if(!o||!o->v) ierror(0);
+  if(cponly){
+    if(is_volatile_obj(o))
+      return 0;
+  }else{
+    if((o->flags&VAR)&&(o->v->vtyp->flags&VOLATILE))
+      return 0;
+  }
+  if(disable&8) return 0;
+  v=o->v;
+  i=v->index;
+  /* do not replace in ICs of the form move char with size!=1,
+     because these are builtin memcpy */
+  if(cponly&&sic->code==ASSIGN&&(sic->typf&NQ)==CHAR&&!zmeqto(sic->q2.val.vmax,l2zm(1L)))
+    return 0;
+  if(cponly&&(o->flags&DREFOBJ)) i+=vcount-rcount;
+  if(DEBUG&2048){
+    printf("propagate(cponly=%d) <%s>(%p)\n",cponly,o->v->identifier,(void *)v);
+    if(o->flags&DREFOBJ) printf("(DREFOBJ)");
+    printf("\nall reaching definitions:\n");print_rd(rd_defs);
+    printf("defs for var:\n");
+    print_rd(var_defs[i]);
+  }
+  if(v->nesting==0||v->storage_class==STATIC||v->storage_class==EXTERN){
+    /*  Wenn moeglich bei statischen Variablen den Wert bei der         */
+    /*  Initialisierung ermitteln.                                      */
+    /*if(cponly&&ISARITH(v->vtyp->flags)&&((v->vtyp->flags&CONST)||(v->nesting>0&&!(v->flags&(USEDASADR|USEDASDEST))))){*/
+    if(cponly&&is_const(v->vtyp)){
+      /*  Variable hat noch den Wert der Initialisierung.         */
+      if(v->clist){
+	int t;
+	if(o==&sic->q1) t=q1typ(sic);
+	else if(o==&sic->q2) t=q2typ(sic);
+	else if(o==&sic->z) t=ztyp(sic);
+	else ierror(0);
+	if(ISARITH(v->vtyp->flags)){
+	  /*  Der Wert der Initialisierung ist noch gespeichert.  */
+	  if(DEBUG&1024) printf("using static initializer\n");
+	  o->val=v->clist->val;
+	  o->flags=KONST;
+	  return 1;
+	}else if(ISINT(t&NQ)){
+	  int state;
+	  if(DEBUG&1024) printf("using static initializer (new version)\n");
+	  gval.vumax=get_clist_int(v->vtyp,v->clist,o->val.vmax,sizetab[t&NQ],&state);
+	  if(state){
+	    if(DEBUG&1024) printf("using static initializer (new version)\n");
+	    eval_const(&gval,UNSIGNED|MAXINT);
+	    insert_const(&o->val,t);
+	    o->flags=KONST;
+	    return 1;
+	  }
+	}
+      }else{
+	/*  Hier evtl. eine implizite 0 erkennen.               */
+      }
+    }
+  }
+  found=0;
+  for(j=1;j<=dcount;j++){
+    if((!BTST(rd_defs,UNDEF(j))||!BTST(var_defs[i],UNDEF(j)))&&
+       (!BTST(rd_defs,j)||!BTST(var_defs[i],j))) continue;
+    found=1;
+    p=dlist[j];
+    if(!(p->z.flags&VAR)) return 0;
+    if(p->z.v!=o->v) continue;
+    t=ztyp(p)&NU;
+    if(cponly&&!ISSCALAR(t)) continue;
+    if(!zmeqto(p->z.val.vmax,o->val.vmax)) continue;
+    if(cponly){
+      if(p->z.flags!=o->flags) continue;
+    }else{
+      if((p->z.flags|DREFOBJ)!=o->flags) continue;
+      if(p->z.flags&DREFOBJ) continue;
+    }
+    if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))) return 0;
+    if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],j)) return 0;
+
+    if((p->code!=ASSIGN||((p->q1.flags&(KONST|DREFOBJ))!=KONST&&(p->q1.flags&(VARADR|DREFOBJ))!=VARADR))
+       &&(p->code!=ADDRESS||!(o->flags&DREFOBJ))) return 0;
+    if(p->q1.flags&KONST){
+      if(vaddr) return 0;
+      if(val){
+	if((p->typf&NQ)!=(t&NQ)) return 0;
+	if(compare_const(&p->q1.val,val,t)) return 0;
+      }else{
+	val=&p->q1.val;t=p->typf&NU;
+      }
+    }
+    if(p->code==ADDRESS||(p->q1.flags&VARADR)){
+      if(val) return 0;
+      if(vaddr){
+	if(p->q1.v!=vaddr||!zmeqto(p->q1.val.vmax,voff)) return 0;
+      }
+      vaddr=p->q1.v;
+      voff=p->q1.val.vmax;
+    }
+  }
+
+  /* found constant */
+  if(val){
+    if(cponly){
+      if(o==&sic->q1&&(q1typ(sic)&NQ)!=(t&NQ)) return 0;
+      if(o==&sic->q2&&(q2typ(sic)&NQ)!=(t&NQ)) return 0;
+      if(o==&sic->z&&(ztyp(sic)&NQ)!=(t&NQ)) return 0;
+      
+      if(DEBUG&1024) printf("can replace %ld+<%s>(%p) by constant\n",zm2l(o->val.vmax),o->v->identifier,o->v);
+      /* TODO: do we need eval_const/insert_const (if representation of unsigned is different? */
+      o->val=*val;
+      o->flags=KONST;
+    }else{
+      if(DEBUG&1024) printf("can replace <%s> by constant address\n",o->v->identifier);
+      o->val=*val;
+      o->flags|=KONST;
+      o->flags&=~VAR;
+      o->v=0;
+    }
+    return 1;
+  }
+  if(vaddr&&(vaddr->storage_class==EXTERN||vaddr->storage_class==STATIC)){
+    if(DEBUG&1024) printf("can replace <%s> by varadr\n",o->v->identifier);
+    o->v=vaddr;
+    o->val.vmax=voff;
+    if((o->flags&DREFOBJ)&&!cponly)
+      o->flags=VAR;
+    else
+      o->flags=VAR|VARADR;
+    return 2;
+  }
+  if(vaddr&&(o->flags&DREFOBJ)){
+    t=vaddr->vtyp->flags&NU;
+    if(o==&sic->q1&&(q1typ(sic)&NU)!=t) return 0;
+    if(o==&sic->q2&&(q2typ(sic)&NU)!=t) return 0;
+    if(o==&sic->z&&(ztyp(sic)&NU)!=t) return 0;
+    if(DEBUG&1024) printf("can replace *<%s> by address\n",o->v->identifier);
+    o->v=vaddr;
+    o->val.vmax=voff;
+    o->flags&=~DREFOBJ;
+    return 2;
+  }
+  /* no definition found */
+  if(!found&&global&&v->storage_class!=EXTERN&&v->storage_class!=STATIC&&!(v->flags&USEDBEFORE)&&v->reg==0&&zmleq(l2zm(0L),v->offset)){
+    if(*v->identifier||!(optflags&4096)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      error(171,v->identifier);v->flags|=USEDBEFORE;
+      if(!*v->identifier) {printf("<%p>\n",(void *)v);ierror(0);}
+    }
+  }
+  return 0;
+}
+
+/* searches for constant objects and uninitialized variables; if  */
+/* global!=0, reaching definitions are used, otherwise only local */
+/* constant propagation will be done                              */
+int constant_propagation(flowgraph *fg,int global)
+{
+  IC *p;int changed=0,i,t;flowgraph *g;
+  rd_defs=mymalloc(dsize);
+  g=fg;
+  while(g){
+    if(global)
+      memcpy(rd_defs,g->rd_in,dsize);
+    else
+      memset(rd_defs,0,dsize);
+    p=g->start;
+    while(p){
+      int c=p->code;
+      /* if(DEBUG&1024){print_rd(rd_defs);pric2(stdout,p);}*/
+      if(c!=ADDRESS&&c!=NOP&&ISSCALAR(p->typf)&&(c<LABEL||c>BRA)){
+	if((p->q1.flags&(VAR|VARADR))==VAR){
+	  if(!(q1typ(p)&VOLATILE)&&!is_volatile_obj(&p->q1))
+	    changed|=propagate(p,&p->q1,1,global);
+	  if((p->q1.flags&DREFOBJ)&&!(p->q1.v->vtyp->flags&VOLATILE))
+	    changed|=propagate(p,&p->q1,0,global);
+	}
+	if((p->q2.flags&(VAR|VARADR))==VAR){
+	  if(!(q2typ(p)&VOLATILE)&&!is_volatile_obj(&p->q2))
+	    changed|=propagate(p,&p->q2,1,global);
+	  if((p->q2.flags&DREFOBJ)&&!(p->q2.v->vtyp->flags&VOLATILE))
+	    changed|=propagate(p,&p->q2,0,global);
+	}
+      }
+      /* only there to detect uninitialized variables */
+      if(((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))){
+	if(!(p->z.v->vtyp->flags&VOLATILE))
+	  changed|=propagate(p,&p->z,0,global);
+      }
+      rd_change(p);
+      
+      if(p==g->end) break;
+      p=p->next;
+    }
+    break;
+    g=g->normalout;
+  }
+  
+  gchanged|=changed;
+  
+  free(rd_defs);
+  return changed;
+}
+
+/* performs changes to rd_defs which are caused by IC p */
+void rd_change(IC *p)
+{
+  if(DEBUG&4096) print_rd(rd_defs);
+  if(p->defindex){
+    bvdiff(rd_defs,defs_kill[p->defindex],dsize);
+    bvunite(rd_defs,defs_gen[p->defindex],dsize);
+  }
+  if(DEBUG&4096) pric2(stdout,p);
+}
+
diff --git a/rd_tst.c b/rd_tst.c
new file mode 100644
index 0000000..d64de4f
--- /dev/null
+++ b/rd_tst.c
@@ -0,0 +1,647 @@
+/*  $VER: vbcc (rd.c) $Revision: 1.16 $    */
+/*  reaching definitions and constant propagation   */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+unsigned int dcount;
+size_t dsize;
+IC **dlist;
+bvtype *rd_defs;
+bvtype **defs_kill;    /* definitions killed */
+bvtype **defs_gen;     /* definitions undefined */
+bvtype **var_defs;     /* definitions of a variable */
+bvtype **var_undefs;   /* definitions which are undefined by writing to this var */
+bvtype *rd_matrix;
+
+int def_overwrites(IC *new,IC *old);
+#define NO_OVERWRITE 0
+#define FULL_OVERWRITE 1
+#define PARTIAL_OVERWRITE 2
+#define EXACT_OVERWRITE 3
+
+/*  compares two constants; -1, if q1<q2; 0, if q1==q1; 1 otherwise  */
+int compare_const(union atyps *q1,union atyps *q2,int t)
+{
+  zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+  t&=NU;
+  eval_const(q1,t);d1=vldouble;l1=vmax;u1=vumax;
+  eval_const(q2,t);d2=vldouble;l2=vmax;u2=vumax;
+  if(ISFLOAT(t)) return(zldleq(d2,d1)?!zldeqto(d1,d2):-1);
+  if(ISPOINTER(t)||(t&UNSIGNED)) return(zumleq(u2,u1)?!zumeqto(u1,u2):-1);
+  return(zmleq(l2,l1)?!zmeqto(l1,l2):-1);
+}
+
+/* prints definitions in a bitvector */
+void print_rd(bvtype *bitvector)
+{
+  unsigned int i;
+  if(!bitvector) {printf("reaching definitions not available\n");return;}
+  for(i=1;i<=dcount;i++){
+    if(BTST(bitvector,i)) {printf("%3u:",i);pric2(stdout,dlist[i]);}
+    if(BTST(bitvector,UNDEF(i))) {printf("%3u(ud):",i);pric2(stdout,dlist[i]);}
+  }
+}
+
+/* numbers all definitions and creates some bitvectors */
+void num_defs(void)
+{
+  int i,j;IC *p;
+  size_t matrix_size;
+  bvtype *bp;
+  unsigned long heapsize=0;
+  if(DEBUG&1024) printf("numerating definitions\n");
+  i=0;
+  for(p=first_ic;p;p=p->next){
+    if(!(p->z.flags&(VAR|DREFOBJ))&&p->code!=CALL){p->defindex=0;continue;}
+    p->defindex=++i;
+  }
+  dcount=i;
+  /*dsize=(2*dcount+1+CHAR_BIT)/CHAR_BIT;    /* +1, da bei 1 anfaengt */
+  dsize=BVSIZE(2*(dcount+1));
+  if(DEBUG&(16384|1024)) printf("%lu definitions, dsize=%lu\n",(unsigned long)dcount,(unsigned long)dsize);
+  
+  /* get big memory block to store defs_kill, defs_gen, vars, var_defs and var_undefs */
+  matrix_size=(2*(dcount+vcount)*dsize);
+  rd_matrix=bp=mymalloc(matrix_size);
+  memset(bp,0,matrix_size);
+  heapsize+=matrix_size;
+
+  /* calculate bit-vector which contains all definitions killed or */
+  /* undefined (=partially overwritten) by this definition         */
+  defs_kill=mymalloc(sizeof(*defs_kill)*(dcount+1));
+  defs_gen=mymalloc(sizeof(*defs_gen)*(dcount+1));
+  heapsize+=2*sizeof(*defs_kill)*(dcount+1);
+
+  for(i=1;i<=dcount;i++){
+    defs_kill[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+    defs_gen[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+  }
+  
+  /* calculate bit vector with all undefined definitions of each variable */
+  var_defs=mymalloc(sizeof(*var_defs)*vcount);
+  heapsize+=sizeof(*var_defs)*vcount;
+  var_undefs=mymalloc(sizeof(*var_undefs)*vcount);
+  heapsize+=sizeof(*var_undefs)*vcount;
+  for(i=0;i<vcount;i++){
+    var_defs[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+    var_undefs[i]=bp;
+    bp+=dsize/sizeof(bvtype);
+  }
+  
+  /* calculate pointers to IC for every definition */
+  dlist=mymalloc((dcount+1)*sizeof(*dlist));
+  heapsize+=(dcount+1)*sizeof(*dlist);
+
+  for(p=first_ic;p;p=p->next){
+    if(p->defindex){
+      dlist[p->defindex]=p;
+      if(p->z.flags&VAR){
+        Var *v=p->z.v;
+        i=v->index;
+        if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+        BSET(var_defs[i],p->defindex);
+	BSET(var_defs[i],UNDEF(p->defindex));
+	if(i<rcount){
+	  BSET(var_defs[i+vcount-rcount],p->defindex);
+	  BSET(var_defs[i+vcount-rcount],UNDEF(p->defindex));
+	}
+        BSET(var_undefs[i],UNDEF(p->defindex));
+      }
+    }
+  }
+  
+  for(i=1;i<=dcount;i++){
+    p=dlist[i];
+    for(j=0;j<p->change_cnt;j++){
+      int idx;
+      idx=p->change_list[j].v->index;
+      if(p->change_list[j].flags&DREFOBJ) idx+=vcount-rcount;
+      if(idx>=vcount) continue;	
+      BSET(var_defs[idx],i);
+      bvunite(defs_gen[i],var_undefs[idx],dsize);
+    }
+    if(p->z.flags&VAR){
+      for(j=1;j<=dcount;j++){
+	int ow;
+	IC *p2;
+	if(i==j) continue;
+	p2=dlist[j];
+	if(!(p2->z.flags&VAR)||p->z.v!=p2->z.v||p->z.flags!=p2->z.flags)
+	  continue;
+	ow=def_overwrites(p,p2);
+	if(ow==FULL_OVERWRITE||ow==EXACT_OVERWRITE){
+	  BSET(defs_kill[i],j);
+	  BSET(defs_kill[i],UNDEF(j));
+	}
+	if(ow==EXACT_OVERWRITE||ow==NO_OVERWRITE){
+	  BCLR(defs_gen[i],j);
+	  BCLR(defs_gen[i],UNDEF(j));
+	}
+      }
+    }
+    /* every definition defines itself) */
+    BSET(defs_gen[i],i);
+    BCLR(defs_gen[i],UNDEF(i));
+    BSET(defs_kill[i],UNDEF(i));
+  }
+  
+  if(DEBUG&2048){
+    for(i=0;i<vcount;i++){
+      printf("var_defs for var %i %s(%p):\n",i,vilist[i]->identifier,vilist[i]);
+      print_rd(var_defs[i]);
+    }
+	
+    for(i=1;i<=dcount;i++){
+      printf("Def%3d: ",i);pric2(stdout,dlist[i]);
+      printf(" kills:\n");
+      for(j=1;j<=dcount;j++){
+	if(BTST(defs_kill[i],j)) {printf("  ");pric2(stdout,dlist[j]);}
+	if(BTST(defs_kill[i],UNDEF(j))) {printf("  (ud)");pric2(stdout,dlist[j]);}
+      }
+      printf(" gens:\n");
+      for(j=1;j<=dcount;j++){
+	if(BTST(defs_gen[i],j)) {printf("  ");pric2(stdout,dlist[j]);}
+	if(BTST(defs_gen[i],UNDEF(j))) {printf("  (ud)");pric2(stdout,dlist[j]);}
+      }
+    }
+  }
+
+  if(DEBUG&16384) printf("num_defs heapsize=%lu\n",heapsize);
+
+  free(var_undefs);
+}
+
+/* returns whether n overwrites the definition p */
+int def_overwrites(IC *n,IC *o)
+{
+  zmax nstart,nend,ostart,oend,nsize,osize;
+  if(!(n->z.flags&VAR)) ierror(0);
+  if(!(o->z.flags&VAR)) ierror(0);
+  if((n->z.flags&DREFOBJ)!=(o->z.flags&DREFOBJ)) ierror(0);
+  if(n->code==ASSIGN){
+    nsize=n->q2.val.vmax;
+  }else{
+    nsize=sizetab[ztyp(n)&NQ];
+  }
+  if(o->code==ASSIGN){
+    osize=o->q2.val.vmax;
+  }else{
+    osize=sizetab[ztyp(o)&NQ];
+  }
+  if(n->z.flags&DREFOBJ)
+    return zmleq(osize,nsize);
+
+  nstart=n->z.val.vmax;
+  nend=zmsub(zmadd(nstart,nsize),l2zm(1L));
+  ostart=o->z.val.vmax;
+  oend=zmsub(zmadd(ostart,osize),l2zm(1L));
+
+  if(zmeqto(nstart,ostart)&&zmeqto(nend,oend))
+    return EXACT_OVERWRITE;
+
+  if(zmleq(nstart,ostart)&&zmleq(oend,nend))
+    return FULL_OVERWRITE;
+
+  if(zmleq(ostart,nstart)&&zmleq(nstart,oend))
+    return PARTIAL_OVERWRITE;
+  if(zmleq(ostart,nend)&&zmleq(nend,oend))
+    return PARTIAL_OVERWRITE;
+
+  return NO_OVERWRITE;
+}
+
+/* performs data flow analysis for reaching definitions */
+void reaching_definitions(flowgraph *fg)
+{
+  flowgraph *g;IC *p;bvtype *tmp,*init;
+  int changed,pass,i,j;
+  unsigned long heapsize=0;
+  /*  rd_gen und rd_kill fuer jeden Block berechnen   */
+  if(DEBUG&1024) printf("analysing reaching definitions\n");
+  tmp=mymalloc(dsize);
+  init=mymalloc(dsize);
+  heapsize+=2*dsize;
+  memset(init,0,dsize);
+  for(i=1;i<=dcount;i++){
+    p=dlist[i];
+    if(p->z.flags&VAR){
+      Var *v=p->z.v;
+      if(v->storage_class==EXTERN||v->storage_class==STATIC||v->reg!=0||!zmleq(l2zm(0L),v->offset)){
+	BSET(init,UNDEF(i));
+      }
+    }
+  }
+  g=fg;
+  while(g){
+    g->rd_in=mymalloc(dsize);
+    memset(g->rd_in,0,dsize);
+    g->rd_out=mymalloc(dsize);
+    memset(g->rd_out,0,dsize);
+    g->rd_gen=mymalloc(dsize);
+    memset(g->rd_gen,0,dsize);
+    g->rd_kill=mymalloc(dsize);
+    memset(g->rd_kill,0,dsize);
+    heapsize+=4*dsize;
+    p=g->end;
+    while(p){
+      if(p->defindex){
+	bvunite(g->rd_gen,defs_gen[p->defindex],dsize);
+	bvdiff(g->rd_gen,g->rd_kill,dsize);
+	bvunite(g->rd_kill,defs_kill[p->defindex],dsize);
+	bvdiff(g->rd_kill,g->rd_gen,dsize);
+      }
+      if(p==g->start) break;
+      p=p->prev;
+    }
+    memcpy(g->rd_out,g->rd_gen,dsize);
+    g=g->normalout;
+  }
+
+  /*  rd_in und rd_out fuer jeden Block berechnen */
+  /*  out(b)=gen(B) vorinitialisiert              */
+  if(DEBUG&1024) {printf("pass:");pass=0;}
+  do{
+    if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+    changed=0;
+    g=fg;
+    while(g){
+      flowlist *lp;
+      /*  in(B)=U out(C) : C Vorgaenger von B */
+      if(g==fg)
+	memcpy(g->rd_in,init,dsize);
+      else
+	memset(g->rd_in,0,dsize);
+      lp=g->in;
+      while(lp){
+	if(!lp->graph) ierror(0);
+	if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA)
+	  bvunite(g->rd_in,lp->graph->rd_out,dsize);
+	lp=lp->next;
+      }
+      /*  out(b)=gen(B) U (in(B)-kill(B)  */
+      memcpy(tmp,g->rd_in,dsize);
+      bvdiff(tmp,g->rd_kill,dsize);
+      bvunite(tmp,g->rd_gen,dsize);
+      if(!bvcmp(tmp,g->rd_out,dsize)){changed=1;memcpy(g->rd_out,tmp,dsize);}
+      g=g->normalout;
+    }
+  }while(changed);
+  if(DEBUG&1024) printf("\n");
+  if(DEBUG&16384) printf("reaching_defs heapsize=%lu\n",heapsize);
+  free(tmp);
+  free(init);
+}
+
+/* calculates z:=q1 op q2 with constants */
+/* if p is non-zero q1typ,q2typ from p will be used */
+void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p)
+{
+  zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+  if(p) t=q1typ(p);
+  eval_const(q1,t);
+  d1=vldouble;l1=vmax;u1=vumax;
+  if(c!=MINUS&&c!=KOMPLEMENT){
+    if(p)
+      eval_const(q2,q2typ(p));
+    else
+      eval_const(q2,t);
+    d2=vldouble;l2=vmax;u2=vumax;
+  }
+  if(c==ADD){ vldouble=zldadd(d1,d2);vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+  if(c==SUB){ vldouble=zldsub(d1,d2);vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+  if(c==ADDI2P){ vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+  if(c==SUBIFP){ vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+  if(c==MULT){ vldouble=zldmult(d1,d2);vmax=zmmult(l1,l2);vumax=zummult(u1,u2);}
+  if(c==DIV||c==MOD){
+    if(zldeqto(d2,d2zld(0.0))&&zmeqto(l2,l2zm(0L))&&zumeqto(u2,ul2zum(0UL))){
+      err_ic=p;error(210);err_ic=0;
+      vmax=l2zm(0L);vumax=ul2zum(0L);vldouble=d2zld(0.0);
+    }else{
+      if(c==DIV){
+	vldouble=zlddiv(d1,d2);
+	if(!zmeqto(l2,l2zm(0L))) vmax=zmdiv(l1,l2);
+	if(!zumeqto(u2,ul2zum(0UL))) vumax=zumdiv(u1,u2);
+      }else{
+	if(!zmeqto(l2,l2zm(0L))) vmax=zmmod(l1,l2);
+	if(!zumeqto(u2,ul2zum(0UL))) vumax=zummod(u1,u2);
+      }
+    }
+  }
+  if(c==AND){ vmax=zmand(l1,l2);vumax=zumand(u1,u2);}
+  if(c==OR){ vmax=zmor(l1,l2);vumax=zumor(u1,u2);}
+  if(c==XOR){ vmax=zmxor(l1,l2);vumax=zumxor(u1,u2);}
+  if(c==LSHIFT){ vmax=zmlshift(l1,l2);vumax=zumlshift(u1,l2);}
+  if(c==RSHIFT){ vmax=zmrshift(l1,l2);vumax=zumrshift(u1,l2);}
+  if(c==MINUS){ vldouble=zldsub(d2zld(0.0),d1);vmax=zmsub(l2zm(0L),l1);vumax=zumsub(ul2zum(0UL),u1);}
+  if(c==KOMPLEMENT){ vmax=zmkompl(l1);vumax=zumkompl(u1);}
+
+  if(ISFLOAT(t)){
+    gval.vldouble=vldouble;
+    eval_const(&gval,LDOUBLE);
+  }else if(t&UNSIGNED){
+    gval.vumax=vumax;
+    eval_const(&gval,(UNSIGNED|MAXINT));
+  }else{
+    gval.vmax=vmax;
+    eval_const(&gval,MAXINT);
+  }
+  if(p) t=ztyp(p);
+  insert_const(z,t);
+}
+
+/* folds constant ICs */
+int fold(IC *p)
+{
+  int c;
+  if(!p) ierror(0);
+  c=p->code;
+  if(c==SUBPFP||c==ASSIGN||c==PUSH||c==SETRETURN) return 0;
+  if(DEBUG&1024) {printf("folding IC:\n");pric2(stdout,p);}
+  if(c==TEST||c==COMPARE){
+    union atyps val;int cc; /*  condition codes */
+    IC *bp;
+    if(c==TEST){
+      eval_const(&p->q1.val,p->typf);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+	cc=0; 
+      else
+	cc=1;
+    }else{
+      if(p->q1.flags&VARADR)
+	cc=compare_const(&p->q1.val,&p->q2.val,UNSIGNED|MAXINT);
+      else
+	cc=compare_const(&p->q1.val,&p->q2.val,p->typf);
+    }
+    bp=p->next;
+    if(bp->code>=BEQ&&bp->code<=BGT&&(!p->z.flags||p->z.v==bp->q1.v)){
+      if(DEBUG&1024) printf("(cc=%d; comparison eliminated)\n",cc);
+      if(have_alias){ free(p->use_list);free(p->change_list);}
+      remove_IC(p);
+      while(1){   /*  zugehoerigen Branch suchen  */
+	if(!bp||bp->code==LABEL||bp->code==BRA) ierror(0);
+	c=bp->code;
+	if(c>=BEQ&&c<=BGT) break;
+	bp=bp->next;
+      }
+      if((c==BEQ&&cc==0)||(c==BNE&&cc!=0)||(c==BLT&&cc<0)||(c==BGT&&cc>0)||(c==BLE&&cc<=0)||(c==BGE&&cc>=0)){
+	if(DEBUG&1024){ printf("changed following branch to BRA:\n");pric2(stdout,bp);}
+	bp->code=BRA;bp->q1.flags=0;
+      }else{
+	if(DEBUG&1024){ printf("removed following branch:\n");pric2(stdout,bp);}
+	if(have_alias){ free(bp->use_list);free(bp->change_list);}
+	remove_IC(bp);
+      }
+      return 1;
+    }
+    if(p->z.flags==0){
+      p->code=NOP;
+      p->q1.flags=p->q2.flags=p->z.flags=0;
+      return 1;
+    }else
+      return 0;
+  }
+  if(c==CONVERT){
+    eval_const(&p->q1.val,p->typf2);
+    insert_const(&p->q1.val,p->typf);
+  }else
+    calc(c,p->typf,&p->q1.val,&p->q2.val,&p->q1.val,p);
+  p->q2.flags=0;
+  if(p->code==ADDI2P||p->code==SUBIFP)
+    p->typf=p->typf2;
+  p->q2.val.vmax=sizetab[p->typf&NQ];
+  p->code=ASSIGN;
+  if(DEBUG&1024){printf("becomes\n");pric2(stdout,p);}
+  return 1;
+}
+
+/* tries to replace objects by constants and detects some uninitialized */
+/* variables; if cponly==0, address-constants will be replaced, */
+/* otherwise only real constants are replaced, sic points to the IC */
+/* containing the object pointed to by o */
+int propagate(IC *sic,obj *o,int cponly,int global)
+{
+  unsigned int i,j,t,found;union atyps *val=0;
+  Var *v,*vaddr=0;IC *p;
+  zmax voff;
+  if(!o||!o->v) ierror(0);
+  if(cponly){
+    if(is_volatile_obj(o))
+      return 0;
+  }else{
+    if((o->flags&VAR)&&(o->v->vtyp->flags&VOLATILE))
+      return 0;
+  }
+  if(disable&8) return 0;
+  v=o->v;
+  i=v->index;
+  /* do not replace in ICs of the form move char with size!=1,
+     because these are builtin memcpy */
+  if(cponly&&sic->code==ASSIGN&&(sic->typf&NQ)==CHAR&&!zmeqto(sic->q2.val.vmax,l2zm(1L)))
+    return 0;
+  if(cponly&&(o->flags&DREFOBJ)) i+=vcount-rcount;
+  if(DEBUG&2048){
+    printf("propagate(cponly=%d) <%s>(%p)\n",cponly,o->v->identifier,(void *)v);
+    if(o->flags&DREFOBJ) printf("(DREFOBJ)");
+    printf("\nall reaching definitions:\n");print_rd(rd_defs);
+    printf("defs for var:\n");
+    print_rd(var_defs[i]);
+  }
+  if(v->nesting==0||v->storage_class==STATIC||v->storage_class==EXTERN){
+    /*  Wenn moeglich bei statischen Variablen den Wert bei der         */
+    /*  Initialisierung ermitteln.                                      */
+    /*if(cponly&&ISARITH(v->vtyp->flags)&&((v->vtyp->flags&CONST)||(v->nesting>0&&!(v->flags&(USEDASADR|USEDASDEST))))){*/
+    printf("var1(%s) %d\n",v->identifier,cponly);
+    if(cponly&&is_const(v->vtyp)){
+      /*  Variable hat noch den Wert der Initialisierung.         */
+      if(v->clist){
+	int t;
+	if(o==&sic->q1) t=q1typ(sic);
+	else if(o==&sic->q2) t=q2typ(sic);
+	else if(o==&sic->z) t=ztyp(sic);
+	else ierror(0);
+	printf("var2(%s)\n",v->identifier);
+	if(ISARITH(v->vtyp->flags)||ISPOINTER(v->vtyp->flags)){
+	  /*  Der Wert der Initialisierung ist noch gespeichert.  */
+	  if(DEBUG&1024) printf("using static initializer\n");
+	  o->val=v->clist->val;
+	  o->flags=KONST;
+	  return 1;
+	}else if(ISINT(t&NQ)){
+	  int state;
+	  if(DEBUG&1024) printf("using static initializer (new version)\n");
+	  gval.vumax=get_clist_int(v->vtyp,v->clist,o->val.vmax,sizetab[t&NQ],&state);
+	  if(state){
+	    if(DEBUG&1024) printf("using static initializer (new version)\n");
+	    eval_const(&gval,UNSIGNED|MAXINT);
+	    insert_const(&o->val,t);
+	    o->flags=KONST;
+	    return 1;
+	  }
+	}
+      }else{
+	/*  Hier evtl. eine implizite 0 erkennen.               */
+      }
+    }
+  }
+  found=0;
+  for(j=1;j<=dcount;j++){
+    if((!BTST(rd_defs,UNDEF(j))||!BTST(var_defs[i],UNDEF(j)))&&
+       (!BTST(rd_defs,j)||!BTST(var_defs[i],j))) continue;
+    found=1;
+    p=dlist[j];
+    if(!(p->z.flags&VAR)) return 0;
+    if(p->z.v!=o->v) continue;
+    t=ztyp(p)&NU;
+    if(cponly&&!ISSCALAR(t)) continue;
+    if(!zmeqto(p->z.val.vmax,o->val.vmax)) continue;
+    if(cponly){
+      if(p->z.flags!=o->flags) continue;
+    }else{
+      if((p->z.flags|DREFOBJ)!=o->flags) continue;
+      if(p->z.flags&DREFOBJ) continue;
+    }
+    if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))) return 0;
+    if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],j)) return 0;
+
+    if((p->code!=ASSIGN||((p->q1.flags&(KONST|DREFOBJ))!=KONST&&(p->q1.flags&(VARADR|DREFOBJ))!=VARADR))
+       &&(p->code!=ADDRESS||!(o->flags&DREFOBJ))) return 0;
+    if(p->q1.flags&KONST){
+      if(vaddr) return 0;
+      if(val){
+	if((p->typf&NQ)!=(t&NQ)) return 0;
+	if(compare_const(&p->q1.val,val,t)) return 0;
+      }else{
+	val=&p->q1.val;t=p->typf&NU;
+      }
+    }
+    if(p->code==ADDRESS||(p->q1.flags&VARADR)){
+      if(val) return 0;
+      if(vaddr){
+	if(p->q1.v!=vaddr||!zmeqto(p->q1.val.vmax,voff)) return 0;
+      }
+      vaddr=p->q1.v;
+      voff=p->q1.val.vmax;
+    }
+  }
+
+  /* found constant */
+  if(val){
+    if(cponly){
+      if(o==&sic->q1&&(q1typ(sic)&NQ)!=(t&NQ)) return 0;
+      if(o==&sic->q2&&(q2typ(sic)&NQ)!=(t&NQ)) return 0;
+      if(o==&sic->z&&(ztyp(sic)&NQ)!=(t&NQ)) return 0;
+      
+      if(DEBUG&1024) printf("can replace %ld+<%s>(%p) by constant\n",zm2l(o->val.vmax),o->v->identifier,o->v);
+      /* TODO: do we need eval_const/insert_const (if representation of unsigned is different? */
+      o->val=*val;
+      o->flags=KONST;
+    }else{
+      if(DEBUG&1024) printf("can replace <%s> by constant address\n",o->v->identifier);
+      o->val=*val;
+      o->flags|=KONST;
+      o->flags&=~VAR;
+      o->v=0;
+    }
+    return 1;
+  }
+  if(vaddr&&(vaddr->storage_class==EXTERN||vaddr->storage_class==STATIC)){
+    if(DEBUG&1024) printf("can replace <%s> by varadr\n",o->v->identifier);
+    o->v=vaddr;
+    o->val.vmax=voff;
+    if((o->flags&DREFOBJ)&&!cponly)
+      o->flags=VAR;
+    else
+      o->flags=VAR|VARADR;
+    return 2;
+  }
+  if(vaddr&&(o->flags&DREFOBJ)){
+    t=vaddr->vtyp->flags&NU;
+    if(o==&sic->q1&&(q1typ(sic)&NU)!=t) return 0;
+    if(o==&sic->q2&&(q2typ(sic)&NU)!=t) return 0;
+    if(o==&sic->z&&(ztyp(sic)&NU)!=t) return 0;
+    if(DEBUG&1024) printf("can replace *<%s> by address\n",o->v->identifier);
+    o->v=vaddr;
+    o->val.vmax=voff;
+    o->flags&=~DREFOBJ;
+    return 2;
+  }
+  /* no definition found */
+  if(!found&&global&&v->storage_class!=EXTERN&&v->storage_class!=STATIC&&!(v->flags&USEDBEFORE)&&v->reg==0&&zmleq(l2zm(0L),v->offset)){
+    if(*v->identifier||!(optflags&4096)){
+#ifdef HAVE_MISRA
+      misra_neu(30,9,1,0,v->identifier);
+#endif
+      error(171,v->identifier);v->flags|=USEDBEFORE;
+      if(!*v->identifier) {printf("<%p>\n",(void *)v);ierror(0);}
+    }
+  }
+  return 0;
+}
+
+/* searches for constant objects and uninitialized variables; if  */
+/* global!=0, reaching definitions are used, otherwise only local */
+/* constant propagation will be done                              */
+int constant_propagation(flowgraph *fg,int global)
+{
+  IC *p;int changed=0,i,t;flowgraph *g;
+  rd_defs=mymalloc(dsize);
+  g=fg;
+  while(g){
+    if(global)
+      memcpy(rd_defs,g->rd_in,dsize);
+    else
+      memset(rd_defs,0,dsize);
+    p=g->start;
+    while(p){
+      int c=p->code;
+      /* if(DEBUG&1024){print_rd(rd_defs);pric2(stdout,p);}*/
+      if(c!=ADDRESS&&c!=NOP&&ISSCALAR(p->typf)&&(c<LABEL||c>BRA)){
+	if((p->q1.flags&(VAR|VARADR))==VAR){
+	  if(!(q1typ(p)&VOLATILE)&&!is_volatile_obj(&p->q1))
+	    changed|=propagate(p,&p->q1,1,global);
+	  if((p->q1.flags&DREFOBJ)&&!(p->q1.v->vtyp->flags&VOLATILE))
+	    changed|=propagate(p,&p->q1,0,global);
+	}
+	if((p->q2.flags&(VAR|VARADR))==VAR){
+	  if(!(q2typ(p)&VOLATILE)&&!is_volatile_obj(&p->q2))
+	    changed|=propagate(p,&p->q2,1,global);
+	  if((p->q2.flags&DREFOBJ)&&!(p->q2.v->vtyp->flags&VOLATILE))
+	    changed|=propagate(p,&p->q2,0,global);
+	}
+      }
+      /* only there to detect uninitialized variables */
+      if(((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))){
+	if(!(p->z.v->vtyp->flags&VOLATILE))
+	  changed|=propagate(p,&p->z,0,global);
+      }
+      rd_change(p);
+      
+      if(p==g->end) break;
+      p=p->next;
+    }
+    break;
+    g=g->normalout;
+  }
+  
+  gchanged|=changed;
+  
+  free(rd_defs);
+  return changed;
+}
+
+/* performs changes to rd_defs which are caused by IC p */
+void rd_change(IC *p)
+{
+  if(DEBUG&4096) print_rd(rd_defs);
+  if(p->defindex){
+    bvdiff(rd_defs,defs_kill[p->defindex],dsize);
+    bvunite(rd_defs,defs_gen[p->defindex],dsize);
+  }
+  if(DEBUG&4096) pric2(stdout,p);
+}
+
diff --git a/regs.c b/regs.c
new file mode 100644
index 0000000..e1eddcd
--- /dev/null
+++ b/regs.c
@@ -0,0 +1,2102 @@
+/*  $VER: vbcc (regs.c) $Revision: 1.31 $   */
+/*  Registerzuteilung           */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+typedef struct regp {int treg;Var *tvar,*tmp;} regp;
+int sregsa[MAXR+1];
+
+void do_load_parms(regp [],flowgraph *);
+void load_one_parm(int,int,Var *,Var *,flowgraph *);
+
+#ifndef NO_OPTIMIZER
+
+int (*savings)[MAXR+1],regu[MAXR+1];
+int *rvlist;
+
+static int const_vars;
+
+static bvtype bregs[BVSIZE(MAXR+1)/sizeof(bvtype)];
+static bvtype bregsm[BVSIZE(MAXR+1)/sizeof(bvtype)];
+
+Var *lparms[MAXR+1];
+
+static void insert_cobj(obj *o,obj *co);
+
+#ifndef HAVE_TARGET_RALLOC
+int reg_prio[MAXR+1];
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 4
+
+int cost_savings(IC *p,int r,obj *o)
+{
+  int c=p->code;
+  if(o->flags&VKONST) return 0;
+  if(o->flags&DREFOBJ){
+    int t;
+    if(o==&p->q1){
+      t=q1typ(p);
+    }else if(o==&p->q2){
+      t=q2typ(p);
+    }else{
+      t=ztyp(p);
+    }
+    if(regok(r,o->v->vtyp->flags,t)) return 4;
+  }
+  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+  return 2;
+}
+#endif
+
+int cmp_savings(const void *v1,const void *v2)
+/*  Vergleichsfkt, um rvlist nach savings zu sortieren  */
+{
+    return savings[*(int *)v2][0]-savings[*(int *)v1][0];
+}
+int entry_load(flowgraph *fg,int i)
+/*  Testet, ob die Variable in Register i am Anfang von Block fg geladen    */
+/*  werden muss, d.h. ein Vorgaenger sie nicht im selben Register hat.      */
+{
+    flowlist *lp;
+    Var *v=fg->regv[i];
+    int vi=v->index;
+    lp=fg->in;
+
+    while(lp){
+        if(lp->graph&&lp->graph->regv[i]!=v&&(vi>=vcount-rcount||BTST(lp->graph->av_out,vi))) return 1;
+        lp=lp->next;
+    }
+    return 0;
+}
+
+/* checks if variable i can be held in a register in loop start-end */
+/* currently we check whether an IC uses/modifies the variable and */
+/* has a corresponding drefobj which might alias the variable */
+int check_cacheable(int i,flowgraph *start,flowgraph *end)
+{
+  int j,k;
+  IC *p;Var *v;
+  flowgraph *g;
+  /* constants are always cacheable */
+  if(vilist[i]->identifier[0]==' ')
+    return 1;
+  if(i<vcount-rcount){
+    /* simple local variables are also easy */
+    v=vilist[i];
+    if(v->storage_class!=STATIC&&v->storage_class!=EXTERN&&!(v->flags&USEDASADR))
+      return 1;
+  }
+  if(disable&16384) return 0;
+  for(g=start;g;g=g->normalout){
+    for(p=g->start;p;p=p->next){
+      for(j=0;j<p->use_cnt;j++){
+	k=p->use_list[j].v->index;
+	if(p->use_list[j].flags&DREFOBJ)
+	  k+=vcount-rcount;
+	if(k==i&&(p->code==CALL||(p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)))
+	  return 0;
+      }
+      for(j=0;j<p->change_cnt;j++){
+	k=p->change_list[j].v->index;
+	if(p->change_list[j].flags&DREFOBJ)
+	  k+=vcount-rcount;
+	if(k==i&&(p->code==CALL||(p->z.flags&DREFOBJ)))
+	  return 0;
+      }
+      if(p==g->end) break;
+    }
+    if(g==end) break;
+  }
+  /*printf("assigned static %s to reg\n",vilist[i]->identifier);*/
+  return 1;
+}
+int exit_save(flowgraph *fg,int i)
+/*  Testet, ob die Variable in Register i am Ende von Block fg gespeichert  */
+/*  werden muss, d.h. der Vorgaenger eines Nachfolgers nicht dieselbe       */
+/*  Variable im selben Register hat.                                        */
+{
+    flowlist *lp;
+    /* Konstanten muessen nie gespeichert werden */
+    if(fg->regv[i]->index>=vcount-rcount) return 0;
+    if(!fg->normalout){
+      /* letzter Block, statische Variablen und drefobjs aktiv */
+      int sc=fg->regv[i]->storage_class;
+      return sc==STATIC||sc==EXTERN;
+    }
+    if((fg->normalout&&(!fg->end||fg->end->code!=BRA))&&BTST(fg->normalout->av_in,fg->regv[i]->index)){
+        if(fg->normalout->regv[i]!=fg->regv[i]) return 1;
+        lp=fg->normalout->in;
+        while(lp){
+            if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]) return 1;
+            lp=lp->next;
+        }
+    }
+    if(fg->branchout&&BTST(fg->branchout->av_in,fg->regv[i]->index)){
+        if(fg->branchout->regv[i]!=fg->regv[i]) return 1;
+        lp=fg->branchout->in;
+        while(lp){
+            if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]) return 1;
+            lp=lp->next;
+        }
+    }
+    return 0;
+}
+void load_reg_parms(flowgraph *fg)
+/*  Laedt Registerparameter, falls noetig.                              */
+{
+    int i,j; Var *v;
+    regp regp[MAXR+1]={0};
+/*     for(i=1;i<=MAXR;i++){ regp[i].treg=0;regp[i].tvar=0;} */
+    for(i=0;i<vcount-rcount;i++){
+        v=vilist[i];
+        if((v->flags&REGPARM)&&(fg->regv[abs(v->reg)]!=v||(v->flags&CONVPARAMETER))&&(BTST(fg->av_in,i)||(v->flags&USEDASADR))){
+	  regp[abs(v->reg)].tvar=v;
+	  for(j=1;j<=MAXR;j++)
+	    if(fg->regv[j]==v||lparms[j]==v) regp[abs(v->reg)].treg=j;
+	}
+    }
+    do_load_parms(regp,fg);
+}
+
+static int check_retreg(flowgraph *fg)
+{
+  IC *p;int retreg=0;
+  for(p=fg->start;p;p=p->next){
+    if(p->code==SETRETURN&&p->z.reg>=0){
+      retreg=p->z.reg;
+      break;
+    }
+  }
+  for(p=last_ic;retreg&&p;p=p->prev){
+    if(p->code==FREEREG){
+      if(p->q1.reg==retreg)
+	retreg=0;
+    }else
+      break;
+  }
+  if(DEBUG&1024) printf("check_retreg: %s\n",regnames[retreg]);
+  return retreg;
+}
+void insert_regs(flowgraph *fg1)
+/*  Fuegt Registervariablen in die ICs ein.                             */
+{
+  int i,exit_block;IC *p,*lic=0,*new;flowgraph *lfg=0,*fg;
+    if(DEBUG&9216) printf("inserting register variables\n");
+    fg=fg1;
+    while(fg){
+        if(DEBUG&8192) printf("block %d:\n",fg->index);
+	if(fg!=fg1&&!fg->branchout&&!fg->normalout&&fg->start==fg->end)
+	  exit_block=1;
+	else
+	  exit_block=0;
+        p=fg->start;
+        while(p){
+            for(i=1;i<=MAXR;i++){
+                if(!fg->regv[i]) continue;
+                if(p->code==ALLOCREG&&p->q1.reg==i) ierror(0);
+                if((p->q1.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->q1.v==fg->regv[i]&&(p->q1.v->index<vcount-rcount||cost_savings(p,i,&p->q1)>0)){
+		    if(p->q1.v->index>=vcount-rcount)
+		      p->q1.flags&=~(KONST|VAR|VARADR);
+		    p->q1.flags|=REG;
+                    p->q1.reg=i;
+                }
+                if((p->q2.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->q2.v==fg->regv[i]&&(p->q2.v->index<vcount-rcount||cost_savings(p,i,&p->q2)>0)){
+		    if(p->q2.v->index>=vcount-rcount)
+		      p->q2.flags&=~(KONST|VAR|VARADR);
+		    p->q2.flags|=REG;
+                    p->q2.reg=i;
+                }
+                if((p->z.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->z.v==fg->regv[i]&&(p->z.v->index<vcount-rcount||cost_savings(p,i,&p->z)>0)){
+		  if(p->z.v->index>=vcount-rcount)
+		    p->z.flags&=~(KONST|VAR|VARADR);
+		  p->z.flags|=REG;
+		  p->z.reg=i;
+                }
+            }
+	    /* evtl. const-Variablen ruecksubstituieren */
+	    if((p->q1.flags&VAR)&&p->q1.v->index>=vcount-rcount){
+	      insert_cobj(&p->q1,&p->q1.v->cobj);
+	    }
+	    if((p->q2.flags&VAR)&&p->q2.v->index>=vcount-rcount){
+	      insert_cobj(&p->q2,&p->q2.v->cobj);
+	    }
+	    if((p->z.flags&VAR)&&p->z.v->index>=vcount-rcount){
+	      insert_cobj(&p->z,&p->z.v->cobj);
+	    }
+            if(DEBUG&8192) pric2(stdout,p);
+            if(p==fg->end) break;
+            p=p->next;
+        }
+        if(fg->start&&fg->start->code==LABEL&&fg!=fg1) lic=fg->start;
+        for(i=1;i<=MAXR;i++){
+            if(fg->regv[i]){
+                if(DEBUG&8192){
+                    printf("(%s),%ld(%p) assigned to %s\n",fg->regv[i]->identifier,zm2l(fg->regv[i]->offset),(void *)fg->regv[i],regnames[i]);
+                    if(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)) printf("active at the start of block\n");
+                    if(fg->regv[i]->index<vcount-rcount&&BTST(fg->av_out,fg->regv[i]->index)) printf("active at the end of block\n");
+                }
+
+                if(fg->regv[i]->index<vcount-rcount&&BTST(fg->av_out,fg->regv[i]->index)){
+                /*  Variable beim Austritt aktiv?   */
+                    if(exit_save(fg,i)){
+		      IC *tp;int mark_retreg=0;
+                        if(DEBUG&8192) printf("\thave to save it at end of block\n");
+                        new=new_IC();
+                        new->line=0;
+                        new->file=0;
+                        new->code=ASSIGN;
+                        new->typf=fg->regv[i]->vtyp->flags;
+                        /* vla */
+                        if(ISARRAY(new->typf)) 
+                          new->typf=POINTER_TYPE(fg->regv[i]->vtyp->next);
+                        /*  cc  */
+                        if(new->typf==0) ierror(0);
+                        new->q1.flags=VAR|REG;
+                        new->q1.val.vmax=l2zm(0L);
+                        new->q1.v=fg->regv[i];
+                        new->q1.reg=i;
+                        new->q2.flags=0;
+                        new->q2.val.vmax=szof(fg->regv[i]->vtyp);
+                        new->z.flags=VAR|DONTREGISTERIZE;
+                        new->z.val.vmax=l2zm(0L);
+                        new->z.v=fg->regv[i];
+                        new->q1.am=new->q2.am=new->z.am=0;
+                        new->use_cnt=new->change_cnt=0;
+                        new->use_list=new->change_list=0;
+                        /*  Vor FREEREGs und evtl. Branch+COMPARE/TEST setzen   */
+                        if(fg->end){
+                            tp=fg->end;
+			    if(!tp->next){
+			      mark_retreg=check_retreg(fg1);
+			      if(DEBUG&1024) printf("save at end, markretreg=%s\n",regnames[mark_retreg]);
+			    }
+                            while(tp!=fg->start&&(tp->code==FREEREG||tp->code==SETRETURN||tp->code==NOP)){
+			      if(tp->code==SETRETURN) mark_retreg=0;
+			      tp=tp->prev;
+			    }
+                            if(tp&&tp->code>=BEQ&&tp->code<=BRA){
+                                if(tp->code<BRA){
+                                    int c;
+                                    do{
+                                        tp=tp->prev;
+                                        c=tp->code;
+                                        if(c!=FREEREG&&c!=COMPARE&&c!=TEST) ierror(0);
+                                    }while(c!=COMPARE&&c!=TEST);
+                                }
+                                tp=tp->prev;
+                            }
+                        }else tp=lic;
+                        insert_IC_fg(fg,tp,new);
+			if(mark_retreg){
+			  IC *nop;
+			  insert_allocreg(fg,tp,ALLOCREG,mark_retreg);
+			  insert_allocreg(fg,new,FREEREG,mark_retreg);
+			  nop=new_IC();
+			  nop->code=NOP;
+			  nop->q1.flags=REG;
+			  nop->q1.reg=mark_retreg;
+			  insert_IC_fg(fg,new,nop);
+			}
+                    }
+                }
+                if(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)){
+		  if(!exit_block&&(fg==fg1||entry_load(fg,i))&&(fg!=fg1||!(fg->regv[i]->flags&REGPARM))){
+                        if(DEBUG&8192) printf("\thave to load it at start of block\n");
+                        new=new_IC();
+                        new->line=0;
+                        new->file=0;
+                        new->code=ASSIGN;
+                        new->typf=fg->regv[i]->vtyp->flags;
+                        /* vla */
+                        if(ISARRAY(new->typf)) 
+                          new->typf=POINTER_TYPE(fg->regv[i]->vtyp->next);
+                        /*  cc  */
+                        if(new->typf==0) ierror(0);
+			if(fg->regv[i]->index>=vcount-rcount){
+			  insert_cobj(&new->q1,&fg->regv[i]->cobj);
+			}else{
+			  new->q1.flags=VAR|DONTREGISTERIZE;
+			  new->q1.val.vmax=l2zm(0L);
+			  new->q1.v=fg->regv[i];
+			}
+			new->q2.flags=0;
+                        new->q2.val.vmax=szof(fg->regv[i]->vtyp);
+			if(fg->regv[i]->index>=vcount-rcount)
+			  new->z.flags=REG;
+			else
+			  new->z.flags=VAR|REG;
+                        new->z.val.vmax=l2zm(0L);
+                        new->z.v=fg->regv[i];
+                        new->z.reg=i;
+                        new->q1.am=new->q2.am=new->z.am=0;
+                        new->use_cnt=new->change_cnt=0;
+                        new->use_list=new->change_list=0;
+                        insert_IC_fg(fg,lic,new);
+                    }
+                }
+                if(!lfg||!lfg->regv[i]) insert_allocreg(fg,lic,ALLOCREG,i);
+                if(!fg->normalout||!fg->normalout->regv[i])
+                    insert_allocreg(fg,fg->end?fg->end:lic,FREEREG,i);
+            }
+        }
+        if(fg->end) lic=fg->end;
+        lfg=fg;
+        fg=fg->normalout;
+    }
+    load_reg_parms(fg1);
+}
+
+void do_loop_regs(flowgraph *start,flowgraph *end,int intask)
+/*  Macht die Variablenzuweisung in Schleife start-end.                 */
+/*  Wenn end==0 Registerzuweisung fuer die ganze Funktion, ansonsten    */
+/*  fuer die Schleife, die zum Header start gehoert.                    */
+{
+  flowgraph *g,*lend;
+  int i,r,iterations;
+  Var *lregs[MAXR+1]={0};
+  unsigned char regu[MAXR+1]={0};
+  bvtype *isused=mymalloc(vsize);
+  /*  Berechnen, wieviel ungefaehr eingespart wird, wenn eine Variable    */
+  /*  fuer diese Schleife in einem best. Register gehalten wird.          */
+  /*  Die savings in einer Schleife werden multipliziert, um das          */
+  /*  Laden/Speichern ausserhalb der Schleife geringer zu wichten.        */
+  /*    if(end&&(!g->normalout||!g->normalout->loopend||g->normalout->loopend->normalout->index!=-2)) ierror(0);*/
+  /*  alle auf 0  */
+
+  for(i=0;i<vcount-rcount+const_vars;i++){
+    if(i<vcount-rcount&&(vilist[i]->vtyp->flags&VOLATILE)){
+      for(r=1;r<=MAXR;r++){
+	savings[i][r]=INT_MIN;
+      }
+    }else{
+      for(r=1;r<=MAXR;r++){
+	savings[i][r]=0;
+      }
+    }
+  }
+  if(end){
+    Var *v;
+    /* estimated number of iterations, avoid too big values */
+    if(optsize)
+      iterations=1;
+    else
+      iterations=4;
+    /*  Evtl. Kosten fuers Laden/Speichern beim Ein-/Austritt in die    */
+    /*  Schleife.                                                       */
+    end=start->normalout->loopend;
+    g=end->normalout;
+    if(DEBUG&9216) printf("assigning regs to blocks %d to %d\n",start->normalout->index,end->index);
+    /*  Werte modifizieren, falls Variable am Anfang/Ende der Schleife  */
+    /*  geladen/gespeichert werden muss.                                */
+    /*  FIXME: Evtl. noetige stores/loads in anderen Bloecken!          */
+    for(i=0;i<vcount-rcount+const_vars;i++){
+      v=vilist[i];
+      if(i>=vcount-rcount||BTST(start->av_in,i)){
+ 	for(r=1;r<=MAXR;r++)
+	  if(start->regv[r]!=v&&savings[i][r]!=INT_MIN)
+	    savings[i][r]-=cost_load_reg(r,v);
+      }
+      if(i<vcount-rcount&&BTST(g->av_out,i)){
+	for(r=1;r<=MAXR;r++)
+	  if(g->regv[r]!=v&&savings[i][r]!=INT_MIN)
+	    savings[i][r]-=cost_save_reg(r,v);
+      }
+    }
+    /*  Werte modifizieren, falls eine andere Variable gespeichert oder */
+    /*  geladen werden muss. Hmm..stimmt das so?                        */
+    for(r=1;r<=MAXR;r++){
+      v=start->regv[r];
+      if(v&&v->index<vcount-rcount&&BTST(start->av_in,v->index)){
+	for(i=0;i<vcount-rcount;i++)
+	  if(v->index!=i&&savings[i][r]!=INT_MIN)
+	    savings[i][r]-=cost_load_reg(r,vilist[i]);
+      }
+      if(v&&v->index<vcount-rcount&&BTST(g->av_out,v->index)){
+	for(i=0;i<vcount-rcount;i++)
+	  if(v->index!=i&&savings[i][r]!=INT_MIN)
+	    savings[i][r]-=cost_save_reg(r,vilist[i]);
+      }
+    }
+    g=start->normalout;
+  }else{
+    iterations=1;
+    /*  Bei Registervergabe fuer die ganze Funktion muessen alle beim   */
+    /*  Eintritt der Funktion aktiven Variablen geladen werden.         */
+    /* statics have to be saved at the end */
+    if(DEBUG&9216) printf("assigning regs to whole function\n");
+    for(i=0;i<vcount-rcount+const_vars;i++){
+      if(i<vcount-rcount&&(vilist[i]->storage_class==STATIC||vilist[i]->storage_class==EXTERN)){
+	for(r=1;r<=MAXR;r++)
+	  if(savings[i][r]!=INT_MIN)
+	    savings[i][r]-=cost_save_reg(r,vilist[i]);
+      }
+      if(i>=vcount-rcount||BTST(start->av_in,i)){
+	int pr=abs(vilist[i]->reg);
+	for(r=1;r<=MAXR;r++){
+	  if(savings[i][r]!=INT_MIN){
+	    if(pr==0){
+	      savings[i][r]-=cost_load_reg(r,vilist[i]);
+	    }else if(!regsa[r]){
+	      if(r==pr)
+		savings[i][r]+=cost_save_reg(r,vilist[i]);
+	      else
+		/* factor of 2, because load_parms is not always optimal */
+		savings[i][r]+=(cost_save_reg(r,vilist[i])-cost_move_reg(pr,r))/2;
+	    }
+	  }
+	}
+      }
+    }
+    /*  Nonscratchregister muessen geladen/gesichert werden. */
+    /*FIXME: einige unschoene Effekte(?) */
+    if(!intask){
+      for(r=1;r<=MAXR;r++){
+	if(!regscratch[r]&&!regsa[r]){
+	  for(i=0;i<vcount-rcount+const_vars;i++)
+	    if(savings[i][r]!=INT_MIN)
+	      savings[i][r]-=cost_pushpop_reg(r);
+	}
+      }
+    }
+    g=start;
+  }
+  if(DEBUG&9216) printf("calculating approximate savings\n");
+
+  lend=0;
+  for(;g;g=g->normalout){
+    IC *p;Var *v;
+    int t,vt;
+    if(!end&&!lend){
+      lend=g->loopend;
+      if(lend&&iterations==1&&!optsize) iterations=4;
+    }
+
+    /*  Wenn das Register in dem Block benutzt wird, muss man es retten */
+    for(r=1;r<=MAXR;r++){
+      if(BTST(g->regused,r)||(reg_pair(r,&rp)&&(BTST(g->regused,rp.r1)||BTST(g->regused,rp.r2)))){
+	int vi;
+	if(g->regv[r]) vi=g->regv[r]->index; else vi=-1;
+	for(i=0;i<vcount-rcount+const_vars;i++){
+	  if(i>=vcount-rcount||BTST(g->av_out,i)||BTST(g->av_gen,i))
+	    if(vi!=i&&savings[i][r]!=INT_MIN)
+	      savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i]));
+	}
+      }
+    }
+    memcpy(isused,g->av_out,vsize);
+    p=g->end;
+    while(p){
+      if((p->q1.flags&(VAR|VARADR|REG))==VAR){
+	v=p->q1.v;vt=v->vtyp->flags;
+        /* vla */
+        if(ISARRAY(vt)&&is_vlength(v->vtyp))
+          vt=POINTER_TYPE(v->vtyp->next);
+	if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){
+	  i=v->index;
+	  if(p->code==ADDRESS||((p->code==ASSIGN||p->code==PUSH)&&(q1typ(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))){
+	    for(r=1;r<=MAXR;r++)
+	      savings[i][r]=INT_MIN;
+	  }else{
+	    for(r=1;r<=MAXR;r++){
+	      if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&&regok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+		int s=cost_savings(p,r,&p->q1);
+		if(s==INT_MIN||savings[i][r]==INT_MIN)
+		  savings[i][r]=INT_MIN;
+		else
+		  savings[i][r]+=iterations*s;
+	      }
+	    }
+	  }
+	}
+      }
+      if((p->q2.flags&(VAR|VARADR|REG))==VAR){
+	v=p->q2.v;vt=v->vtyp->flags;
+        /* vla */
+        if(ISARRAY(vt)&&is_vlength(v->vtyp))
+          vt=POINTER_TYPE(v->vtyp->next);
+	if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){
+	  i=v->index;
+	  for(r=1;r<=MAXR;r++){
+	    if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&&regok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+	      int s=cost_savings(p,r,&p->q2);
+	      if(s==INT_MIN||savings[i][r]==INT_MIN)
+		savings[i][r]=INT_MIN;
+	      else
+		savings[i][r]+=iterations*s;
+	    }
+	  }
+	}
+      }
+      if((p->z.flags&(VAR|VARADR|REG))==VAR){
+	v=p->z.v;vt=v->vtyp->flags;
+        if(ISARRAY(vt)&&is_vlength(v->vtyp))
+          vt=POINTER_TYPE(v->vtyp->next);
+	if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){
+	  i=v->index;
+	  if(p->code==ASSIGN&&(ztyp(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L))){
+	    for(r=1;r<=MAXR;r++)
+	      savings[i][r]=INT_MIN;
+	  }
+	  for(r=1;r<=MAXR;r++){
+	    if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&&regok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+	      int s=cost_savings(p,r,&p->z);
+	      if(s==INT_MIN||savings[i][r]==INT_MIN)
+		savings[i][r]=INT_MIN;
+	      else
+		savings[i][r]+=iterations*s;
+	    }
+	  }
+	}
+      }
+      /* bei Funktionsaufruf zerstoert... */
+      if(p->code==CALL){
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){
+	  for(i=0;i<vcount-rcount+const_vars;i++){
+	    if(i>=vcount-rcount||BTST(isused,i)){
+	      for(r=1;r<=MAXR;r++){
+		if(regscratch[r]&&savings[i][r]!=INT_MIN&&BTST(p->q1.v->fi->regs_modified,r))
+		  savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i]));
+	      }
+	    }	  
+	  }
+	}else{
+	  for(i=0;i<vcount-rcount+const_vars;i++){
+	    if(i>=vcount-rcount||BTST(isused,i)){
+	      for(r=1;r<=MAXR;r++){
+		if(regscratch[r]&&savings[i][r]!=INT_MIN)
+		  savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i]));
+	      }
+	    }
+	  }
+	}
+      }
+      if(p==g->start) break;
+      if(p->change_cnt!=0||p->use_cnt!=0)
+	av_update(p,isused);
+      p=p->prev;
+    }
+    if(g==end) break;
+    if(!end){
+      if(g==lend) {lend=0;iterations=1;}
+    }
+  }
+  /*  Maximum ermitteln   */
+  memset(bregs,0,sizeof(bregs));
+  for(i=0;i<vcount-rcount+const_vars;i++){
+    int m=0,t;Var *v;
+    v=vilist[i];t=v->vtyp->flags;
+    if(ISARRAY(t)&&is_vlength(v->vtyp))
+      t=POINTER_TYPE(v->vtyp->next);
+    if(!(optflags&1024)&&((v->storage_class!=AUTO&&v->storage_class!=REGISTER)||(v->flags&USEDASADR))){
+      for(r=0;r<=MAXR;r++)
+	savings[i][r]=INT_MIN;
+    }else{
+      int one=0;
+      for(r=1;r<=MAXR;r++){
+	/*  Variables should have been put to argument registers by local_regs()  */
+	/*if(r==abs(v->reg)&&!(v->flags&REGPARM)) savings[i][r]=INT_MAX;*/
+	if(regsa[r]||!regok(r,t,-1)) savings[i][r]=INT_MIN;
+	if(savings[i][r]>m){
+	  m=savings[i][r];
+	  one=r;
+	}else if(savings[i][r]==m){
+	  one=0;
+	}
+      }
+      savings[i][0]=m;
+      if(one) BSET(bregs,one); /* mark one register has unique value */
+    }
+  }
+  if(DEBUG&8192){
+    for(i=0;i<vcount-rcount+const_vars;i++){
+      printf("(%s),%ld(best=%d):\n",vilist[i]->identifier,zm2l(vilist[i]->offset),savings[i][0]);
+      for(r=1;r<=MAXR;r++)
+	printf("%s=%d ",regnames[r],savings[i][r]);
+      printf("\n");
+    }
+    for(r=0;r<=MAXR;r++)
+      if(BTST(bregs,r))
+	printf("reg %s unique\n",regnames[r]);
+  }
+  /*  Suchen, welche Variablen/Registerkombination das beste Ergebnis */
+  /*  liefert. Nur angenaehert, da sonst wohl zu aufwendig. Simplex?  */
+  for(i=0;i<vcount-rcount+const_vars;i++) rvlist[i]=i;
+  vqsort(rvlist,vcount-rcount+const_vars,sizeof(*rvlist),cmp_savings);
+  for(i=0;i<vcount-rcount+const_vars;i++){
+    int use=0,m=0,prio=0,vi;
+    vi=rvlist[i];
+    /*if(vilist[vi]->flags&USEDASADR) continue;*/
+    if(DEBUG&8192) printf("%d: (%s),%ld(best=%d)\n",i,vilist[vi]->identifier,zm2l(vilist[vi]->offset),savings[vi][0]);
+    for(r=1;r<=MAXR;r++){
+      if(!lregs[r]&&!regu[r]&&savings[vi][r]>=m&&(!reg_pair(r,&rp)||(!regu[rp.r1]&&!regu[rp.r2]))){
+	int better=0;
+	if(savings[vi][r]>m){
+	  better=1;
+	}else if(savings[vi][r]==m){
+	  if(reg_prio[r]>prio){
+	    better=1;
+	  }else if(BTST(bregs,use)&&!BTST(bregs,r)){
+	    better=1;
+	  }
+	}
+	if(better){
+	  m=savings[vi][r];prio=reg_prio[r];
+	  use=r;
+	}
+      }
+    }
+    if(m>0&&check_cacheable(vi,start,end)){
+      if(DEBUG&9216) printf("assigned (%s),%ld(%p) to %s, saving=%d\n",vilist[vi]->identifier,zm2l(vilist[vi]->offset),(void *)vilist[vi],regnames[use],m);
+      lregs[use]=vilist[vi];
+      regu[use]=1;
+      if(reg_pair(use,&rp))
+	regu[rp.r1]=regu[rp.r2]=1;
+    }
+  }
+  /*  Registervariablen in alle Bloecke der Schleife eintragen    */
+  /*  dabei beruecksichtigen, dass sie in manchen Bloecken nicht  */
+  /*  in Register kommen koennen, wenn das Register da schon von  */
+  /*  local_regs benutzt wird                                     */
+  /*  Gegebenenfalls auch in Header/Footer einer Schleife         */
+  /*  eintragen.                                                  */
+  if(DEBUG&9216) printf("propagate register vars\n");
+  for(g=start;g;g=g->normalout){
+    for(r=1;r<=MAXR;r++){
+      if(lregs[r]&&!BTST(g->regused,r)&&(!reg_pair(r,&rp)||(!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+	/*  Falls Variable schon in anderem Register, loeschen  */
+	for(i=1;i<=MAXR;i++){
+	  if(g->regv[i]==lregs[r]) g->regv[i]=0;
+	  if(reg_pair(i,&rp)){
+	    if(rp.r1==r||rp.r2==r) g->regv[i]=0;
+	  }
+	}
+	g->regv[r]=lregs[r];
+	if(reg_pair(r,&rp)) g->regv[rp.r1]=g->regv[rp.r2]=0;
+      }
+    }
+    if(end&&g==end->normalout) break;
+  }
+}
+void block_regs(flowgraph *fg)
+/*  macht die Variablenzuweisung fuer einzelne Bloecke  */
+{
+    flowgraph *g,**fgp;
+    int i,r,changed,fgz;
+    if(DEBUG&9216) printf("block_regs\n");
+
+    savings=mymalloc((vcount-rcount)*sizeof(*savings));
+    rvlist=mymalloc((vcount-rcount)*sizeof(*rvlist));
+
+    /*  Array auf Bloecke im Flussgraphen mangels doppelter Verkettung  */
+    fgp=mymalloc(basic_blocks*sizeof(*fgp));
+    g=fg;fgz=0;
+    while(g){
+        fgp[fgz]=g;fgz++;
+        g=g->normalout;
+    }
+    if(fgz>basic_blocks) ierror(0); else basic_blocks=fgz;
+    /*  alle auf 0  */
+    do{
+        changed=0;
+        if(DEBUG&9216) printf("block_regs pass\n");
+        for(fgz=basic_blocks-1;fgz>=0;fgz--){
+            IC *p;Var *v;flowlist *lp;
+            int t,vt;
+            g=fgp[fgz];
+            if(DEBUG&8192) printf("assigning regs to block %d\n",g->index);
+            /*  berechnen, wieviel ungefaehr eingespart wird, wenn eine Variable    */
+            /*  fuer diesen Block in einem best. Register gehalten wird             */
+            if(DEBUG&8192) printf("calculating approximate savings\n");
+
+            for(i=0;i<vcount-rcount;i++){
+                for(r=1;r<=MAXR;r++){
+                    if(!g->regv[r]||g->regv[r]->index!=i){
+                        int w=0;
+                        /*  Variable muss evtl. geladen/gespeichert werden  */
+                        if(BTST(g->av_in,i)) w--;
+                        if(BTST(g->av_out,i)) w--;
+                        savings[i][r]=w;
+                    }
+                }
+            }
+            if(g->calls>0){
+            /*  bei Funktionsaufrufen muessen Scratchregister gespeichert werden */
+                for(r=1;r<=MAXR;r++)
+                    if(regscratch[r])
+                        for(i=0;i<vcount-rcount;i++) savings[i][r]-=g->calls*2;
+            }
+            /*  Wenn Vorgaenger/Nachfolger selbe Variable im selben */
+            /*  Register hat, entfaellt Laden/Speichern in diesem   */
+            /*  Block und vermutlich auch im Vorgaenger/Nachfolger  */
+            /*  nicht immer, aber naeherungsweise...                */
+            lp=g->in;
+            while(lp){
+                if(lp->graph){
+                    for(r=1;r<=MAXR;r++){
+                        if(lp->graph->regv[r]&&BTST(g->av_in,lp->graph->regv[r]->index)) savings[lp->graph->regv[r]->index][r]+=2;
+                    }
+                }
+                lp=lp->next;
+            }
+            if(g->branchout){
+                for(r=1;r<=MAXR;r++){
+                    if(g->branchout->regv[r]&&BTST(g->av_out,g->branchout->regv[r]->index)) savings[g->branchout->regv[r]->index][r]+=2;
+                }
+            }
+            if(g->normalout&&(!g->normalout->end||g->normalout->end->code!=BRA)){
+                for(r=1;r<=MAXR;r++){
+                    if(g->normalout->regv[r]&&BTST(g->av_out,g->normalout->regv[r]->index)) savings[g->normalout->regv[r]->index][r]+=2;
+                }
+            }
+
+            p=g->start;
+            while(p){
+                if((p->q1.flags&(VAR|VARADR|REG))==VAR){
+                    v=p->q1.v;
+                    if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){
+                        vt=v->vtyp->flags&NU;
+                        i=v->index;
+                        if(p->q1.flags&DREFOBJ) t=p->typf&NU; else t=0;
+                        for(r=1;r<=MAXR;r++){
+                            if(!regsa[r]&&!BTST(g->regused,r)){
+                                /*  extra saving, falls passendes Reg fuer DREF */
+                                if(t&&regok(r,vt,t)) savings[i][r]++;
+                                if(regok(r,vt,0)) savings[i][r]++;
+                            }
+                        }
+                    }
+                }
+                if((p->q2.flags&(VAR|VARADR|REG))==VAR){
+                    v=p->q2.v;
+                    if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){
+                        vt=v->vtyp->flags&NU;
+                        i=v->index;
+                        if(p->q2.flags&DREFOBJ) t=p->typf&NU; else t=0;
+                        for(r=1;r<=MAXR;r++){
+                            if(!regsa[r]&&!BTST(g->regused,r)){
+                                /*  extra saving, falls passendes Reg fuer DREF */
+                                if(t&&regok(r,vt,t)) savings[i][r]++;
+                                if(regok(r,vt,0)) savings[i][r]++;
+                            }
+                        }
+                    }
+                }
+                if((p->z.flags&(VAR|VARADR|REG))==VAR){
+                    v=p->z.v;
+                    if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){
+                        vt=v->vtyp->flags&NU;
+                        i=v->index;
+                        if(p->z.flags&DREFOBJ) t=p->typf&NU; else t=0;
+                        for(r=1;r<=MAXR;r++){
+                            if(!regsa[r]&&!BTST(g->regused,r)){
+                                /*  extra saving, falls passendes Reg fuer DREF */
+                                if(t&&regok(r,vt,t)) savings[i][r]++;
+                                if(regok(r,vt,0)) savings[i][r]++;
+                            }
+                        }
+                    }
+                }
+                if(p==g->end) break;
+                p=p->next;
+            }
+            /*  moegliche Kandidaten suchen; muss nicht immer die beste */
+            /*  Kombination finden, sollte aber bei lokaler Vergabe     */
+            /*  selten einen Unterschied machen                         */
+            for(r=1;r<=MAXR;r++){
+                if(g->regv[r]||BTST(g->regused,r)) continue;
+                for(i=0;i<vcount-rcount;i++){
+                    if(savings[i][r]>0){
+                        int flag;Var *v=vilist[i];
+                        /*  Variable schon in anderem Register? */
+                        for(flag=1;flag<=MAXR;flag++)
+                            if(g->regv[flag]==v){flag=-1;break;}
+                        if(flag>0){
+                            if(DEBUG&9216) printf("assigned (%s),%ld(%p) to %s; saving=%d\n",vilist[i]->identifier,zm2l(vilist[i]->offset),(void *)vilist[i],regnames[r],savings[i][r]);
+			    if(vilist[i]&&!vilist[i]->vtyp->flags) ierror(0);
+                            g->regv[r]=vilist[i];
+                            changed=1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }while(changed);
+    /*  jetzt nochmal globale Register vergeben */
+/*    do_loop_regs(fgp[0],fgp[basic_blocks-1]);*/
+
+    free(fgp);
+    free(rvlist);
+    free(savings);
+}
+
+void loop_regs(flowgraph *fg,int intask)
+/*  weist Variablen in Schleifen Register zu    */
+{
+    flowgraph *g;
+    if(disable&4096) return;
+    if(DEBUG&9216) printf("assigning regs to function\n");
+    savings=mymalloc((vcount-rcount+const_vars)*sizeof(*savings));
+    rvlist=mymalloc((vcount-rcount+const_vars)*sizeof(*rvlist));
+    do_loop_regs(fg,0,intask);
+    if(DEBUG&9216) printf("assigning regs in loops\n");
+    for(g=fg;g;g=g->normalout){
+        if(g->index==-1&&!(disable&32768)) do_loop_regs(g,g,0);
+    }
+    free(rvlist);
+    free(savings);
+}
+void insert_allocreg(flowgraph *fg,IC *p,int code,int reg)
+/*  Fuegt ein ALLOCREG/FREEREG (in code) hinter p ein - bei p==0 in */
+/*  first_ic.                                                       */
+{
+    IC *new=new_IC();
+    /*    printf("%s %s",code==FREEREG?"freereg":"allocreg",regnames[reg]);pric2(stdout,p);*/
+    new->line=0;
+    new->file=0;
+    BSET(fg->regused,reg);
+    if(reg_pair(reg,&rp)){
+	BSET(fg->regused,rp.r1);
+	BSET(fg->regused,rp.r2);
+	regused[rp.r1]=regused[rp.r2]=1;
+    }
+    regused[reg]=1;
+    new->code=code;
+    new->typf=0;
+    new->q1.am=new->q2.am=new->z.am=0;
+    new->q1.flags=REG;
+    new->q1.reg=reg;
+    new->q2.flags=new->z.flags=0;
+    new->use_cnt=new->change_cnt=0;
+    new->use_list=new->change_list=0;
+    insert_IC_fg(fg,p,new);
+}
+
+Var *lregv[MAXR+1],*first_const,*last_const;
+flowgraph *lfg;
+static int is_header;
+
+/* re-inserts a cobj into an obj */
+static void insert_cobj(obj *o,obj *co)
+{
+  int dt=o->dtyp,df=o->flags&DREFOBJ;
+  *o=*co;
+  o->flags|=df;
+  o->dtyp=dt;
+}
+
+static Var *find_const_var(obj *o,int t)
+{
+  Var *v;
+  for(v=first_const;v;v=v->next){
+    if((v->ctyp&NQ)==(t&NQ)&&!compare_objs(o,&v->cobj,t))
+      return v;
+  }
+  return 0;
+}
+
+static long cidx;
+
+static Var *add_const_var(obj *o,int t)
+{
+  Var *v;
+  static type vt={VOID},tt;
+  int m=o->flags;
+  if(o->flags&DREFOBJ){
+    t=o->dtyp;
+    o->flags&=~DREFOBJ;
+  }
+  if(v=find_const_var(o,t)){
+    o->flags=m;
+    return v;
+  }
+  v=mymalloc(sizeof(*v));
+  v->storage_class=AUTO;
+  v->cobj=*o;
+  v->ctyp=t;
+  tt.flags=t;
+  if(ISPOINTER(t)) tt.next=&vt;
+  v->vtyp=clone_typ(&tt);
+  v->next=0;
+  v->identifier=" constant";
+  v->flags=0;
+  v->reg=0;
+#ifdef HAVE_TARGET_ATTRIBUTES
+  v->tattr=0;
+#endif
+  cidx++;
+  v->offset=l2zm(cidx);
+  if(last_const){
+      last_const->next=v;
+  }else{
+      first_const=v;
+      const_vars=0;
+  }
+  last_const=v;
+  v->index=vcount-rcount+const_vars;
+  const_vars++;
+  /* Wir ueberschreiben die Eintraege von vcount-rcount bis vcount. */
+  /* Da sie nicht mehr benutzt werden, sollte das ok sein.          */
+  vilist=myrealloc(vilist,sizeof(*vilist)*(vcount-rcount+const_vars));
+  vilist[vcount-rcount+const_vars-1]=v;
+  o->flags=m;
+  return v;
+}
+
+void create_const_vars(flowgraph *fg)
+{
+  IC *p;int t;
+  Var *v;
+  if(DEBUG&1024) printf("creating const-vars\n");
+  cidx=0;
+  const_vars=0;
+  first_const=last_const=0;
+  for(;fg;fg=fg->normalout){
+    for(p=fg->start;p;p=p->next){
+      if(p->q1.flags&(KONST|VARADR)){
+	t=q1typ(p);
+	v=add_const_var(&p->q1,t);
+	p->q1.flags&=~(KONST|VARADR);
+	p->q1.flags|=(VAR|VKONST);
+	p->q1.v=v;
+	p->q1.val.vmax=l2zm(0L);
+      }
+      if(p->q2.flags&(KONST|VARADR)){
+	t=q2typ(p);
+	v=add_const_var(&p->q2,t);
+	p->q2.flags&=~(KONST|VARADR);
+	p->q2.flags|=(VAR|VKONST);
+	p->q2.v=v;
+	p->q2.val.vmax=l2zm(0L);
+      }
+      if(p->z.flags&(KONST|VARADR)){
+	t=ztyp(p);
+	v=add_const_var(&p->z,t);
+	p->z.flags&=~(KONST|VARADR);
+	p->z.flags|=(VAR|VKONST);
+	p->z.v=v;
+	p->z.val.vmax=l2zm(0L);
+      }
+      if(p==fg->end) break;
+    }
+  }
+  if(DEBUG&1024){
+    Var *v;
+    printf("const-vars:\n");
+    for(v=first_const;v;v=v->next){
+      printf("%d: ",v->index);
+      probj(stdout,&v->cobj,v->ctyp);
+      printf(" (t=%d)\n",v->ctyp);
+    }
+  }
+}
+
+void free_const_vars(void)
+{
+  Var *v,*m;
+  if(DEBUG&1024) printf("free_const_vars()\n");
+  for(v=first_const;v;){
+    m=v->next;
+    free(v);
+    v=m;
+  }
+}
+
+#if 0
+int free_hreg(flowgraph *fg,IC *p,int reg,int mustr)
+/*  Macht das Register reg frei, damit es als lokale Variable im IC p   */
+/*  zur Verfuegung steht. Wenn mustr!=0, muss das Register unbedingt    */
+/*  freigemacht werden, ansonsten kann davon abgesehen werden.          */
+{
+    IC *m,*first;Var *v;
+    int preg[MAXR+1]={0},calls[MAXR+1]={0},rreg,i;
+    first=0;
+    v=lregv[reg];
+    if(!v)
+      ierror(0);
+    if(DEBUG&8192) printf("free_hreg %s,%s,%d\n",regnames[reg],v->identifier,mustr);
+    if(v->reg&&!*v->identifier) ierror(0);
+    for(m=p;m;m=m->next){
+      if(m->code==CALL){
+	if((m->q1.flags&(VAR|DREFOBJ))==VAR&&m->q1.v->fi&&(m->q1.v->fi->flags&ALL_REGS)){
+	  for(i=1;i<=MAXR;i++)
+	    if(BTST(m->q1.v->fi->regs_modified,i)) calls[i]++;
+	}else{
+	  for(i=1;i<=MAXR;i++)
+	    if(regscratch[i]) calls[i]++;
+	}
+      }
+      if(m->code==ALLOCREG){
+	preg[m->q1.reg]=1;
+	if(m->q1.reg==reg) ierror(0);
+      }
+      if(m->code==FREEREG){
+	preg[m->q1.reg]=1;
+	if(m->q1.reg==reg) break;
+      }
+      if(!USEQ2ASZ){
+	if((m->q2.flags&VAR)&&m->q2.v==v&&(m->z.flags&(REG|DREFOBJ))==REG&&
+	   (!(m->z.flags&VAR)||m->z.v!=v))
+	  preg[m->z.reg]=1;
+      }
+      if(((m->q1.flags&VAR)&&m->q1.v==v)||
+	 ((m->q2.flags&VAR)&&m->q2.v==v)||
+	 ((m->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&m->z.v==v))
+	first=m;
+      /*        if((m->z.flags&(REG|DREFOBJ))==REG&&m->z.reg==reg) break;*/
+    }
+    if(!first) {pric(stdout,p);ierror(0);}
+    rp.r1=rp.r2=0;
+    for(rreg=0,i=1;i<=MAXR;i++){
+        if(preg[i]||regu[i]||regsa[i]||!regok(i,v->vtyp->flags,0)) continue;
+	if(reg_pair(i,&rp)&&(preg[rp.r1]||preg[rp.r2]||regu[rp.r1]||regu[rp.r2]||regsa[rp.r1]||regsa[rp.r2])) continue;
+        if(calls[i]==0&&regscratch[i]){rreg=i;break;}
+	if(calls[i]==0) rreg=i;
+    }
+    if(!rreg&&!mustr) return 0;
+    for(m=p;m!=first->next;m=m->next){
+        if((m->q1.flags&VAR)&&m->q1.v==v)
+            {if(!rreg) m->q1.flags&=~REG; else m->q1.reg=rreg;}
+        if((m->q2.flags&VAR)&&m->q2.v==v)
+            {if(!rreg) m->q2.flags&=~REG; else m->q2.reg=rreg;}
+	if((m->z.flags&VAR)&&m->z.v==v)
+	  {if(!rreg) m->z.flags&=~REG; else m->z.reg=rreg;} 
+#if 0
+	if((m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==v)
+	  break;
+#endif
+    }
+    if(rreg){
+	lregv[rreg]=lregv[reg];
+	regused[rreg]=1;regu[rreg]=1;BSET(fg->regused,rreg);
+	if(reg_pair(rreg,&rp)){
+	    regused[rp.r1]=1;regu[rp.r1]=1;BSET(fg->regused,rp.r1);
+	    regused[rp.r2]=1;regu[rp.r2]=1;BSET(fg->regused,rp.r2);
+	}
+    }
+    lregv[reg]=0;regu[reg]=0;
+    if(reg_pair(reg,&rp))
+	regu[rp.r1]=regu[rp.r2]=0;
+
+    for(m=first->next;m&&m->code==FREEREG;m=m->next){
+        if(m->q1.reg==reg){
+            if(!rreg) remove_IC_fg(fg,m); else m->q1.reg=rreg;
+/*            if(rreg) insert_allocreg(fg,first,FREEREG,rreg);*/
+            return rreg;
+        }
+    }
+    insert_allocreg(fg,first->prev,ALLOCREG,reg);
+    if(rreg)
+      insert_allocreg(fg,first,FREEREG,rreg);
+    return rreg;
+}
+#endif
+int replace_local_reg(obj *o)
+/*  tested, ob o eine Scratch-Variable ist und ersetzt sie gegebenenfalls   */
+{
+    int i;Var *v;
+    if((o->flags&(VAR|REG|VARADR))==VAR){
+        v=o->v;i=v->index;
+        if((BTST(lfg->av_kill,i)||is_header)&&!BTST(lfg->av_out,i)){
+            for(i=1;i<=MAXR;i++){
+                if(lregv[i]==v){
+                    o->flags|=(REG|SCRATCH);
+/*                    o->flags&=~VAR;*/
+                    o->reg=i;
+                    return i;
+                }
+            }
+        }
+    }
+    return 0;
+}
+void local_combine(flowgraph *fg)
+/*  Versucht, Zuweisungen der Form (x)->tmp in ein direkt folgendes IC */
+/*  einzugliedern. Nur einfache Tests, da nur loads eliminiert werden  */
+/*  sollen, die zum leichten Erkennen per cse explizit wurden.         */
+{
+  IC *p,*pprev;int i,cl;
+  bvtype *used=mymalloc(vsize);
+  if(DEBUG&1024) printf("local combining\n");
+  for(;fg;fg=fg->normalout){
+    memcpy(used,fg->av_out,vsize);
+    for(p=fg->end;p;){
+      if(p->code==NOP||(!p->q1.flags&&!p->q2.flags)){
+	if(p==fg->start) break;
+	if(p->z.flags&VAR) BSET(used,p->z.v->index);
+	p=p->prev;
+	continue;
+      }
+      pprev=p->prev;
+      while(pprev&&pprev->code==NOP) pprev=pprev->prev;
+      if(pprev&&p->code==ASSIGN&&zmeqto(p->q2.val.vmax,sizetab[p->typf&NQ])&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&pprev->z.flags==p->q1.flags&&p->q1.v==pprev->z.v&&(!(p->z.flags&VAR)||p->z.v!=p->q1.v)&&ztyp(pprev)==q1typ(p)&&!BTST(used,p->q1.v->index)&&(pprev->code!=ASSIGN||zmeqto(pprev->q2.val.vmax,sizetab[pprev->typf&NQ]))){
+	/* x op y ->tmp; move tmp->*p => x op y ->*p */
+	if(DEBUG&1024){
+	  printf("local combine(3):\n");
+	  pric2(stdout,pprev);pric2(stdout,p);
+	}
+	pprev->z=p->z;
+	pprev->change_cnt=p->change_cnt;
+	pprev->change_list=p->change_list;
+	p->change_cnt=0;
+	p->change_list=0;
+	pprev->use_list=myrealloc(pprev->use_list,(pprev->use_cnt+p->use_cnt)*VLS);
+	memcpy(&pprev->use_list[pprev->use_cnt],p->use_list,p->use_cnt*VLS);
+	pprev->use_cnt+=p->use_cnt;
+	p->q1.flags=p->z.flags=0;
+	p->code=NOP;
+	/* restart */
+	memcpy(used,fg->av_out,vsize);
+	p=fg->end;
+	continue;
+      }
+      if((pprev)&&pprev->code==ASSIGN&&zmeqto(pprev->q2.val.vmax,sizetab[pprev->typf&NQ])
+	 &&zmeqto(pprev->q2.val.vmax,sizetab[p->typf&NQ])
+	 &&((pprev->q1.flags&DREFOBJ)||(static_cse&&(pprev->q1.flags&(VAR|VARADR))==VAR&&(pprev->q1.v->storage_class==EXTERN||pprev->q1.v->storage_class==STATIC)))&&(pprev->z.flags&(VAR|DREFOBJ))==VAR
+	 &&!BTST(used,pprev->z.v->index)&&pprev->z.v->storage_class==AUTO
+	 &&!(pprev->z.v->flags&USEDASADR)
+	 &&((p->code!=ASSIGN&&p->code!=PUSH)||zmeqto(p->q2.val.vmax,sizetab[p->typf&NQ]))){
+	cl=0;
+	i=pprev->z.v->index;
+	if((p->z.flags&VAR)&&p->z.v->index==i) cl=4;
+	if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+	  if(p->q1.v->index==i&&zmeqto(p->q1.val.vmax,pprev->z.val.vmax))
+	    cl|=1;
+	}
+	if((p->q2.flags&(VAR|DREFOBJ))==VAR){
+	  if(p->q2.v->index==i&&zmeqto(p->q2.val.vmax,pprev->z.val.vmax))
+	    cl|=2;
+	}
+	if(cl==1||cl==2){
+	  if(cl!=2||USEQ2ASZ||compare_objs(&pprev->q1,&p->z,p->typf)){
+	    if(DEBUG&1024){printf("local combine:\n");pric2(stdout,pprev);pric2(stdout,p);}
+	    if(cl==1)
+	      p->q1=pprev->q1;
+	    else
+	      p->q2=pprev->q1;
+	    p->use_list=myrealloc(p->use_list,(p->use_cnt+pprev->use_cnt)*VLS);
+	    memcpy(&p->use_list[p->use_cnt],pprev->use_list,pprev->use_cnt*VLS);
+	    p->use_cnt+=pprev->use_cnt;
+	    pprev->code=NOP;
+	    pprev->q1.flags=pprev->z.flags=0;
+	    pprev->typf=0;
+	    /* restart */
+	    memcpy(used,fg->av_out,vsize);
+	    p=fg->end;
+	    continue;
+	  }
+	}
+      }
+      if(p==fg->start) break;
+      if(p->q1.flags&VAR) BSET(used,p->q1.v->index);
+      if(p->q2.flags&VAR) BSET(used,p->q2.v->index);
+      if(p->z.flags&VAR) BSET(used,p->z.v->index);
+      p=p->prev;
+    }
+  }
+  free(used);
+}
+
+/* Fuegt evtl. noetige allocreg/freereg nach local_regs in Block ein. */
+/* Kann durch free_hreg noetig werden. */
+void fix_local_allocreg(flowgraph *fg)
+{
+  char regs[MAXR+1]={0};
+  IC *p=fg->end;
+  while(p){
+    if(p->code==ALLOCREG){
+      if(!regs[p->q1.reg]) ierror(0);
+      regs[p->q1.reg]=0;
+    }else if(p->code==FREEREG){
+      if(regs[p->q1.reg]){
+	ierror(0);
+      }
+      regs[p->q1.reg]=1;
+    }else{
+      if((p->q1.flags&REG)&&!regs[p->q1.reg]){
+	insert_allocreg(fg,p,FREEREG,p->q1.reg);
+	regs[p->q1.reg]=1;
+      }
+      if((p->q2.flags&REG)&&!regs[p->q2.reg]){
+	insert_allocreg(fg,p,FREEREG,p->q2.reg);
+	regs[p->q2.reg]=1;
+      }
+      if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&!regs[p->z.reg]){
+	insert_allocreg(fg,p,FREEREG,p->z.reg);
+	regs[p->z.reg]=1;
+      }
+      if((p->z.flags&(REG|DREFOBJ))==REG){
+	if(!(p->q1.flags&REG)||p->q1.reg!=p->z.reg){
+	  if(!(p->q2.flags&REG)||p->q2.reg!=p->z.reg){
+	    IC *p2;
+	    for(p2=p->prev;p2;p2=p2->prev){
+	      if(p2->code==ALLOCREG&&p2->q1.reg==p->z.reg) break;
+	      if(p2->code!=ALLOCREG&&p2->code!=FREEREG) break;
+	    }
+	    if(p2->code!=ALLOCREG||p2->q1.reg!=p->z.reg){
+	      insert_allocreg(fg,p->prev,ALLOCREG,p->z.reg);
+	    }
+	  }
+	}
+      }
+    }
+    if(p==fg->start) return;
+    p=p->prev;
+  }
+}
+
+/* searches back to determine the best local register for v 
+   register-pairs must not be alive in the same instruction as
+   one of the halves */
+int find_best_local_reg(IC *fp,Var *v,int preferred)
+{
+  int r,used,tmp,savings[MAXR+1]={0};
+  IC *p=fp;
+
+  if(v->reg&&!*v->identifier)
+    return abs(v->reg);
+  if(v->vtyp->flags&VOLATILE)
+    return 0;
+  if(!USEQ2ASZ&&(p->q2.flags&VAR)&&p->q2.v==v)
+    savings[preferred]=INT_MIN;
+  else
+    savings[preferred]=1;
+  if(reg_pair(preferred,&rp)){
+    savings[rp.r1]=INT_MIN;
+    savings[rp.r2]=INT_MIN;
+  }
+  for(r=1;r<=MAXR;r++){
+    if(regu[r]||regsa[r]==REGSA_NEVER){
+      savings[r]=INT_MIN;
+      if(reg_pair(r,&rp)){
+	savings[rp.r1]=INT_MIN;
+	savings[rp.r2]=INT_MIN;
+      }
+    }else if(reg_pair(r,&rp)){
+      if(rp.r1==preferred||rp.r2==preferred||regu[rp.r1]||regsa[rp.r1]==REGSA_NEVER||regu[rp.r2]||regsa[rp.r2]==REGSA_NEVER)
+	savings[r]=INT_MIN;
+    }
+    if(savings[r]!=INT_MIN&&!regok(r,v->vtyp->flags,-1))
+      savings[r]=INT_MIN;
+  }
+  for(r=1;r<=MAXR;r++){
+    if(savings[r]!=INT_MIN&&reg_pair(r,&rp)){
+      if(regu[rp.r1]||regu[rp.r2]||regsa[rp.r1]==REGSA_NEVER||regsa[rp.r2]==REGSA_NEVER)
+	savings[r]=INT_MIN;
+    }
+  }
+  while(1){
+    if(!p){
+      if(!is_header)
+	ierror(0);
+      break;
+    }
+    if(!p||(p!=fp&&p->code>=LABEL&&p->code<=BRA)) return 0;
+    if(p!=fp){
+      if((p->z.flags&VAR)&&p->z.v->reg&&!*p->z.v->identifier){
+	if(p->z.v==v)
+	  return abs(p->z.v->reg);
+	else
+	  savings[abs(p->z.v->reg)]=INT_MIN;
+      }
+    }
+    used=0;
+    if((p->q1.flags&VAR)&&p->q1.v==v){
+      if(p->code==ADDRESS) return 0;
+      if((p->code==ASSIGN||p->code==PUSH)&&(q1typ(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))
+	return 0;
+      used=1;
+      for(r=1;r<=MAXR;r++){
+	if(savings[r]!=INT_MIN){
+	  tmp=cost_savings(p,r,&p->q1);
+	  if(tmp==INT_MIN)
+	    savings[r]=INT_MIN;
+	  else
+	    savings[r]+=tmp;
+	}
+      }
+    }
+    if((p->q2.flags&VAR)&&p->q2.v==v){
+      used=1;
+      for(r=1;r<=MAXR;r++){
+	if(savings[r]!=INT_MIN){
+	  tmp=cost_savings(p,r,&p->q2);
+	  if(tmp==INT_MIN)
+	    savings[r]=INT_MIN;
+	  else
+	    savings[r]+=tmp;
+	}
+      }
+    }
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->code==ASSIGN&&(ztyp(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))
+	return 0;
+      for(r=1;r<=MAXR;r++){
+	if(savings[r]!=INT_MIN){
+	  tmp=cost_savings(p,r,&p->z);
+	  if(tmp==INT_MIN)
+	    savings[r]=INT_MIN;
+	  else
+	    savings[r]+=tmp;
+	}
+      }
+      if(used==0&&!(p->z.flags&DREFOBJ))
+	break;
+    }
+    if(p->code==CALL){
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){
+	for(r=1;r<=MAXR;r++){
+	  if(regscratch[r]&&BTST(p->q1.v->fi->regs_modified,r))
+	    savings[r]=INT_MIN;
+	}
+      }else{
+	for(r=1;r<=MAXR;r++){
+	  if(regscratch[r])
+	    savings[r]=INT_MIN;
+	}
+      }
+    }
+
+    /* check for register arguments */
+    if((p->z.flags&(VAR|DREFOBJ))==VAR&&!*p->z.v->identifier&&p->z.v->reg){
+      if(p->code==ASSIGN&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v==v){
+	savings[abs(p->z.v->reg)]++;
+      }else{
+	savings[abs(p->z.v->reg)]=INT_MIN;
+	if(reg_pair(abs(p->z.v->reg),&rp)){
+	  savings[rp.r1]=INT_MIN;
+	  savings[rp.r2]=INT_MIN;
+	}
+      }
+    }
+
+    p=p->prev;
+  }
+  r=0;
+  savings[0]=0;
+  for(tmp=1;tmp<=MAXR;tmp++){
+    if(savings[tmp]>savings[r]){
+      r=tmp;
+    }else if(savings[tmp]==savings[r]){
+      if(reg_prio[tmp]>reg_prio[r])
+	r=tmp;
+      else if(reg_prio[tmp]==reg_prio[r]){
+	if(regscratch[tmp]&&!regscratch[r])
+	  r=tmp;
+	else if(regscratch[tmp]==regscratch[r]&&BTST(bregs,r)&&!BTST(bregs,tmp))
+	  /* if equal, prefer to leave registers used by parameters */
+	  r=tmp;
+      }
+    }
+  }
+  return r;
+}
+
+static bvtype *late_changes;
+
+void search_late_opt(flowgraph *fg,IC *n,obj *o)
+{
+  Var *v=o->v;
+  IC *p=n->prev,*cp;
+  if(!zmeqto(o->val.vmax,Z0)) return;
+  if(o->v->reg!=0) return;
+  while(1){
+    if(!p) ierror(0);
+    if(p->code==LABEL) ierror(0);
+    if((p->q1.flags&VAR)&&p->q1.v==v) return;
+    if((p->q2.flags&VAR)&&p->q2.v==v) return;
+    if((p->z.flags&VAR)&&p->z.v==v){
+      if(p->z.flags&DREFOBJ) return;
+      if(p->code==CONVERT&&!must_convert(p->typf,p->typf2,0)){
+	int ucnt=0;
+	if((p->q1.flags&DREFOBJ)&&(o->flags&DREFOBJ)) return;
+	if(p->q1.flags&VARADR) return;
+	if((n->q1.flags&VAR)&&n->q1.v==o->v) ucnt++;
+	if((n->q2.flags&VAR)&&n->q2.v==o->v) ucnt++;
+	if((n->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&n->q1.v==o->v) ucnt++;
+	if(ucnt!=1) return;
+	memset(late_changes,vsize,0);
+	if((p->q1.flags&(VAR|VARADR))==VAR){
+	  int i=p->q1.v->index;
+	  if(p->q1.flags&DREFOBJ) i+=vcount-rcount;
+	  for(cp=p;cp&&cp!=n;cp=cp->next){
+	    ic_changes(cp,late_changes);
+	    if(BTST(late_changes,i)) return;
+	  }
+	}
+	if(DEBUG&1024){printf("removing CONVERT (!must_convert)\n");pric2(stdout,p);pric2(stdout,n);}
+	o->v=p->q1.v;
+	o->val.vmax=p->q1.val.vmax;
+	if(p->q1.flags&DREFOBJ){
+	  o->flags|=DREFOBJ;
+	  o->dtyp=p->q1.dtyp;
+	}
+	n->use_list=myrealloc(n->use_list,VLS*(n->use_cnt+p->use_cnt));
+	memcpy(&n->use_list[n->use_cnt],&p->use_list[0],p->use_cnt*VLS);
+	n->use_cnt+=p->use_cnt;
+	remove_IC_fg(fg,p);
+      }
+#if 0/* BIGENDIAN||LITTLEENDIAN*/
+      if(p->code==CONVERT&&ISINT(p->typf)&&ISINT(p->typf2)&&(p->typf&NQ)<=(p->typf2&NQ)){
+	if((p->q1.flags&DREFOBJ)&&(o->flags&DREFOBJ)) return;
+	if(DEBUG&1024){printf("removing CONVERT (int=>smallint)\n");pric2(stdout,p);pric2(stdout,n);}
+	o->v=p->q1.v;
+	o->val.vmax=p->q1.val.vmax;
+	if(p->q1.flags&DREFOBJ){
+	  o->flags|=DREFOBJ;
+	  o->dtyp=p->q1.dtyp;
+	}
+#if BIGENDIAN
+	o->val.vmax=zmadd(o->val.vmax,zmsub(sizetab[p->typf2&NQ],sizetab[p->typf&NQ]));
+#endif
+	remove_IC_fg(fg,p);
+      }
+#endif
+      return;
+    }
+    if(p==fg->start) {pric2(stdout,n);ierror(0);}
+    p=p->prev;
+  }
+}
+
+
+void late_opt(flowgraph *fg)
+{
+  IC *p;int j;bvtype *isused;
+  isused=mymalloc(vsize);
+  late_changes=mymalloc(vsize);
+  while(fg){
+    if(DEBUG&1024) printf("late opt pass block %d\n",fg->index);
+    memcpy(isused,fg->av_out,vsize);
+    for(p=fg->end;p;p=p->prev){
+      if(p->code!=NOP&&p->code!=ADDRESS&&(p->q1.flags&(VAR|VARADR))==VAR){
+	j=p->q1.v->index;
+	if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j))
+	  search_late_opt(fg,p,&p->q1);
+      }
+      if(p->code!=NOP&&(p->q2.flags&(VAR|VARADR))==VAR){
+	j=p->q2.v->index;
+	if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j))
+	  search_late_opt(fg,p,&p->q2);
+      }
+      if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+	j=p->z.v->index;
+	if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j))
+	  search_late_opt(fg,p,&p->z);
+      }
+      if(p==fg->start) break;
+      if(p->change_cnt||p->use_cnt)
+	av_update(p,isused);
+    }
+    fg=fg->normalout;
+  }
+  free(isused);
+  free(late_changes);
+}
+
+void local_regs(flowgraph *fg)
+/*  versucht Variablen, die nur innerhalb eines Basic Blocks benutzt    */
+/*  werden (kill==true und out==false), Register zuzuweisen.            */
+{
+  IC *p;
+  int i,j,t,r,nr,mustalloc,savings,prio,nr1,nr2;
+  late_opt(fg);
+  if(DEBUG&1024) print_flowgraph(fg);
+  bvtype *inmem=mymalloc(vsize);
+  if(DEBUG&9216) printf("assigning temporary variables to registers\n");
+  memset(inmem,0,vsize);
+  memset(bregs,0,sizeof(bregs));
+  for(i=0;i<=MAXR;i++) lparms[i]=0;
+  /* mark registers used by parameters */
+  for(p=first_ic;p;p=p->next){
+    if((p->q1.flags&VAR)&&p->q1.v->reg) BSET(bregs,abs(p->q1.v->reg));
+    if((p->q2.flags&VAR)&&p->q2.v->reg) BSET(bregs,abs(p->q2.v->reg));
+    if((p->z.flags&VAR)&&p->z.v->reg) BSET(bregs,abs(p->z.v->reg));
+  }
+  memcpy(bregsm,bregs,sizeof(bregs));
+  lfg=fg;
+  while(lfg){
+    if(DEBUG&1024) printf("block %d\n",lfg->index);
+    for(i=1;i<=MAXR;i++){lregv[i]=0; regu[i]=(regsa[i]==REGSA_NEVER); lfg->regv[i]=0;}
+    memset(&lfg->regused,0,RSIZE);
+    lfg->calls=0;
+    //    if(lfg==fg&&!lfg->in) is_header=1; else is_header=0;
+    /* unmark registers used as register arguments */
+    memcpy(bregs,bregsm,sizeof(bregs));
+    for(p=lfg->start;p;p=p->next){
+      if((p->z.flags&VAR)&&!*p->z.v->identifier&&p->z.v->reg!=0) BCLR(bregs,abs(p->z.v->reg));
+      if(p==lfg->end) break;
+    }
+    p=lfg->end;
+    while(p){
+      nr=nr1=nr2=0;
+      i=replace_local_reg(&p->z);
+      if((p->z.flags&(VAR|DREFOBJ))==VAR){
+	if(i){
+	  lregv[i]=0;regu[i]=0;
+	  if(reg_pair(i,&rp)){
+	    nr1=rp.r1;
+	    nr2=rp.r2;
+	    regu[nr1]=regu[nr2]=0;
+	  }
+	  nr=i;mustalloc=1;
+	  if(DEBUG&8192) printf("regu[%s] decremented to %d\n",regnames[i],regu[i]);
+	}else{
+	  BCLR(inmem,p->z.v->index);
+	}
+      }
+      if(p->code!=ADDRESS){
+	if(replace_local_reg(&p->q1)==nr) mustalloc=0;
+	if(replace_local_reg(&p->q2)==nr) mustalloc=0;
+      }
+      if((p->q1.flags&(VAR|REG|VARADR))==VAR&&!(p->q1.v->flags&USEDASADR)&&(!(p->q1.v->vtyp->flags&VOLATILE)||p->q1.v->reg)&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)){
+	j=p->q1.v->index;
+	if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){
+	  r=find_best_local_reg(p,p->q1.v,nr);
+	  if(r){
+	    if(r!=nr) 
+	      insert_allocreg(lfg,p,FREEREG,r);
+	    else
+	      mustalloc=0;
+	    lregv[r]=p->q1.v;regused[r]=regu[r]=1;
+	    if(reg_pair(r,&rp)){
+	      regu[rp.r1]=regu[rp.r2]=1;
+	      regused[rp.r1]=regused[rp.r2]=1;
+	    }
+	    if(replace_local_reg(&p->q1)!=r) ierror(0);
+	    replace_local_reg(&p->q2);
+	    replace_local_reg(&p->z);
+	    if((DEBUG&9216)&&*p->q1.v->identifier) printf("temporary <%s> assigned to %s (v3)\n",p->q1.v->identifier,regnames[r]);
+	    if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v3)\n",p->q1.v->identifier,(void *)p->q1.v,regnames[r]);
+	  }else BSET(inmem,j);
+	}
+      }
+      /*  hier wegen USEQ2ASZ aufpassen; kommutative ICs sollten so   */
+      /*  angeordnet werden, dass ein evtl. Register rechts steht     */
+      if((p->q2.flags&(VAR|REG|VARADR))==VAR&&!(p->q2.v->flags&USEDASADR)&&!(p->q2.v->vtyp->flags&VOLATILE)&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)){
+	j=p->q2.v->index;
+	if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){
+	  r=find_best_local_reg(p,p->q2.v,nr);
+	  if(r){
+	    if(r!=nr) insert_allocreg(lfg,p,FREEREG,r);
+	    else mustalloc=0;
+	    lregv[r]=p->q2.v;regused[r]=regu[r]=1;
+	    if(reg_pair(r,&rp)){
+	      regu[rp.r1]=regu[rp.r2]=1;
+	      regused[rp.r1]=regused[rp.r2]=1;
+	    }
+	    if(replace_local_reg(&p->q2)!=r) ierror(0);
+	    replace_local_reg(&p->z);
+	    if((DEBUG&9216)&&*p->q2.v->identifier) printf("temporary <%s> assigned to %s (v1)\n",p->q2.v->identifier,regnames[r]);
+	    if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v1)\n",p->q2.v->identifier,(void *)p->q2.v,regnames[r]);
+	  }else BSET(inmem,j);
+	}
+      }
+      if((p->z.flags&(VAR|REG|DREFOBJ))==(VAR|DREFOBJ)&&!(p->z.v->flags&USEDASADR)&&!(p->z.v->vtyp->flags&VOLATILE)&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)){
+	j=p->z.v->index;
+	if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){
+	  r=find_best_local_reg(p,p->z.v,nr);
+	  if(r){
+	    insert_allocreg(lfg,p,FREEREG,r);
+	    lregv[r]=p->z.v;regused[r]=regu[r]=1;
+	    if(reg_pair(r,&rp)){
+	      regu[rp.r1]=regu[rp.r2]=1;
+	      regused[rp.r1]=regused[rp.r2]=1;
+	    }
+	    if(replace_local_reg(&p->z)!=r){
+	      for(i=1;i<=MAXR;i++) if(lregv[i]) printf("%d:%s=%s(%p)\n",i,regnames[i],lregv[i]->identifier,(void*)lregv[i]);
+	      ierror(r);}
+	    if((DEBUG&9216)&&*p->z.v->identifier) printf("temporary <%s> assigned to %s (v2)\n",p->z.v->identifier,regnames[r]);
+	    if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v2)\n",p->z.v->identifier,(void *)p->z.v,regnames[r]);
+	  }else BSET(inmem,j);
+	}
+      }
+      if(p->code==CALL){
+	lfg->calls++;
+#if 0
+	/*  falls Scratchregister bei Funktionsaufruf benutzt   */
+	/*  wird, moeglichst auf ein anderes ausweichen         */
+	for(i=1;i<=MAXR;i++){
+	  if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+	    if(lregv[i]&&regscratch[i]&&BTST(p->q1.v->fi->regs_modified,i)){
+	      int j=lregv[i]->index;
+	      if(lregv[i]->reg&&!*lregv[i]->identifier) ierror(0);
+	      if(free_hreg(lfg,p,i,1/*0*/)==0) BSET(inmem,j);
+	    }		    
+	  }else{
+	    if(lregv[i]&&regscratch[i]){
+	      int j=lregv[i]->index;
+	      if(lregv[i]->reg&&!*lregv[i]->identifier) ierror(0);
+	      if(free_hreg(lfg,p,i,1/*0*/)==0) BSET(inmem,j);
+	    }
+	  }
+	}
+#endif
+      }
+      /*  die Faelle beachten, wenn schon im IC ein Register          */
+      /*  angesprochen wird (sollte nur bei CALL und return auftreten */
+      if(p->code==FREEREG){
+	ierror(0);
+      }
+      if(p->code==ALLOCREG){
+	ierror(0);
+      }
+      if(p==lfg->start) i=1; else i=0;
+      p=p->prev;
+      if(nr&&mustalloc) insert_allocreg(lfg,p,ALLOCREG,nr);
+      if(i) break;
+    }
+    fix_local_allocreg(lfg);
+    lfg=lfg->normalout;
+    if(is_header){
+      for(i=1;i<=MAXR;i++)
+	lparms[i]=lregv[i];
+    }
+  }
+  free(inmem);
+}
+void insert_saves(flowgraph *fg)
+/*  fuegt speichern von Registern bei Funktionsaufrufen ein */
+{
+  int r,c,i;IC *p,*new,*n,*before,*after;Var *v;
+  bvtype *isused=mymalloc(vsize);
+  if(DEBUG&9216) printf("insert_saves\n");
+  for(;fg;fg=fg->normalout){
+   memcpy(isused,fg->av_out,vsize);
+    p=fg->end;
+    while(p){
+      c=p->code;
+      if(c==CALL){
+	if(p==fg->start) n=0; else n=p->prev;
+	for(r=1;r<=MAXR;r++){
+	  i=0;
+	  if((v=fg->regv[r])&&(v->index>=vcount-rcount||BTST(isused,v->index))){
+	    if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){
+	      if(regscratch[r]&&BTST(p->q1.v->fi->regs_modified,r)) i=1;
+	    }else{
+	      if(regscratch[r]) i=1;
+	    }
+	  }
+	  if(i){
+	    if(!n) before=fg->start->prev; else before=n;
+	    after=p->next;
+	    while(after&&(after->code==FREEREG||after->code==ALLOCREG||after->code==NOP))
+	      after=after->next;
+	    if(!after||after->code!=GETRETURN){
+	      after=p;
+	    }else{
+	      if((after->z.flags&REG)&&after->z.reg==r) after->z.flags&=~REG;
+	    }
+	    if(v->index>=vcount-rcount){
+	      /* it is a const_var; reload instead of store */
+	      new=new_IC();
+	      new->code=ASSIGN;
+	      new->typf=v->vtyp->flags;
+	      insert_cobj(&new->q1,&v->cobj);
+	      new->q2.flags=0;
+	      new->q2.val.vmax=szof(v->vtyp);
+	      new->z.flags=REG;
+	      new->z.reg=r;
+	      new->z.val.vmax=l2zm(0L);
+	      new->z.v=v;
+	      new->file=p->file;
+	      new->line=p->line;
+	      /* fake, we do nothing with this afterwards */
+	      new->use_cnt=new->change_cnt=0;
+	      new->change_list=new->use_list=0;
+	      insert_IC_fg(fg,after,new);
+	    }else{
+	      new=new_IC();
+	      new->code=ASSIGN;
+	      new->typf=v->vtyp->flags;
+              /* vla */
+              if(ISARRAY(new->typf))
+                new->typf=POINTER_TYPE(v->vtyp->next);
+	      new->q1.flags=VAR|REG;
+	      new->q1.v=v;
+	      new->q1.val.vmax=l2zm(0L);
+	      new->q1.reg=r;
+	      new->q2.flags=0;
+	      new->q2.val.vmax=szof(v->vtyp);
+	      new->z.flags=VAR;
+	      new->z.val.vmax=l2zm(0L);
+	      new->z.v=v;
+	      new->file=p->file;
+	      new->line=p->line;
+	      /* fake, we do nothing with this afterwards */
+	      new->use_cnt=new->change_cnt=0;
+	      new->change_list=new->use_list=0;
+	      insert_IC_fg(fg,before,new);
+	      new=new_IC();
+	      new->code=ASSIGN;
+	      new->typf=v->vtyp->flags;
+              /* vla */
+              if(ISARRAY(new->typf))
+                new->typf=POINTER_TYPE(v->vtyp->next);
+	      new->q1.flags=VAR;
+	      new->q1.v=v;
+	      new->q1.val.vmax=l2zm(0L);
+	      new->q2.flags=0;
+	      new->q2.val.vmax=szof(v->vtyp);
+	      new->z.flags=VAR|REG;
+	      new->z.v=v;
+	      new->z.val.vmax=l2zm(0L);
+	      new->z.reg=r;
+	      new->file=p->file;
+	      new->line=p->line;
+	      /* fake, we do nothing with this afterwards */
+	      new->use_cnt=new->change_cnt=0;
+	      new->change_list=new->use_list=0;
+	      insert_IC_fg(fg,after,new);
+	    }
+	  }
+	}
+	if(p->change_cnt!=0||p->use_cnt!=0)
+	  av_update(p,isused);
+	p=n;
+	continue;
+      }
+      if(p==fg->start) break;
+      if(p->change_cnt!=0||p->use_cnt!=0)
+	av_update(p,isused);
+      p=p->prev;
+    }
+  }
+  free(isused);
+}
+
+
+#endif
+
+void insert_simple_allocreg(IC *p,int code,int reg)
+/*  Fuegt ein ALLOCREG/FREEREG (in code) hinter p ein - bei p==0 in */
+/*  first_ic.                                                       */
+{
+    IC *new=new_IC();
+    new->line=0;
+    new->file=0;
+    regused[reg]=1;
+    if(reg_pair(reg,&rp))
+	regused[rp.r1]=regused[rp.r2]=1;
+    new->code=code;
+    new->typf=0;
+    new->q1.am=new->q2.am=new->z.am=0;
+    new->q1.flags=REG;
+    new->q1.reg=reg;
+    new->q2.flags=new->z.flags=0;
+    new->use_cnt=new->change_cnt=0;
+    new->use_list=new->change_list=0;
+    insert_IC(p,new);
+}
+
+void load_simple_reg_parms(void)
+/*  Laedt Registerparameter, falls noetig. Nicht-optimierende Version.  */
+{
+  int i,j; Var *v;
+  regp regp[MAXR+1]={0};
+/*   for(i=1;i<=MAXR;i++) {regp[i].treg=0;regp[i].tvar=0;} */
+  for(i=0;i<=1;i++){
+    if(i==0) v=vl3; else v=vl2;
+    for(;v;v=v->next){
+      if((v->flags&REGPARM)&&(regsv[abs(v->reg)]!=v||(v->flags&CONVPARAMETER))){
+	regp[abs(v->reg)].tvar=v;
+	for(j=1;j<=MAXR;j++)
+	  if(regsv[j]==v) regp[abs(v->reg)].treg=j;
+      }
+    }
+  }
+  do_load_parms(regp,0);
+}
+
+extern zmax recalc_start_offset;
+
+void do_load_parms(regp regp[],flowgraph *fg)
+{
+  int i,i1,i2,j,j1,j2,c,k,notdone;
+  struct {int freg,treg;Var *tvar,*tmp;} order[MAXR]={0};
+  if(DEBUG&1){
+    printf("do_load_parms:\n");
+    for(i=1;i<=MAXR;i++)
+      if(regp[i].tvar)
+	printf("%s->%s(%s)\n",regnames[i],regnames[regp[i].treg],regp[i].tvar->identifier);
+  }
+  do{
+    c=0;
+    do{
+      notdone=0;
+      for(i=1;i<=MAXR;i++){
+	int notfree;
+	if(reg_pair(i,&rp)){
+	  i1=rp.r1;
+	  i2=rp.r2;
+	}else
+	  i1=i2=0;
+	if(!regp[i].tvar) continue;
+	j=regp[i].treg;
+	if(j&&reg_pair(j,&rp)){
+	  j1=rp.r1;
+	  j2=rp.r2;
+	}else
+	  j1=j2=0;
+	notfree=0;
+	for(k=1;k<=MAXR;k++){
+	  if(regp[k].tvar&&reg_pair(k,&rp)&&(rp.r1==j||rp.r1==j1||rp.r1==j2||rp.r2==j||rp.r2==j1||rp.r2==j2)){
+	    notfree=1;
+	    break;
+	  }
+	}
+	if(j==0||(!notfree&&!regp[j].tvar&&(!j1||!regp[j1].tvar)&&(!j2||!regp[j2].tvar))||i==j||regp[i].tmp){
+	  order[c].freg=i;
+	  order[c].treg=j;
+	  order[c].tvar=regp[i].tvar;
+	  if(regp[i].tmp){order[c].treg=0;order[c].tvar=regp[i].tmp;}
+	  c++; notdone=1;
+	  regp[i].treg=0;
+	  regp[i].tvar=0;
+	}
+      }
+    }while(notdone);
+    for(i=c-1;i>=0;i--)
+      load_one_parm(order[i].freg,order[i].treg,0,order[i].tvar,fg);
+    notdone=0;
+    /* first try to spill register-pair (probably suboptimal, but should
+       avoid a deadlock) */
+    for(i=1;i<=MAXR;i++){
+      if(regp[i].tvar&&reg_pair(i,&rp))
+	break;
+    }
+    if(i>MAXR){
+      for(i=1;i<=MAXR;i++){
+	if(regp[i].tvar)
+	  break;
+      }
+    }
+    if(i<=MAXR){
+      static type dtyp={DOUBLE};
+      if(!regp[i].tvar) ierror(0);
+      if(regp[i].tvar->flags&CONVPARAMETER)
+	regp[i].tmp=add_tmp_var(clone_typ(&dtyp));
+      else
+	regp[i].tmp=add_tmp_var(clone_typ(regp[i].tvar->vtyp));
+      /* num_vars is already done, so mark it by -1 */
+      regp[i].tmp->index=-1;
+      /* allocate memory for recalc_offsets */
+#ifndef NO_OPTIMIZER
+      if(fg){
+	regp[i].tmp->offset=l2zm(0L);
+	if(zmleq(recalc_start_offset,regsize[i]))
+	  recalc_start_offset=regsize[i];
+      }
+#endif
+      load_one_parm(0,regp[i].treg,regp[i].tmp,regp[i].tvar,fg);
+      notdone=1;
+    }
+  }while(notdone);
+}
+void load_one_parm(int freg,int treg,Var *fvar,Var *tvar,flowgraph *fg)
+{
+  IC *new;
+  if(DEBUG&1) printf("lop: %s(%s)->%s(%s)\n",regnames[freg],fvar?fvar->identifier:empty,regnames[treg],tvar?tvar->identifier:empty);
+  if(freg&&freg!=treg){
+    if(fg){
+#ifndef NO_OPTIMIZER
+      insert_allocreg(fg,0,FREEREG,freg);
+#endif
+    }else
+      insert_simple_allocreg(0,FREEREG,freg);
+  }
+  new=new_IC();
+  new->line=0;
+  new->file=0;
+  if(tvar->flags&CONVPARAMETER){
+    new->code=CONVERT;
+    new->typf=tvar->vtyp->flags;
+    new->typf2=DOUBLE;
+  }else{
+    new->code=ASSIGN;
+    new->typf=tvar->vtyp->flags;
+  }
+  if(ISFLOAT(new->typf)) float_used=1;
+  if(fvar){
+    new->q1.flags=VAR;
+    new->q1.v=fvar;
+    new->q1.val.vmax=l2zm(0L);
+  }else{
+    new->q1.flags=REG;
+    new->q1.reg=freg;
+  }
+  new->q2.flags=0;
+  new->q2.val.vmax=szof(tvar->vtyp);
+  if(treg)
+    new->z.flags=REG|VAR;
+  else
+    new->z.flags=VAR;
+  new->z.val.vmax=l2zm(0L);
+  new->z.v=tvar;
+  new->z.reg=treg;
+  new->q1.am=new->q2.am=new->z.am=0;
+  new->use_cnt=new->change_cnt=0;
+  new->use_list=new->change_list=0;
+  if((new->typf&NQ)==CHAR&&!regok(new->q1.reg,new->typf,0)){
+    new->code=CONVERT;
+    new->typf2=INT;
+  }
+  if(fg){
+#ifndef NO_OPTIMIZER
+    insert_IC_fg(fg,0,new);
+    if(freg&&freg!=treg) insert_allocreg(fg,0,ALLOCREG,freg);
+#endif
+  }else{
+    insert_IC(0,new);
+    if(freg&&freg!=treg) insert_simple_allocreg(0,ALLOCREG,freg);
+  }
+  if(new->z.flags&REG){
+    /*  ALLOCREG verschieben    */
+    IC *p;
+    if(fg){
+#ifndef NO_OPTIMIZER
+      insert_allocreg(fg,0,ALLOCREG,treg);
+#endif
+    }else
+      insert_simple_allocreg(0,ALLOCREG,treg);
+    for(p=new->next;p;p=p->next){
+      if(p->code==ALLOCREG&&p->q1.reg==treg){
+	if(fg){
+#ifndef NO_OPTIMIZER
+	  remove_IC_fg(fg,p);
+#endif
+	}else
+	  remove_IC(p);
+	break;
+      }
+    }
+    if(!p) ierror(0);
+  }
+}
+
+void simple_regs(void)
+/*  haelt Variablen in Registern, simple Version            */
+{
+  int i2,i,j;int pri;Var *v;
+  IC *icp,*start=first_ic;
+  if(!first_ic) return;
+  for(i=1;i<=MAXR;i++) regsv[i]=0;
+  for(i2=0;i2<=MAXR*4;i2++){
+    int only_best,pointertype=0;
+    if(i2<=MAXR*2){i=i2;only_best=1;} else {i=i2/2;pointertype=only_best=0;}
+    if(i<=MAXR&&regsv[i]) continue;
+    if(i>MAXR&&regsv[i-MAXR]) continue;
+    if(i>MAXR||!regsv[i]){
+      if(i>MAXR){
+	i-=MAXR;
+	if(regsv[i]) continue;
+      }else{
+	/*  Ziehe Scratchregister vor, wenn kein Funktionsaufruf */
+	/*  erfolgt, sonst erst andere                           */
+	if(!regscratch[i]) continue;
+      }
+      if(regused[i]) continue;
+      if(sregsa[i]==REGSA_TEMPS) continue;
+      if(reg_pair(i,&rp)){
+	if(regused[rp.r1]||regused[rp.r2]) continue;
+      }
+      if(simple_scratch[i]) continue;
+      /*pri=2;*/ pri=0;
+      for(j=0;j<=1;j++){
+	if(j==0) v=vl3; else v=vl2;
+	while(v){
+	  if(v->storage_class==AUTO||v->storage_class==REGISTER){
+	    if(!(v->flags&USEDASADR)&&!(v->vtyp->flags&VOLATILE)){
+              int vt=v->vtyp->flags&NU;
+              /* vla */
+              if(ISARRAY(vt)&&is_vlength(v->vtyp))
+                vt=POINTER_TYPE(v->vtyp->next);
+	      if(only_best&&v->vtyp->next) pointertype=v->vtyp->next->flags;
+	      if(v->priority>pri&&regok(i,vt,pointertype)){
+		regsv[i]=v;pri=v->priority;
+	      }
+	    }
+	  }
+	  v=v->next;
+	}
+      }
+    }
+    if(regsv[i]){
+      if(DEBUG&1) printf("Assigned <%s>(%p) to %s,%d\n",regsv[i]->identifier,(void *)regsv[i],regnames[i],i);
+      regsv[i]->priority=0;regused[i]=1;
+      if(reg_pair(i,&rp)) {regused[rp.r1]=regused[rp.r2]=1;}
+      if(!zmleq(l2zm(0L),regsv[i]->offset)&&!(regsv[i]->flags&(CONVPARAMETER|REGPARM))){
+	icp=new_IC();
+	icp->line=0;
+	icp->file=0;
+	icp->q1.am=icp->q2.am=icp->z.am=0;
+	icp->code=ASSIGN;
+	icp->typf=regsv[i]->vtyp->flags&NU;
+	icp->q1.flags=VAR;
+	icp->q1.v=regsv[i];
+	icp->q1.val.vmax=l2zm(0L);
+	icp->q2.flags=0;
+	icp->q2.val.vmax=szof(regsv[i]->vtyp);
+	icp->z.flags=REG;
+	icp->z.reg=i;
+	icp->next=first_ic;
+	icp->prev=0;
+	first_ic->prev=icp;
+	first_ic=icp;
+      }
+      icp=new_IC();
+      icp->line=0;
+      icp->file=0;
+      icp->q1.am=icp->q2.am=icp->z.am=0;
+      icp->code=ALLOCREG;
+      icp->q1.flags=REG;
+      icp->q1.reg=i;
+      icp->q2.flags=icp->z.flags=icp->typf=0;
+      icp->next=first_ic;
+      icp->prev=0;
+      first_ic->prev=icp;
+      first_ic=icp;
+      icp=new_IC();
+      icp->q1.am=icp->q2.am=icp->z.am=0;
+      icp->code=FREEREG;
+      icp->q1.flags=REG;
+      icp->q1.reg=i;
+      icp->q2.flags=icp->z.flags=icp->typf=0;
+      icp->next=0;
+      add_IC(icp);
+    }
+  }
+  icp=start;
+  while(icp){
+    if((icp->code==ALLOCREG||icp->code==FREEREG)&&regsv[icp->q1.reg]){
+      /*  irgendwelche allocreg/freereg im Code entfernen     */
+      /*  sollte nur beim Returnregister vorkommen            */
+      IC *m=icp->next;
+      remove_IC(icp);
+      icp=m;continue;
+    }
+    for(i=1;i<=MAXR;i++){
+      if(!regsv[i]) continue;
+      if((icp->q1.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->q1.v==regsv[i]){
+	icp->q1.flags|=REG;
+	icp->q1.reg=i;
+      }
+      if((icp->q2.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->q2.v==regsv[i]){
+	icp->q2.flags|=REG;
+	icp->q2.reg=i;
+      }
+      if((icp->z.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->z.v==regsv[i]){
+	icp->z.flags|=REG;
+	icp->z.reg=i;
+      }
+    }
+    icp=icp->next;
+  }
+}
+
+
diff --git a/statements.c b/statements.c
new file mode 100644
index 0000000..1779ceb
--- /dev/null
+++ b/statements.c
@@ -0,0 +1,1288 @@
+/*  $VER: vbcc (statements.c)  $Revision: 1.30 $  */
+
+#include "vbcc_cpp.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+int cont_label=0;
+int test_assignment(type *,np);
+
+static int switchbreak;
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+#define cr()
+#ifndef cr
+void cr(void)
+/*  tested Registerbelegung */
+{
+  int i;
+  for(i=0;i<=MAXR;i++)
+    if(regs[i]!=regsa[i]) {error(149,regnames[i]);regs[i]=regsa[i];}
+}
+#endif
+
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+
+void statement(void)
+/*  bearbeitet ein statement                                    */
+{
+  token mtok;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+  cr();
+  killsp();
+  if(ctok->type==LBRA){
+    enter_block();
+    if(nesting>0) local_offset[nesting]=local_offset[nesting-1];
+    compound_statement();
+    leave_block();
+    return;
+  }
+  if(ctok->type==NAME){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifndef HAVE_MISRA
+    if(!strcmp("if",ctok->name)){next_token();if_statement(); return;}
+    if(!strcmp("switch",ctok->name)){next_token();switch_statement(); return;}
+    if(!strcmp("for",ctok->name)){next_token();for_statement(); return;}
+    if(!strcmp("while",ctok->name)){next_token();while_statement(); return;}
+    if(!strcmp("do",ctok->name)){next_token();do_statement(); return;}
+    if(!strcmp("goto",ctok->name)){next_token();goto_statement(); return;}
+    if(!strcmp("continue",ctok->name)){next_token();continue_statement(); return;}
+    if(!strcmp("break",ctok->name)){next_token();break_statement(); return;}
+    if(!strcmp("return",ctok->name)){next_token();return_statement(); return;}
+    if(!strcmp("case",ctok->name)){next_token(); labeled_statement(); return;}
+    if(!strcmp("default",ctok->name)){cpbez(buff,0);next_token();labeled_statement(); return;}
+#endif
+	}
+  cpbez(buff,1);
+  copy_token(&mtok,ctok);
+  next_token();killsp();
+  if(ctok->type==T_COLON){labeled_statement();return;}
+  push_token(&mtok);
+  free(mtok.name);
+  expression_statement(); /* if there is an expression statement set misra_last_break to false */
+}
+void labeled_statement(void)
+/*  bearbeitet labeled_statement                                */
+{
+  llist *lp;int def=0;
+  nocode=0;
+  if(ctok->type==T_COLON){
+    next_token();
+    if(!*buff){
+      error(130);
+      return;
+    }
+    if(!strcmp("default",buff)){
+      def=1;
+      lp=0;
+    } else lp=find_label(buff);
+    if(lp&&lp->flags&LABELDEFINED){
+      error(131,buff);
+      return;
+    }
+    if(!lp) lp=add_label(buff);
+    lp->flags|=LABELDEFINED;
+    lp->switch_count=0;
+    if(def){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+      if(switch_act==0) error(150);
+      lp->flags|=LABELDEFAULT;
+      lp->switch_count=switch_act;
+    }else {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+		}
+    gen_label(lp->label);
+    afterlabel=0;
+  }else{
+    /*  case    */
+    np tree;llist *lp;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    tree=expression();
+    killsp();
+    if(ctok->type==T_COLON){
+      next_token();
+      killsp();
+    } else error(70);
+    if(!switch_count){
+      error(132);
+    } else {
+      if(!tree||!type_expression(tree,0))
+	{
+	} else {
+	if(tree->flags!=CEXPR||tree->sidefx){
+	  error(133);
+	} else {
+	  if(!ISINT(tree->ntyp->flags)){
+	    error(134);
+	  } else {
+	    lp=add_label(empty);
+	    lp->flags=LABELDEFINED;
+	    lp->switch_count=switch_act;
+	    eval_constn(tree);
+	    insert_const(&lp->val,switch_typ);
+	    gen_label(lp->label);
+	  }
+	}
+      }
+    }
+    if(tree) free_expression(tree);
+  }
+  cr();
+  killsp();
+  if(ctok->type!=RBRA) statement();
+}
+void if_statement(void)
+/*  bearbeitet if_statement                                     */
+{
+  int ltrue,lfalse,lout,cexpr=0,cm,tm,merk_elseneed;
+  np tree;IC *new;
+  static int elseneed;
+  merk_elseneed=elseneed;
+  elseneed=0;
+  killsp();
+  if(ctok->type==LPAR) next_token(); else error(151);
+  killsp();cm=nocode;
+  tree=expression();
+  if(!tree){
+    error(135);
+  }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    ltrue=++label;lfalse=++label;
+    simple_alg_opt(tree);
+    if(type_expression(tree,andcomp(tree,0))){
+      tree=makepointer(tree);
+      if(!ISARITH(tree->ntyp->flags)&&!ISPOINTER(tree->ntyp->flags)){
+	error(136);
+      }else{
+	if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+	gen_IC(tree,ltrue,lfalse);
+	if(tree->flags==CEXPR){
+	  eval_const(&tree->val,tree->ntyp->flags&NU);
+	  if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) cexpr=2; else cexpr=1;
+	}else
+	  cexpr=0;
+	if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&cexpr) free_reg(tree->o.reg);
+	if(tree->o.flags&&!cexpr){
+	  gen_test(&tree->o,tree->ntyp->flags,BEQ,lfalse);
+#if 0
+	  new=new_IC();
+	  new->code=TEST;
+	  new->q1=tree->o;
+	  new->q2.flags=new->z.flags=0;
+	  new->typf=tree->ntyp->flags;
+	  add_IC(new);
+	  new=new_IC();
+	  new->code=BEQ;
+	  new->typf=lfalse;
+	  add_IC(new);
+#endif
+	}
+	if(cexpr==2){
+	  new=new_IC();
+	  new->code=BRA;
+	  new->typf=lfalse;
+	  add_IC(new);
+	}
+      }
+    }
+    tm=tree->o.flags;
+    free_expression(tree);
+  }
+  killsp(); if(ctok->type==RPAR) next_token(); else error(59);
+  if(cexpr==2) nocode=1;
+  if(!cexpr&&!tm) gen_label(ltrue);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+  statement();
+  killsp();
+  if(ctok->type!=NAME||strcmp("else",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    nocode=cm;
+    if(cexpr!=1) gen_label(lfalse);
+    elseneed=merk_elseneed;
+    return;
+  }
+  next_token();
+  lout=++label;
+  if(cexpr!=2){
+    new=new_IC();
+    new->code=BRA;
+    new->typf=lout;
+    add_IC(new);
+  }
+  if(cexpr!=1) {nocode=cm;gen_label(lfalse);}
+  if(cexpr==1) nocode=1; else nocode=cm;
+  if(ctok->type!=LBRA){
+	  if(ctok->type!=NAME||strcmp("if",ctok->name)) {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	  }
+    else
+      elseneed=1;
+  }
+  statement();
+  elseneed=merk_elseneed;
+  nocode=cm;
+  if(cexpr!=2) gen_label(lout);
+  cr();
+}
+
+
+void switch_statement(void)
+/*  bearbeitet switch_statement                                 */
+{
+  np tree;int merk_typ,merk_count,merk_break,num_cases;
+	IC *merk_fic,*merk_lic,*new;llist *lp,*l1,*l2;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  nocode=0;
+  killsp();
+  if(ctok->type==LPAR){
+		next_token();killsp();
+	} else error(151);
+  tree=expression(); killsp();
+  if(ctok->type==RPAR){
+		next_token();killsp();
+	} else error(59);
+  merk_typ=switch_typ;merk_count=switch_act;merk_break=break_label;
+  if(!tree){
+    error(137);
+  } else {
+    if(!type_expression(tree,0)){
+    }else{
+      if(!ISINT(tree->ntyp->flags)){
+	error(138);
+      } else {
+	int m1,m2,m3,def=0,rm,rm1,rm2,minflag;
+	zmax l,ml,s;zumax ul,mul,us;
+	if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif 
+	m3=break_label=++label;m1=switch_act=++switch_count;
+	m2=switch_typ=tree->ntyp->flags&NU;
+	gen_IC(tree,0,0);
+	if((SWITCHSUBS&&!shortcut(SUB,m2))||(!SWITCHSUBS&&!shortcut(COMPARE,m2))){
+	  switch_typ=m2=int_erw(m2);
+	  convert(tree,m2);
+	}
+	if((tree->o.flags&(DREFOBJ|SCRATCH))!=SCRATCH){
+	  new=new_IC();
+	  new->code=ASSIGN;
+	  new->q1=tree->o;
+	  new->q2.flags=0;
+	  new->q2.val.vmax=sizetab[m2&NQ];
+	  get_scratch(&new->z,m2,0,0);
+	  new->typf=m2;
+	  tree->o=new->z;
+	  add_IC(new);
+	}
+	if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)){
+	  int r=tree->o.reg;
+	  rm=regs[r];
+	  regs[r]=regsa[r];
+	  if(reg_pair(r,&rp)){
+	    rm1=regs[rp.r1];
+	    rm2=regs[rp.r2];
+	    regs[rp.r1]=regsa[rp.r1];
+	    regs[rp.r2]=regsa[rp.r2];
+	  }
+	}
+	merk_fic=first_ic;merk_lic=last_ic;
+	
+	first_ic=last_ic=0;
+	{
+	  int merk_sb=switchbreak;
+	  switchbreak=1;
+	  statement();
+	  switchbreak=merk_sb;
+	}
+	
+	if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)){
+	  int r=tree->o.reg;
+	  regs[r]=rm;
+	  if(reg_pair(r,&rp)){
+	    regs[rp.r1]=rm1;
+	    regs[rp.r2]=rm2;
+	  }
+	}
+	minflag=0;s=l2zm(0L);us=ul2zum(0UL);
+	num_cases=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+	for(l1=first_llist;l1;l1=l1->next)
+	  if(l1->switch_count==m1) num_cases++;
+	for(l1=first_llist;l1;l1=l1->next){
+	  if(l1->switch_count!=m1) continue;
+	  if(l1->flags&LABELDEFAULT){
+	    if(def) error(139);
+	    def=l1->label;
+	    continue;
+	  }
+	  lp=0;minflag&=~1;
+	  for(l2=first_llist;l2;l2=l2->next){
+	    if(l2->switch_count!=m1) continue;
+	    if(l2->flags&LABELDEFAULT) continue;
+	    eval_const(&l2->val,m2);
+	    if(minflag&2){
+	      if(m2&UNSIGNED){
+		if(zumleq(vumax,mul)||zumeqto(vumax,mul)) continue;
+	      }else{
+		if(zmleq(vmax,ml)||zmeqto(vmax,ml)) continue;
+	      }
+	    }
+	    if(minflag&1){
+	      if(m2&UNSIGNED){
+		if(!(minflag&4)&&zumeqto(vumax,ul)){ 
+		  error(201);
+		  minflag|=4;
+		}
+		if(zumleq(vumax,ul)){
+		  lp=l2;
+		  ul=vumax;
+		}
+	      }else{
+		if(!(minflag&4)&&zmeqto(vmax,l)){ error(201);minflag|=4;}
+		if(zmleq(vmax,l)){lp=l2;l=vmax;}
+	      }
+	    }else{
+	      minflag|=1;
+	      l=vmax;
+	      ul=vumax;
+	      lp=l2;
+	    }
+	  }
+	  if(!lp) continue;
+	  ml=l;mul=ul;minflag|=2;
+	  if(SWITCHSUBS&&num_cases<JUMP_TABLE_LENGTH){
+	    new=new_IC();
+	    new->line=0;
+	    new->file=0;
+	    new->typf=m2;
+	    new->code=SUB;
+	    new->q1=tree->o;
+	    new->z=tree->o;
+	    new->q2.flags=KONST;
+	    eval_const(&lp->val,m2);
+	    if(m2&UNSIGNED){
+	      gval.vumax=zumsub(vumax,us);
+	      eval_const(&gval,UNSIGNED|MAXINT);
+	    }else{
+	      gval.vmax=zmsub(vmax,s);
+	      eval_const(&gval,MAXINT);
+	    }
+	    insert_const(&new->q2.val,m2);
+	    new->q1.am=new->q2.am=new->z.am=0;
+	    s=l;us=ul;
+	    new->prev=merk_lic;
+	    if(merk_lic) merk_lic->next=new; else merk_fic=new;
+	    merk_lic=new;
+	    new=new_IC();
+	    new->line=0;
+	    new->file=0;
+	    new->typf=m2;
+	    new->code=TEST;
+	    new->q1=tree->o;
+	    new->q2.flags=new->z.flags=0;
+	    new->prev=merk_lic;
+	    new->q1.am=new->q2.am=new->z.am=0;
+	    if(merk_lic) merk_lic->next=new; else merk_fic=new;
+	    merk_lic=new;
+	  }else{
+	    new=new_IC();
+	    new->line=0;
+	    new->file=0;
+	    new->code=COMPARE;
+	    new->typf=m2;
+	    new->q1=tree->o;
+	    new->q2.flags=KONST;
+	    new->q2.val=lp->val;
+	    new->z.flags=0;
+	    new->prev=merk_lic;
+	    new->q1.am=new->q2.am=new->z.am=0;
+	    if(merk_lic) merk_lic->next=new; else merk_fic=new;
+	    merk_lic=new;
+	  }
+	  new=new_IC();
+	  new->line=0;
+	  new->file=0;
+	  new->code=BEQ;
+	  new->typf=lp->label;
+	  new->q1.flags=new->q2.flags=new->z.flags=0;
+	  new->prev=merk_lic;
+	  new->q1.am=new->q2.am=new->z.am=0;
+	  merk_lic->next=new;
+	  merk_lic=new;
+	}
+	if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)){   /* free_reg(tree->o.reg); */
+	  new=new_IC();
+	  new->line=0;
+	  new->file=0;
+	  new->code=FREEREG;new->typf=0;
+	  new->q2.flags=new->z.flags=0;
+	  new->q1.flags=REG;
+	  new->q1.reg=tree->o.reg;
+	  new->prev=merk_lic;
+	  new->q1.am=new->q2.am=new->z.am=0;
+	  if(merk_lic) merk_lic->next=new; else merk_fic=new;
+	  merk_lic=new;
+	  regs[tree->o.reg]=regsa[tree->o.reg];
+	  if(reg_pair(tree->o.reg,&rp)){ regs[rp.r1]=regsa[rp.r1];regs[rp.r2]=regsa[rp.r2];}
+	}
+	new=new_IC();
+	new->line=0;
+	new->file=0;
+	new->code=BRA;
+	if(def) new->typf=def; else {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	  new->typf=m3;
+	}
+	new->q1.flags=new->q2.flags=new->z.flags=0;
+	if(merk_lic) merk_lic->next=new; else merk_fic=new;
+	new->prev=merk_lic;
+	if(first_ic){
+	  first_ic->prev=new;
+	  new->next=first_ic;
+	}else{
+	  last_ic=new;
+	  new->next=first_ic;
+	}
+	new->q1.am=new->q2.am=new->z.am=0;
+	first_ic=merk_fic;
+	gen_label(m3);
+      }
+    }
+  }
+  switch_typ=merk_typ;switch_act=merk_count;break_label=merk_break;
+  if(tree) free_expression(tree);
+  cr();
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+}
+void repair_tree(np p)
+/*  Bearbeitet einen Ausdruckbaum so, dass er ein zweites Mal   */
+/*  mit gen_IC erzeugt werden kann.                             */
+{
+  if(p->left) repair_tree(p->left);
+  if(p->right) repair_tree(p->right);
+  if(p->flags==IDENTIFIER||p->flags==(IDENTIFIER|256))
+    p->o.v=find_var(p->identifier,0);
+  if(p->flags==CALL){
+    argument_list *al=p->alist;
+    while(al){
+      repair_tree(al->arg);
+      al=al->next;
+    }
+  }
+}
+void while_statement(void)
+/*  bearbeitet while_statement                                  */
+{
+  np tree;int lloop,lin,lout,cm,cexpr,contm,breakm;
+  IC *new,*mic; int line,tvalid;char *file;
+  killsp();
+  if(ctok->type==LPAR) {next_token();killsp();} else error(151);
+  tree=expression();
+  cexpr=0;
+  if(tree){
+    simple_alg_opt(tree);
+    if(tvalid=type_expression(tree,andcomp(tree,0))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      tree=makepointer(tree);
+      if(!ISARITH(tree->ntyp->flags)&&!ISPOINTER(tree->ntyp->flags)){
+	error(140);
+	cexpr=-1;
+      }else{
+	if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+	if(tree->flags==CEXPR){
+	  eval_const(&tree->val,tree->ntyp->flags);
+	  if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) cexpr=1; else cexpr=2;
+	  if(cexpr==1) error(152);
+	}
+      }
+    }else cexpr=-1;
+  } else error(141);
+  lloop=++label;lin=++label;lout=++label;cm=nocode;
+  contm=cont_label;breakm=break_label;
+  if(!cexpr||tree->sidefx) cont_label=lin; else cont_label=lloop;
+  if(!cexpr||tree->sidefx){
+    if(c_flags_val[0].l&2){ /*  bei Optimierung */
+      if(tvalid){
+	gen_IC(tree,lloop,lout);
+	if(tree->o.flags){
+	  gen_test(&tree->o,tree->ntyp->flags,BEQ,lout);
+#if 0
+	  new=new_IC();
+	  new->code=TEST;
+	  new->typf=tree->ntyp->flags;
+	  new->q1=tree->o;
+	  new->q2.flags=new->z.flags=0;
+	  add_IC(new);
+	  new=new_IC();
+	  new->code=BEQ;
+	  new->typf=lout;
+	  add_IC(new);
+#endif
+	}
+	repair_tree(tree);
+      }
+    }else{
+      new=new_IC();
+      new->code=BRA;
+      new->typf=lin;
+      new->flags|=LOOP_COND_TRUE;
+      add_IC(new);
+    }
+  }
+  if(cexpr==1){
+    new=new_IC();
+    new->code=BRA;
+    new->typf=lout;
+    add_IC(new);
+  }else{
+    gen_label(lloop);
+    last_ic->flags|=LOOP_COND_TRUE;
+  }
+  line=last_ic->line;file=last_ic->file;
+  cm=nocode;break_label=lout;
+  if(cexpr==1) nocode=1;
+  currentpri*=looppri;
+  killsp();
+  if(ctok->type==RPAR) {next_token();killsp();} else error(59);
+  {
+    int merk_sb=switchbreak;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    switchbreak=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    statement();
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    switchbreak=merk_sb;
+  }
+  mic=last_ic;
+  nocode=cm;cont_label=contm;break_label=breakm;
+  if(!cexpr||tree->sidefx) gen_label(lin);
+  /* correct if mic was a branch to label lin and eliminated */
+  if(last_ic->prev!=mic) mic=last_ic;
+  if(tree&&cexpr>=0){
+    if(cexpr!=1||tree->sidefx){
+      gen_IC(tree,lloop,lout);
+      if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&cexpr) free_reg(tree->o.reg);
+    }
+    if(tree->o.flags&&!cexpr){
+      gen_test(&tree->o,tree->ntyp->flags,BNE,lloop);
+#if 0
+      new=new_IC();
+      new->code=TEST;
+      new->typf=tree->ntyp->flags;
+      new->q1=tree->o;
+      new->q2.flags=new->z.flags=0;
+      add_IC(new);
+      new=new_IC();
+      new->code=BNE;
+      new->typf=lloop;
+      add_IC(new);
+#endif
+    }
+    if(cexpr==2){
+      new=new_IC();
+      new->code=BRA;
+      new->typf=lloop;
+      add_IC(new);
+    }
+  }
+  if(tree) free_expression(tree);
+  for(mic=mic->next;mic;mic=mic->next){
+    mic->line=line;mic->file=file;
+  }
+  gen_label(lout);
+  currentpri/=looppri;
+  cr();
+}
+void for_statement(void)
+/*  bearbeitet for_statement                                    */
+{
+  np tree1=0,tree2=0,tree3=0;int lloop,lin,lout,cm,cexpr=0,contm,breakm,with_decl,tvalid;
+  IC *new,*mic;int line;char *file;
+  killsp();
+  if(ctok->type==LPAR) {next_token();killsp();} else error(59);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+  if(c99&&declaration(0)){
+    with_decl=1;
+    enter_block();
+    if(nesting>0) local_offset[nesting]=local_offset[nesting-1];
+    for_decl=1;
+    var_declaration();
+    for_decl=0;
+  }else{
+    with_decl=0;
+    if(ctok->type!=SEMIC) tree1=expression();
+    if(tree1){
+      if(tree1->flags==POSTINC) tree1->flags=PREINC;
+      if(tree1->flags==POSTDEC) tree1->flags=PREDEC;
+      if(type_expression(tree1,0)){
+	if(tree1->sidefx){
+	  gen_IC(tree1,0,0);
+	  if(tree1&&(tree1->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree1->o.reg);
+	}else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+		error(153);
+	}
+      }
+      free_expression(tree1);
+    }
+    killsp();
+    if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+  }
+  if(ctok->type!=SEMIC) {tree2=expression();killsp();} else {cexpr=2;}
+  if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+  if(ctok->type!=RPAR) tree3=expression();
+  killsp();
+  if(ctok->type==RPAR) {next_token();killsp();} else error(59);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+  if(tree3){
+    if(!type_expression(tree3,0)){
+      free_expression(tree3);
+      tree3=0;
+    }
+  }
+  if(tree2){
+    simple_alg_opt(tree2);
+    if(tvalid=type_expression(tree2,andcomp(tree2,0))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      tree2=makepointer(tree2);
+      if(!ISARITH(tree2->ntyp->flags)&&!ISPOINTER(tree2->ntyp->flags)){
+	error(142);
+	cexpr=-1;
+      }else{
+	if(tree2->flags==ASSIGN&&tree2->right->flags!=CALL) error(164);
+	if(tree2->flags==CEXPR){
+	  eval_const(&tree2->val,tree2->ntyp->flags);
+	  if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) cexpr=1; else cexpr=2;
+	  if(cexpr==1) error(152);
+	}
+      }
+    }else cexpr=-1;
+  }
+  lloop=++label;lin=++label;lout=++label;cm=nocode;
+  contm=cont_label;breakm=break_label;
+  cont_label=++label;break_label=lout;
+  if(!cexpr||(tree2&&tree2->sidefx)){
+    if(c_flags_val[0].l&2){ /*  bei Optimierung */
+      if(tvalid){
+	gen_IC(tree2,lloop,lout);
+	if(tree2->o.flags){
+	  gen_test(&tree2->o,tree2->ntyp->flags,BEQ,lout);
+#if 0
+	  new=new_IC();
+	  new->code=TEST;
+	  new->typf=tree2->ntyp->flags;
+	  new->q1=tree2->o;
+	  new->q2.flags=new->z.flags=0;
+	  add_IC(new);
+	  new=new_IC();
+	  new->code=BEQ;
+	  new->typf=lout;
+	  add_IC(new);
+#endif
+	}
+	repair_tree(tree2);
+      }
+    }else{
+      new=new_IC();
+      new->code=BRA;
+      new->typf=lin;
+      new->flags|=LOOP_COND_TRUE;
+      add_IC(new);
+    }
+  }
+  if(cexpr==1){
+    new=new_IC();
+    new->code=BRA;
+    new->typf=lout;
+    add_IC(new);
+  }else{
+    gen_label(lloop);
+    last_ic->flags|=LOOP_COND_TRUE;
+  }
+  line=last_ic->line;file=last_ic->file;
+  cm=nocode;
+  if(cexpr==1) nocode=1;
+  currentpri*=looppri;
+  {
+    int merk_sb=switchbreak;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    switchbreak=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+    statement();
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    switchbreak=merk_sb;
+  }
+  mic=last_ic;
+  nocode=cm;
+  gen_label(cont_label);
+  cont_label=contm;break_label=breakm;
+  if(tree3){
+    if(tree3->flags==POSTINC) tree3->flags=PREINC;
+    if(tree3->flags==POSTDEC) tree3->flags=PREDEC;
+    if(tree3->sidefx){
+      gen_IC(tree3,0,0);
+      if(tree3&&(tree3->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree3->o.reg);
+    }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+		error(153);}
+    free_expression(tree3);
+  }
+  if(!cexpr||(tree2&&tree2->sidefx)) gen_label(lin);
+  if(tree2&&cexpr>=0){
+    if(cexpr!=1||tree2->sidefx){
+      gen_IC(tree2,lloop,lout);
+      if((tree2->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&cexpr) free_reg(tree2->o.reg);
+    }
+    if(tree2->o.flags&&!cexpr){
+      gen_test(&tree2->o,tree2->ntyp->flags,BNE,lloop);
+#if 0
+      new=new_IC();
+      new->code=TEST;
+      new->typf=tree2->ntyp->flags;
+      new->q1=tree2->o;
+      new->q2.flags=new->z.flags=0;
+      add_IC(new);
+      new=new_IC();
+      new->code=BNE;
+      new->typf=lloop;
+      add_IC(new);
+#endif
+    }
+    if(cexpr==2){
+      new=new_IC();
+      new->code=BRA;
+      new->typf=lloop;
+      add_IC(new);
+    }
+  }
+  if(!tree2&&cexpr==2){
+    new=new_IC();
+    new->code=BRA;
+    new->typf=lloop;
+    add_IC(new);
+  }
+  if(tree2) free_expression(tree2);
+  for(mic=mic->next;mic;mic=mic->next){
+    mic->line=line;mic->file=file;
+  }
+  gen_label(lout);
+  currentpri/=looppri;
+  cr();
+  if(with_decl)
+    leave_block();
+}
+void do_statement(void)
+/*  bearbeitet do_statement                                     */
+{
+  np tree;int lloop,lout,contm,breakm;
+  IC *new;
+  lloop=++label;lout=++label;currentpri*=looppri;
+  gen_label(lloop);
+  breakm=break_label;contm=cont_label;cont_label=++label;break_label=lout;
+  {
+    int merk_sb=switchbreak;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    switchbreak=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+    statement();
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    switchbreak=merk_sb;
+  }
+  killsp();
+  gen_label(cont_label);cont_label=contm;break_label=breakm;
+  if(ctok->type!=NAME||strcmp("while",ctok->name)) error(154);
+  next_token();killsp();
+  if(ctok->type==LPAR) {next_token();killsp();} else error(151);
+  tree=expression();
+  if(tree){
+    simple_alg_opt(tree);
+    if(type_expression(tree,andcomp(tree,0))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      tree=makepointer(tree);
+      if(ISARITH(tree->ntyp->flags)||ISPOINTER(tree->ntyp->flags)){
+	if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+	if(tree->flags==CEXPR){
+	  eval_const(&tree->val,tree->ntyp->flags);
+	  if(tree->sidefx) gen_IC(tree,0,0);
+	  if(!zldeqto(vldouble,d2zld(0.0))){
+	    new=new_IC();
+	    new->code=BRA;
+	    new->typf=lloop;
+	    add_IC(new);
+	  }
+	}else{
+	  gen_IC(tree,lloop,lout);
+	  if(tree->o.flags){
+	    gen_test(&tree->o,tree->ntyp->flags,BNE,lloop);
+#if 0
+	    new=new_IC();
+	    new->code=TEST;
+	    new->typf=tree->ntyp->flags;
+	    new->q1=tree->o;
+	    new->q2.flags=new->z.flags=0;
+	    add_IC(new);
+	    new=new_IC();
+	    new->code=BNE;
+	    new->typf=lloop;
+	    add_IC(new);
+#endif
+	  }
+	}
+      }else error(143);
+    }
+    free_expression(tree);
+  }
+  killsp();
+  if(ctok->type==RPAR) {next_token();killsp();} else error(59);
+  if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+  gen_label(lout);
+  currentpri/=looppri;
+  cr();
+}
+void goto_statement(void)
+/*  bearbeitet goto_statement                                   */
+{
+  llist *lp;
+  IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+  killsp();
+  if(ctok->type!=NAME){
+    error(144);
+  }else{
+    if(is_keyword(ctok->name)) error(216,ctok->name);
+    lp=find_label(ctok->name);
+    if(!lp){
+      lp=add_label(ctok->name);
+      lp->switch_count=0;
+    }
+    lp->flags|=LABELUSED;
+    new=new_IC();
+    new->typf=lp->label;
+    new->code=BRA;
+    new->typf=lp->label;
+    add_IC(new);
+    next_token();
+    killsp();
+    if(ctok->type==SEMIC){next_token();killsp();} else error(54);
+    cr();
+    goto_used=1;
+  }
+}
+void continue_statement(void)
+/*  bearbeitet continue_statement                               */
+{
+  IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+  if(cont_label==0){error(145);return;}
+  //if(block_vla[nesting]) freevl();
+  new=new_IC();
+  new->code=BRA;
+  new->typf=cont_label;
+  add_IC(new);
+  killsp();
+  if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+  cr();
+}
+void break_statement(void)
+/*  bearbeitet break_statement                                  */
+{
+  IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+  if(break_label==0){error(146);return;}
+  //if(block_vla[nesting]) freevl();
+  new=new_IC();
+  new->code=BRA;
+  new->typf=break_label;
+  add_IC(new);
+  killsp();
+  if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+  cr();
+}
+static void check_auto_return(np tree)
+/*  Testet, ob Knoten Adresse einer automatischen Variable ist. */
+{
+  if((tree->flags==ADDRESS||tree->flags==ADDRESSS||tree->flags==ADDRESSA)&&tree->left->flags==IDENTIFIER){
+    Var *v;
+    if(v=find_var(tree->left->identifier,0)){
+      if(v->storage_class==AUTO) error(224);
+    }
+  }
+}
+extern int has_return;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+void return_statement(void)
+/*  bearbeitet return_statement                                 */
+/*  SETRETURN hat Groesse in q2.reg und z.reg==ffreturn(rtyp)    */
+{
+  np tree;
+  IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+  has_return=1;
+  killsp();
+  if(ctok->type!=SEMIC){
+    if(tree=expression()){
+      if(!return_typ){
+	if(type_expression(tree,0)){
+	  tree=makepointer(tree);
+	  if((tree->ntyp->flags&NQ)!=VOID)
+	    error(155);
+	  else{
+	    error(225);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	  }
+	  gen_IC(tree,0,0);
+	  if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree->o.reg);
+	}
+      }else{
+	if(type_expression(tree,return_typ)){
+	  tree=makepointer(tree);
+	  if(tree->flags==ADD||(tree->flags==SUB&&ISPOINTER(tree->ntyp->flags))){
+	    check_auto_return(tree->left);
+	    check_auto_return(tree->right);
+	  }else{
+	    check_auto_return(tree);
+	  }
+	  if(!test_assignment(return_typ,tree)){free_expression(tree);return;}
+	  gen_IC(tree,0,0);
+	  convert(tree,return_typ->flags);
+#ifdef OLDPARMS   /*  alte CALL/RETURN-Methode    */
+	  new=new_IC();
+	  new->code=ASSIGN;
+	  new->typf=return_typ->flags&NU;
+	  new->q1=tree->o;
+	  new->q2.flags=0;
+	  new->q2.val.vmax=szof(return_typ);
+	  if(ffreturn(return_typ)){
+	    new->z.flags=SCRATCH|REG;
+	    new->z.reg=ffreturn(return_typ);
+	    if(!regs[new->z.reg]){
+	      IC *alloc=new_IC();
+	      alloc->code=ALLOCREG;
+	      alloc->q1.flags=REG;
+	      alloc->q2.flags=alloc->z.flags=0;
+	      alloc->q1.reg=new->z.reg;
+	      regs[new->z.reg]=1;
+	      add_IC(alloc);
+	    }
+	  }else{
+	    new->z.reg=0;
+	    new->z.v=return_var;
+	    new->z.flags=SCRATCH|VAR;
+	    new->z.val.vmax=l2zm(0L);
+	  }
+	  add_IC(new);
+	  /*  das hier ist nicht sehr schoen, aber wie sonst? */
+	  if((new->z.flags&(SCRATCH|REG))==(SCRATCH|REG)&&regs[new->z.reg]) free_reg(new->z.reg);
+#else
+	  new=new_IC();
+	  if(return_var){ /*  Returnwert ueber Zeiger */
+	    new->code=ASSIGN;
+	    new->z.flags=VAR|DREFOBJ;
+	    new->z.dtyp=POINTER_TYPE(return_typ);
+	    new->z.val.vmax=l2zm(0L);
+	    new->z.v=return_var;
+	    new->z.reg=0;
+	  }else{
+	    new->code=SETRETURN;
+	    new->z.reg=ffreturn(return_typ);
+	    new->z.flags=0;
+	  }
+	  new->typf=return_typ->flags;
+	  /*new->typf=tree->ntyp->flags;*/
+	  new->q1=tree->o;
+	  new->q2.flags=0;
+	  new->q2.val.vmax=szof(return_typ);
+	  add_IC(new);
+#endif
+	}
+      }
+      free_expression(tree);
+      killsp();
+      if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+    }else{
+      if(return_typ) error(156);
+    }
+  }else{ 
+    next_token(); 
+    if(return_typ) error(156);
+  }
+  new=new_IC();
+  new->code=BRA;
+  new->typf=return_label;
+  add_IC(new);
+  cr();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+}
+
+void expression_statement(void)
+/*  bearbeitet expression_statement                             */
+{
+  np tree;
+  killsp();
+  if(ctok->type==SEMIC){
+    int oline=ctok->line;
+    next_token();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    return;
+  }
+  if(tree=expression()){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    if(tree->flags==POSTINC) tree->flags=PREINC;
+    if(tree->flags==POSTDEC) tree->flags=PREDEC;
+    if(type_expression(tree,0)){
+      if(DEBUG&2){
+	pre(stdout,tree);
+	printf("\n");
+      }
+      if(tree->sidefx){
+	gen_IC(tree,0,0);
+	if((tree->o.flags&(SCRATCH|REG))==REG) ierror(0);
+	if(tree&&(tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree->o.reg);
+      }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	error(153);
+	if(DEBUG&2) prd(stdout,tree->ntyp);
+      }
+    }
+    free_expression(tree);
+  }
+  killsp();
+  if(ctok->type==SEMIC) next_token(); else error(54);
+  cr();
+}
+void compound_statement(void)
+/*  bearbeitet compound_statement (block)                       */
+{
+  killsp();
+  if(ctok->type==LBRA) next_token(); else error(157);
+  if(c99||ecpp){
+    killsp();
+    while(ctok->type!=RBRA){
+      if(declaration(0))
+	var_declaration();
+      else
+	statement();
+      killsp();
+    }
+  }else{
+    killsp();
+    while(declaration(0)){
+      var_declaration();
+      killsp();
+    }
+    while(ctok->type!=RBRA){
+      statement();
+      killsp();
+    }
+  }
+  next_token();/*killsp();*/
+}
+llist *add_label(char *identifier)
+/*  Fuegt label in Liste                                        */
+{
+  llist *new;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  new=mymalloc(LSIZE);
+  new->next=0;new->label=++label;new->flags=0;
+  new->identifier=add_identifier(identifier,strlen(identifier));
+  if(first_llist==0){
+    first_llist=last_llist=new;
+  }else{
+    last_llist->next=new;
+    last_llist=new;
+  }
+  return last_llist; /* return(new) sollte aequiv. sein */
+}
+llist *find_label(char *identifier)
+/*  Sucht Label, gibt Zeiger auf llist oder 0 bei Fehler zurueck    */
+{
+  llist *p;
+  p=first_llist;
+  while(p){
+    if(!strcmp(p->identifier,identifier)) return p;
+    p=p->next;
+  }
+  return 0;
+}
+void free_llist(llist *p)
+/*  Gibt llist frei                                             */
+
+{
+  llist *merk;
+  while(p){
+    merk=p->next;
+    if(!(p->flags&LABELDEFINED)) error(147,p->identifier);
+    if(!(p->flags&LABELUSED)&&!p->switch_count) error(148,p->identifier);
+    free(p);
+    p=merk;
+  }
+}
diff --git a/supp.c b/supp.c
new file mode 100644
index 0000000..fd10032
--- /dev/null
+++ b/supp.c
@@ -0,0 +1,2012 @@
+/*  $VER: vbcc (supp.c) $Revision: 1.49 $     */
+
+#include "supp.h"
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+#ifndef HAVE_EXT_TYPES
+char *typname[]={"strange","char","short","int","long","long long",
+                 "float","double","long double","void",
+                 "pointer","array","struct","union","enum","function",
+                 "bool","vector"};
+#endif
+
+char *storage_class_name[]={"strange","auto","register","static","extern","typedef"};
+
+char *ename[]={"strange","sequence","move","set+","set-","set*","set/","set%",
+               "set&","set^","set|","set<<","set>>","?:","lor","land","or",
+               "eor","and","eq","neq","lt","le","gt","ge","lsl",
+               "lsr","add","sub","mul","div","mod","negate",
+               "not","preinc","postinc","predec","postdec","neg",
+               "dref-pointer","address-of","cast","call","index",
+               "dref-struct-pointer","dref-struct","identifier","constant",
+               "string","member",
+                "convert","convert-short","convert-int","convert-long",
+                "convert-float","convert-double","convert-void","convert-pointer",
+                "convert-uchar","convert-ushort","convert-uint","convert-ulong",
+                "address-of-array","first-element-of-array","pmult",
+                "allocreg","freereg","pconstant","test","label","beq","bne",
+                "blt","bge","ble","bgt","bra","compare","push","pop",
+                "address-of-struct","add-int-to-pointer","sub-int-from-pointer",
+                "sub-pointer-from-pointer","push-reg","pop-reg","pop-args",
+                "save-regs","restore-regs","identifier-label","dc","align",
+                "colon","get-return","set-return","move-from-reg","move-to-reg",
+                "nop","bitfield"};
+
+char *empty="";
+zchar vchar; zuchar vuchar;
+zshort vshort; zushort vushort;
+zint vint; zuint vuint;
+zlong vlong; zulong vulong;
+zllong vllong; zullong vullong;
+zmax vmax; zumax vumax;
+zfloat vfloat; zdouble vdouble;
+zldouble vldouble;
+
+union atyps gval;
+
+#ifndef DEBUG
+int DEBUG;
+#endif
+
+int label;
+
+int regs[MAXR+1],regused[MAXR+1],simple_scratch[MAXR+1];
+Var *regsv[MAXR+1];
+int goto_used;
+int ic_count;
+zmax max_offset;
+int function_calls,vlas;
+int coloring;
+int dmalloc;
+int disable;
+int multiple_ccs;
+int lastlabel,return_label;
+int only_inline;
+IC *err_ic;
+long maxoptpasses=30;
+long optflags;
+int optsize,optspeed,unroll_all,stack_check;
+int cross_module,final,no_emit;
+int debug_info;
+long inline_size=100;
+long inline_depth=1;
+long unroll_size=200;
+long clist_copy_stack=6;
+long clist_copy_static=6;
+long clist_copy_pointer=20;
+long inline_memcpy_sz=INLINEMEMCPY;
+int fp_assoc,noaliasopt,noitra;
+char *filename;
+IC *first_ic,*last_ic;
+int float_used;
+bvtype regs_modified[RSIZE/sizeof(bvtype)];
+/*  Das haette ich gern woanders    */
+Var *vl0,*vl1,*vl2,*vl3;
+int align_arguments=1;
+zmax stackalign;
+int misracheck,misraversion,misracomma,misratok;
+int pack_align;
+int short_push;
+int default_unsigned;
+Var *add_attr_haddecl;
+
+char *emit_buffer[EMIT_BUF_DEPTH];
+char *emit_p;
+int emit_f,emit_l;
+int no_inline_peephole;
+
+static int get_scalar_byte(int f,union atyps *v,zmax n, zuchar *out)
+/* Yields byte n of a constant */
+{
+  if(!zmleq(l2zm(0L),n)) ierror(0);
+  f&=NQ;
+  if(f>=CHAR&&f<=LLONG){
+    int j;
+    eval_const(v,f);
+    if(LITTLEENDIAN)
+      j=zm2l(n);
+    else
+      j=(int)sizetab[f]-(int)zm2l(n)-1;
+    while(j){
+      vumax=zumrshift(vumax,char_bit);
+      j--;
+    }
+    *out=zum2zuc(vumax);
+    return 1;
+  }else
+    return 0;
+}
+
+zumax get_clist_int(type *t, const_list *cl, zmax n, int sz,int *state)
+/* yields an integer of size sz from offset n */
+{
+  zuchar zuc;
+  zumax val = ZU0;
+
+  if(LITTLEENDIAN)
+    n=zmadd(n,l2zm((long)(sz-1)));
+  
+  while(sz){
+    val=zumlshift(val,char_bit);
+    if(!get_clist_byte(t,cl,n,&zuc)) {*state=0;return ZU0;}
+    val=zumadd(val,zuc2zum(zuc));
+    sz--;
+    n=LITTLEENDIAN?zmsub(n,Z1):zmadd(n,Z1);
+  }
+  *state=1;
+  return val;
+}
+
+int get_clist_byte(type *t,const_list *cl, zmax n, zuchar *out)
+/* Yields byte n from a const list */
+{
+  if(!cl){
+    *out=zum2zuc(ul2zum(0UL));
+    return 1;
+  }
+
+  if(ISARRAY(t->flags)){
+    zmax i,j,x;
+    x=szof(t->next);
+    i=zmdiv(n,x);
+    while(1){
+      if(!cl) break;
+      if(zmleq(i,cl->idx)) break;
+      cl=cl->next;
+    }
+    if(!cl||!zmeqto(cl->idx,i)){
+      *out=zum2zuc(ul2zum(0UL));
+      return 1;
+    }
+    return get_clist_byte(t->next,cl->other,zmmod(n,x),out);
+  }
+  if(ISUNION(t->flags)){
+    int i=zm2l(cl->idx);
+    if(cl->tree) return 0;
+    return get_clist_byte((*t->exact->sl)[i].styp,cl->other,n,out);
+  }
+  if(ISSTRUCT(t->flags)){
+    zmax al;int fl;type *st;
+    int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL);
+
+    sz=l2zm(0L);
+    if(cl&&cl->tree){
+      /* initialized by another */
+      return 0;
+    }else{
+      for(i=0;i<t->exact->count&&cl;i++){
+	if(!cl->other){ierror(0);}
+	st=(*t->exact->sl)[i].styp;
+	al=(*t->exact->sl)[i].align;
+	if(!(*t->exact->sl)[i].identifier) ierror(0);
+	bfo=(*t->exact->sl)[i].bfoffset;
+	if(!zmeqto(zmmod(sz,al),l2zm(0L))){
+	  sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
+	  if(!zmleq(sz,n)){
+	    *out=zum2zuc(ul2zum(0L));
+	    return 1;
+	  }
+	}
+	if(bfo>=0){
+	  /* bitfield */
+
+	  if((*t->exact->sl)[i].identifier[0]){
+	    bfs=(*t->exact->sl)[i].bfsize;
+	    if(zmeqto(l2zm((long)i),cl->idx)){
+	      eval_const(&cl->other->val,st->flags);
+	      cl=cl->next;
+	    }else{
+	      vumax=ul2zum(0UL);
+	    }
+	    vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL)));
+	    bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags))));
+	  }          
+	  if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
+	    /* last bitfield in integer */
+	    gval.vumax=bfval;
+	    eval_const(&gval,UNSIGNED|MAXINT);
+	    insert_const(&gval,st->flags&NU);
+	    bfval=ul2zum(0L);
+	    sz=zmadd(sz,szof(st));
+	    if(!zmleq(sz,n))
+	      return get_scalar_byte(st->flags,&gval,zmsub(n,zmsub(sz,szof(st))),out);
+	  }
+	}else{
+	  sz=zmadd(sz,szof(st));
+	  if(!zmleq(sz,n)){
+	    if(zmeqto(l2zm((long)i),cl->idx)){
+	      return get_clist_byte(st,cl->other,zmsub(n,zmsub(sz,szof(st))),out);
+	    }else{
+	      *out=zum2zuc(ul2zum(0UL));
+	      return 1;
+	    }
+	  }
+	  if(zmeqto(l2zm((long)i),cl->idx))
+	    cl=cl->next;
+	}
+      }
+    }
+    *out=zum2zuc(ul2zum(0UL));
+    return 1;
+  }
+
+  if(zmeqto(cl->idx,l2zm(-1L)))
+    return 0;
+  else{
+    if(cl->tree)
+      return 0;
+    else
+      return get_scalar_byte(t->flags,&cl->val,n,out);
+
+  }
+  ierror(0);
+}
+
+type *new_typ(void)
+/*  Erzeigt neuen (leeren) Typ.  */
+{
+  type *new=mymalloc(TYPS);
+  new->flags=0;
+  new->next=0;
+  new->exact=0;
+  new->attr=0;
+  new->dsize=0;
+  new->reg=0;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+  return new;
+}
+
+type *clone_typ(type *old)
+/*  Erzeugt Kopie eines Typs und liefert Zeiger auf Kopie.  */
+{
+  type *new;
+  if(!old) return 0;
+  new=new_typ();
+  *new=*old;
+  if(old->attr){
+    new->attr=mymalloc(strlen(old->attr)+1);
+    strcpy(new->attr,old->attr);
+  }
+  if(new->next) new->next=clone_typ(new->next);
+  return new;
+}
+Var *new_var(void)
+{
+  Var *new=mymalloc(sizeof(*new));
+  new->clist=0;
+  new->vtyp=0;
+  new->storage_class=0;
+  new->reg=0;
+  new->vattr=0;
+  new->next=0;
+  new->flags=0;
+  new->fi=0;
+  new->nesting=0;
+  new->filename=0;
+  new->line=0;
+  new->dfilename=0;
+  new->dline=0;
+  new->description=0;
+  new->tunit=0;
+  new->offset=l2zm(0L);
+  new->identifier=0;
+#ifdef HAVE_TARGET_ATTRIBUTES
+  new->tattr=0;
+#endif 
+#ifdef ALEX_REG
+  new->iRegCopyNr = -1;
+  new->iRegCopyNrHc12V = -1;
+#endif
+  return new;
+}  
+
+IC *new_IC(void)
+{
+  IC *p=mymalloc(ICS);
+  p->change_cnt=0;
+  p->use_cnt=0;
+  p->call_cnt=0;
+  p->arg_cnt=0;
+  p->use_list=0;
+  p->change_list=0;
+  p->call_list=0;
+  p->arg_list=0;
+  p->line=0;
+  p->file=0;
+  p->flags=0;
+  p->q1.flags=p->q2.flags=p->z.flags=0;
+  p->q1.am=p->q2.am=p->z.am=0;
+  p->q1.val.vmax=p->q2.val.vmax=p->z.val.vmax=l2zm(0L);
+  p->savedsp=0;
+  p->typf=p->typf2=0;
+#ifdef ALEX_REG
+  p->iZWebIndex = -1;
+  p->iQ1WebIndex = -1;
+  p->iQ2WebIndex = -1;
+  p->pFlow = NULL;
+#endif /* GC_RALLOC */
+
+  return p;
+}
+/* (partially) clones an IC list */
+IC *clone_ic(IC *p)
+{
+  IC *new,*first,*last;
+  first=last=new=0;
+  while(p){
+    new=mymalloc(sizeof(*new));
+    *new=*p;
+    p->copy=new;
+
+    if(p->q1.am||p->q2.am||p->z.am) ierror(0);
+    
+    if(new->code==CALL){
+      int i;
+      new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+      for(i=0;i<new->arg_cnt;i++){
+	if(!p->arg_list[i])
+	  ierror(0);
+	if(!p->arg_list[i]->copy)
+	  ierror(0);
+        new->arg_list[i]=p->arg_list[i]->copy;
+      }
+    }
+    new->prev=last;
+    new->next=0;
+    if(!first) first=new;
+    if(last) last->next=new;
+    last=new;
+    p=p->next;
+  }
+  return first;
+}    
+void free_IC(IC *p)
+/*  Gibt IC-Liste inkl. Typen frei.                 */
+{
+  IC *merk;
+  if(DEBUG&1) printf("free_IC()\n");
+  while(p){
+    /*if(p->q1.am&&!p->q1.flags) ierror(0);
+    if(p->q2.am&&!p->q2.flags) ierror(0);
+    if(p->z.am&&!p->z.flags) ierror(0);*/
+
+    if(p->q1.am&&p->q1.am==p->q2.am)
+      ierror(0);
+
+    if(p->q1.am) free(p->q1.am);
+    if(p->q2.am) free(p->q2.am);
+    if(p->z.am) free(p->z.am);
+    if(p->code==CALL) free(p->arg_list);
+    merk=p->next;
+    free(p);
+    p=merk;
+  }
+}
+void move_IC(IC *after,IC *p)
+{
+  if(p->prev)
+    p->prev->next=p->next;
+  else
+    first_ic=p->next;
+  if(p->next)
+    p->next->prev=p->prev;
+  else
+    last_ic=p->prev;
+  insert_IC(after,p);
+}
+void remove_IC(IC *p)
+/*  Entfernt IC p aus Liste. */
+{
+  if(p->prev) p->prev->next=p->next; else first_ic=p->next;
+  if(p->next) p->next->prev=p->prev; else last_ic=p->prev;
+  if(p->q1.am) free(p->q1.am);
+  if(p->q2.am) free(p->q2.am);
+  if(p->z.am) free(p->z.am);
+  free(p);
+}
+void freetyp(type *p)
+/* Gibt eine Typ-Liste frei, aber keine struct_declaration oder so. */
+{
+  int f;type *merk;
+  if(DEBUG&8){printf("freetyp: ");prd(stdout,p);printf("\n");}
+  while(p){
+    merk=p->next;
+    f=p->flags&NQ;
+    if(merk&&!ISARRAY(f)&&!ISPOINTER(f)&&!ISFUNC(f)&&!ISVECTOR(f)) 
+      ierror(0);
+    free(p->attr);
+    free(p);
+    p=merk;
+  }
+}
+
+#ifndef HAVE_TGT_FALIGN
+zmax falign(type *t)
+/*  Liefert Alignment eines Typs. Funktioniert im Gegensatz zum  */
+/*  align[]-Array auch mit zusammengesetzten Typen.              */
+{
+  int i,f; zmax al,alt;
+  f=t->flags&NQ;
+  if(ISVECTOR(f)) return szof(t);
+  al=align[f];
+  if(ISSCALAR(f)) return al;
+  if(ISARRAY(f)){
+    do{ 
+      t=t->next; 
+      f=t->flags&NQ;
+    }while(ISARRAY(f)||ISVECTOR(f));
+    alt=falign(t);
+    if(zmleq(al,alt)) return alt; else return al;
+  }
+  if(ISUNION(f)||ISSTRUCT(f)){
+    if(!t->exact) ierror(0);
+    for(i=0;i<t->exact->count;i++){
+      alt=(*t->exact->sl)[i].align;
+      if(!zmleq(alt,al)) al=alt;
+    }
+  }
+  return al;
+}
+#endif
+
+/* check, whether t is a variable length array */
+int is_vlength(type *t)
+{
+  if(!ISARRAY(t->flags))
+    return 0;
+  if(t->dsize)
+    return 1;
+  else 
+    return is_vlength(t->next);
+}
+
+/* calculate size of a variable length array */
+Var *vlength_szof(type *t)
+{
+  IC *new;type *nt;
+  if(!ISARRAY(t->flags))
+    ierror(0);
+  new=new_IC();
+  new->code=MULT;
+  new->typf=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG);
+  if(t->dsize){
+    new->q1.flags=VAR;
+    new->q1.v=t->dsize;
+    new->q1.val.vmax=l2zm(0L);
+  }else{
+    new->q1.flags=KONST;
+#if HAVE_INT_SIZET
+    new->q1.val.vuint=zum2zui(zm2zum(t->size));
+#else
+    new->q1.val.vulong=zum2zul(zm2zum(t->size));
+#endif
+  }
+  new->z.flags=VAR;
+  nt=new_typ();
+  nt->flags=new->typf;
+  new->z.v=add_tmp_var(nt);
+  new->z.val.vmax=l2zm(0L);
+  if(is_vlength(t->next)){
+    new->q2.flags=VAR;
+    new->q2.v=vlength_szof(t->next);
+    new->q2.val.vmax=l2zm(0L);
+  }else{
+    new->q2.flags=KONST;
+#if HAVE_INT_SIZET
+    new->q2.val.vuint=zum2zui(zm2zum(szof(t->next)));
+#else
+    new->q2.val.vulong=zum2zul(zm2zum(szof(t->next)));
+#endif
+  }
+  add_IC(new);
+  return new->z.v;
+}
+
+/* return the type of a d-dim vector of base type x */
+int mkvec(int x,int d)
+{
+  int t=x&NQ,r;
+  if(d!=2&&d!=3&&d!=4&&d!=8&&d!=16) ierror(0);
+  switch(t){
+  case BOOL:
+    r=VECBOOL;break;
+  case CHAR:
+    r=VECCHAR;break;
+  case SHORT:
+    r=VECSHORT;break;
+  case INT:
+    r=VECINT;break;
+  case LONG:
+    r=VECLONG;break;
+  case FLOAT:
+    r=VECFLOAT;break;
+  default:
+    ierror(0);
+  }
+  return (r+d-1)|(x&~NQ);
+}
+
+/* return the base type of a vector */
+int VECTYPE(int x)
+{
+  int t=x&NQ,r=0;
+  if(t>=VECBOOL&&t<=VECBOOL+MAXVECDIM)
+    r=BOOL;
+  if(t>=VECCHAR&&t<=VECCHAR+MAXVECDIM)
+    r=CHAR;
+  if(t>=VECSHORT&&t<=VECSHORT+MAXVECDIM)
+    r=SHORT;
+  if(t>=VECINT&&t<=VECINT+MAXVECDIM)
+    r=INT;
+  if(t>=VECLONG&&t<=VECLONG+MAXVECDIM)
+    r=LONG;
+  if(t>=VECFLOAT&&t<=VECFLOAT+MAXVECDIM)
+    r=FLOAT;
+  if(!r) ierror(0);
+  return r|(x&~NQ);
+}
+
+
+#ifndef HAVE_TGT_SZOF
+zmax szof(type *t)
+/*  Liefert die benoetigte Groesse eines Typs in Bytes.     */
+{
+  int i=t->flags&NQ,j;zmax size,m;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+
+  if(ISSCALAR(i)) return sizetab[i];
+  if(ISARRAY(i)){
+    if(is_vlength(t))
+      return sizetab[POINTER_TYPE(t->next)];
+    size=zmmult((t->size),szof(t->next));
+    m=align[ARRAY];
+    return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
+  }
+  if(ISVECTOR(i)){
+    zmax dim=VECDIM(i);
+    if(zmeqto(dim,l2zm(3L))) dim=l2zm(4L);
+    return zmmult(dim,sizetab[VECTYPE(i)&NQ]);
+  }
+  if(ISUNION(i)){
+    for(j=0,size=l2zm(0L);j<t->exact->count;j++){
+      m=szof((*t->exact->sl)[j].styp);
+      if(zmeqto(m,l2zm(0L))) return l2zm(0L);
+      if(!zmleq(m,size)) size=m;
+    }
+    m=falign(t);
+    return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
+  }
+  if(ISSTRUCT(i)){
+    size=l2zm(0L);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    for(j=0;j<t->exact->count;j++){
+      type *h=(*t->exact->sl)[j].styp;
+      if((*t->exact->sl)[j].bfoffset<=0){
+	int n;size_t al;
+        al=(*t->exact->sl)[j].align;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+        if(zmeqto(al,l2zm(0L))) {prd(stdout,h);ierror(0);}
+        m=szof(h);
+	/* find the largest type in a bitfield */
+	for(n=j+1;n<t->exact->count&&(*t->exact->sl)[n].bfoffset>0;n++){
+	  size_t tmp=szof((*t->exact->sl)[n].styp);
+	  if(zmleq(m,tmp))
+	    m=tmp;
+	}
+        size=zmmult(zmdiv(zmadd(size,zmsub(al,l2zm(1L))),al),al);
+        /*if(zmeqto(m,l2zm(0L))) return l2zm(0L);*/
+        size=zmadd(size,m);
+      }
+    }
+    m=falign(t);
+    return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
+  }
+  return sizetab[i];
+}
+zmax struct_offset(struct_declaration *sd,const char *identifier)
+{
+  int i=0,intbitfield=-1;zmax offset=l2zm(0),al;
+  while(i<sd->count&&strcmp((*sd->sl)[i].identifier,identifier)){
+    if((*sd->sl)[i].bfoffset>=0){
+      if(i+1<sd->count&&(*sd->sl)[i+1].bfoffset>0){
+        i++;
+        continue;
+      }
+    }
+    al=(*sd->sl)[i].align;
+    offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
+    offset=zmadd(offset,szof((*sd->sl)[i].styp));
+    i++;
+  }
+  if(i>=sd->count) {error(23,identifier);return l2zm(0L);}
+  al=(*sd->sl)[i].align;
+  offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
+  return offset;
+}
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#endif
+
+#ifndef HAVE_TGT_PRINTVAL
+void printval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+  if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+  if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);}
+  if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);}
+  /*FIXME*/
+  if(t==POINTER){fprintf(f,"P");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+}
+void emitval(FILE *f,union atyps *p,int t)
+/*  Gibt atyps aus.                                     */
+{
+  t&=NU;
+  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+  if(t==LDOUBLE){emitzld(f,p->vldouble);}
+  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+  if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+  if(t==MAXINT){emitzm(f,p->vmax);}
+  if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);}
+  /*FIXME*/
+  if(t==POINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+}
+#endif
+
+void pric2(FILE *f,IC *p)
+/*  Gibt ein IC aus.  */
+{
+  if(p->code>NOP) ierror(0);
+  if(p->next&&p->next->prev!=p) ierror(0);
+  if(p->code>=LABEL&&p->code<=BRA){
+    if(p->code==LABEL)
+      fprintf(f,"L%d",p->typf);
+    else{
+      fprintf(f,"\t%s L%d",ename[p->code],p->typf);
+      if(p->q1.flags){ fprintf(f,",");probj(f,&p->q1,0);}
+    }
+    if(p->code==LABEL&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (while-loop)");
+    if(p->code==BRA&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (to-loop-test)");
+  }else{
+    fprintf(f,"\t%s ",ename[p->code]);
+    if(p->typf&VOLATILE) fprintf(f,"volatile ");
+    if(p->typf&CONST) fprintf(f,"const ");
+    if(p->typf&UNSIGNED) fprintf(f,"unsigned ");
+    if(p->typf){
+      if(ISVECTOR(p->typf))
+	fprintf(f,"%s%d ",typname[VECTYPE(p->typf)&NQ],VECDIM(p->typf));
+      else
+	fprintf(f,"%s ",typname[p->typf&NQ]);
+    }
+    probj(f,&p->q1,q1typ(p));
+    if(p->q2.flags){fprintf(f,",");probj(f,&p->q2,q2typ(p));}
+    if(p->z.flags){fprintf(f,"->");probj(f,&p->z,ztyp(p));}
+    if(p->code==ASSIGN||p->code==PUSH||p->code==POP||p->code==CALL)
+      fprintf(f," size=%ld",zm2l(p->q2.val.vmax));
+    if((p->code==SAVEREGS||p->code==RESTOREREGS)&&p->q1.reg)
+      fprintf(f," except %s",regnames[p->q1.reg]);
+    if(p->code==CONVERT)
+      fprintf(f," from %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
+    if(p->code==LSHIFT||p->code==RSHIFT)
+      fprintf(f," shift-type %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
+    if(p->code==ADDI2P||p->code==SUBIFP||p->code==SUBPFP||p->code==ADDRESS)
+      fprintf(f," ptype=%s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
+    if(p->code==ASSIGN||p->code==PUSH)
+      if(p->typf2) fprintf(f," align=%d\n",p->typf2);
+  }
+  if(p->code==CALL){
+    fprintf(f," =>");
+    if(p->call_cnt==0)
+      fprintf(f,"(unknown)");
+    else{
+      int i;
+      for(i=0;i<p->call_cnt;i++)
+        fprintf(f," %s",p->call_list[i].v->identifier);
+    }
+    
+  }
+  if(p->flags&EFF_IC) fprintf(f," (eff_ic)");
+  fprintf(f,"\n");
+#if 0
+  if(p->code==CALL){
+    int i;
+    //fprintf(f,"c=%p\n",p);
+    for(i=0;i<p->arg_cnt;i++){
+      //fprintf(f,"%p!\n",p->arg_list[i]);
+      fprintf(f,"%02d:",i);
+      pric2(f,p->arg_list[i]);
+    }
+  }
+#endif
+}
+void pric(FILE *f,IC *p)
+/*  Gibt IC-Liste auf dem Bildschirm aus.             */
+{
+  while(p){
+    pric2(f,p);
+/*        if(p->q1.am||p->q2.am||p->z.am) ierror(0);*/
+    p=p->next;
+  }
+}
+void printzm(FILE *f,zmax x)
+/*  Konvertiert zmax nach ASCII.                       */
+/*  Basiert noch einigermassen auf                      */
+/*  Zweierkomplementdarstellung (d.h. -MIN>MAX).        */
+/*  Ausserdem muss max(abs(max))<=max(unsigned max).  */
+{
+  zmax zm;zumax zum;
+  zm=l2zm(0L);
+  if(zmleq(x,zm)&&!zmeqto(x,zm)){
+    fprintf(f,"-");zm=zum2zm(t_max(MAXINT));
+    if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){
+      /*  aufpassen, da -x evtl. >LONG_MAX    */
+      zum=t_max(MAXINT);
+      x=zmadd(x,zm);
+    }else 
+      zum=ul2zum(0UL);
+    x=zmsub(l2zm(0L),x);
+    vumax=zm2zum(x);
+    zum=zumadd(zum,vumax);
+  }else
+    zum=zm2zum(x);
+  printzum(f,zum);
+}
+void printzum(FILE *f,zumax x)
+/*  Konvertiert zumax nach ASCII.                      */
+{
+  zumax zum;unsigned long l;
+  zum=ul2zum(10UL);
+  if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) printzum(f,zumdiv(x,zum));
+  zum=zummod(x,zum);l=zum2ul(zum);
+  fprintf(f,"%c",(int)(l+'0'));
+}
+
+void printzld(FILE *f,zldouble x)
+/*  Konvertiert zdouble nach ASCII, noch nicht fertig.  */
+{
+  fprintf(f,"fp-constant");
+}
+void emitzm(FILE *f,zmax x)
+/*  Konvertiert zmax nach ASCII.                       */
+/*  Basiert noch einigermassen auf                      */
+/*  Zweierkomplementdarstellung (d.h. -MIN>MAX).        */
+/*  Ausserdem muss max(abs(max))<=max(unsigned max).  */
+{
+  zmax zm;zumax zum;
+  zm=l2zm(0L);
+  if(zmleq(x,zm)&&!zmeqto(x,zm)){
+    emit(f,"-");zm=zum2zm(t_max(MAXINT));
+    if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){
+      /*  aufpassen, da -x evtl. >LONG_MAX    */
+      zum=t_max(MAXINT);
+      x=zmadd(x,zm);
+    }else 
+      zum=ul2zum(0UL);
+    x=zmsub(l2zm(0L),x);
+    vumax=zm2zum(x);
+    zum=zumadd(zum,vumax);
+  }else
+    zum=zm2zum(x);
+  emitzum(f,zum);
+}
+void emitzum(FILE *f,zumax x)
+/*  Konvertiert zumax nach ASCII.                      */
+{
+  zumax zum;unsigned long l;
+  zum=ul2zum(10UL);
+  if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) emitzum(f,zumdiv(x,zum));
+  zum=zummod(x,zum);l=zum2ul(zum);
+  emit(f,"%c",(int)(l+'0'));
+}
+
+void emitzld(FILE *f,zldouble x)
+/*  Konvertiert zdouble nach ASCII, noch nicht fertig.  */
+{
+  emit(f,"fp-constant");
+}
+
+typedef struct memblock {struct memblock *next;void *p;} memblock;
+static memblock *first_mb;
+
+static void add_mb(void *p)
+{
+  memblock *mb_second=first_mb;
+  memblock *mb=malloc(sizeof(*mb));
+  if(!mb){
+    error(12);
+    raus();
+  }
+  first_mb=mb;
+  mb->next=mb_second;
+  mb->p=p;
+}  
+
+static void remove_mb(void *p)
+{
+  memblock *mb_prev=0;
+  memblock *mb=first_mb;
+  while(mb){
+    if(mb->p==p){
+      if(mb_prev==0) first_mb=mb->next;
+      else mb_prev->next=mb->next;
+      (free)(mb);
+      return;
+    }
+    mb_prev=mb;
+    mb=mb->next;
+  }
+  ierror(0);
+}
+
+void *mymalloc(size_t size)
+/*  Allocate memory and quit on failure.  */
+{
+  void *p;
+  if(dmalloc)
+    size+=sizeof(size);
+  else if(size==0)
+    /* Not very nice, but simplest way to avoid a failure when size==0. */
+    size=1;
+  if(!(p=malloc(size))){
+    error(12);
+    raus();
+  }
+  if(DEBUG&32768){
+    printf("malloc %p (s=%lu)\n",p,(unsigned long)size);
+    fflush(stdout);
+  }
+  if(DEBUG&65536) add_mb(p);
+  if(dmalloc){
+    *(size_t *)p=size;
+    p=((char *)p)+sizeof(size);
+    memset(p,0xaa,size-sizeof(size));
+  } 
+  return p;
+}
+
+void *myrealloc(void *p,size_t size)
+/*  Reallocate memory and quit on failure.  */
+{
+  void *new;
+  if(!p) return mymalloc(size);
+  if(dmalloc){
+    size+=sizeof(size);
+    new=realloc(((char *)p)-sizeof(size),size);
+    if(!new){
+      error(12);
+      raus();
+    }
+    if(DEBUG&32768){
+      printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size);
+      fflush(stdout);
+    }
+    if(DEBUG&65536){
+      remove_mb(p);
+      add_mb(new);
+    }
+    *(size_t *)new=size;
+    new=((char *)new)+sizeof(size);
+    return new;
+  }else{
+    new=realloc(p,size);
+    if(!new){
+      error(12);
+      raus();
+    }
+    if(DEBUG&32768){
+      printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size);
+      fflush(stdout);
+    }
+    if(DEBUG&65536){
+      remove_mb(p);
+      add_mb(new);
+    }
+    return new;
+  }
+}
+
+void myfree(void *p)
+{
+  if(p&&dmalloc){
+    p=((char*)p)-sizeof(size_t);
+    memset(p,0xbb,*(size_t *)(p));
+  }
+  if(DEBUG&32768){
+    printf("free %p\n",p);
+    fflush(stdout);
+  }
+  if((DEBUG&65536)&&p) remove_mb(p);
+  (free)(p);  /* supp.h has #define free(x) myfree(x) */
+}
+
+char *mystrdup(char *p)
+{
+  char *new=mymalloc(strlen(p)+1);
+  strcpy(new,p);
+  return new;
+}
+
+/* Testet, ob zwei objs dieselben Register belegen. */
+int collides(obj *x,obj *y)
+{
+    int x1,x2,y1,y2;
+    if(!(x->flags&REG)||!(y->flags&REG)) return 0;
+    if(reg_pair(x->reg,&rp)){
+        x1=rp.r1;x2=rp.r2;
+    }else{
+        x1=x->reg;x2=-1;
+    }
+    if(reg_pair(y->reg,&rp)){
+        y1=rp.r1;y2=rp.r2;
+    }else{
+        y1=y->reg;y2=-2;
+    }
+    if(x1==y1||x1==y2||x2==y1||x2==y2)
+        return 1;
+    else
+        return 0;
+}
+
+/* Versucht, ein IC so zu drehen, dass q2 und z kein gemeinsames */
+/* Register belegen. Liefert Null, wenn das nicht moeglich ist.  */
+int switch_IC(IC *p)
+{
+    int c;
+    obj o;
+    if(!collides(&p->q2,&p->z)) return 1;
+    c=p->code;
+    if((c<OR||c>AND)&&c!=ADD&&c!=MULT&&c!=ADDI2P) return 0;
+    if(c==ADDI2P&&must_convert(q1typ(p),q2typ(p),0)) return 0;
+    if(collides(&p->q1,&p->z)) return 0;
+    o=p->q2;p->q2=p->q1;p->q1=o;
+    return 1;
+}
+
+void probj(FILE *f,obj *p,int t)
+/*  Gibt Objekt auf Bildschirm aus.                    */
+{
+  if(p->am){ fprintf(f,"[tgt-addressing-mode]");return;}
+  if(p->flags&DREFOBJ){
+    fprintf(f,"([");
+    if(p->dtyp&CONST) fprintf(f,"const ");
+    if(p->dtyp&VOLATILE) fprintf(f,"volatile ");
+    if(p->dtyp&PVOLATILE) fprintf(f,"pvolatile ");
+    fprintf(f,"%s]",typname[p->dtyp&NQ]);
+  }
+  if(p->flags&VARADR) fprintf(f,"#");
+  if(p->flags&VAR) {
+    if(!(p->flags&REG))
+      printval(f,&p->val,MAXINT);
+    if(p->flags&REG){
+        fprintf(f,"%s",regnames[p->reg]);
+    }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+        fprintf(f,"+%ld(FP)", zm2l(p->v->offset));
+    }else{
+      if(p->v->storage_class==STATIC){
+        fprintf(f,"+L%ld",zm2l(p->v->offset));
+      }else{
+        fprintf(f,"+_%s",p->v->identifier);
+      }
+    }
+    if(*p->v->identifier)
+      fprintf(f,"(%s)",p->v->identifier);
+    else if(p->v->description)
+      fprintf(f,"(%s)",p->v->description);
+    else
+      fprintf(f,"(%p)",(void *)p->v);
+    if(p->v->reg) fprintf(f,":%s",regnames[abs(p->v->reg)]);
+  }
+  if((p->flags&REG)&&!(p->flags&VAR)) fprintf(f,"%s",regnames[p->reg]);
+  if(p->flags&KONST){
+    fprintf(f,"#");
+    if(p->flags&DREFOBJ)
+      printval(f,&p->val,p->dtyp&NU);
+    else
+      printval(f,&p->val,t&NU);
+  }
+  if(p->flags&SCRATCH) fprintf(f,"[S]");
+  if(p->flags&DREFOBJ) fprintf(f,")");
+}
+void prl(FILE *o,struct_declaration *p)
+/* Gibt eine struct_declaration auf dem Bildschirm aus. */
+{
+  int i;
+  static int recurse=2;
+  int merk_recurse=recurse;
+  --recurse;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  for(i=0;i<p->count;i++){
+    fprintf(o," %d.:",i);
+    if(recurse>=0){
+      if((*p->sl)[i].identifier)fprintf(o," ident: %s; ",(*p->sl)[i].identifier);
+      prd(o,(*p->sl)[i].styp);
+    }
+  }
+  recurse=merk_recurse;
+}
+void prd(FILE *o,type *p)
+/* Gibt einen Typ auf dem Bildschirm aus.    */
+{
+  int f;
+  if(!p) {fprintf(o,"empty type ");return;}
+    f=p->flags;
+/*    fprintf(o,"(Sizeof=%ld,flags=%d)",zl2l(szof(p)),f);*/
+/*    if(type_uncomplete(p)) {fprintf(o,"incomplete ");}*/
+  if(f&CONST) {fprintf(o,"const ");f&=~CONST;}
+  if(f&STRINGCONST) {fprintf(o,"string-const ");f&=~STRINGCONST;}
+  if(f&VOLATILE) {fprintf(o,"volatile ");f&=~VOLATILE;}
+  if(f&UNSIGNED) {fprintf(o,"unsigned ");f&=~UNSIGNED;}
+  if(p->attr) fprintf(o,"attr(%s) ",p->attr);
+  if(p->reg) fprintf(o,"reg(%s) ",regnames[p->reg]);
+  if(ISFUNC(f)){
+    fprintf(o,"%s with parameters (",typname[f&NQ]);
+    prl(o,p->exact);
+    fprintf(o,") returning ");prd(o,p->next);return;
+  }
+  if(ISSTRUCT(f)||ISUNION(f)){
+    fprintf(o,"%s with components {",typname[f&NQ]);
+    prl(o,p->exact); fprintf(o,"} ");
+    return;
+  }
+  if(ISPOINTER(f)) {fprintf(o,"%s to ",typname[f&NQ]);prd(o,p->next);return;}
+  if(ISARRAY(f)) {fprintf(o,"%s [size %ld] of ",typname[f&NQ],zm2l(p->size));prd(o,p->next);return;}
+  if(ISVECTOR(f)) {fprintf(o,"vector [size %ld] of %s",zm2l(p->size),typname[VECTYPE(f)&NQ]);return;}
+
+  fprintf(o,"%s",typname[f&NQ]);
+}
+void print_var(FILE *o,Var *p)
+/* Gibt eine Variable aus. */
+{
+  if(p->identifier&&*p->identifier){
+    fprintf(o, "ident: %s: ", p->identifier);
+  }
+  prd(o, p->vtyp);
+}
+
+/* returns the first base Type in an compound type */
+int get_first_base_type(type *t) 
+{
+  if (!t) return 0;
+  if (ISARRAY(t->flags)) {
+        return get_first_base_type(t->next);
+  } else if ((ISSTRUCT(t->flags)) || (ISUNION(t->flags))) {
+    return get_first_base_type((*t->exact->sl)[0].styp);
+  } else return t->flags;
+}
+
+
+#ifndef HAVE_EXT_TYPES
+
+void insert_const(union atyps *p,int t)
+/*  Traegt Konstante in entprechendes Feld ein.       */
+{
+  if(!p) ierror(0);
+  t&=NU;
+  if(t==CHAR) {p->vchar=vchar;return;}
+  if(t==SHORT) {p->vshort=vshort;return;}
+  if(t==INT) {p->vint=vint;return;}
+  if(t==LONG) {p->vlong=vlong;return;}
+  if(t==LLONG) {p->vllong=vllong;return;}
+  if(t==MAXINT) {p->vmax=vmax;return;}
+  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+  if(t==FLOAT) {p->vfloat=vfloat;return;}
+  if(t==DOUBLE) {p->vdouble=vdouble;return;}
+  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+  if(t==POINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
+{
+  int f=t&NQ;
+  if(!p) ierror(0);
+  if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+    if(!(t&UNSIGNED)){
+      if(f==CHAR) vmax=zc2zm(p->vchar);
+      else if(f==SHORT)vmax=zs2zm(p->vshort);
+      else if(f==INT)  vmax=zi2zm(p->vint);
+      else if(f==LONG) vmax=zl2zm(p->vlong);
+      else if(f==LLONG) vmax=zll2zm(p->vllong);
+      else if(f==MAXINT) vmax=p->vmax;
+      else ierror(0);
+      vumax=zm2zum(vmax);
+      vldouble=zm2zld(vmax);
+    }else{
+      if(f==CHAR) vumax=zuc2zum(p->vuchar);
+      else if(f==SHORT)vumax=zus2zum(p->vushort);
+      else if(f==INT)  vumax=zui2zum(p->vuint);
+      else if(f==LONG) vumax=zul2zum(p->vulong);
+      else if(f==LLONG) vumax=zull2zum(p->vullong);
+      else if(f==MAXINT) vumax=p->vumax;
+      else ierror(0);
+      vmax=zum2zm(vumax);
+      vldouble=zum2zld(vumax);
+    }
+  }else{
+    if(ISPOINTER(f)){
+      vumax=zul2zum(p->vulong);
+      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+    }else{
+      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+      else vldouble=p->vldouble;
+      vmax=zld2zm(vldouble);
+      vumax=zld2zum(vldouble);
+    }
+  }
+  vfloat=zld2zf(vldouble);
+  vdouble=zld2zd(vldouble);
+  vuchar=zum2zuc(vumax);
+  vushort=zum2zus(vumax);
+  vuint=zum2zui(vumax);
+  vulong=zum2zul(vumax);
+  vullong=zum2zull(vumax);
+  vchar=zm2zc(vmax);
+  vshort=zm2zs(vmax);
+  vint=zm2zi(vmax);
+  vlong=zm2zl(vmax);
+  vllong=zm2zll(vmax);
+}
+#endif
+
+function_info *new_fi(void)
+/*  Belegt neue function_info-Struktur und initialisiert sie.  */
+{
+  function_info *new;
+  new=mymalloc(sizeof(*new));
+  new->first_ic=new->last_ic=new->opt_ic=0;
+  new->vars=0;
+  new->statics=0;
+  new->inline_asm=0;
+  new->flags=0;
+  new->call_cnt=new->use_cnt=new->change_cnt=0;
+  new->call_list=new->use_list=new->change_list=0;
+  memset(new->regs_modified,0,sizeof(new->regs_modified));
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  new->stack1=ul2zum(0UL);
+  new->stack2=ul2zum(0UL);
+  new->inline_size=-1;
+  new->inline_depth=0;
+  return new;
+}
+void free_fi(function_info *p)
+/*  Gibt ein function_info mit Inhalt frei.                     */
+{
+  if(p->first_ic) free_IC(p->first_ic);
+  if(p->opt_ic) free_IC(p->opt_ic);
+  if(p->vars) free_var(p->vars);
+  /* do not free statics */
+  free(p->call_list);
+  free(p->use_list);
+  free(p->change_list);
+  free(p->inline_asm);
+  free(p);
+}
+
+void print_fi(FILE *f,function_info *p)
+/*  Gibt function_info aus. */
+{
+  int i;
+  fprintf(f,"function_info:\n");
+  if(p->first_ic){
+    IC *ic=p->first_ic;
+    fprintf(f," inline_code:\n");
+    pric2(f,ic);
+    while(ic!=p->last_ic){
+      ic=ic->next;
+      pric2(f,ic);
+    }
+  }
+  if(p->inline_asm)
+    fprintf(f," inline_asm:\n%s\n",p->inline_asm);
+  if(p->flags&ALL_CALLS)
+    fprintf(f," all calls have been evaluated\n");
+  if(p->flags&ALL_USES)
+    fprintf(f," all uses have been evaluated\n");
+  if(p->flags&ALL_MODS)
+    fprintf(f," all changes have been evaluated\n");
+  if(p->flags&ALL_REGS){
+    fprintf(f," all reg-changes have been evaluated\n");
+    for(i=1;i<=MAXR;i++)
+      if(BTST(p->regs_modified,i)) fprintf(f,"  %s\n",regnames[i]);
+  }
+  fprintf(f," call_list:\n");print_varlist(f,p->call_list,p->call_cnt);
+  fprintf(f," use_list:\n");print_varlist(f,p->use_list,p->use_cnt);
+  fprintf(f," change_list:\n");print_varlist(f,p->change_list,p->change_cnt);
+  if(p->flags&ALL_STACK){
+    fprintf(f,"stack1: ");printzum(f,p->stack1);fprintf(f,"\n");
+    fprintf(f,"stack2: ");printzum(f,p->stack2);fprintf(f,"\n");
+  }
+  if(p->flags&NEVER_RETURNS)
+    fprintf(f," never returns\n");
+  if(p->flags&ALWAYS_RETURNS)
+    fprintf(f," always returns\n");
+  if(p->flags&NOSIDEFX)
+    fprintf(f," no side effects\n");
+}
+
+void print_varlist(FILE *f,varlist *p,int n)
+{
+  int i;
+  char *s;
+  for(i=0;i<n;i++){
+    if(p[i].v) s=p[i].v->identifier; else s="<unknown>";
+    fprintf(f,"  %s(%p), flags=%d\n",s,(void*)p[i].v,p[i].flags);
+  }
+}
+
+int is_const(type *t)
+/*  tested, ob ein Typ konstant (und damit evtl. in der Code-Section) ist   */
+{
+  if(!(t->flags&(CONST|STRINGCONST))){
+    do{
+      if(t->flags&(CONST|STRINGCONST)) return(1);
+      if((t->flags&NQ)!=ARRAY) return 0;
+      t=t->next;
+    }while(1);
+  }else return 1;
+}
+
+/* is object volatile? */
+int is_volatile_obj(obj *o)
+{
+  if(o->flags&DREFOBJ){
+    if(o->dtyp&(VOLATILE|PVOLATILE)){
+      return 1;
+    }
+    if((o->flags&VAR)&&ISPOINTER(o->v->vtyp->flags)&&(o->v->vtyp->next->flags&VOLATILE)){
+      return 1;
+    }
+  }
+  if(o->flags&VAR){
+    return o->v->vtyp->flags&VOLATILE;
+  }else{
+    return 0;
+  }
+}
+
+/* is IC volatile? */
+int is_volatile_ic(IC *p)
+{
+  if(p->q1.flags){
+    if(is_volatile_obj(&p->q1)||(q1typ(p)&VOLATILE)) return 1;
+  }
+  if(p->q2.flags){
+    if(is_volatile_obj(&p->q2)||(q2typ(p)&VOLATILE)) return 1;
+  }
+  if(p->z.flags){
+    if(is_volatile_obj(&p->z)||(ztyp(p)&VOLATILE)) return 1;
+  }
+  return 0;
+}
+
+/* removes last asm-line from emit-buffer */
+void remove_asm(void)
+{
+  emit_l--;
+  if(emit_l<0) emit_l=EMIT_BUF_DEPTH-1;
+}
+
+/* flush the asm-output buffer */
+void emit_flush(FILE *f)
+{
+  if(!f||no_emit) return;
+  while(emit_f!=emit_l){
+    fputs(emit_buffer[emit_f],f);
+    emit_f++;
+    if(emit_f>=EMIT_BUF_DEPTH) emit_f=0;
+  }
+  emit_l=emit_f=0;
+  emit_p=emit_buffer[0];
+}
+
+/* emit inline-asm, depending on no_inline_peephole, feed it through
+   asm_peephole() or flush the buffer and print it directly to the file */
+void emit_inline_asm(FILE *f,char *p)
+{
+  if(!f||no_emit) return;
+  if(no_inline_peephole){
+    emit_flush(f);
+    fprintf(f,"%s\n",p);
+  }else{
+    while(*p){
+      emit(f,"%c",*p++);
+    }
+    emit(f,"\n");
+  }
+}
+
+/* print output; this is only to be used for assembly output! */
+void emit(FILE *f,const char *fmt,...)
+{
+  static char tmp[EMIT_BUF_LEN];
+  char *p;
+  va_list vl;
+  if(!f||no_emit) return;
+  va_start(vl,fmt);
+  vsprintf(tmp,fmt,vl);
+  p=tmp;
+  while(*p){
+    *emit_p++=*p++;
+    if(p[-1]=='\n'){
+      *emit_p=0;
+#if HAVE_TARGET_PEEPHOLE
+      while(emit_peephole());
+#endif
+      emit_l++;
+      if(emit_l>=EMIT_BUF_DEPTH) emit_l=0;
+      emit_p=emit_buffer[emit_l];
+      if(emit_l==emit_f){
+        /* FIXME: error check */
+        fputs(emit_buffer[emit_f],f);
+        emit_f++;
+        if(emit_f>=EMIT_BUF_DEPTH) emit_f=0;
+      }
+    }
+  }
+  *emit_p=0;
+}
+
+void emit_char(FILE *f,int c)
+{
+  static char tmp[2];
+  tmp[0]=c;
+  emit(f,tmp);
+}
+
+/* detect whether the following code resembles a switch-case-statement */
+/* will return the longest sequence which has at least min_density */
+case_table *calc_case_table(IC *p,double min_density)
+{
+  static case_table ct;
+  obj *o,*ccr;
+  static union atyps *vals;
+  union atyps min,max;
+  zumax diff;
+  static int *labels,cur_size;
+  double cur_density;
+  int t,j,num;
+  if(p->code!=COMPARE||!(p->q2.flags&KONST))
+    return 0;
+  o=&p->q1;t=p->typf;
+  if(!ISINT(t)||(t&VOLATILE)) return 0;
+  num=0;
+  ct.num=0;
+  if(t&UNSIGNED){
+    max.vumax=t_min(UNSIGNED|MAXINT);
+    min.vumax=t_max(UNSIGNED|MAXINT);
+  }else{
+    max.vmax=t_min(MAXINT);
+    min.vmax=t_max(MAXINT);
+  }
+  while(p&&p->code==COMPARE&&(p->q2.flags&KONST)&&p->typf==t&&objs_equal(o,&p->q1,t)){
+    zumax zum;zmax zm;
+    if(multiple_ccs) ccr=&p->z;
+    if(num>=cur_size){
+      cur_size+=64;
+      labels=myrealloc(labels,cur_size*sizeof(*labels));
+      vals=myrealloc(vals,cur_size*sizeof(*vals));
+    }
+    for(j=0;j<num;j++){
+      if(!compare_const(&vals[j],&p->q2.val,t)){
+        return 0; /* FIXME? Could simply ignore? */
+      }
+    }
+    vals[num]=p->q2.val;
+    p=p->next;
+    while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next;
+    if(p->code!=BEQ||(multiple_ccs&&!objs_equal(ccr,&p->q1,0))) break;
+    labels[num]=p->typf;
+    p=p->next;
+    while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next;
+    eval_const(&vals[num],t);
+    num++;
+    if(t&UNSIGNED){
+      if(zumleq(vumax,min.vumax))
+        insert_const(&min,UNSIGNED|MAXINT);
+      if(zumleq(max.vumax,vumax))
+        insert_const(&max,UNSIGNED|MAXINT);
+      cur_density=num/(1+zld2d(zum2zld(zumsub(max.vumax,min.vumax))));
+      if(cur_density>=min_density){
+        ct.num=num;
+        ct.next_ic=p;
+        ct.min=min;
+        ct.max=max;
+        ct.diff=zumsub(max.vumax,min.vumax);
+        ct.density=cur_density;
+      }
+    }else{
+      if(zmleq(vmax,min.vmax))
+        insert_const(&min,MAXINT);
+      if(zmleq(max.vmax,vmax))
+        insert_const(&max,MAXINT);
+      cur_density=num/zld2d(zum2zld((1+zumsub(zm2zum(max.vmax),zm2zum(min.vmax)))));
+      if(cur_density>=min_density){
+        ct.num=num;
+        ct.next_ic=p;
+        ct.min=min;
+        ct.max=max;
+        ct.diff=zumsub(zm2zum(max.vmax),zm2zum(min.vmax));
+        ct.density=cur_density;
+      }
+    }
+  }
+  ct.vals=vals;
+  ct.labels=labels;
+  ct.typf=t;
+  return &ct;
+}
+
+/* emit a list of jump-table entries */
+void emit_jump_table(FILE *f,case_table *ct,char *da,char *labprefix,int defl)
+{
+  unsigned long l,e;
+  int i;
+  zmax zm;zumax zum;
+  if(ct->typf&UNSIGNED){
+    zum=ct->min.vumax;
+    zm=zum2zm(zum);
+  }else{
+    zm=ct->min.vmax;
+    zum=zm2zum(zm);
+  }
+  e=zum2ul(ct->diff);
+  for(l=0;l<=e;l++){
+    emit(f,"%s",da);
+    for(i=0;i<ct->num;i++){
+      eval_const(&ct->vals[i],ct->typf);
+      if(zmeqto(vmax,zm)&&zumeqto(vumax,zum)){
+        emit(f,"%s%d\n",labprefix,ct->labels[i]);
+        break;
+      }
+    }
+    if(i>=ct->num)
+      emit(f,"%s%d\n",labprefix,defl);
+    zm=zmadd(zm,l2zm(1L));
+    zum=zumadd(zum,ul2zum(1UL));
+  }
+}
+/* display warnings if specified stack-size cannot be guaranteed */
+void static_stack_check(Var *v)
+{
+  /*FIXME*/
+}
+
+#ifdef HAVE_REGPARMS
+/* return the offset of the first variable-argument-macro to the
+   beginning of the argument-area (i.e. the space occupied by
+   normal arguments on the stack */
+zmax va_offset(Var *v)
+{
+  int i;
+  zmax offset=l2zm(0L);
+  static type rp={0};
+  treg_handle rh=empty_reg_handle;
+  if((v->vtyp->next->flags&NQ)!=VOID&&!freturn(v->vtyp->next)){
+    rp.next=v->vtyp->next;
+    rp.flags=POINTER_TYPE(v->vtyp->next);
+    if(!reg_parm(&rh,&rp,0,v->vtyp)){
+      ierror(0);
+    }
+  }
+  for(i=0;i<v->vtyp->exact->count;i++){
+#if 0
+    if((*v->vtyp->exact->sl)[i].reg!=0)
+      continue;
+#endif
+    if(((*v->vtyp->exact->sl)[i].styp->flags&NQ)==VOID)
+      ierror(0);
+    if(reg_parm(&rh,(*v->vtyp->exact->sl)[i].styp,0,v->vtyp)!=0)
+      continue;
+    offset=zmadd(offset,szof((*v->vtyp->exact->sl)[i].styp));
+    offset=zmmult(zmdiv(zmadd(offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign); 
+  }
+  return offset;
+}
+#endif
+
+/* We provide an own qsort to get reproducable results. */
+void vqsort (void *base,size_t nmemb,size_t size,int (*compar)(const void *,const void *))
+{ char *base2=(char *)base;
+  char tmp;
+  size_t i,a,b,c;
+  while(nmemb>1)
+  { a=0;
+    b=nmemb-1;
+    c=(a+b)/2; /* Middle element */
+    for(;;)
+    { while((*compar)(&base2[size*c],&base2[size*a])>0)
+        a++; /* Look for one >= middle */
+      while((*compar)(&base2[size*c],&base2[size*b])<0)
+        b--; /* Look for one <= middle */
+      if(a>=b)
+        break; /* We found no pair */
+      for(i=0;i<size;i++) /* swap them */
+      { tmp=base2[size*a+i];
+        base2[size*a+i]=base2[size*b+i];
+        base2[size*b+i]=tmp; }
+      if(c==a) /* Keep track of middle element */
+        c=b;
+      else if(c==b)
+        c=a;
+      a++; /* These two are already sorted */
+      b--;
+    } /* a points to first element of right intervall now (b to last of left) */
+    b++;
+    if(b<nmemb-b) /* do recursion on smaller intervall and iteration on larger one */
+    { vqsort(base2,b,size,compar);
+      base2=&base2[size*b];
+      nmemb=nmemb-b;
+    }
+    else
+    { vqsort(&base2[size*b],nmemb-b,size,compar);
+      nmemb=b; }
+  }
+  return;
+}
+
+/* calculates registers used by this call IC
+   returns 0 if not possible */
+int calc_regs(IC *p,int showwarnings)
+{
+  int i;
+  if(p->call_cnt){
+    for(i=0;i<p->call_cnt;i++){
+      if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_REGS)){
+        bvunite(regs_modified,p->call_list[i].v->fi->regs_modified,RSIZE);
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+      }else{
+        int r;
+        for(r=1;r<=MAXR;r++) if(regscratch[r]) BSET(regs_modified,r);
+        err_ic=p;
+        if(!p->call_list[i].v->fi) p->call_list[i].v->fi=new_fi();
+        if(!(p->call_list[i].v->fi->flags&WARNED_REGS)){
+          error(318,p->call_list[i].v->identifier);
+          p->call_list[i].v->fi->flags|=WARNED_REGS;
+        }
+        return 0;
+      }
+    }
+    return 1;
+  }
+  err_ic=p;if(showwarnings) error(320);
+  return 0;
+}
+
+
+
+#ifndef HAVE_TARGET_BFLAYOUT
+int bflayout(int bfoffset,int bfsize,int t)
+{
+  if(BIGENDIAN)
+    return (int)zm2l(zmmult(sizetab[t&NQ],char_bit))-bfoffset-bfsize;
+  else
+    return bfoffset;
+}
+#endif
+
+long get_pof2(zumax x)
+/*  Yields log2(x)+1 oder 0. */
+{
+  zumax p;int ln=1,max=(int)zm2l(zmmult(sizetab[LLONG],char_bit));
+  p=ul2zum(1L);
+  while(ln<=max&&zumleq(p,x)){
+    if(zumeqto(x,p)) return ln;
+    ln++;p=zumadd(p,p);
+  }
+  return 0;
+}
+
+/* check if type is a varargs function */
+int is_varargs(type *t)
+{
+  int c;
+  if(t->exact&&(c=t->exact->count)!=0&&(*t->exact->sl)[c-1].styp->flags!=VOID)
+    return 1;
+  else
+    return 0;
+}
+
+/* add string to type- oder variable-aatribute */
+void add_attr(char **attr,char *new)
+{
+  int ln,lo;
+  if(!new) return;
+  if(*attr&&strstr(*attr,new)) return;
+  if(add_attr_haddecl&&(!*attr||!strstr(*attr,new))) error(371,add_attr_haddecl->identifier,new);
+  ln=strlen(new);
+  if(*attr){
+    lo=strlen(*attr);
+    *attr=myrealloc(*attr,lo+ln+2);
+  }else{
+    lo=0;
+    *attr=mymalloc(ln+2);
+  }
+  (*attr)[lo]=';';
+  strcpy(*attr+lo+1,new);
+}
+
+
+hashtable *new_hashtable(size_t size)
+{
+  hashtable *new = mymalloc(sizeof(*new));
+
+  new->size = size;
+  new->collisions = 0;
+  new->entries = mymalloc(size*sizeof(*new->entries));
+  memset(new->entries,0,size*sizeof(*new->entries));
+  return new;
+}
+
+size_t hashcode(char *name)
+{
+  size_t h = 5381;
+  int c;
+
+  while (c = (unsigned char)*name++)
+    h = ((h << 5) + h) + c;
+  return h;
+}
+
+/* add to hashtable; name must be unique */
+void add_hashentry(hashtable *ht,char *name,hashdata data)
+{
+  size_t i=(hashcode(name)%ht->size);
+  hashentry *new=mymalloc(sizeof(*new));
+  new->name=name;
+  new->data=data;
+  if(DEBUG&1){
+    if(ht->entries[i])
+      ht->collisions++;
+  }
+  new->next=ht->entries[i];
+  ht->entries[i]=new;
+}
+
+/* finds unique entry in hashtable */
+hashdata find_name(hashtable *ht,char *name)
+{
+  size_t i=hashcode(name)%ht->size;
+  hashentry *p;
+  for(p=ht->entries[i];p;p=p->next){
+    if(!strcmp(name,p->name)){
+      return p->data;
+    }else
+      ht->collisions++;
+  }
+  return 0;
+}
+
+#ifndef CHARBACK
+unsigned char CHARBACK(unsigned char x)
+{
+  static unsigned char tab[256],init=0;
+  if(!init){
+    int i,j;
+    for(i=0;i<256;i++)
+      for(j=0;j<256;j++)
+	if(tab[j]==0&&CHARCONV(i)==j){
+	  tab[j&255]=i;
+	  break;
+	}
+    init=1;
+  }
+  return tab[x&255];
+}
+
+void STRBACK(unsigned char *p)
+{
+  while(p&&*p){
+    *p=CHARBACK(*p);
+    p++;
+  }
+}
+#endif
+
+int objs_equal(obj *o1,obj *o2,int t)
+/*  Vergleicht die beiden Objekte; liefert 1, wenn sie gleich sind, sonst 0 */
+{
+    int i1,i2;
+    i1=o1->flags&~SCRATCH;i2=o2->flags&~SCRATCH;
+    if(i1!=i2) return 0;
+    if(i1&DREFOBJ){
+      if(o1->dtyp!=o2->dtyp) return 0;
+    }
+    if(i1&KONST) return(!compare_const(&o1->val,&o2->val,t));
+    if(i1&VAR){
+      if(o1->v!=o2->v) return 0;
+      if(!zmeqto(o1->val.vmax,o2->val.vmax)) return 0;
+    }
+    return 1;
+}
+
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
diff --git a/supp.h b/supp.h
new file mode 100644
index 0000000..7313fce
--- /dev/null
+++ b/supp.h
@@ -0,0 +1,880 @@
+/*  $VER: vbcc (supp.h) $Revision: 1.58 $     */
+
+
+#ifndef SUPP_H
+#define SUPP_H 1
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <ctype.h>
+/* typenames */
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define ARRAY 11
+#define STRUCT 12
+#define UNION 13
+#define ENUM 14
+#define FUNKT 15
+#define BOOL 16
+#define MAXINT 17 /* should not be accessible to application */
+#define MAX_TYPE MAXINT
+#define MAXVECDIM 16
+#define VECBOOL (MAXINT+1)
+#define VECCHAR (VECBOOL+MAXVECDIM)
+#define VECSHORT (VECCHAR+MAXVECDIM)
+#define VECINT (VECSHORT+MAXVECDIM)
+#define VECLONG (VECINT+MAXVECDIM)
+#define VECFLOAT (VECLONG+MAXVECDIM)
+#define VECLAST (VECFLOAT+MAXVECDIM)
+#define NQ 255   /* f&NQ gives type without any qualifiers */
+#define NU 511   /* f&NU gives type without any qualifiers but UNSIGNED */
+#define q1typ(p) ((p->code==ADDI2P||p->code==SUBIFP||p->code==CONVERT||p->code==SUBPFP)?p->typf2:p->typf)
+#define q2typ(p) ((p->code==SUBPFP||p->code==LSHIFT||p->code==RSHIFT)?p->typf2:p->typf)
+#define ztyp(p) ((p->code==ADDI2P||p->code==SUBIFP||p->code==ADDRESS)?p->typf2:p->typf)
+#define iclabel(p) (p->typf)
+#define opsize(p) (p->q2.val.vmax)
+#define pushsize(p) (p->z.val.vmax)
+#define pushedargsize(p) (p->q2.val.vmax)
+#define isstatic(x) ((x)==STATIC)
+#define isextern(x) ((x)==EXTERN)
+#define isauto(x)   ((x)==AUTO||(x)==REGISTER)
+/* operations on bit-vectors */
+typedef unsigned int bvtype;
+#define BVBITS (sizeof(bvtype)*CHAR_BIT)
+#define BVSIZE(x) ((((x)+BVBITS-1)/BVBITS)*sizeof(bvtype))
+#define BSET(array,bit) (array)[(bit)/BVBITS]|=1<<((bit)%BVBITS)
+#define BCLR(array,bit) (array)[(bit)/BVBITS]&=~(1<<((bit)%BVBITS))
+#define BTST(array,bit) ((array)[(bit)/BVBITS]&(1<<((bit)%BVBITS)))
+/* type-qualifiers */
+#define UNSIGNED (NQ+1)
+#define CONST (UNSIGNED<<1)
+#define VOLATILE (CONST<<1)
+#define RESTRICT (VOLATILE<<1)
+#define UNCOMPLETE (RESTRICT<<1)
+#define STRINGCONST (UNCOMPLETE<<1)
+#define BOOLEAN (STRINGCONST<<1)
+#define SIGNED_CHARACTER (BOOLEAN<<1)
+#define PVOLATILE (SIGNED_CHARACTER<<1)
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#define t_min(x) (((x)&UNSIGNED)?l2zm(0L):t_min[(x)&NQ])
+#define t_max(x) (((x)&UNSIGNED)?tu_max[(x)&NQ]:t_max[(x)&NQ])
+/*  macro for internal errors */
+#define ierror(a) error(-1,(a),__LINE__,FILE_)
+/* macros for target errors */
+#define twarning(x) error(323,x);
+#define terror(x) error(324,x);
+/* this header is provided by the code generator */
+#include "machine.h"
+#define Z0 l2zm(0L)
+#define Z1 l2zm(1L)
+#define ZU0 ul2zum(0UL)
+#define ZU1 ul2zum(1UL)
+
+#ifndef HAVE_EXT_TYPES
+typedef zllong zmax;
+typedef zullong zumax;
+#endif
+#ifndef ISPOINTER
+#define ISPOINTER(x) ((x&NQ)==POINTER)
+#endif
+#ifndef ISINT
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#endif
+#ifndef ISFLOAT
+#define ISFLOAT(x) ((x&NQ)>=FLOAT&&(x&NQ)<=LDOUBLE)
+#endif
+#ifndef ISFUNC
+#define ISFUNC(x) ((x&NQ)==FUNKT)
+#endif
+#ifndef ISSTRUCT
+#define ISSTRUCT(x) ((x&NQ)==STRUCT)
+#endif
+#ifndef ISUNION
+#define ISUNION(x) ((x&NQ)==UNION)
+#endif
+#ifndef ISARRAY
+#define ISARRAY(x) ((x&NQ)==ARRAY)
+#endif
+#ifndef ISVECTOR
+#define ISVECTOR(x) ((x&NQ)>=VECBOOL&&(x&NQ)<=VECLAST)
+#endif
+#ifndef VECDIM
+#define VECDIM(x) ((((x&NQ)-VECBOOL)&15)+1)
+#endif
+#ifndef ISSCALAR
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=POINTER)
+#endif
+#ifndef ISARITH
+#define ISARITH(x) (ISINT(x)||ISFLOAT(x))
+#endif
+#ifndef POINTER_TYPE
+#define POINTER_TYPE(x) POINTER
+#endif
+#ifndef MAXINT
+#define MAXINT LLONG
+#endif
+#ifndef HAVE_INT_SIZET
+#define HAVE_INT_SIZET 0
+#endif
+#ifndef PTRDIFF_T
+#define PTRDIFF_T(x) INT
+#endif
+#ifndef MAXADDI2P
+#define MAXADDI2P LLONG
+#endif
+#ifndef MINADDUI2P
+#define MINADDUI2P (MINADDI2P|UNSIGNED)
+#endif
+#ifndef MAXADDUI2P
+#define MAXADDUI2P (MAXADDI2P|UNSIGNED)
+#endif
+#ifndef BESTCOPYT
+#define BESTCOPYT INT
+#endif
+#define RSIZE BVSIZE(MAXR+1)
+#define ALL_CALLS 1
+#define ALL_REGS  2
+#define ALL_USES  4
+#define ALL_MODS  8
+#define ALL_STACK 16
+#define ALWAYS_RETURNS 32
+#define NEVER_RETURNS 64
+#define NOSIDEFX 128
+#define WARNED_STACK 256
+#define WARNED_REGS 512
+#define USES_VLA 1024
+#define NO_INLINE 2048
+#define FULL_INLINE 4096
+typedef struct reg_handle treg_handle;
+typedef struct tunit{
+  struct Var *statics;
+  struct tunit *next;
+} tunit;
+/*  additional information for functions; used by the optimizer  */
+typedef struct function_info{
+  struct IC *first_ic;    /* inline copy of function starts here */
+  struct IC *last_ic;     /*  "       "       "      ends here   */
+  struct IC *opt_ic;      /* code after optimizing */
+  struct Var *vars;       /* pointer to list of vars of that function */
+  struct Var *statics;    /* static variables of translation-unit */
+  char *inline_asm;       /* pointer to code for inline assembler */
+  unsigned long flags;    /* misc flags, see above */
+  /* functions called, variables used and changed */
+  int call_cnt,use_cnt,change_cnt;
+  struct varlist *call_list;
+  struct varlist *use_list;
+  struct varlist *change_list;
+  zmax max_offset;
+  /* registers used and modified by that function */
+  bvtype regs_modified[RSIZE/sizeof(bvtype)];
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+#endif
+  zumax stack1;
+  zumax stack2;
+  long inline_size;  /* size after inlining/optimizing for cross-module */
+  int inline_depth;  /* minimum depth for cross-module-inlining */
+} function_info;
+typedef int typfl;
+#if PVOLATILE >= INT_MAX
+#error "need host with larger int size"
+#endif
+/*  struct for types.    */
+typedef struct Typ{
+  typfl flags;  /*  see above   */
+  struct Typ *next;
+  struct struct_declaration *exact;   /* used for STRUCT/UNION/FUNKT  */
+  zmax size;     /*  used for ARRAY  */
+  struct Var *dsize; /* used for variable-length arrays */
+  char *attr;
+  int reg;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+} type;
+#define TYPS sizeof(type)
+#ifndef HAVE_EXT_TYPES
+typedef union atyps{
+  zchar vchar;
+  zuchar vuchar;
+  zshort vshort;
+  zushort vushort;
+  zint vint;
+  zuint vuint;
+  zlong vlong;
+  zulong vulong;
+  zllong vllong;
+  zullong vullong;
+  zmax vmax;
+  zumax vumax;
+  zfloat vfloat;
+  zdouble vdouble;
+  zldouble vldouble;
+} atyps;
+#endif
+/* This struct represents objects in the intermediate code. */
+typedef struct obj{
+  int flags;      /* see below */
+  int reg;        /* number of reg if flags&REG */
+  int dtyp;       /* type of pointer for DREFOBJ */
+  struct Var *v;
+  struct AddressingMode *am;
+  union atyps val;
+} obj;
+/*  Available flags in struct obj.  */
+                    /*  KONST muss immer am kleinsten sein, um beim Swappen */
+                    /*  fuer available_expressions und Konstanten nach      */
+                    /*  rechts nicht in eine Endlosschleife zu kommen.      */
+#define KONST 1     /*  The object is a constant. Its value is stored in    */
+                    /*  val.                                                */
+#define VAR 2       /*  The object is a variable (stored in v).             */
+#define SCRATCH 8   /*  The object is a temporary.                          */
+#define STACK 16    /*  obsolete                                            */
+#define DREFOBJ 32  /*  The object must be dereferenced.                    */
+#define REG 64      /*  The object is contained in a hardware register.     */
+#define VARADR 128  /*  The object is the address of a static variable.     */
+#define DONTREGISTERIZE 256 /*  Do not put this object into a register.     */
+#define VKONST 512  /*  Variable containing a constant (for reg-alloc).     */
+typedef struct Var{
+  int storage_class;  /* see below    */
+  int reg;            /* Var is assigned to this hard-reg */
+  int priority;       /* Priority to be used in simple_regs() */
+  long flags;         /* see below */
+  char *identifier;   /* name of the variable */
+  int nesting;        /* can be freely used by the frontend */
+  int index;          /* used by the optimizer */
+  int inr;            /* counter for num_vars */
+  zmax offset;        /* offset relative to the stack frame */
+  int line;           /* line number of first declaration */
+  char *filename;     /* filename of first declaration */
+  int dline;          /* line number of definition */
+  char *dfilename;    /* filename of definition */
+  type *vtyp;   /* type of the variable */
+  struct const_list *clist;   /* initialized? */
+  struct Var *next;   /* pointer to next variable */
+  struct function_info *fi;   /* used by the optimizer */
+  struct Var *inline_copy;    /* used for function-inlining */
+  struct tunit *tunit; /* translation unit the variable belongs to */
+  char *vattr;         /* extended variable attributes */
+  char *description;   /* description of variable meaning */
+  struct obj cobj;     /* used for register-allocation of constants */
+  int ctyp;            /*   ----------------- " -----------------   */
+#ifdef HAVE_TARGET_ATTRIBUTES
+  unsigned long tattr;        /* target-specific attributes */
+#endif
+#ifdef ALEX_REG
+  int iRegCopyNr;
+  int iRegCopyNrHc12V;
+#endif
+} Var;
+/* available storage-classes */
+#define AUTO 1          /* var is allocated on the stack */
+#define REGISTER 2      /* basically the same as AUTO (C-only) */
+#define STATIC 3        /* var is static but has no external linkage */
+#define EXTERN  4       /* var is static and has external linkage */
+#define TYPEDEF 5       /* C-only */
+/* available flags in struct Var */
+#define USEDASSOURCE 1      /* the var has been read */
+#define USEDASDEST 2        /* the var has been written */
+#define DEFINED 4           /* the var has been defined (i.e. storage will
+                               be allocated in the current file) */
+#define USEDASADR 8         /* the address of the var has been taken */
+#define GENERATED 16        /* code for static vars has been generated */
+#define CONVPARAMETER 32
+#define TENTATIVE 64        /* C-only */
+#define USEDBEFORE 128      /* used by the optimizer */
+#define INLINEV 256         /*  "               "    */
+#define PRINTFLIKE 512      /* C-only */
+#define SCANFLIKE 1024      /* C-only */
+#define NOTTYPESAFE 2048    /* used by the optimizer */
+#define DNOTTYPESAFE 4096   /*  "               "    */
+#define REGPARM 8192        /* the var is a register parameter */
+#define DBLPUSH 16384       /* parameter is also on the stack */
+#define NOTINTU 32768       /* variable not (yet) defined in this translation-unit */
+#define REFERENCED 65536    /* variable referenced */
+#define STATICAUTO 131072   /* auto variable converted to static */
+#define INLINEFUNC (STATICAUTO*2)
+#define INLINEEXT (INLINEFUNC*2)
+#define BUILTIN (INLINEEXT*2)
+#define NEEDS (BUILTIN*2)
+
+/* C-only */
+typedef struct struct_list{
+  char *identifier;   /* name of the struct/union-tag */
+  type *styp;   /* type of the member/parameter */
+  zmax align;         /* alignment of struct-member */
+  int bfoffset;       /* bitfield-offset */
+  int bfsize;         /* bitfield-size */
+  int storage_class;  /* storage-class of function-parameter */
+  int reg;            /* register to pass function-parameter */
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+} struct_list;
+
+#define SLSIZE 32   /* realloc struct_lists in those steps */
+/*  These structs are used to describe members of STRUCT/UNION or   */
+/*  parameters of FUNKT. Some of the entries in struct_list are not */
+/*  relevant for both alternatives.                                 */
+typedef struct struct_declaration{
+  int count;  /* number of members/parameters */
+  int label; /* used for debug output */
+  int typ;
+  struct tunit *tunit;
+  struct struct_declaration *next;
+  struct struct_list (*sl)[];
+  char *identifier;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+} struct_declaration;
+
+/*  The quads in the intermediate code. */
+typedef struct IC{
+  struct IC *prev;    /* pointer to the next IC */
+  struct IC *next;    /* pointer to the previous IC */
+  int code;           /* see below */
+  int typf;           /* usually type of the operands, see interface.doc */
+  int typf2;          /* used for CONVERT,ADDI2P,SUBIFP,SUBPFP */
+  int defindex;       /* used by optimizer */
+  int expindex;
+  int copyindex;
+  int change_cnt;
+  int use_cnt;
+  int call_cnt;
+  int line;           /* corresponding line in source file (or 0) */
+  struct varlist *change_list;    /* used by optimizer */
+  struct varlist *use_list;
+  struct varlist *call_list;
+  struct obj q1;      /* source 1 */
+  struct obj q2;      /* source 2 */
+  struct obj z;       /* target */
+  char *file;         /* filename of the source file */
+  int arg_cnt;
+  struct IC **arg_list; /* pointers to function argument ICs (only for code==CALL) */
+  struct IC *copy;    /* for copying/inlining */
+  type *ityp;
+  long flags;
+  struct Var *savedsp; /* only for branch instructions and vlas */
+#ifdef HAVE_EXT_IC
+  struct ext_ic ext;
+#endif
+#ifdef ALEX_REG
+  int iZWebIndex; /* web for z in case z is a pointer and its value is defed*/
+  int iQ1WebIndex; /* web for argument q1 */
+  int iQ2WebIndex; /* web for argument q2 */
+  void *pFlow;           /* flowgraph reverse lookup */
+#endif
+} IC;
+#define ICS sizeof(struct IC)
+/* flags for ICs */
+#define LOOP_COND_TRUE 1  /* loop condition is true at first iteration */
+#define EFF_IC 2          /* do not transform IC with doubtful optimizations */
+#define ORDERED_PUSH_COPY 4 /* mark a copy of an ordered push */
+
+/*  Available codes for struct IC. See interface.doc. */
+#define KOMMA 1
+#define ASSIGN 2
+#define ASSIGNOP 3
+
+#if 0
+/* obsolete */
+#define ASSIGNADD 3
+#define ASSIGNSUB 4
+#define ASSIGNMULT 5
+#define ASSIGNDIV 6
+#define ASSIGNMOD 7
+#define ASSIGNAND 8
+#define ASSIGNXOR 9
+#define ASSIGNOR 10
+#define ASSIGNLSHIFT 11
+#define ASSIGNRSHIFT 12
+#endif
+
+#define COND 13
+#define LOR 14
+#define LAND 15
+#define OR 16
+#define XOR 17
+#define AND 18
+#define EQUAL 19
+#define INEQUAL 20
+#define LESS 21
+#define LESSEQ 22
+#define GREATER 23
+#define GREATEREQ 24
+#define LSHIFT 25
+#define RSHIFT 26
+#define ADD 27
+#define SUB 28
+#define MULT 29
+#define DIV 30
+#define MOD 31
+#define NEGATION 32
+#define KOMPLEMENT 33
+#define PREINC 34
+#define POSTINC 35
+#define PREDEC 36
+#define POSTDEC 37
+#define MINUS 38
+#define CONTENT 39
+#define ADDRESS 40
+#define CAST 41
+#define CALL 42
+#define INDEX 43
+#define DPSTRUCT 44
+#define DSTRUCT 45
+#define IDENTIFIER 46
+#define CEXPR 47
+#define STRING 48
+#define MEMBER 49
+#define CONVERT 50
+#if 0
+#define CONVCHAR 50
+#define CONVSHORT 51
+#define CONVINT 52
+#define CONVLONG 53
+#define CONVFLOAT 54
+#define CONVDOUBLE 55
+#define CONVVOID 56
+#define CONVPOINTER 57
+#define CONVUCHAR 58
+#define CONVUSHORT 59
+#define CONVUINT 60
+#define CONVULONG 61
+#endif
+#define ADDRESSA 62
+#define FIRSTELEMENT 63
+#define PMULT 64
+#define ALLOCREG 65
+#define FREEREG 66
+#define PCEXPR 67
+#define TEST 68
+#define LABEL 69
+#define BEQ 70
+#define BNE 71
+#define BLT 72
+#define BGE 73
+#define BLE 74
+#define BGT 75
+#define BRA 76
+#define COMPARE 77
+#define PUSH 78
+#define POP 79
+#define ADDRESSS 80
+#define ADDI2P 81
+#define SUBIFP 82
+#define SUBPFP 83
+#define PUSHREG 84
+#define POPREG 85
+#define POPARGS 86
+#define SAVEREGS 87
+#define RESTOREREGS 88
+#define ILABEL 89
+#define DC 90
+#define ALIGN 91
+#define COLON 92
+#define GETRETURN 93
+#define SETRETURN 94
+#define MOVEFROMREG 95
+#define MOVETOREG 96
+#define NOP 97
+#define BITFIELD 98
+#define LITERAL 99
+#define REINTERPRET 100
+extern char *typname[];
+extern zmax sizetab[];
+extern char *storage_class_name[];
+extern char *ename[];
+extern int align_arguments; /* arguments correctly aligned on stack or
+			       just stackalign? */
+extern zmax align[],maxalign,stackalign;
+/*  an empty string */
+extern char *empty;
+extern zchar vchar; extern zuchar vuchar;
+extern zshort vshort; extern zushort vushort;
+extern zint vint; extern zuint vuint;
+extern zlong vlong; extern zulong vulong;
+extern zllong vllong; extern zullong vullong;
+extern zmax vmax; extern zumax vumax;
+extern zfloat vfloat; extern zdouble vdouble;
+extern zldouble vldouble;
+extern union atyps gval;
+#ifndef DEBUG
+extern int DEBUG;
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+/*  used by the optimizer */
+/* for lists in ICs flags may be DREFOBJ to mark dereferences */
+/* for lists in function infos flags is the type of access */
+typedef struct varlist{
+  struct Var *v;
+  int flags;
+} varlist;
+#define VLS sizeof(struct varlist)
+extern struct IC *first_ic,*last_ic;
+#define REGSA_NEVER 1
+#define REGSA_TEMPS 2
+extern int regs[MAXR+1],regsa[MAXR+1],regused[MAXR+1],simple_scratch[MAXR+1];
+extern int sregsa[MAXR+1];
+extern int reg_prio[MAXR+1],regscratch[MAXR+1];
+extern zmax regsize[MAXR+1];
+extern type *regtype[MAXR+1];
+extern struct Var *regsv[MAXR+1];
+extern char *regnames[];
+extern bvtype regs_modified[RSIZE/sizeof(bvtype)];
+extern int optspeed,optsize,unroll_all,stack_check;
+extern int cross_module,final,no_emit;
+extern int debug_info;
+extern int label,return_label;
+/* The structures used for available options of the code generator. */
+union ppi {char *p;long l;void (*f)(char *);};
+#define USEDFLAG 1
+#define STRINGFLAG 2
+#define VALFLAG 4
+#define FUNCFLAG 8
+extern int g_flags[MAXGF];
+extern char *g_flags_name[MAXGF];
+extern union ppi g_flags_val[MAXGF];
+extern zmax max_offset;
+extern int function_calls,vlas;
+extern int coloring;
+extern int dmalloc;
+extern int sec_per_obj;
+extern int disable;
+extern int misracheck,misraversion,misracomma,misratok;
+extern int pack_align;
+extern int short_push;
+extern int static_cse,dref_cse;
+extern int no_eff_ics,early_eff_ics;
+extern int force_statics,prefer_statics;
+extern int range_opt;
+extern int default_unsigned;
+extern Var *add_attr_haddecl;
+
+/*  Das haette ich gern woanders    */
+extern struct struct_declaration *add_sd(struct struct_declaration *,int);
+typedef struct node{
+  int flags,lvalue,sidefx;
+  int bfs,bfo;
+  type *ntyp;
+  struct node *left;
+  struct node *right;
+  struct argument_list *alist;
+  char *identifier;
+  struct const_list *cl;
+  struct Var *dsize;
+  union atyps val;
+  struct obj o;
+} node;
+typedef node *np;
+#define NODES sizeof(struct node)
+typedef struct const_list{
+  union atyps val;
+  np tree;
+  zmax idx;
+  struct const_list *other,*next;
+} const_list;
+#define CLS sizeof(struct const_list)
+typedef struct case_table{
+  int num,typf;
+  struct IC *next_ic;
+  double density;
+  union atyps *vals;
+  int *labels;
+  union atyps min,max;
+  zumax diff;
+} case_table;
+extern zmax t_min[];
+extern zumax t_max[];
+extern zumax tu_max[];
+extern zmax char_bit;
+extern char cg_copyright[];
+#ifdef HAVE_TARGET_ATTRIBUTES
+extern char *g_attr_name[];
+#endif
+extern char **target_macros;
+extern int goto_used;
+extern int ic_count;
+extern int only_inline;
+extern int multiple_ccs;
+extern int float_used;
+extern IC *err_ic;
+extern long maxoptpasses,optflags,inline_size,unroll_size,inline_depth;
+extern long clist_copy_stack;
+extern long clist_copy_static;
+extern long clist_copy_pointer;
+extern long inline_memcpy_sz;
+extern int noaliasopt,fp_assoc,noitra;
+extern Var *vl0,*vl1,*vl2,*vl3;
+extern char *filename;
+extern char *emit_buffer[EMIT_BUF_DEPTH];
+extern char *emit_p;
+extern int emit_f,emit_l;
+extern int no_inline_peephole;
+extern int ecpp;
+/* functions which must be provided by the frontend */
+extern void add_IC(IC *);
+extern void error(int,...);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+extern Var *add_tmp_var(type *);
+extern void free_var(Var *);
+extern void raus(void);
+/* functions provided by supp.c */
+#define printtype prd
+#define printobj probj
+#define printic pric2
+#define printiclist pric
+extern void free_IC(IC *);
+extern void insert_IC(IC *,IC *);
+extern void move_IC(IC *,IC *);
+extern void pric(FILE *,IC *);
+extern void pric2(FILE *,IC *);
+extern void probj(FILE *,obj *,int);
+extern void emit(FILE *,const char *,...);
+extern void emit_char(FILE *,int);
+void emit_flush(FILE *);
+void remove_asm(void);
+#if HAVE_TARGET_PEEPHOLE
+extern int emit_peephole(void);
+#endif
+extern void emit_remove(void);
+extern void emit_inline_asm(FILE *,char *);
+extern void emitzm(FILE *,zmax);
+extern void emitzum(FILE *,zumax);
+extern void emitzld(FILE *,zldouble);
+extern void emitval(FILE *,union atyps *,int);
+extern void printzm(FILE *,zmax);
+extern void printzum(FILE *,zumax);
+extern void printzld(FILE *,zldouble);
+extern void printval(FILE *,union atyps *,int);
+extern void insert_const(union atyps *,int);
+extern void prd(FILE *,type *);
+extern void print_var(FILE *,Var *);
+extern void freetyp(type *);
+extern type *new_typ(void);
+extern type *clone_typ(type *);
+#ifdef HAVE_EXT_TYPES
+extern void conv_typ(type *);
+#endif
+extern int VECTYPE(int);
+extern int mkvec(int,int);
+extern zmax szof(type *);
+extern int is_vlength(type *);
+extern Var *vlength_szof(type *);
+extern zmax struct_offset(struct_declaration *,const char *);
+extern zmax falign(type *);
+int get_first_base_type(type *);
+extern int objs_equal(obj *,obj *,int);
+extern void eval_const(union atyps *,int);
+extern int get_clist_byte(type *,const_list *, zmax, zuchar *);
+extern zumax get_clist_int(type *, const_list *, zmax, int, int *);
+extern function_info *new_fi(void);
+extern void free_fi(function_info *);
+extern void print_fi(FILE *,function_info *);
+extern void static_stack_check(Var *);
+#ifdef HAVE_REGPARMS
+extern zmax va_offset(Var *);
+#endif
+extern void print_varlist(FILE *f,varlist *,int);
+extern void add_attr(char **,char *);
+extern int switch_IC(IC *);
+extern int collides(obj *,obj *);
+extern int is_const(type *);
+extern int is_volatile_obj(obj *);
+extern int is_volatile_ic(IC *);
+extern case_table *calc_case_table(IC *,double);
+int calc_regs(IC *,int);
+Var *declare_builtin(char *name,int ztyp,int q1typ,int q1reg,int q2typ,int q2reg,int nosidefx,char *asm);
+extern void emit_jump_table(FILE *,case_table *,char *,char *,int);
+extern void optimize(long, Var *);
+int bvcmp(bvtype *dest,bvtype *src,size_t len);
+int bvdointersect(bvtype *,bvtype *,size_t len);
+void bvunite(bvtype *dest,bvtype *src,size_t len);
+void bvintersect(bvtype *dest,bvtype *src,size_t len);
+void bvdiff(bvtype *dest,bvtype *src,size_t len);
+void vqsort (void *,size_t,size_t,int (*)(const void *,const void *));
+#define bvcopy(dest,src,len) memcpy(dest,src,len)
+#define bvclear(dest,len) memset(dest,0,len)
+#define bvsetall(dest,len) memset(dest,-1,len)
+extern void remove_IC(IC *);
+extern IC *clone_ic(IC *);
+extern IC *new_IC(void);
+extern Var *new_var(void);
+extern void insert_bitfield(obj *,obj *,obj *,int,int,int,int);
+extern void *mymalloc(size_t);
+extern void *myrealloc(void *,size_t);
+extern void myfree(void *p);
+#define free(x) myfree(x)
+extern char *mystrdup(char *);
+extern void simple_regs(void);
+extern int bflayout(int,int,int);
+/*  functions provided by the code generator */
+extern int regok(int,int,int);
+typedef struct rpair {int r1,r2;} rpair;
+int reg_pair(int,rpair *);
+extern rpair rp;
+extern int freturn(type *);
+#define ffreturn(x) ((x)->reg?(x)->reg:freturn(x))
+extern void gen_code(FILE *,IC *,Var *,zmax);
+extern int init_cg(void);
+extern void cleanup_cg(FILE *);
+extern void init_db(FILE *);
+void cleanup_db(FILE *);
+extern int dangerous_IC(IC *);
+extern void gen_dc(FILE *,int,const_list *);
+extern void gen_ds(FILE *,zmax,type *);
+extern void gen_var_head(FILE *,Var *);
+extern void gen_align(FILE *,zmax);
+extern int shortcut(int, int);
+extern int must_convert(int,int,int);
+long get_pof2(zumax);
+int is_varargs(type *);
+
+typedef void *hashdata;
+
+typedef struct hashentry {
+  char *name;
+  hashdata data;
+  struct hashentry *next;
+} hashentry;
+
+typedef struct hashtable {
+  hashentry **entries;
+  size_t size;
+  int collisions;
+} hashtable;
+
+hashtable *new_hashtable(size_t);
+size_t hashcode(char *);
+void add_hashentry(hashtable *,char *,hashdata);
+hashdata find_name(hashtable *,char *);
+
+#ifdef HAVE_TARGET_PRAGMAS
+extern int handle_pragma(const char *);
+#endif
+#ifdef HAVE_LIBCALLS
+extern char *use_libcall(int code,int t1,int t2);
+#ifndef LIBCALL_CMPTYPE
+#define LIBCALL_CMPTYPE INT
+#endif
+#endif
+#ifdef HAVE_TARGET_VARHOOK_PRE
+extern void add_var_hook_pre(const char *,type *,int,const_list *);
+#endif
+#ifdef HAVE_TARGET_VARHOOK_POST
+extern void add_var_hook_post(Var *);
+#endif
+extern int cost_savings(IC *,int,obj *);
+/* additional declarations for targets which pass arguments in */
+/* registers by default.                                       */
+#ifdef HAVE_REGPARMS
+extern treg_handle empty_reg_handle;
+/* last parameter is function type or return type or pointer to function type */
+extern int reg_parm(treg_handle *, type *,int,type *);
+#endif
+#ifdef HAVE_TARGET_EFF_IC
+extern void mark_eff_ics(void);
+#else
+#define mark_eff_ics()
+#endif
+#ifndef JUMP_TABLE_DENSITY
+#define JUMP_TABLE_DENSITY 1
+#endif
+#ifndef JUMP_TABLE_LENGTH
+#define JUMP_TABLE_LENGTH 1000
+#endif
+#ifndef ALLOCVLA_REG
+#define ALLOCVLA_REG 0
+#endif
+#ifndef ALLOCVLA_INLINEASM
+#define ALLOCVLA_INLINEASM 0
+#endif
+#ifndef FREEVLA_REG
+#define FREEVLA_REG 0
+#endif
+#ifndef FREEVLA_INLINEASM
+#define FREEVLA_INLINEASM 0
+#endif
+#ifndef OLDSPVLA_INLINEASM
+#define OLDSPVLA_INLINEASM 0
+#endif
+#ifndef FPVLA_REG
+#define FPVLA_REG 0
+#endif
+#ifndef MIN_INT_TO_FLOAT_TYPE
+#define MIN_INT_TO_FLOAT_TYPE CHAR
+#endif
+#ifndef MIN_FLOAT_TO_INT_TYPE
+#define MIN_FLOAT_TO_INT_TYPE CHAR
+#endif
+#ifndef AVOID_FLOAT_TO_UNSIGNED
+#define AVOID_FLOAT_TO_UNSIGNED 0
+#endif
+#ifndef AVOID_UNSIGNED_TO_FLOAT
+#define AVOID_UNSIGNED_TO_FLOAT 0
+#endif
+#ifndef CHARCONV
+#define CHARCONV(x) (x)
+#define CHARBACK(x) (x)
+#define STRBACK(x)
+#else
+unsigned char CHARBACK(unsigned char);
+void STRBACK(unsigned char *);
+#endif
+
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+
+#endif /* SUPP_H */
diff --git a/t1.h b/t1.h
new file mode 100644
index 0000000..e6f8b57
--- /dev/null
+++ b/t1.h
@@ -0,0 +1,4 @@
+/* $Revision: 1.2 $ */
+
+#include "t2.h"
+
diff --git a/t2.h b/t2.h
new file mode 100755
index 0000000..8ffe1e3
--- /dev/null
+++ b/t2.h
@@ -0,0 +1,2 @@
+t2 is here
+
diff --git a/tasm.c b/tasm.c
new file mode 100755
index 0000000..fb6374f
--- /dev/null
+++ b/tasm.c
@@ -0,0 +1,128 @@
+/*  Test-language for vbcc. */
+
+#include "supp.h"
+
+struct Var *fv;
+
+struct Typ tint,mfunc;
+struct struct_declaration msd; /* initialized to zero */
+
+void raus(void)
+{
+    while(fv){
+        struct Var *m=fv->next;
+        free(fv);
+        fv=m;
+    }
+    while(first_ic){
+        struct IC *m=first_ic->next;
+        free(first_ic);
+        first_ic=m;
+    }
+    exit(0);
+}
+void add_IC(struct IC *new)
+{
+    new->next=0;
+    new->prev=last_ic;
+    new->change_cnt=new->use_cnt=0;
+    new->change_list=new->use_list=0;
+    new->line=0;
+    new->file=0;
+    if(!last_ic){
+        first_ic=new;
+    }else{
+        last_ic->next=new;
+    }
+    last_ic=new;
+}
+struct Var *add_var(char *name,struct Typ *t,int sc)
+{
+    struct Var *v=mymalloc(sizeof(*v));
+    v->vtyp=t;
+    v->storage_class=sc;
+    v->reg=0;
+    v->identifier=name;
+    v->offset=max_offset;
+    if(sc==AUTO) max_offset=zmadd(max_offset,sizetab[t->flags&NQ]);
+    v->priority=1;
+    v->flags=0;
+    v->next=fv;
+    v->clist=0;
+    v->fi=0;
+    v->inline_copy=0;
+    fv=v;
+    return v;
+}
+struct Var *add_tmp_var(struct Typ *t)
+{
+    return add_var(empty,t,AUTO);
+}
+struct Var *get_var(char *name)
+{
+    struct Var *v;char *buf;
+    for(v=fv;v;v=v->next){
+        if(!strcmp(name,v->identifier)) return v;
+    }
+    buf=mymalloc(strlen(name)+1);
+    strcpy(buf,name);
+    return add_var(buf,&tint,AUTO);
+}
+
+void read_ics()
+{
+    char s[400],q1[100],q2[100],z[100],op;
+    struct IC *new;
+    gets(s);
+    while(sscanf(s,"%99s = %99s %c %99s",z,q1,&op,q2)==4){
+        new=new_IC();
+        switch(op){
+            case '+': new->code=ADD;break;
+            case '*': new->code=MULT;break;
+            case '-': new->code=SUB;break;
+            case '/': new->code=DIV;break;
+            default: return;
+        }
+        new->typf=INT;
+        new->q1.flags=new->q2.flags=new->z.flags=VAR;
+        new->q1.am=new->q2.am=new->z.am=0;
+        new->q1.val.vmax=l2zm(0L);
+        new->q2.val.vmax=l2zm(0L);
+        new->z.val.vmax=l2zm(0L);
+        new->q1.v=get_var(q1);
+        new->q2.v=get_var(q2);
+        new->z.v=get_var(z);
+        add_IC(new);
+        gets(s);
+    }
+}
+void error(int n,...)
+{
+    printf("error %d\n",n);
+    raus();
+}
+void savescratch()
+{}
+
+main()
+{
+    struct Var *main;
+    max_offset=l2zm(0L);
+    if(!init_cg()) raus();
+    tint.flags=INT;
+    tint.next=0;
+    mfunc.flags=FUNKT;
+    mfunc.next=&tint;
+    mfunc.exact=&msd;
+    main=add_var("main",&mfunc,EXTERN);
+    read_ics();
+    printf("optflags: ");
+    scanf("%ld",&optflags);
+    pric(stdout,first_ic);
+    vl1=vl3=0;
+    vl2=fv;
+    optimize(optflags,main);
+    pric(stdout,first_ic);
+    gen_code(stdout,first_ic,main,max_offset);
+    raus();
+}
diff --git a/tt.h b/tt.h
new file mode 100755
index 0000000..9de6d55
--- /dev/null
+++ b/tt.h
@@ -0,0 +1,3 @@
+test1
+test2
+
diff --git a/type_expr.c b/type_expr.c
new file mode 100644
index 0000000..4c68805
--- /dev/null
+++ b/type_expr.c
@@ -0,0 +1,3090 @@
+/*  $VER: vbcc (type_expr.c) $Revision: 1.64 $   */
+
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+#define CONSTADDR 256
+
+
+/* if MASK is set, a specialized version will be generated */
+#define USEHALF  (1L<<1)
+#define USELONG  (1L<<2)
+#define USELLONG (1L<<3)
+#define USEFLOAT (1L<<4)
+#define USEHEXL  (1L<<5)
+#define USEHEXU  (1L<<6)
+#define USEDEC   (1L<<7)
+#define USEOCT   (1L<<8)
+#define USEINT   (1L<<9)
+#define USEUNS   (1L<<10)
+#define USESTR   (1L<<11)
+#define USECHAR  (1L<<12)
+#define USEPERC  (1L<<13)
+#define USECNT   (1L<<14)
+#define USEALT   (1L<<15)
+#define USEZPAD  (1L<<16)
+#define USELALGN (1L<<17)
+#define USEBLANK (1L<<18)
+#define USESIGN  (1L<<19)
+#define USEWIDTH (1L<<20)
+#define USEAST   (1L<<21)
+#define USEPREC  (1L<<22)
+#define USESPEC  (1L<<23)
+#define USEREXP  (1L<<24)
+
+int alg_opt(np,type *);
+void simple_alg_opt(np);
+int test_assignment(type *,np);
+int type_expression2(np,type *);
+void make_cexpr(np);
+
+int dontopt;
+int no_cast_free;
+
+type uct={UNSIGNED|CHAR};
+type ust={UNSIGNED|SHORT};
+type uit={UNSIGNED|INT};
+type ult={UNSIGNED|LONG};
+
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+
+
+
+
+void insert_constn(np p)
+/*  Spezialfall fuer np */
+{
+    if(!p||!p->ntyp) ierror(0);
+    insert_const(&p->val,p->ntyp->flags);
+}
+int const_typ(type *p)
+/*  Testet, ob Typ konstant ist oder konstante Elemente enthaelt    */
+{
+    int i;struct_declaration *sd;
+    if(p->flags&CONST) return(1);
+    if(ISSTRUCT(p->flags)||ISUNION(p->flags))
+        for(i=0;i<p->exact->count;i++)
+            if(const_typ((*p->exact->sl)[i].styp)) return(1);
+    return 0;
+}
+int arith_flag(int ta,int tb)
+{
+  /* TODO: volatile? */
+  ta&=NU;tb&=NU;
+  if(ta==LDOUBLE||tb==LDOUBLE) return LDOUBLE;
+  if(ta==DOUBLE||tb==DOUBLE) return DOUBLE;
+  if(ta==FLOAT||tb==FLOAT) return FLOAT;
+  ta=int_erw(ta);tb=int_erw(tb);
+  if(ta==(UNSIGNED|LLONG)||tb==(UNSIGNED|LLONG)) return UNSIGNED|LLONG;
+  if(ta==LLONG||tb==LLONG) return LLONG;
+  if(ta==(UNSIGNED|LONG)||tb==(UNSIGNED|LONG)) return UNSIGNED|LONG;
+  if((ta==LONG&&tb==(UNSIGNED|INT))||(ta==(UNSIGNED|INT)&&tb==LONG)){
+    if(zumleq(t_max(UNSIGNED|INT),t_max(LONG))) 
+      return LONG;
+    else
+      return UNSIGNED|LONG;
+  }
+  if(ta==LONG||tb==LONG) return LONG;
+  if(ta==(UNSIGNED|INT)||tb==(UNSIGNED|INT)) return UNSIGNED|INT;
+  return INT;
+}
+
+type *arith_typ(type *a,type *b)
+/*  Erzeugt Typ fuer arithmetische Umwandlung von zwei Operanden    */
+{
+  int ta,tb,va,vol;type *new;
+    new=new_typ();
+    ta=a->flags&NU;tb=b->flags&NU;
+    vol=(a->flags&VOLATILE)|(b->flags&VOLATILE);
+    if(ta==LDOUBLE||tb==LDOUBLE){new->flags=LDOUBLE|vol;return new;}
+    if(ta==DOUBLE||tb==DOUBLE){new->flags=DOUBLE|vol;return new;}
+    if(ta==FLOAT||tb==FLOAT){new->flags=FLOAT|vol;return new;}
+    ta=int_erw(ta);tb=int_erw(tb);
+    if(ta==(UNSIGNED|LLONG)||tb==(UNSIGNED|LLONG)){new->flags=UNSIGNED|LLONG|vol;return new;}
+    if(ta==LLONG||tb==LLONG){new->flags=LLONG|vol;return new;}
+    if(ta==(UNSIGNED|LONG)||tb==(UNSIGNED|LONG)){new->flags=UNSIGNED|LONG|vol;return new;}
+    if((ta==LONG&&tb==(UNSIGNED|INT))||(ta==(UNSIGNED|INT)&&tb==LONG)){
+        if(zumleq(t_max(UNSIGNED|INT),t_max(LONG))) new->flags=LONG|vol; else new->flags=UNSIGNED|LONG|vol;
+        return new;
+    }
+    if(ta==LONG||tb==LONG){new->flags=LONG|vol;return new;}
+    if(ta==(UNSIGNED|INT)||tb==(UNSIGNED|INT)){new->flags=UNSIGNED|INT|vol;return new;}
+    new->flags=INT|vol;
+    return new;
+}
+int int_erw(int t)
+/*  Fuehrt Integer_Erweiterung eines Typen durch                */
+{
+    if((t&NQ)>=INT) return t;
+    if(t&UNSIGNED){
+      if((t&NQ)<=CHAR&&zumleq(t_max(UNSIGNED|CHAR),t_max(INT))) return INT;
+      if((t&NQ)<=SHORT&&zumleq(t_max(UNSIGNED|SHORT),t_max(INT))) return INT;
+      return UNSIGNED|INT;
+    }
+    return INT;
+}
+#if HAVE_AOS4
+static int aos4err;
+int aos4_attr(type *p,char *s)
+{
+  if(p->attr&&strstr(p->attr,s))
+    return 1;
+  if(p->next)
+    return aos4_attr(p->next,s);
+  else
+    return 0;
+}
+static np aos4_clone_tree(np p)
+{
+  np new;
+  if(!p) return 0;
+  new=new_node();
+  *new=*p;
+  new->ntyp=clone_typ(p->ntyp);
+  new->left=aos4_clone_tree(p->left);
+  new->right=aos4_clone_tree(p->right);
+  new->alist=0;new->cl=0;new->dsize=0;
+  if(p->flags==CALL/*||p->cl||p->dsize*/) aos4err=1;
+  return new;
+}
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+int type_expression(np p,type *ttyp)
+/*  Art Frontend fuer type_expression2(). Setzt dontopt auf 0   */
+{
+		int ret_val;
+    dontopt=0;
+    simple_alg_opt(p);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+   ret_val = type_expression2(p,ttyp);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+		return ret_val;
+
+}
+
+static void fix_addr_ptype(np op)
+{
+  np p=op;
+  while(p->flags==FIRSTELEMENT) p=p->left;
+  if(p->left->flags==CONTENT){
+    int pt=p->left->left->ntyp->flags;
+    if(!ISPOINTER(pt)) ierror(0);
+    if(!ISPOINTER(op->ntyp->flags)) ierror(0);
+    op->ntyp->flags=pt;
+  }
+}
+
+static int ptype(np op)
+{
+#ifdef POINTER_VARADR
+  Var *v=0;
+  np p=op;
+
+  while(p->flags==FIRSTELEMENT/*||p->flags==CONTENT*/) p=p->left;
+  
+  if(p->flags==IDENTIFIER)
+    v=find_var(p->identifier,0);
+  if(v) 
+    return POINTER_VARADR(v);
+  else
+    return POINTER_TYPE(op->ntyp);
+#else
+  return POINTER_TYPE(op->ntyp);
+#endif
+}
+
+static int decide_shortcut(np p,type *ttyp)
+{
+  int ttf=ttyp->flags,f=p->flags;
+  if(f==PMULT) f=MULT;
+  if(!shortcut(f,ttyp->flags&NU)||
+     ISFLOAT(ttf)||ISFLOAT(p->left->ntyp->flags)||ISFLOAT(p->right->ntyp->flags)
+     )
+    return 0;
+  ttf&=NQ;
+  if(ttf<INT) return 1;
+  if(zm2l(sizetab[ttf])<zm2l(sizetab[(p->left->ntyp->flags&NQ)])) return 1;
+  if(zm2l(sizetab[ttf])<zm2l(sizetab[(p->right->ntyp->flags&NQ)])) return 1;
+  return 0;
+}
+
+
+
+static type *best_addi2pt(zmax sz)
+{
+  if(!zmeqto(sizetab[CHAR],sizetab[INT])&&!zmeqto(sz,Z0)&&MINADDI2P<=CHAR&&zumleq(zm2zum(sz),zumadd(tu_max[CHAR],ZU1))){
+    return &uct;
+  }else if(!zmeqto(sizetab[SHORT],sizetab[INT])&&!zmeqto(sz,Z0)&&MINADDI2P<=SHORT&&zumleq(zm2zum(sz),zumadd(tu_max[SHORT],ZU1))){
+    return &ust;
+  }
+  return 0;
+}
+
+type *andcomp(np and,np cmp)
+{
+  int i=0;zmax sval;zumax uval;
+  if(cmp){
+    if((cmp->flags==CEXPR||cmp->flags==PCEXPR)){i=1;eval_constn(cmp);sval=vmax;uval=vumax;}
+  }else{
+    sval=Z0;uval=ZU0;
+    i=1;
+  }
+  if(and->flags==AND&&(and->left->flags==CEXPR||and->left->flags==PCEXPR)){i|=2;eval_constn(and->left);}
+  if(and->flags==AND&&(and->right->flags==CEXPR||and->right->flags==PCEXPR)){i|=2;eval_constn(and->right);}
+  if(i&2){
+    /*printf("CHECK: x&%ld ==/!= %ld\n",zm2l(vmax),(i&1)?zm2l(sval):-1L);*/
+    if(shortcut(COMPARE,UNSIGNED|CHAR)&&shortcut(AND,UNSIGNED|CHAR)&&!zmeqto(sizetab[CHAR],sizetab[SHORT])){
+      if(zmleq(vmax,t_max[CHAR]))
+	return &uct;
+      else if((i&1)&&zumleq(vumax,tu_max[CHAR])&&zumleq(uval,tu_max[CHAR]))
+	return &uct;
+    }
+    if(shortcut(COMPARE,UNSIGNED|SHORT)&&shortcut(AND,UNSIGNED|SHORT)&&!zmeqto(sizetab[SHORT],sizetab[INT])){
+      if(zmleq(vmax,t_max[SHORT]))
+	return &ust;
+      else if((i&1)&&zumleq(vumax,tu_max[SHORT])&&zumleq(uval,tu_max[SHORT]))
+	return &ust;
+    }
+    if(!zmeqto(sizetab[INT],sizetab[LONG])){
+      if(zmleq(vmax,t_max[INT]))
+	return &uit;
+      else if((i&1)&&zumleq(vumax,tu_max[INT])&&zumleq(uval,tu_max[INT]))
+	return &uit;
+    }
+    if(!zmeqto(sizetab[LONG],sizetab[LLONG])){
+      if(zmleq(vmax,t_max[LONG]))
+	return &ult;
+      else if((i&1)&&zumleq(vumax,tu_max[LONG])&&zumleq(uval,tu_max[LONG]))
+	return &ult;
+    }
+  }
+  return 0;
+}
+
+static int nullpointer(np p)
+{
+  if(p->flags!=CEXPR) return 0;
+  eval_constn(p); /* TODO: do we need to use other measure to verify null pointer? */
+  if(zmeqto(Z0,vmax)) return 1;
+  return 0;
+}
+
+int type_expression2(np p,type *ttyp)
+/*  Erzeugt Typ-Strukturen fuer jeden Knoten des Baumes und     */
+/*  liefert eins zurueck, wenn der Baum ok ist, sonst 0         */
+/*  Die Berechnung von Konstanten und andere Vereinfachungen    */
+/*  sollten vielleicht in eigene Funktion kommen                */
+{
+  int ok,f=p->flags,mopt=dontopt,ttf;
+  type *shorttyp;
+  static int assignop;
+  int aoflag;
+#if HAVE_AOS4
+  np thisp=0;
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+  if(!p){ierror(0);return(1);}
+  if(ttyp) ttf=ttyp->flags&NQ;
+  /*    if(p->ntyp) printf("Warnung: ntyp!=0\n");*/
+  p->lvalue=0;
+  p->sidefx=0;
+  ok=1;
+  if(!ecpp&&f==CALL&&p->left->flags==IDENTIFIER&&!find_var(p->left->identifier,0)){
+    /*  implizite Deklaration bei Aufruf einer Funktion     */
+    struct_declaration *sd;type *t;Var *v;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    error(161,p->left->identifier);
+    if(v=find_ext_var(p->left->identifier)){
+      if(!ISFUNC(v->vtyp->flags)||v->vtyp->next->flags!=INT){
+	error(68,p->left->identifier);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      }
+      v->flags&=~NOTINTU;
+    }else{	
+      sd=mymalloc(sizeof(*sd));
+      sd->count=0;
+      t=new_typ();
+      t->flags=FUNKT;
+      t->exact=add_sd(sd,FUNKT);
+      t->next=new_typ();
+      t->next->flags=INT;
+      add_var(p->left->identifier,t,EXTERN,0);
+    }
+  }
+#if HAVE_AOS4
+  if(f==CALL&&p->left->flags==DSTRUCT){
+    thisp=new_node();
+    thisp->flags=ADDRESS;
+    aos4err=0;
+    thisp->left=aos4_clone_tree(p->left->left);
+    thisp->right=0;
+    thisp->alist=0;thisp->cl=0;thisp->dsize=0;thisp->ntyp=0;
+  }
+#endif
+#if HAVE_ECPP
+  if(ecpp&&f==CALL){
+    argument_list *al=p->alist;
+    if(al/*&&!al->arg->ntyp*/){
+      while(al){
+        if(!al->arg) ierror(0);
+        if(!type_expression2(al->arg,0)) return 0;
+        al->arg=makepointer(al->arg);
+        if(type_uncomplete(al->arg->ntyp)) error(39);
+        al=al->next;
+      }
+    }
+  }
+  if(ecpp&&f==CALL){
+    ecpp_merk_al=ecpp_al;
+    ecpp_al=p->alist;
+  }
+#endif
+  dontopt=0;
+  if(f==ADDRESS&&p->left->flags==IDENTIFIER) {p->left->flags|=CONSTADDR;/*puts("&const");*/}
+  if(ttyp&&(f==OR||f==AND||f==XOR||f==ADD||f==SUB||f==MULT||f==PMULT||f==DIV||f==MOD||f==KOMPLEMENT||f==MINUS)&&!ISPOINTER(ttyp->flags)&&shortcut(f==PMULT?MULT:f,ttyp->flags&NU))
+    shorttyp=ttyp;
+  else
+    shorttyp=0;
+  if(assignop){
+    aoflag=1;
+    assignop=0;
+  }else
+    aoflag=0;
+
+  if(!shorttyp){
+    if(f==EQUAL||f==INEQUAL){
+      if(p->left->flags==AND) shorttyp=andcomp(p->left,p->right);
+      if(p->right->flags==AND) shorttyp=andcomp(p->right,p->left);
+    }
+  }
+  if(!shorttyp&&(f==LAND||f==LOR)&&p->left->flags==AND) shorttyp=andcomp(p->left,0);
+  if(p->left&&p->flags!=ASSIGNOP){
+    struct_declaration *sd;
+    /*  bei ASSIGNOP wird der linke Zweig durch den Link bewertet  */
+    if(!p->left) ierror(0);
+    if(p->flags==CAST)
+      ok&=type_expression2(p->left,p->ntyp);
+    else
+      ok&=type_expression2(p->left,shorttyp);
+    if(p->left) p->sidefx|=p->left->sidefx;
+    if(!ok) return 0;
+  }
+  if(aoflag){
+    if(!p->left||!p->right) ierror(0);
+    shorttyp=p->left->ntyp;
+    ttyp=shorttyp;
+    ttf=ttyp->flags&NQ;
+  }
+
+  if(f==LAND||f==LOR){
+    shorttyp=0;
+    if(p->right->flags==AND) shorttyp=andcomp(p->right,0);
+  }
+
+  if(f==ADD){
+    if(p->left->flags==ADDRESSS||p->left->flags==ADDRESSA||p->left->flags==ADDRESSS){
+      zmax sz=szof(p->left->left->ntyp);
+      shorttyp=best_addi2pt(sz);
+    }
+    if((p->left->ntyp->flags&NQ)==ARRAY){
+      zmax sz=szof(p->left->ntyp);
+      shorttyp=best_addi2pt(sz);
+      if(shorttyp){
+	np new=new_node();
+	new->flags=CAST;
+	new->ntyp=clone_typ(shorttyp);
+	new->left=p->right;
+	p->right=new;
+      }
+    }
+  }
+  if(p->right&&p->right->flags!=MEMBER){
+    struct_declaration *sd;
+    if(p->flags==ASSIGNOP){
+      dontopt=1;
+      assignop=1;
+    }else
+      dontopt=0;
+    if(p->flags==ASSIGN)
+      ok&=type_expression2(p->right,p->left->ntyp);
+    else
+      ok&=type_expression2(p->right,shorttyp);
+    p->sidefx|=p->right->sidefx;
+    if(!ok) return 0;
+  }
+#if HAVE_AOS4
+  if(thisp){
+    if(aos4_attr(p->left->ntyp,"libcall")){
+      argument_list *n=mymalloc(sizeof(*n));
+      n->arg=thisp;
+      n->next=p->alist;
+      n->pushic=0;
+      p->alist=n;
+      if(aos4err) {pre(stdout,thisp);ierror(0);}
+    }else{
+      free_expression(thisp);
+    }
+  }
+#endif
+#if HAVE_ECPP
+  if(ecpp&&f==CALL){
+    ecpp_al=ecpp_merk_al;
+  }
+#endif
+/*    printf("bearbeite %s\n",ename[p->flags]);*/
+/*  Erzeugung von Zeigern aus Arrays                            */
+/*  Hier muss noch einiges genauer werden (wie gehoert das?)    */
+  if(p->left&&f!=PCEXPR&&(ISARRAY(p->left->ntyp->flags)||ISFUNC(p->left->ntyp->flags))){
+    if(f!=ADDRESS&&f!=ADDRESSA&&f!=ADDRESSS&&f!=FIRSTELEMENT&&f!=DSTRUCT&&(f<PREINC||f>POSTDEC)&&(f<ASSIGN||f>ASSIGNOP)){
+      np new=new_node();
+      zmax sz=szof(p->left->ntyp);
+      if((p->left->ntyp->flags&NQ)==ARRAY) new->flags=ADDRESSA;
+      else new->flags=ADDRESS;
+      new->ntyp=0;
+      new->left=p->left;
+      new->right=0;new->lvalue=0;new->sidefx=0; /* sind sidefx immer 0? */
+      p->left=new;
+      ok&=type_expression2(p->left,0);
+    }
+  }
+  if(p->right&&f!=PCEXPR&&f!=FIRSTELEMENT&&f!=DSTRUCT&&f!=ADDRESSS&&p->right->ntyp&&(ISARRAY(p->right->ntyp->flags)||ISFUNC(p->right->ntyp->flags))){
+    np new=new_node();
+    if(ISARRAY(p->right->ntyp->flags)) new->flags=ADDRESSA;
+    else new->flags=ADDRESS;
+    new->ntyp=0;
+    new->left=p->right;
+    new->right=0;new->lvalue=0;new->sidefx=0; /* sind sidefx immer 0? */
+    p->right=new;
+    ok&=type_expression2(p->right,0);
+  }
+
+  if(f==IDENTIFIER||f==(IDENTIFIER|CONSTADDR)){
+    int ff;Var *v;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(!ecpp){
+      if(p->identifier==empty)
+	/* variable sizeof-expression */
+	v=p->dsize;
+      else{
+	char buf[20];
+	v=find_var(p->identifier,0);
+	if(v&&v->storage_class==EXTERN){
+	  if(!strcmp(p->identifier,"strtod")){sprintf(buf,"vfscanf.%ld",1|USEFLOAT);needs(buf);}
+	  if(!strcmp(p->identifier,"strtof")){sprintf(buf,"vscanf.%ld",1|USEFLOAT);needs(buf);}
+	  if(!strcmp(p->identifier,"atof")){sprintf(buf,"vscanf.%ld",1|USEFLOAT);needs(buf);}
+	  if(!strcmp(p->identifier,"tmpnam")){sprintf(buf,"vfprintf.%ld",1|USEDEC);needs(buf);}
+	  if(!strcmp(p->identifier,"fopen")){
+	    needs("__read.2");
+	    needs("__write.2");
+	    needs("stdin.2");
+	    needs("stdout.2");
+	    needs("stderr.2");
+	  }
+	}
+      }
+    }
+    if(v==0){error(82,p->identifier);return(0);}
+    if(disallow_statics&&v->storage_class==STATIC&&v->nesting==0&&*v->identifier){
+      error(302,v->identifier);
+      return 0;
+    }
+    ff=v->vtyp->flags&NQ;
+    if(ISARITH(ff)||ISPOINTER(ff)||ISSTRUCT(ff)||ISUNION(ff)||ISVECTOR(ff)) p->lvalue=1;
+    p->ntyp=clone_typ(v->vtyp);
+    /*  arithmetischen const Typ als Konstante behandeln, das muss noch
+	deutlich anders werden, bevor man es wirklich so machen kann
+        if((p->ntyp->flags&CONST)&&ISARITH(p->ntyp->flags)&&v->clist&&!(f&CONSTADDR)){
+	p->flags=CEXPR;
+	p->val=v->clist->val;
+	v->flags|=USEDASSOURCE;
+        }*/
+    p->flags&=~CONSTADDR;
+    if((p->ntyp->flags&NQ)==ENUM){
+      /*  enumerations auch als Konstante (int) behandeln */
+      p->flags=CEXPR;
+      if(!v->clist) ierror(0);
+      p->val=v->clist->val;
+      p->ntyp->flags=CONST|INT;
+    }
+    p->o.v=v;
+    if (p->ntyp->flags&VOLATILE) p->sidefx=1; /* Touching a volatile may have side effects */
+    return 1;
+  }
+
+  if(f==CEXPR||f==PCEXPR||f==STRING) return 1;
+
+  if(f==REINTERPRET){
+    /* todo: add checks */
+    return 1;
+  }
+
+  if(f==BITFIELD) return 1;
+
+  if(f==LITERAL){
+    p->lvalue=1;
+    return 1;
+  }
+
+  if(f==KOMMA){
+    if(const_expr){error(46);return 0;}
+    p->ntyp=clone_typ(p->right->ntyp);
+    if(f==CEXPR) p->val=p->right->val;
+    return ok;
+  }
+  if(f==ASSIGN||f==ASSIGNOP){
+    if(!p) ierror(0);
+    if(!p->left) ierror(0);
+    if(p->left->lvalue==0) {error(86);/*prd(p->left->ntyp);*/return 0;}
+    if(const_typ(p->left->ntyp)) {error(87);return 0;}
+    if(type_uncomplete(p->left->ntyp)) {error(88);return 0;}
+    if(type_uncomplete(p->right->ntyp)) {error(88);return 0;}
+    p->ntyp=clone_typ(p->left->ntyp);
+    p->sidefx=1;
+    return(test_assignment(p->left->ntyp,p->right));
+  }
+  if(f==LOR||f==LAND){
+    int a1=-1,a2=-1,m;
+    if(ISVECTOR(p->left->ntyp->flags)){
+      if(ISVECTOR(p->right->ntyp->flags)){
+	if((p->left->ntyp->flags&NU)!=(p->right->ntyp->flags&NU)){error(89);return 0;}
+      }else{
+	if(!ISINT(p->right->ntyp->flags)){error(89);return 0;}
+      }
+      p->ntyp=new_typ();
+      p->ntyp->flags=p->left->ntyp->flags&NQ;
+      return ok;
+    }
+    if(ISVECTOR(p->right->ntyp->flags)){
+      if(!ISINT(p->left->ntyp->flags)){error(89);return 0;}
+      p->ntyp->flags=p->right->ntyp->flags&NQ;
+      return ok;
+    }
+    if(f==LAND) m=1; else m=0;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    p->ntyp=new_typ();
+    p->ntyp->flags=INT;
+    if(!ISARITH(p->left->ntyp->flags)&&!ISPOINTER(p->left->ntyp->flags))
+      {error(89);ok=0;}
+    if(!ISARITH(p->right->ntyp->flags)&&!ISPOINTER(p->right->ntyp->flags))
+      {error(89);ok=0;}
+    if(p->left->flags==CEXPR){
+      eval_constn(p->left);
+      if(!zldeqto(vldouble,d2zld(0.0))||!zumeqto(vumax,ul2zum(0UL))||!zmeqto(vmax,l2zm(0L))) a1=1; else a1=0;
+    }
+    if(p->right->flags==CEXPR){
+      eval_constn(p->right);
+      if(!zldeqto(vldouble,d2zld(0.0))||!zumeqto(vumax,ul2zum(0UL))||!zmeqto(vmax,l2zm(0L))) a2=1; else a2=0;
+    }
+    if(a1==1-m||a2==1-m||(a1==m&&a2==m)){
+      p->flags=CEXPR;p->sidefx=0;
+      if(!p->left->sidefx) {free_expression(p->left);p->left=0;} else p->sidefx=1;
+      if(!p->right->sidefx||a1==1-m) {free_expression(p->right);p->right=0;} else p->sidefx=0;
+      if(a1==1-m||a2==1-m) {p->val.vint=zm2zi(l2zm((long)(1-m)));}
+      else {p->val.vint=zm2zi(l2zm((long)m));}
+    }
+    return ok;
+  }
+  if(f==OR||f==AND||f==XOR){
+    if(ISVECTOR(p->left->ntyp->flags)){
+      if(!ISINT(VECTYPE(p->left->ntyp->flags))){error(90);return 0;}
+      if(ISVECTOR(p->right->ntyp->flags)){
+	if((p->left->ntyp->flags&NU)!=(p->right->ntyp->flags&NU)){error(98);return 0;}
+      }else{
+	if(!ISINT(p->right->ntyp->flags)){error(90);return 0;}
+      }
+      p->ntyp=clone_typ(p->left->ntyp);
+      return ok;
+    }
+    if(ISVECTOR(p->right->ntyp->flags)){
+      if(!ISINT(VECTYPE(p->right->ntyp->flags))){error(90);return 0;}
+      if(!ISINT(p->left->ntyp->flags)){error(90);return 0;}
+      p->ntyp=clone_typ(p->right->ntyp);
+      return ok;
+    }
+    if(!ISINT(p->left->ntyp->flags)){error(90);return 0;}
+    if(!ISINT(p->right->ntyp->flags)){error(90);return 0;}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    if(ttyp&&decide_shortcut(p,ttyp))
+      p->ntyp=clone_typ(ttyp);
+    else
+      p->ntyp=arith_typ(p->left->ntyp,p->right->ntyp);
+    if(!mopt){
+      if(!alg_opt(p,ttyp)) ierror(0);
+    }
+    return ok;
+  }
+  if(f==LESS||f==LESSEQ||f==GREATER||f==GREATEREQ||f==EQUAL||f==INEQUAL){
+    /*  hier noch einige Abfragen fuer sichere Entscheidungen einbauen  */
+    /*  z.B. unigned/signed-Vergleiche etc.                             */
+    /*  die val.vint=0/1-Zuweisungen muessen noch an zint angepasst     */
+    /*  werden                                                          */
+    zmax s1,s2;zumax u1,u2;zldouble d1,d2;int c=0;
+    type *t;
+    if(ISVECTOR(p->left->ntyp->flags)){
+      if(ISVECTOR(p->right->ntyp->flags)){
+	if((p->left->ntyp->flags&NU)!=(p->right->ntyp->flags&NU)){error(89);return 0;}
+      }
+      p->ntyp=new_typ();
+      if(ISFLOAT(VECTYPE(p->left->ntyp->flags)))
+	p->ntyp->flags=mkvec(INT,VECDIM(p->left->ntyp->flags));
+      else
+	p->ntyp->flags=p->left->ntyp->flags&NQ;
+      return ok;
+    }
+    if(ISVECTOR(p->right->ntyp->flags)){
+      p->ntyp=new_typ();
+      if(ISFLOAT(VECTYPE(p->right->ntyp->flags)))
+	p->ntyp->flags=mkvec(INT,VECDIM(p->left->ntyp->flags));
+      else
+	p->ntyp->flags=p->right->ntyp->flags&NQ;
+      return ok;
+    }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(!ISARITH(p->left->ntyp->flags)||!ISARITH(p->right->ntyp->flags)){
+      if(!ISPOINTER(p->left->ntyp->flags)||!ISPOINTER(p->right->ntyp->flags)){
+	if(f!=EQUAL&&f!=INEQUAL){
+	  error(92);return 0;
+	}else{
+	  if((!ISPOINTER(p->left->ntyp->flags)||p->right->flags!=CEXPR)&&
+	     (!ISPOINTER(p->right->ntyp->flags)||p->left->flags!=CEXPR)){
+	    error(93);return 0;
+	  }else{
+	    if(p->left->flags==CEXPR) eval_constn(p->left);
+	    else                     eval_constn(p->right);
+	    if(!zldeqto(vldouble,d2zld(0.0))||!zmeqto(vmax,l2zm(0L))||!zumeqto(vumax,ul2zum(0UL)))
+	      {error(40);return 0;}
+	  }
+	}
+      }else{
+	if(compatible_types(p->left->ntyp->next,p->right->ntyp->next,NQ)){
+	}else{
+	  if(f!=EQUAL&&f!=INEQUAL) error(41);
+	  if((p->left->ntyp->next->flags&NQ)!=VOID&&(p->right->ntyp->next->flags&NQ)!=VOID)
+	    {error(41);}
+	}
+      }
+    }
+    if(p->left->flags==CEXPR){
+      eval_constn(p->left);
+      d1=vldouble;u1=vumax;s1=vmax;c|=1;
+      if((p->right->ntyp->flags&UNSIGNED)&&!(p->left->ntyp->flags&UNSIGNED)){
+	if(zldleq(d1,d2zld(0.0))&&zmleq(s1,l2zm(0L))){
+	  if(!zldeqto(d1,d2zld(0.0))||!zmeqto(s1,l2zm(0L))){
+	    if(zumleq(tu_max[p->right->ntyp->flags&NQ],t_max[p->left->ntyp->flags&NQ]))
+	      error(165);
+	  }else{
+	    if(f==GREATER||f==LESSEQ) error(165);
+	  }
+	}
+      }
+    }
+    if(p->right->flags==CEXPR){
+      eval_constn(p->right);
+      d2=vldouble;u2=vumax;s2=vmax;c|=2;
+      if((p->left->ntyp->flags&UNSIGNED)&&!(p->right->ntyp->flags&UNSIGNED)){
+	if(zldleq(d2,d2zld(0.0))&&zmleq(s2,l2zm(0L))){
+	  if(!zldeqto(d2,d2zld(0.0))||!zmeqto(s2,l2zm(0L))){
+	    if(zumleq(tu_max[p->left->ntyp->flags&NQ],t_max[p->right->ntyp->flags&NQ]))
+	      error(165);
+	  }else{
+	    if(f==LESS||f==GREATEREQ) error(165);
+	  }
+	}
+      }
+    }
+    p->ntyp=new_typ();
+    p->ntyp->flags=INT;
+    if(c==3){
+      p->flags=CEXPR;
+      t=arith_typ(p->left->ntyp,p->right->ntyp);
+      if(!p->left->sidefx) {free_expression(p->left);p->left=0;}
+      if(!p->right->sidefx) {free_expression(p->right);p->right=0;}
+      if(ISFLOAT(t->flags)){
+	if(f==EQUAL) p->val.vint=zm2zi(l2zm((long)zldeqto(d1,d2)));
+	if(f==INEQUAL) p->val.vint=zm2zi(l2zm((long)!zldeqto(d1,d2)));
+	if(f==LESSEQ) p->val.vint=zm2zi(l2zm((long)zldleq(d1,d2)));
+	if(f==GREATER) p->val.vint=zm2zi(l2zm((long)!zldleq(d1,d2)));
+	if(f==LESS){
+	  if(zldleq(d1,d2)&&!zldeqto(d1,d2))
+	    p->val.vint=zm2zi(l2zm(1L));
+	  else
+	    p->val.vint=zm2zi(l2zm(0L));
+	}
+	if(f==GREATEREQ){
+	  if(!zldleq(d1,d2)||zldeqto(d1,d2))
+	    p->val.vint=zm2zi(l2zm(1L));
+	  else
+	    p->val.vint=zm2zi(l2zm(0L));
+	}
+      }else{
+	if(t->flags&UNSIGNED){
+	  if(f==EQUAL) p->val.vint=zm2zi(l2zm((long)zumeqto(u1,u2)));
+	  if(f==INEQUAL) p->val.vint=zm2zi(l2zm((long)!zumeqto(u1,u2)));
+	  if(f==LESSEQ) p->val.vint=zm2zi(l2zm((long)zumleq(u1,u2)));
+	  if(f==GREATER) p->val.vint=zm2zi(l2zm((long)!zumleq(u1,u2)));
+	  if(f==LESS){
+	    if(zumleq(u1,u2)&&!zumeqto(u1,u2))
+	      p->val.vint=zm2zi(l2zm(1L));
+	    else
+	      p->val.vint=zm2zi(l2zm(0L));
+	  }
+	  if(f==GREATEREQ){
+	    if(!zumleq(u1,u2)||zumeqto(u1,u2))
+	      p->val.vint=zm2zi(l2zm(1L));
+	    else 
+	      p->val.vint=zm2zi(l2zm(0L));
+	  }
+	}else{
+	  if(f==EQUAL) p->val.vint=zm2zi(l2zm((long)zmeqto(s1,s2)));
+	  if(f==INEQUAL) p->val.vint=zm2zi(l2zm((long)!zmeqto(s1,s2)));
+	  if(f==LESSEQ) p->val.vint=zm2zi(l2zm((long)zmleq(s1,s2)));
+	  if(f==GREATER) p->val.vint=zm2zi(l2zm((long)!zmleq(s1,s2)));
+	  if(f==LESS){
+	    if(zmleq(s1,s2)&&!zmeqto(s1,s2))
+	      p->val.vint=zm2zi(l2zm(1L));
+	    else 
+	      p->val.vint=zm2zi(l2zm(0L));
+	  }
+	  if(f==GREATEREQ){
+	    if(!zmleq(s1,s2)||zmeqto(s1,s2))
+	      p->val.vint=zm2zi(l2zm(1L));
+	    else 
+	      p->val.vint=zm2zi(l2zm(0L));
+	  }
+	}
+      }
+      freetyp(t);
+    }
+    return ok;
+  }
+  if(f==ADD||f==SUB||f==MULT||f==DIV||f==MOD||f==LSHIFT||f==RSHIFT||f==PMULT){
+    if(ISVECTOR(p->left->ntyp->flags)){
+      if((f==MOD||f==LSHIFT||f==RSHIFT)&&ISFLOAT(VECTYPE(p->left->ntyp->flags))){
+	error(98);
+	return 0;
+      }
+      if(ISARITH(p->right->ntyp->flags)){
+	p->ntyp=clone_typ(p->left->ntyp);
+	return ok;
+      }
+      if((p->left->ntyp->flags&NU)==(p->right->ntyp->flags&NU)){
+	p->ntyp=clone_typ(p->left->ntyp);
+	return ok;
+      }
+      error(98);
+      return 0;
+    }
+    if(ISVECTOR(p->right->ntyp->flags)){
+      if((f==MOD||f==LSHIFT||f==RSHIFT)&&ISFLOAT(VECTYPE(p->right->ntyp->flags))){
+	error(98);
+	return 0;
+      }
+      if(ISARITH(p->left->ntyp->flags)){
+	p->ntyp=clone_typ(p->right->ntyp);
+	return ok;
+      }
+      error(98);
+      return 0;
+    }
+    if(!ISARITH(p->left->ntyp->flags)||!ISARITH(p->right->ntyp->flags)){
+      np new;zmax sz; int typf=0;
+#ifdef MAXADDI2P
+      static type pmt={MAXADDI2P};
+#endif
+      if(f!=ADD&&f!=SUB){error(94);return 0;}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+      if(ISPOINTER(p->left->ntyp->flags)){
+	if((p->left->ntyp->next->flags&NQ)==VOID)
+	  {error(95);return 0;}
+	if(ISPOINTER(p->right->ntyp->flags)){
+	  if((p->right->ntyp->next->flags&NQ)==VOID)
+	    {error(95);return 0;}
+	  if(!compatible_types(p->left->ntyp->next,p->right->ntyp->next,NQ))
+	    {error(41);}
+	  if(f!=SUB){
+	    error(96);
+	    return 0;
+	  }else{
+	    typf=3;
+	  }
+	}else{
+	  if(!ISINT(p->right->ntyp->flags))
+	    {error(97,ename[f]);return 0;}
+	  if(p->right->flags!=PMULT&&p->right->flags!=PCEXPR){
+	    new=new_node();
+	    new->flags=PMULT;
+	    new->ntyp=0;
+	    new->left=p->right;
+	    new->right=new_node();
+	    if(is_vlength(p->left->ntyp->next)){
+	      new->right->flags=IDENTIFIER;
+	      new->right->identifier=empty;
+	      new->right->dsize=vlength_szof(p->left->ntyp->next);
+	      new->right->val.vmax=l2zm(0L);
+	      new->right->sidefx=0;
+	    }else{
+	      new->right->flags=PCEXPR;
+	      sz=szof(p->left->ntyp->next);
+	      if(zmeqto(l2zm(0L),sz)) error(78);
+#if HAVE_INT_SIZET
+	      new->right->val.vint=zm2zi(sz);
+#else
+	      new->right->val.vlong=zm2zl(sz);
+#endif
+	    }
+	    new->right->left=new->right->right=0;
+	    new->right->ntyp=new_typ();
+#if HAVE_INT_SIZET
+	    new->right->ntyp->flags=INT;
+#else
+	    new->right->ntyp->flags=LONG;
+#endif
+	    p->right=new;
+#ifdef MAXADDI2P
+	    ok&=type_expression2(new,(shorttyp&&(shorttyp->flags&NQ)<MAXADDI2P)?shorttyp:&pmt);
+#else
+	    ok&=type_expression2(new,shorttyp);
+#endif
+	  }
+	  typf=1;
+	}
+      }else{
+	np merk;
+	if(!ISPOINTER(p->right->ntyp->flags))
+	  {error(98);return 0;}
+	if((p->right->ntyp->next->flags&NQ)==VOID)
+	  {error(95);return 0;}
+	if(!ISINT(p->left->ntyp->flags))
+	  {error(98);return 0;}
+	if(p->flags==SUB){error(99);return 0;}
+	if(p->left->flags!=PMULT&&p->left->flags!=PCEXPR){
+	  new=new_node();
+	  new->flags=PMULT;
+	  new->ntyp=0;
+	  new->left=p->left;
+	  new->right=new_node();
+	  if(is_vlength(p->right->ntyp->next)){
+	    new->right->flags=IDENTIFIER;
+	    new->right->identifier=empty;
+	    new->right->dsize=vlength_szof(p->right->ntyp->next);
+	    new->right->val.vmax=l2zm(0L);
+	    new->right->sidefx=0;
+	  }else{
+	    new->right->flags=PCEXPR;
+	    sz=szof(p->right->ntyp->next);
+	    if(zmeqto(l2zm(0L),sz)) error(78);
+#if HAVE_INT_SIZET
+	    new->right->val.vint=zm2zi(sz);
+#else
+	    new->right->val.vlong=zm2zl(sz);
+#endif
+	  }
+	  new->right->left=new->right->right=0;
+	  new->right->ntyp=new_typ();
+#if HAVE_INT_SIZET
+	  new->right->ntyp->flags=INT;
+#else
+	  new->right->ntyp->flags=LONG;
+#endif
+	  p->left=new;
+#ifdef MAXADDI2P
+	  ok&=type_expression2(new,&pmt);
+#else
+	  ok&=type_expression2(new,0);
+#endif
+	}
+	typf=2;
+	merk=p->left;p->left=p->right;p->right=merk;
+      }
+      if(typf==0){ierror(0);return(0);}
+      else{
+	if(typf==3){
+	  p->ntyp=new_typ();
+	  p->ntyp->flags=PTRDIFF_T(p->left->ntyp->flags);
+	}else{
+	  /*if(typf==1)*/ p->ntyp=clone_typ(p->left->ntyp);
+	  /* else       p->ntyp=clone_typ(p->right->ntyp);*/
+	  /*  Abfrage wegen Vertauschen der Knoten unnoetig   */
+	}
+      }
+    }else{
+      if(f==LSHIFT||f==RSHIFT){
+	if(ttyp&&f==LSHIFT&&(ttf<=INT||ttf<(p->left->ntyp->flags&NQ))&&shortcut(f,ttyp->flags&NU)){
+	  p->ntyp=clone_typ(ttyp);
+	}else if(ttyp&&f==RSHIFT&&ttf<=INT&&ttf<=(p->left->ntyp->flags&NQ)&&shortcut(f,p->left->ntyp->flags&NU)){
+	  p->ntyp=clone_typ(p->left->ntyp);
+	}else{
+	  p->ntyp=arith_typ(p->left->ntyp,p->left->ntyp);
+	  p->ntyp->flags&=~NQ;
+	  p->ntyp->flags|=int_erw(p->left->ntyp->flags);
+	}
+	if(p->right->flags==CEXPR){
+	  eval_constn(p->right);
+	  if(!zmleq(l2zm(0L),vmax)) error(366);
+	  if(zmleq(zmmult(sizetab[p->ntyp->flags&NQ],char_bit),vmax)&&zmleq(zmmult(sizetab[p->left->ntyp->flags&NQ],char_bit),vmax)) error(367);
+	}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+      }else{
+	/* ggfs. in kleinerem Zieltyp auswerten - bei float keinen shortcut (wäre evtl. double=>float unkritisch?) */
+	if(ttyp&&decide_shortcut(p,ttyp))
+	  p->ntyp=clone_typ(ttyp);
+	else
+	  p->ntyp=arith_typ(p->left->ntyp,p->right->ntyp);
+	if(!ISINT(p->ntyp->flags)&&(f==MOD||f==LSHIFT||f==RSHIFT))
+	  {error(101);ok=0;}
+      }
+    }
+    /*  fuegt &a+x zusammen, noch sub und left<->right machen   */
+    /*  Bei CEXPR statt PCEXPR auch machen?                     */
+    if((p->flags==ADD||p->flags==SUB)){
+      np m,c=0,a=0;
+      if(p->left->flags==PCEXPR&&p->flags==ADD) c=p->left;
+      if(p->right->flags==PCEXPR) c=p->right;
+      if(p->left->flags==ADDRESS||p->left->flags==ADDRESSA||p->left->flags==ADDRESSS) a=p->left;
+      if(p->right->flags==ADDRESS||p->right->flags==ADDRESSA||p->right->flags==ADDRESSS) a=p->right;
+      if(c&&a){
+	m=a->left;
+	/*  kann man das hier so machen oder muss man da mehr testen ?  */
+	while(m->flags==FIRSTELEMENT||m->flags==ADDRESS||m->flags==ADDRESSA||m->flags==ADDRESSS) m=m->left;
+	if((m->flags==IDENTIFIER||m->flags==STRING)&&!is_vlength(m->ntyp)){
+	  if(DEBUG&1) printf("&a+x with %s combined\n",ename[p->left->flags]);
+	  eval_const(&c->val,c->ntyp->flags);
+	  if(p->flags==ADD)
+	    m->val.vmax=zumadd(m->val.vmax,vmax);
+	  else 
+	    m->val.vmax=zmsub(m->val.vmax,vmax);
+	  vmax=szof(m->ntyp);
+	  if(!zmeqto(vmax,l2zm(0L))&&zumleq(vmax,m->val.vmax)){
+	    if(zumeqto(vmax,m->val.vmax))
+	      error(79);
+	    else
+	      error(80);
+	  }
+	  vmax=l2zm(0L);
+	  if(!zmeqto(m->val.vmax,l2zm(0L))&&zumleq(m->val.vmax,vmax)) error(80);
+	  free_expression(c);
+	  if(p->ntyp) freetyp(p->ntyp);
+	  *p=*a;
+	  free(a);
+	  return type_expression2(p,0);
+	}
+      }
+    }
+    if(!mopt){
+      if(!alg_opt(p,ttyp)) ierror(0);
+    }
+    return ok;
+  }
+  if(f==CAST){
+    int from=(p->left->ntyp->flags),to=(p->ntyp->flags);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+    from&=NQ;to&=NQ;
+    if(to==VOID) return ok;
+    if(from==VOID)
+      {error(102);return 0;}
+    if((!ISARITH(to)||!ISARITH(from))&&
+       (!ISPOINTER(to)||!ISPOINTER(from))){
+      if(ISPOINTER(to)){
+	if(ISINT(from)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	  if(!zmleq(sizetab[from],sizetab[to])){
+	    error(103);
+	  }
+	}else{
+	  error(104);return 0;
+	}
+      }else{
+	if(!ISPOINTER(from))
+	  {error(105);return 0;}
+	if(ISINT(to)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	  if(!zmleq(sizetab[from],sizetab[to])){
+	    error(106);
+	  }
+	}else{
+	  error(104);return 0;
+	}
+      }
+    }
+    if(ISINT(from)&&ISINT(to)&&!zmleq(sizetab[from],sizetab[to])&&p->left->flags!=CEXPR) error(166);
+    if(ISPOINTER(to)&&ISPOINTER(from)&&!zmleq(falign(p->ntyp->next),falign(p->left->ntyp->next)))
+      error(167);
+    if(p->left->flags==CEXPR){
+      eval_constn(p->left);
+      if(ISPOINTER(p->ntyp->flags))
+	if(!zumeqto(vumax,ul2zum(0UL))||!zmeqto(vmax,l2zm(0L))||!zldeqto(vldouble,d2zld(0.0)))
+	  error(81);
+      insert_constn(p);
+      p->flags=CEXPR;
+      if(!p->left->sidefx){
+	if(!no_cast_free) 
+	  free_expression(p->left);
+	p->left=0;
+      }
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    return ok;
+  }
+  if(f==MINUS||f==KOMPLEMENT||f==NEGATION){
+    if(ISVECTOR(p->left->ntyp->flags)){
+      if(f==NEGATION){
+	if(ISFLOAT(VECTYPE(p->left->ntyp->flags))){error(98);return 0;}
+	p->ntyp=new_typ();
+	p->ntyp->flags=p->left->ntyp->flags&NQ;
+	return ok;
+      }
+      if(f==KOMPLEMENT&&ISFLOAT(VECTYPE(p->left->ntyp->flags))){error(109);return 0;}
+      p->ntyp=clone_typ(p->left->ntyp);
+      return ok;
+    }
+    if(!ISARITH(p->left->ntyp->flags)){
+      if(f!=NEGATION){
+	error(107);return 0;
+      }else{
+	if(!ISPOINTER(p->left->ntyp->flags))
+	  {error(108);return 0;}
+      }
+    }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+    if(f==KOMPLEMENT&&!ISINT(p->left->ntyp->flags))
+      {error(109);return 0;}
+    if(f==NEGATION){
+      p->ntyp=new_typ();
+      p->ntyp->flags=INT;
+    }else{
+      if(!p->left->ntyp) ierror(0);
+      p->ntyp=clone_typ(p->left->ntyp);
+      if(ISINT(p->ntyp->flags)){
+	if(!ttyp||!shortcut(f,ttyp->flags&NU)){
+	  p->ntyp->flags=int_erw(p->ntyp->flags);
+	}else{ 
+	  if((f==MINUS&&!zmleq(sizetab[ttyp->flags&NQ],sizetab[p->ntyp->flags&NQ]))||
+	     (f==KOMPLEMENT&&!zmleq(sizetab[ttyp->flags&NQ],sizetab[p->ntyp->flags&NQ])&&(p->ntyp->flags&UNSIGNED)))
+	    p->ntyp->flags=int_erw(p->ntyp->flags);
+	}
+      }
+    }
+    if(p->left->flags==CEXPR){
+      eval_constn(p->left);
+      if(f==KOMPLEMENT){
+	if(p->ntyp->flags&UNSIGNED){
+	  gval.vumax=zumkompl(vumax);
+	  eval_const(&gval,(UNSIGNED|MAXINT));
+	}else{
+	  gval.vmax=zmkompl(vmax);
+	  eval_const(&gval,MAXINT);
+	}
+      }
+      if(f==MINUS){
+	if(ISFLOAT(p->ntyp->flags)){
+	  gval.vldouble=zldsub(d2zld(0.0),vldouble);
+	  eval_const(&gval,LDOUBLE);
+	}else{
+	  if(p->ntyp->flags&UNSIGNED){
+	    gval.vumax=zumsub(ul2zum(0UL),vumax);
+	    eval_const(&gval,(UNSIGNED|MAXINT));
+	  }else{
+	    gval.vmax=zmsub(l2zm(0L),vmax);
+	    eval_const(&gval,MAXINT);
+	  }
+	}
+      }
+      if(f==NEGATION){
+	if(zldeqto(vldouble,d2zld(0.0))&&zumeqto(vumax,ul2zum(0UL))&&zmeqto(vmax,l2zm(0L)))
+	  gval.vmax=l2zm(1L); 
+	else 
+	  gval.vmax=l2zm(0L);
+	eval_const(&gval,MAXINT);
+      }
+      insert_constn(p);
+      p->flags=CEXPR;
+      if(!p->left->sidefx&&p->left) {free_expression(p->left);p->left=0;}
+    }
+    return ok;
+  }
+  if(f==CONTENT){
+    if(!ISPOINTER(p->left->ntyp->flags))
+      {error(111);return 0;}
+    if(!ISARRAY(p->left->ntyp->next->flags)&&type_uncomplete(p->left->ntyp->next))
+      {error(112);return 0;}
+    p->ntyp=clone_typ(p->left->ntyp->next);
+    if(!ISARRAY(p->ntyp->flags)) p->lvalue=1;
+    if(p->left->flags==ADDRESS&&zumeqto(p->left->val.vumax,ul2zum(0UL))){
+      /*  *&x durch x ersetzen                                */
+      np merk;
+      merk=p->left;
+      if(p->ntyp) freetyp(p->ntyp);
+      if(p->left->ntyp) freetyp(p->left->ntyp);
+      *p=*p->left->left;
+      free(merk->left);
+      free(merk);
+      return ok;
+    }
+    /*  *&ax durch firstelement-of(x) ersetzen  */
+    if(p->left->flags==ADDRESSA||p->left->flags==ADDRESSS){
+      if(!is_vlength(p->left->left->ntyp)){
+	np merk;
+	if(DEBUG&1) printf("substitutet * and %s with FIRSTELEMENT\n",ename[p->left->flags]);
+	p->flags=FIRSTELEMENT;
+	p->lvalue=1;    /*  evtl. hier erst Abfrage ?   */
+	merk=p->left;
+	p->left=merk->left;
+	p->right=merk->right;
+	if(merk->ntyp) freetyp(merk->ntyp);
+	free(merk);
+      }
+    }
+    if (p->ntyp->flags&VOLATILE) p->sidefx=1;
+    return ok;
+  }
+  if(f==FIRSTELEMENT){
+    if(ISARRAY(p->left->ntyp->flags)){
+      p->ntyp=clone_typ(p->left->ntyp->next);
+    }else{
+      int i,n=-1;
+      for(i=0;i<p->left->ntyp->exact->count;i++)
+	if(!strcmp((*p->left->ntyp->exact->sl)[i].identifier,p->right->identifier)) n=i;
+      if(n<0) ierror(0);
+      p->ntyp=clone_typ((*p->left->ntyp->exact->sl)[n].styp);
+    }
+    p->lvalue=1;    /*  hier noch genauer testen ?  */
+    return ok;
+  }
+  if(f==ADDRESS){
+    if(!ISFUNC(p->left->ntyp->flags)&&!ISARRAY(p->left->ntyp->flags)){
+      if(!p->left->lvalue){error(115);return 0;}
+      if(p->left->flags==IDENTIFIER){
+	Var *v;
+	v=find_var(p->left->identifier,0);
+	if(!v){error(116,p->left->identifier);return 0;}
+	if(v->storage_class==REGISTER)
+	  {error(117);return 0;}
+      }
+    }
+    p->ntyp=new_typ();
+    p->ntyp->flags=ptype(p->left);
+    p->ntyp->next=clone_typ(p->left->ntyp);
+    fix_addr_ptype(p);
+    return ok;
+  }
+  if(f==ADDRESSA){
+    p->ntyp=clone_typ(p->left->ntyp);
+    p->ntyp->flags=ptype(p->left);
+    fix_addr_ptype(p);
+    return ok;
+  }
+  if(f==ADDRESSS){
+    int i,n=-1;
+    struct_list *sl=0;
+    if(!ecpp){
+      for(i=0;i<p->left->ntyp->exact->count;i++)
+	if(!strcmp((*p->left->ntyp->exact->sl)[i].identifier,p->right->identifier)) n=i;
+      if(n<0)
+        return 0;
+      else
+        sl=&(*p->left->ntyp->exact->sl)[n];
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    p->ntyp=new_typ();
+    if(!p->left->ntyp) ierror(0);
+    if(!p->left->ntyp->exact) ierror(0);
+    if(!sl->styp) ierror(0);
+    p->ntyp->next=clone_typ(sl->styp);
+    p->ntyp->flags=ptype(p->left);
+    fix_addr_ptype(p);
+    return ok;
+  }
+  if(f==DSTRUCT){
+    struct_declaration *sd=p->left->ntyp->exact;
+    char *identifier=p->right->identifier;
+    int i=0,f,bfs=-1,bfo=-1;type *t;np new;zmax offset=l2zm(0L);
+    if(!ISSTRUCT(p->left->ntyp->flags)&&!ISUNION(p->left->ntyp->flags))
+      {error(8);return 0;}
+    if(type_uncomplete(p->left->ntyp)){error(11);return 0;}
+    if(p->right->flags!=MEMBER) ierror(0);
+    if(i>=p->left->ntyp->exact->count) {error(23,p->right->identifier);return 0;}
+    if(!ecpp){
+      offset=struct_offset(sd,identifier);
+    }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    if(ISUNION(p->left->ntyp->flags)) offset=l2zm(0L);
+    p->flags=CONTENT;
+    if(p->ntyp) {freetyp(p->ntyp);p->ntyp=0;}
+    new=new_node();
+    new->flags=ADD;
+    new->ntyp=0;
+    new->right=new_node();
+    new->right->left=new->right->right=0;
+    new->right->flags=PCEXPR;
+    new->right->ntyp=new_typ();
+    if(/*MINADDI2P<=INT&&*/zumleq(zm2zum(offset),t_max(INT))){
+      new->right->ntyp->flags=INT;
+      new->right->val.vint=zm2zi(offset);
+    }else{
+      new->right->ntyp->flags=LONG;
+      new->right->ntyp->next=0;
+      new->right->val.vlong=zm2zl(offset);
+    }
+    new->left=new_node();
+    new->left->flags=ADDRESSS;
+    new->left->left=p->left;
+    new->left->right=p->right;
+    new->left->ntyp=0;
+    p->left=new;p->right=0;
+
+    /* Check for bitfields */
+    i=0;
+    while(i<sd->count&&strcmp((*sd->sl)[i].identifier,identifier)){
+      i++;
+    }
+    if(i<sd->count){
+      bfo=(*sd->sl)[i].bfoffset;
+      bfs=(*sd->sl)[i].bfsize;
+    }else
+      bfs=-1;
+    if(bfs!=-1){
+      /* create a special node for bitfields */
+      ok|=type_expression2(p,0);
+      new=new_node();
+      *new=*p;
+      p->flags=BITFIELD;
+      p->left=new;
+      p->right=0;
+      p->sidefx=0;
+      p->bfs=bfs;
+      p->bfo=bfo;
+      p->ntyp=clone_typ(new->ntyp);
+      return ok;
+    }
+    return type_expression2(p,0);
+  }
+  if(f==PREINC||f==POSTINC||f==PREDEC||f==POSTDEC){
+    if(!p->left->lvalue){error(86);return 0;}
+    if(p->left->ntyp->flags&CONST){error(87);return 0;}
+    if(!ISARITH(p->left->ntyp->flags)){
+      if(!ISPOINTER(p->left->ntyp->flags)){
+	error(24);
+	return 0;
+      }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+	if((p->left->ntyp->next->flags&NQ)==VOID)
+	  {error(95);return 0;}
+      }
+    }
+    p->ntyp=clone_typ(p->left->ntyp);
+    p->sidefx=1;
+    return ok;
+  }
+  if(f==CALL){
+    argument_list *al;int i,flags=0;char *s=0;
+    struct_declaration *sd;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    al=p->alist;
+    if(!ISPOINTER(p->left->ntyp->flags)||!ISFUNC(p->left->ntyp->next->flags))
+      {error(26);return 0;}
+    if(ok&&p->left->left&&p->left->left->flags==IDENTIFIER&&p->left->left->o.v->storage_class==EXTERN){
+      s=p->left->left->o.v->identifier;
+      flags=p->left->left->o.v->flags;
+    }
+    sd=p->left->ntyp->next->exact;
+    if(!sd) ierror(0);
+    if(sd->count==0){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      error(162);
+      if(s){
+	if(!strcmp(s,"printf")||!strcmp(s,"fprintf")||!strcmp(s,"sprintf")||
+	   !strcmp(s,"scanf")|| !strcmp(s,"fscanf")|| !strcmp(s,"sscanf"))
+	  error(213);
+      }
+    }
+    if(!(ecpp&&al&&al->arg->ntyp)){
+      i=0;
+      while(al){
+	if(!al->arg) ierror(0);
+	if(!type_expression2(al->arg,(short_push&&i<sd->count)?(*sd->sl)[i].styp:0)) return 0;
+	al->arg=makepointer(al->arg);
+	if(type_uncomplete(al->arg->ntyp)) error(39);
+	al=al->next;
+	i++;
+      }
+    }
+    p->sidefx=1;
+    p->ntyp=clone_typ(p->left->ntyp->next->next);
+    i=0;al=p->alist;
+    while(al){
+      if(i>=sd->count) return ok;
+      if(!(*sd->sl)[i].styp) return ok; /* nur Bezeichner, aber kein Typ im Prototype */
+      if(!test_assignment((*sd->sl)[i].styp,al->arg)) return 0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+      if(i==sd->count-1&&(flags&(PRINTFLIKE|SCANFLIKE))){
+	if(al->arg->left&&al->arg->left->flags==STRING){
+	  /*  Argumente anhand des Formatstrings ueberpruefen */
+	  const_list *cl=al->arg->left->cl;
+	  int fused=0;long mask=1;
+	  al=al->next;
+	  while(cl&&cl->other){
+	    int c,fflags=' ',at,lflag;
+	    type *t;
+	    enum{LL=1,HH};
+	    c=(int)zm2l(zc2zm(cl->other->val.vchar));
+ 	    cl=cl->next;
+	    if(c==0){
+	      if(cl) error(215);
+	      break;
+	    }
+	    c=CHARBACK(c);
+	    if(c!='%') continue;
+	    if(!cl){error(214);return ok;}
+	    lflag=0;
+	    c=(int)zm2l(zc2zm(cl->other->val.vchar));
+	    c=CHARBACK(c);
+	    cl=cl->next;
+	    while(isdigit((unsigned char)c)||
+		  c=='-'||c=='+'||c==' '||c=='#'||c=='.'||
+		  c=='h'||c=='l'||c=='L'||c=='z'||c=='j'||c=='t'||c=='*'){
+	      if(c=='-') mask|=USELALGN;
+	      if(c=='+') mask|=USESIGN;
+	      if(c=='#') mask|=USEALT;
+	      if(c=='.') mask|=USEPREC;
+	      if(c==' ') mask|=USEBLANK;
+	      if(c=='0'&&!(mask&USEPREC)&&!(mask&USEWIDTH)) mask|=USEZPAD;
+	      if(isdigit((unsigned char)c)&&!(mask&USEPREC)) mask|=USEWIDTH;
+	      fused|=3;
+	      if(c=='*'&&(flags&PRINTFLIKE)){
+		mask|=USEAST;
+		if(!al) {error(214);return ok;}
+		at=al->arg->ntyp->flags&NQ;
+		al=al->next;
+		if(at>INT) {error(214);return ok;}
+	      }
+	      if((fflags!='*'||(flags&PRINTFLIKE))&&(c=='h'||c=='l'||c=='L'||c=='*'||c=='t'||c=='z'||c=='j')){
+		if(c=='l'&&fflags=='l')
+		  fflags=LL;
+		else if(c=='h'&&fflags=='h')
+		  fflags=HH;
+		else
+		  fflags=c;
+	      }
+	      c=(int)zm2l(zc2zm(cl->other->val.vchar));
+	      c=CHARBACK(c);
+	      cl=cl->next;
+	      if(!cl){error(214);return ok;}
+	    }
+	    /*FIXME: assumes intmax_t==long long */
+	    if(fflags=='j') {mask|=USESPEC;fflags=LL;}
+#if HAVE_INT_SIZET	    
+	    if(fflags=='z') {mask|=USESPEC;fflags=' ';}
+#else
+	    if(fflags=='z') {mask|=USESPEC;fflags='l';}
+#endif
+	    if(fflags=='t'){
+	      mask|=USESPEC;
+	      if(PTRDIFF_T(CHAR)==LLONG)
+		fflags=LL;
+	      else if(PTRDIFF_T(CHAR)==LONG)
+		fflags='l';
+	      else
+		fflags=' ';
+	    }
+	    if(fflags==HH) lflag|=USESPEC;
+	    if(fflags=='h') lflag|=USEHALF;
+	    if(fflags=='l') lflag|=USELONG;
+	    if(fflags==LL) lflag|=USELLONG;
+	    if(DEBUG&1) printf("format=%c%c\n",fflags,c);
+	    if(fflags=='*'&&(flags&SCANFLIKE)) continue;
+	    if(c!='%'){
+	      if(!al){error(214);return ok;}
+	      t=al->arg->ntyp;
+	      if(DEBUG&1){ prd(stdout,t);printf("\n");}
+	      if((flags&SCANFLIKE)){
+		if(!ISPOINTER(t->flags)){error(214);return ok;}
+		t=t->next;
+	      }
+	      at=t->flags&NU;
+	    }
+	    if(flags&PRINTFLIKE){
+	      switch(c){
+	      case '%':
+		mask|=USEPERC;
+		fused|=1;
+		break;
+	      case 'o':
+	      case 'x':
+	      case 'X':
+	      case 'c':
+		at&=NQ;     /*  fall through    */
+	      case 'i':
+	      case 'd':
+		fused|=1;
+		if(at==LLONG&&fflags!=LL){error(214);return ok;}
+		if(at==LONG&&fflags!='l'){error(214);return ok;}
+		if(fflags=='l'&&at!=LONG){error(214);return ok;}
+		if(at<CHAR||at>LLONG){error(214);return ok;}
+		if(c=='o') mask|=USEOCT;
+		if(c=='x') mask|=USEHEXL;
+		if(c=='X') mask|=USEHEXU;
+		if(c=='i') mask|=USEINT;
+		if(c=='d') mask|=USEDEC;
+		if(c=='c') mask|=USECHAR;
+		mask|=lflag;
+		break;
+	      case 'u':
+		mask|=USEUNS;
+		fused|=1;
+		if(al->arg->flags==CEXPR) at|=UNSIGNED;
+		if(at==(UNSIGNED|LLONG)&&fflags!=LL){error(214);return ok;}
+		if(at==(UNSIGNED|LONG)&&fflags!='l'){error(214);return ok;}
+		if(fflags=='l'&&at!=(UNSIGNED|LONG)){error(214);return ok;}
+		if(at<(UNSIGNED|CHAR)||at>(UNSIGNED|LLONG)){error(214);return ok;}
+		mask|=lflag;
+		break;
+	      case 's':
+		mask|=USESTR;
+		fused|=1;
+		if(!ISPOINTER(at)||(t->next->flags&NQ)!=CHAR){error(214);return ok;}
+		break;
+	      case 'f':
+	      case 'e':
+	      case 'E':
+	      case 'g':
+	      case 'G':
+		mask|=USEFLOAT;
+		fused|=7;
+		if(fflags=='L'){
+		  if(at!=LDOUBLE){error(214); return ok;}
+		}else{
+		  if(at!=FLOAT&&at!=DOUBLE){error(214);return ok;}
+		}
+		break;
+	      case 'p':
+		mask|=USESPEC;
+		fused|=3;
+		if(!ISPOINTER(at)||(t->next->flags)!=VOID){error(214);return ok;}
+		break;
+	      case 'n':
+		mask|=USECNT;
+		fused|=3;
+		if(!ISPOINTER(at)){error(214);return ok;}
+		at=t->next->flags&NU;
+		if(fflags==HH&&at!=CHAR){error(214);return ok;}
+		if(fflags=='h'&&at!=SHORT){error(214);return ok;}
+		if(fflags==' '&&at!=INT){error(214);return ok;}
+		if(fflags=='l'&&at!=LONG){error(214);return ok;}
+		if(fflags==LL&&at!=LLONG){error(214);return ok;}
+		break;
+	      default:
+		error(214);return ok;
+	      }
+	    }else{
+	      if(c=='s') mask|=USESTR;
+	      if(c=='c') mask|=USECHAR;
+	      if(c=='n') mask|=USECNT;
+	      if(c=='d') mask|=USEDEC;
+	      if(c=='i') mask|=USEINT;
+	      if(c=='o') mask|=USEOCT;
+	      if(c=='x') mask|=USEHEXL;
+	      if(c=='u') mask|=USEUNS;
+
+	      switch(c){
+	      case '%':
+		mask|=USEPERC;
+		fused|=1;
+		break;
+	      case '[':
+		mask|=USEREXP;
+		fused|=3;
+		do{
+		  c=(int)zm2l(zc2zm(cl->other->val.vchar));
+		  c=CHARBACK(c);
+		  cl=cl->next;
+		  if(!cl){error(214);return ok;}
+		}while(c!=']');     /*  fall through    */
+	      case 's':
+	      case 'c':
+		fused|=1;
+		if((at&NQ)!=CHAR){error(214);return(ok);}
+		break;
+	      case 'n':
+		fused|=3;       /*  fall through    */
+	      case 'd':
+	      case 'i':
+	      case 'o':
+		fused|=1;
+		if(fflags==HH&&at!=CHAR){error(214);return ok;}
+		if(fflags=='h'&&at!=SHORT){error(214);return ok;}
+		if(fflags==' '&&at!=INT){error(214);return ok;}
+		if(fflags=='l'&&at!=LONG){error(214);return ok;}
+		if(fflags==LL&&at!=LLONG){error(214);return ok;}
+		break;
+	      case 'x':
+	      case 'u':
+		fused|=1;
+		if(fflags==HH&&at!=CHAR){error(214);return ok;}
+		if(fflags=='h'&&at!=(UNSIGNED|SHORT)){error(214);return ok;}
+		if(fflags==' '&&at!=(UNSIGNED|INT)){error(214);return ok;}
+		if(fflags=='l'&&at!=(UNSIGNED|LONG)){error(214);return ok;}
+		if(fflags==LL&&at!=(UNSIGNED|LLONG)){error(214);return ok;}
+		break;
+	      case 'e':
+	      case 'f':
+	      case 'g':
+		mask|=USEFLOAT;
+		fused|=7;
+		if(fflags==' '&&at!=FLOAT){error(214);return ok;}
+		if(fflags=='l'&&at!=DOUBLE){error(214);return ok;}
+		if(fflags=='L'&&at!=LDOUBLE){error(214);return ok;}
+		break;
+	      case 'p':
+		mask|=USESPEC;
+		fused|=3;
+		if(!ISPOINTER(at)||(t->next->flags&NQ)!=VOID){error(214);return ok;}
+		break;
+	      default:
+		error(214);return ok;
+	      }
+	    }
+	    if(c!='%') al=al->next;
+	  }
+	  if(al){ error(214);return ok;} /* zu viele */
+	  if(DEBUG&1) printf("fused=%d\n",fused);
+	  if(mask_opt){
+	    Var *v;char repl[MAXI+16];
+	    if(mask){
+	      sprintf(repl,"%s.%lu",s,1L);
+	      v=find_var(repl,0);
+	      if(!v){
+		type *t;
+		v=find_var(s,0);
+		if(!v) ierror(0);
+		v=add_var(repl,clone_typ(v->vtyp),EXTERN,0);
+	      }
+	    }
+	    if(mask)
+	      sprintf(repl,"%s.%lu",(flags&PRINTFLIKE)?"vfprintf":"vfscanf",mask);
+	    else
+	      sprintf(repl,"%s",(flags&PRINTFLIKE)?"vfprintf":"vfscanf");
+	    needs(repl);
+	    p->left->left->o.v=v;
+	    if(DEBUG&1) printf("repl=%s\n",repl);
+	  }else if(fused!=7&&s){
+	    /*  Wenn kein Format benutzt wird, kann man printf, */
+	    /*  scanf etc. durch aehnliches ersetzen.           */
+	    Var *v;char repl[MAXI+6]="__v";
+	    if(fused==3) fused=2;
+	    repl[3]=fused+'0';repl[4]=0;
+	    strcat(repl,s);
+	    if(DEBUG&1) printf("repl=%s\n",repl);
+	    while(fused<=2){
+	      v=find_var(repl,0);
+	      if(v&&v->storage_class==EXTERN){
+		p->left->left->o.v=v;
+		break;
+	      }
+	      fused++;repl[3]++;
+	    }
+	  }
+	  return ok;
+	}
+      }
+      i++;al=al->next;
+    }
+    if(i>=sd->count) return ok;
+    if((*sd->sl)[i].styp&&((*sd->sl)[i].styp->flags&NQ)!=VOID){error(83);/*printf("sd->count=%d\n",sd->count);*/}
+    return ok;
+  }
+  if(f==COND){
+    if(!ISARITH(p->left->ntyp->flags)&&!ISPOINTER(p->left->ntyp->flags)){
+      error(29);
+      return 0;
+    }
+    if(p->left->flags==CEXPR&&!p->left->sidefx){
+      int null;np merk;
+      if(DEBUG&1) printf("constant conditional-expression simplified\n");
+      eval_constn(p->left);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+	null=1; 
+      else 
+	null=0;
+      free_expression(p->left);
+      merk=p->right;
+      if(null){
+	free_expression(p->right->left);
+	*p=*p->right->right;
+      }else{
+	free_expression(p->right->right);
+	*p=*p->right->left;
+      }
+      if(merk->ntyp) freetyp(merk->ntyp);
+      free(merk);
+      return 1;
+    }
+    if(const_expr){error(46);return 0;}
+    p->ntyp=clone_typ(p->right->ntyp);
+    return 1;
+  }
+  if(f==COLON){
+    /*  Hier fehlt noch korrekte Behandlung der Typattribute    */
+    if(ISARITH(p->left->ntyp->flags)&&ISARITH(p->right->ntyp->flags)){
+      p->ntyp=arith_typ(p->left->ntyp,p->right->ntyp);
+      return 1;
+    }
+    if(compatible_types(p->left->ntyp,p->right->ntyp,NQ)){
+      p->ntyp=clone_typ(p->left->ntyp);
+      return 1;
+    }
+    if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){
+      if((p->left->ntyp->next->flags&NQ)==VOID){
+	if(nullpointer(p->left))
+	  p->ntyp=clone_typ(p->right->ntyp);
+	else
+	  p->ntyp=clone_typ(p->left->ntyp);
+	return 1;
+      }
+      if((p->right->ntyp->next->flags&NQ)==VOID){
+	if(nullpointer(p->right))
+	  p->ntyp=clone_typ(p->left->ntyp);
+	else
+	  p->ntyp=clone_typ(p->right->ntyp);
+	return 1;
+      }
+    }
+    if(ISPOINTER(p->left->ntyp->flags)&&p->right->flags==CEXPR){
+      eval_constn(p->right);
+      if(zmeqto(vmax,l2zm(0L))&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+	p->ntyp=clone_typ(p->left->ntyp);
+	return 1;
+      }
+    }
+    if(ISPOINTER(p->right->ntyp->flags)&&p->left->flags==CEXPR){
+      eval_constn(p->left);
+      if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+	p->ntyp=clone_typ(p->right->ntyp);
+	return 1;
+      }
+    }
+    error(31);
+    return 0;
+  }
+  if(f) printf("type_testing fuer diesen Operator (%d) noch nicht implementiert\n",f);
+  return 0;
+}
+
+np makepointer(np p)
+/*  Fuehrt automatische Zeigererzeugung fuer Baumwurzel durch   */
+/*  Durch mehrmaligen Aufruf von type_expression() ineffizient  */
+{
+    struct_declaration *sd;
+    if(ISARRAY(p->ntyp->flags)||ISFUNC(p->ntyp->flags)){
+      np new=new_node();
+        if(ISARRAY(p->ntyp->flags)){
+            new->flags=ADDRESSA;
+            new->ntyp=clone_typ(p->ntyp);
+            new->ntyp->flags=POINTER_TYPE(new->ntyp->next);
+        }else{
+            new->flags=ADDRESS;
+            new->ntyp=new_typ();
+            new->ntyp->flags=POINTER_TYPE(p->ntyp);
+            new->ntyp->next=clone_typ(p->ntyp);
+        }
+        new->left=p;
+        new->right=0;
+        new->lvalue=0;  /* immer korrekt ?  */
+        new->sidefx=p->sidefx;
+/*        type_expression(new);*/
+        return new;
+    }else 
+      return p;
+}
+
+void simple_alg_opt(np p)
+{
+  int c=0,f,t=0;
+  zldouble d1,d2;
+  zumax u1,u2;zmax s1,s2;
+  Var *v;
+
+  if(!p) return;
+
+  f=p->flags;
+
+  if(f==IDENTIFIER&&(v=find_var(p->identifier,0))&&(v->vtyp->flags&NQ)==ENUM){
+    /*  enumerations auch als Konstante (int) behandeln */
+    p->flags=CEXPR;
+    if(!v->clist) ierror(0);
+    p->val=v->clist->val;
+    if(!p->ntyp) p->ntyp=new_typ();
+    p->ntyp->flags=CONST|INT;
+    return;
+  }
+
+
+  if(p->left)
+    simple_alg_opt(p->left);
+  else
+    return;
+  if(p->right)
+    simple_alg_opt(p->right);
+
+  if(p->left->flags==CEXPR||p->left->flags==PCEXPR){
+    eval_constn(p->left);
+    d1=vldouble;u1=vumax;s1=vmax;c|=1;
+  }
+  if(p->right&&(p->right->flags==CEXPR||p->right->flags==PCEXPR)){
+    eval_constn(p->right);
+    d2=vldouble;u2=vumax;s2=vmax;c|=2;
+  }
+
+  if(p->ntyp) t=p->ntyp->flags;
+
+  if(c==3&&((f>=OR&&f<=AND)||(f>=LSHIFT&&f<=MOD))){
+    if(DEBUG&1) printf("did simple_alg constant folding\n");
+    if(!t) t=arith_flag(p->left->ntyp->flags,p->right->ntyp->flags);
+    if(DEBUG&1) printf("did simple constant folding\n");
+
+    if(f==AND&&ISINT(t)){
+      vumax=zumand(u1,u2);
+      vmax=zmand(s1,s2);
+    }
+    if(f==OR&&ISINT(t)){
+      vumax=zumor(u1,u2);
+      vmax=zmor(s1,s2);
+    }
+    if(f==XOR&&ISINT(t)){
+      vumax=zumxor(u1,u2);
+      vmax=zmxor(s1,s2);
+    }
+    if(f==ADD){
+      vumax=zumadd(u1,u2);
+      vmax=zmadd(s1,s2);
+      vldouble=zldadd(d1,d2);
+    }
+    if(f==SUB){
+      vumax=zumsub(u1,u2);
+      vmax=zmsub(s1,s2);
+      vldouble=zldsub(d1,d2);
+    }
+    if(f==MULT||f==PMULT){
+      vumax=zummult(u1,u2);
+      vmax=zmmult(s1,s2);
+      vldouble=zldmult(d1,d2);
+      if(f==PMULT) p->flags=PCEXPR;
+    }
+    if(f==DIV){
+      if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)&&zldeqto(d2zld(0.0),d2)){
+	error(84);
+	vmax=l2zm(0L);vumax=ul2zum(0UL);vldouble=d2zld(0.0);
+      }else{
+	if(!zumeqto(ul2zum(0UL),u2)) vumax=zumdiv(u1,u2);
+	if(!zmeqto(l2zm(0L),s2)) vmax=zmdiv(s1,s2);
+	if(!zldeqto(d2zld(0.0),d2)) vldouble=zlddiv(d1,d2);
+      }
+    }
+    if(f==MOD&&ISINT(t)){
+      if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)){
+	error(84);
+	vmax=l2zm(0L);vumax=zm2zum(vmax);
+      }else{
+	if(!zumeqto(ul2zum(0UL),u2)) vumax=zummod(u1,u2);
+	if(!zmeqto(l2zm(0L),s2)) vmax=zmmod(s1,s2);
+      }
+    }
+    if(f==LSHIFT&&ISINT(t)){
+      vumax=zumlshift(u1,u2);
+      vmax=zmlshift(s1,s2);
+    }
+    if(f==RSHIFT&&ISINT(t)){
+      vumax=zumrshift(u1,u2);
+      vmax=zmrshift(s1,s2);
+    }
+  }else if(c==1&&f==MINUS){
+    if(!t) t=arith_flag(p->left->ntyp->flags,p->left->ntyp->flags);
+    vmax=zmsub(Z0,s1);
+    vumax=zumsub(ZU0,u1);
+    vldouble=zldsub(d2zld(0.0),d1);
+  }else if(c==1&&f==KOMPLEMENT){
+    if(!t) t=arith_flag(p->left->ntyp->flags,p->left->ntyp->flags);
+    if(!ISINT(t)) return;
+    vmax=zmkompl(s1);
+    vumax=zumkompl(u1);
+  }else if(c==1&&f==NEGATION){
+    if(!p->left->ntyp) return;
+    t=INT;
+    if(!ISINT(p->left->ntyp->flags)){
+      if(zldeqto(d1,d2zld(0.0))) vmax=Z1; else vmax=Z0;
+    }else if(p->left->ntyp->flags&UNSIGNED){
+      if(zumeqto(u1,ZU0)) vmax=Z1; else vmax=Z0;
+    }else
+      if(zmeqto(s1,Z0)) vmax=Z1; else vmax=Z0;
+  }else
+    return;
+
+  p->flags=CEXPR;
+  if(p->left&&!p->left->sidefx) {free_expression(p->left);p->left=0;}
+  if(p->right&&p->right->sidefx) {free_expression(p->right);p->right=0;}
+
+  if(ISFLOAT(t)){
+    gval.vldouble=vldouble;
+    eval_const(&gval,LDOUBLE);
+  }else{
+    if(t&UNSIGNED){
+      gval.vumax=vumax;
+      eval_const(&gval,(UNSIGNED|MAXINT));
+    }else{
+      gval.vmax=vmax;
+      eval_const(&gval,MAXINT);
+    }
+  }
+  insert_const(&p->val,t);
+  if(!p->ntyp){p->ntyp=new_typ();p->ntyp->flags=t;}
+}
+
+
+int alg_opt(np p,type *ttyp)
+/*  fuehrt algebraische Vereinfachungen durch                   */
+/*  hier noch genau testen, was ANSI-gemaess erlaubt ist etc.   */
+/*  v.a. Floating-Point ist evtl. kritisch                      */
+{
+    int c=0,f,komm,null1,null2,eins1,eins2;np merk;
+    zldouble d1,d2;zumax u1,u2;zmax s1,s2;
+    f=p->flags;
+    
+    /* do not optimze pointer-pointer */
+    if(f==SUB&&ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags))
+      return 1;
+
+    /*  kommutativ? */
+    if(f==ADD||f==MULT||f==PMULT||(f>=OR&&f<=AND)) komm=1; else komm=0;
+    /*  Berechnet Wert, wenn beides Konstanten sind     */
+    if(p->left->flags==CEXPR||p->left->flags==PCEXPR){
+        eval_constn(p->left);
+        d1=vldouble;u1=vumax;s1=vmax;c|=1;
+    }
+    if(p->right->flags==CEXPR||p->right->flags==PCEXPR){
+        eval_constn(p->right);
+        d2=vldouble;u2=vumax;s2=vmax;c|=2;
+    }
+    if(c==3){
+        p->flags=CEXPR;
+        if(DEBUG&1) printf("did simple constant folding\n");
+        if(!p->left->sidefx) {free_expression(p->left);p->left=0;}
+        if(!p->right->sidefx) {free_expression(p->right);p->right=0;}
+        if(f==AND){
+	  vumax=zumand(u1,u2);
+	  vmax=zmand(s1,s2);
+        }
+        if(f==OR){
+	  vumax=zumor(u1,u2);
+	  vmax=zmor(s1,s2);
+        }
+        if(f==XOR){
+	  vumax=zumxor(u1,u2);
+	  vmax=zmxor(s1,s2);
+        }
+        if(f==ADD){
+	  vumax=zumadd(u1,u2);
+	  vmax=zmadd(s1,s2);
+	  vldouble=zldadd(d1,d2);
+        }
+        if(f==SUB){
+	  vumax=zumsub(u1,u2);
+	  vmax=zmsub(s1,s2);
+	  vldouble=zldsub(d1,d2);
+        }
+        if(f==MULT||f==PMULT){
+	  vumax=zummult(u1,u2);
+	  vmax=zmmult(s1,s2);
+	  vldouble=zldmult(d1,d2);
+	  if(f==PMULT) p->flags=PCEXPR;
+        }
+        if(f==DIV){
+	  if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)&&zldeqto(d2zld(0.0),d2)){
+	    error(84);
+	    vmax=l2zm(0L);vumax=ul2zum(0UL);vldouble=d2zld(0.0);
+	  }else{
+	    if(!zumeqto(ul2zum(0UL),u2)) vumax=zumdiv(u1,u2);
+	    if(!zmeqto(l2zm(0L),s2)) vmax=zmdiv(s1,s2);
+	    if(!zldeqto(d2zld(0.0),d2)) vldouble=zlddiv(d1,d2);
+	  }
+        }
+        if(f==MOD){
+	  if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)){
+	    error(84);
+	    vmax=l2zm(0L);vumax=zm2zum(vmax);
+	  }else{
+	    if(!zumeqto(ul2zum(0UL),u2)) vumax=zummod(u1,u2);
+	    if(!zmeqto(l2zm(0L),s2)) vmax=zmmod(s1,s2);
+	  }
+        }
+        if(f==LSHIFT){
+	  vumax=zumlshift(u1,u2);
+	  vmax=zmlshift(s1,s2);
+        }
+        if(f==RSHIFT){
+	  vumax=zumrshift(u1,u2);
+	  vmax=zmrshift(s1,s2);
+        }
+	if(ISFLOAT(p->ntyp->flags)){
+	  gval.vldouble=vldouble;
+	  eval_const(&gval,LDOUBLE);
+	}else{
+	  if(p->ntyp->flags&UNSIGNED){
+	    gval.vumax=vumax;
+	    eval_const(&gval,(UNSIGNED|MAXINT));
+	  }else{
+	    gval.vmax=vmax;
+	    eval_const(&gval,MAXINT);
+	  }
+	}
+	insert_constn(p);
+        return 1;
+    }
+    /*  Konstanten nach rechts, wenn moeglich       */
+    if(c==1&&komm){
+        if(DEBUG&1) printf("exchanged commutative constant operand\n");
+        merk=p->left;p->left=p->right;p->right=merk;
+        c=2;
+        d2=d1;u2=u1;s2=s1;
+    }
+    /*  Vertauscht die Knoten, um Konstanten                */
+    /*  besser zusammenzufassen (bei allen Type erlaubt?)   */
+    /*  Hier muss noch einiges kontrolliert werden          */
+    if(komm&&c==2&&p->flags==p->left->flags&&(ISINT(p->ntyp->flags)||c_flags[21]&USEDFLAG)){
+        if(p->left->right->flags==CEXPR||p->left->right->flags==PCEXPR){
+            np merk;
+            merk=p->right;p->right=p->left->left;p->left->left=merk;
+            if(DEBUG&1) printf("Vertausche Add-Nodes\n");
+	    dontopt=0;
+            return type_expression2(p,ttyp);
+        }
+    }
+    null1=null2=eins1=eins2=0;
+    if(c&1){
+      if(zldeqto(d1,d2zld(0.0))&&zumeqto(u1,ul2zum(0UL))&&zmeqto(s1,l2zm(0L))) null1=1;   
+      if(zldeqto(d1,d2zld(1.0))&&zumeqto(u1,ul2zum(1UL))&&zmeqto(s1,l2zm(1L))) eins1=1;
+      if(!(p->ntyp->flags&UNSIGNED)&&zldeqto(d1,d2zld(-1.0))&&zmeqto(s1,l2zm(-1L))) eins1=-1;
+    }
+    if(c&2){
+      if(zldeqto(d2,d2zld(0.0))&&zumeqto(u2,ul2zum(0UL))&&zmeqto(s2,l2zm(0L))) null2=1; 
+      if(zldeqto(d2,d2zld(1.0))&&zumeqto(u2,ul2zum(1UL))&&zmeqto(s2,l2zm(1L))) eins2=1; 
+      if(!(p->ntyp->flags&UNSIGNED)&&zldeqto(d2,d2zld(-1.0))&&zmeqto(s2,l2zm(-1L))) eins2=-1;
+    }
+    if(c==2){
+        /*  a+0=a-0=a^0=a>>0=a<<0=a*1=a/1=a   */
+        if(((eins2==1&&(f==MULT||f==PMULT||f==DIV))||(null2&&(f==ADD||f==SUB||f==OR||f==XOR||f==LSHIFT||f==RSHIFT)))&&!p->right->sidefx){
+            if(DEBUG&1){if(f==MULT||f==PMULT||f==DIV) printf("a*/1->a\n"); else printf("a+-^0->a\n");}
+            free_expression(p->right);
+            merk=p->left;
+            *p=*p->left;
+/*            freetyp(merk->ntyp);  das war Fehler  */
+            free(merk);
+	    dontopt=0;
+            return type_expression2(p,ttyp);
+        }
+        /*  a*0=0   */
+        if(null2&&(f==MULT||f==PMULT||f==AND||f==DIV||f==MOD)){
+            if(DEBUG&1) printf("a*&/%%0->0\n");
+            if(null2&&(f==DIV||f==MOD)) error(84);
+            if(p->flags==PMULT) p->flags=PCEXPR; else p->flags=CEXPR;
+	    gval.vint=zm2zi(l2zm(0L));
+	    eval_const(&gval,INT);
+            /*  hier nur int,long,float,double moeglich, hoffe ich  */
+            insert_constn(p);
+            if(!p->left->sidefx){free_expression(p->left);p->left=0;} else make_cexpr(p->left);
+            if(!p->right->sidefx){free_expression(p->right);p->right=0;} else make_cexpr(p->right);
+
+/*            return(type_expression2(p,ttyp));   */
+            return 1;
+        }
+        if(eins2==-1&&(f==MULT||f==PMULT||f==DIV)&&!p->right->sidefx){
+            if(DEBUG&1) printf("a*/(-1)->-a\n");
+            free_expression(p->right);
+            p->right=0;
+            p->flags=MINUS;
+	    dontopt=0;
+            return type_expression2(p,ttyp);
+        }
+	/* check volatile */
+	if(0) /* TODO: make this efficient */
+	{
+	  type st={0};
+	  if(!zmeqto(sizetab[CHAR],sizetab[SHORT])){
+	    //if(f==AND&&(!ttyp||(ttyp->flags&NQ)>CHAR)&&shortcut(AND,CHAR)&&zumleq(u2,t_max[CHAR]))
+	    //st.flags=CHAR;
+	    if(f==AND&&(!ttyp||(ttyp->flags&NQ)>CHAR)/*&&(p->ntyp->flags&UNSIGNED)*/&&shortcut(AND,UNSIGNED|CHAR)&&zumleq(u2,tu_max[CHAR]))
+	      st.flags=UNSIGNED|CHAR;
+	  }
+	  if(!zmeqto(sizetab[SHORT],sizetab[INT])){
+	    //if(f==AND&&(!ttyp||(ttyp->flags&NQ)>SHORT)&&shortcut(AND,SHORT)&&zumleq(s2,t_max[SHORT]))
+	    //st.flags=SHORT;
+	    if(f==AND&&(!ttyp||(ttyp->flags&NQ)>SHORT)/*&&(p->ntyp->flags&UNSIGNED)*/&&shortcut(AND,UNSIGNED|SHORT)&&zumleq(u2,tu_max[SHORT]))
+	      st.flags=UNSIGNED|SHORT;
+	  }
+	  //if(!ttyp&&(p->left->ntyp->flags&NQ)>INT) st.flags=0;
+	  if(st.flags){
+	    int ret;type *otyp;np n;
+	    if(!p->ntyp) ierror(0);
+	    otyp=clone_typ(p->ntyp);
+	    n=new_node();
+	    n->left=p->left;
+	    n->right=0;
+	    n->flags=CAST;
+	    n->ntyp=clone_typ(&st);
+	    eval_const(&p->right->val,p->right->ntyp->flags);
+	    p->right->ntyp->flags=st.flags;
+	    insert_const(&p->right->val,st.flags);
+	    p->left=n;
+	    n=new_node();
+	    *n=*p;
+	    p->left=n;
+	    p->right=0;
+	    p->flags=CAST;
+	    p->ntyp=otyp;
+	    ret=type_expression2(p->left,&st);
+
+	    return ret;
+	  }
+	}
+	
+    }
+    if(c==1){
+        /*  0-a=-a  */
+        if(f==SUB&&null1&&!p->left->sidefx){
+            if(DEBUG&1) printf("0-a->-a\n");
+            free_expression(p->left);
+            p->flags=MINUS;
+            p->left=p->right;
+            p->right=0;
+	    dontopt=0;
+            return type_expression2(p,ttyp);
+        }
+        /*  0/a=0   */
+        if(null1&&(f==DIV||f==MOD||f==LSHIFT||f==RSHIFT)){
+            if(DEBUG&1) printf("0/%%<<>>a->0\n");
+            p->flags=CEXPR;
+	    gval.vint=zm2zi(l2zm(0L));
+	    eval_const(&gval,INT);
+            insert_constn(p);
+            if(!p->left->sidefx){free_expression(p->left);p->left=0;}else make_cexpr(p->left);
+            if(!p->right->sidefx){free_expression(p->right);p->right=0;} else make_cexpr(p->right);
+	    dontopt=0;
+            return type_expression2(p,ttyp);
+        }
+    }
+    return 1;
+}
+void make_cexpr(np p)
+/*  Macht aus einem Knoten, der durch constant-folding ueberfluessig    */
+/*  wurde, eine PCEXPR, sofern er keine Nebenwirkungen von sich aus     */
+/*  erzeugt. Hier noch ueberpruefen, ob CEXPR besser waere.             */
+/*  Fuehrt rekursiven Abstieg durch. Ist das so korrekt?                */
+{
+    int f=p->flags;
+    if(f!=ASSIGN&&f!=ASSIGNOP&&f!=CALL&&f!=POSTINC&&f!=POSTDEC&&f!=PREINC&&f!=PREDEC&&f!=LAND&&f!=LOR){
+        p->flags=PCEXPR;
+        if(p->left) make_cexpr(p->left);
+        if(p->right) make_cexpr(p->right);
+    }
+}
+int test_assignment(type *zt,np q)
+/*  testet, ob q an Typ z zugewiesen werden darf    */
+{
+  type *qt=q->ntyp;
+  if(ISARITH(zt->flags)&&ISARITH(qt->flags)){
+    if(ISINT(zt->flags)&&ISINT(qt->flags)&&
+      !zmleq(sizetab[qt->flags&NQ],sizetab[zt->flags&NQ])&&q->flags!=CEXPR){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+      error(166);
+    }
+    if(q->flags==CEXPR){
+      zmax ms,ns;zumax mu,nu;
+      eval_constn(q);
+      ms=vmax;mu=vumax;
+      insert_const(&gval,zt->flags&~UNSIGNED);
+      eval_const(&gval,zt->flags&~UNSIGNED);
+      ns=vmax;
+      eval_constn(q);
+      insert_const(&gval,zt->flags|UNSIGNED);
+      eval_const(&gval,zt->flags|UNSIGNED);
+      nu=vumax;
+      if(!zumeqto(nu,mu)&&!zmeqto(ns,ms)) 
+	error(363);
+      else{
+	if(zt->flags&UNSIGNED){
+	  if(!zumeqto(nu,mu))
+	    error(362);
+	}else{
+	  if(!zmeqto(ns,ms))
+	    error(362);
+	}
+      }
+    }
+    return 1;
+  }
+  if((ISSTRUCT(zt->flags)&&ISSTRUCT(qt->flags))||
+    (ISUNION(zt->flags)&&ISUNION(qt->flags))){
+      if(!compatible_types(zt,qt,NU)){
+        error(38);
+      return 0;
+    }else 
+  return 1;
+  }
+  if(ISVECTOR(zt->flags)&&(zt->flags&NU)==(qt->flags&NU)){
+      return 1;
+  }
+  if(ISPOINTER(zt->flags)&&ISPOINTER(qt->flags)){
+    if((zt->next->flags&NQ)==VOID&&!ISFUNC(qt->next->flags)) return 1;
+    if((qt->next->flags&NQ)==VOID&&!ISFUNC(qt->next->flags)) return 1;
+    if(!compatible_types(zt->next,qt->next,(c_flags[7]&USEDFLAG)?NU:NQ)){
+      if(!ecpp){
+        error(85);
+      }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+    }else{
+      if((qt->next->flags&CONST)&&!(zt->next->flags&CONST))
+        error(91);
+      if((qt->next->flags&VOLATILE)&&!(zt->next->flags&VOLATILE))
+        error(100);
+      if((qt->next->flags&RESTRICT)&&!(zt->next->flags&RESTRICT))
+        error(298);
+      if(qt->next->next&&zt->next->next&&!compatible_types(zt->next->next,qt->next->next,NU))
+        error(110);
+      }
+    return 1;
+  }
+  if(ISPOINTER(zt->flags)&&q->flags==CEXPR){
+    eval_constn(q);
+    if(!(zldeqto(d2zld(0.0),vldouble)&&zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)))
+      error(113);
+    return 1;
+  }
+  error(39);
+  return 0;
+}
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
diff --git a/ucpp/README b/ucpp/README
new file mode 100755
index 0000000..64ce2ac
--- /dev/null
+++ b/ucpp/README
@@ -0,0 +1,752 @@
+ucpp-1.0 is a C preprocessor mostly compliant to ISO-C99.
+
+Author: Thomas Pornin <thomas.pornin@ens.fr>
+Main site: http://www.di.ens.fr/~pornin/ucpp/
+
+
+
+INTRODUCTION
+------------
+
+A C preprocessor is a part of a C compiler responsible for macro
+replacement, conditional compilation and inclusion of header files.
+It is often found as a stand-alone program on Unix systems.
+
+Ucpp is such a preprocessor; it is designed to be quick and light,
+but anyway fully compliant to the ISO standard 9899:1999, also known
+as C99. Ucpp can be compiled as a stand-alone program, or linked to
+some other code; in the latter case, ucpp will output tokens, one
+at a time, on demand, as an integrated lexer.
+
+Ucpp operates in two modes:
+-- lexer mode: ucpp is linked to some other code and outputs a stream of
+tokens (each call to the lex() function will give one token)
+-- non-lexer mode: ucpp preprocesses text and outputs the resulting text
+on a file descriptor; if linked to some other code, the cpp() function
+must be called repeatedly, otherwise ucpp is a stand-alone binary.
+
+
+
+INSTALLATION
+------------
+
+1. Uncompress the archive file and extract the source files.
+
+2. Edit tune.h. Here is a short explanation of compile-time options:
+
+  LOW_MEM
+     Enable memory-saving functions; this is for low-end and old systems,
+     but seems to be good for larger systems too. Keep it.
+  NO_LIBC_BUF
+  NO_UCPP_BUF
+     Two options used to disable the two bufferings inside ucpp. Define
+     both options for maximum memory saving but you will probably want
+     to keep libc buffering if you want decent performance. Define none
+     on large systems (modern 32 or 64-bit systems).
+  UCPP_MMAP
+     With this option, if ucpp internal buffering is active, ucpp will
+     try to mmap() the input files. This might give a slight performance
+     improvement, but will work only on a limited set of architectures.
+  PRAGMA_TOKENIZE
+     Make ucpp generate tokenized PRAGMA tokens on #pragma and _Pragma();
+     tokenization is made this way: tokens are assembled as a null
+     terminated array of unsigned chars; if a token has a string value
+     (as defined by the STRING_TOKEN macro), the value follows the token,
+     terminated by PRAGMA_TOKEN_END (by default, a newline character cast
+     to unsigned char). Whitespace tokens are skipped. The "name" value
+     of the PRAGMA token is a pointer to that array. This setting is
+     irrelevant in non-lexer mode.
+  PRAGMA_DUMP
+     In non-lexer mode, keep #pragma in output; non-void _Pragma() are
+     translated to the equivalent #pragma. Irrelevant in lexer mode.
+  NO_PRAGMA_IN_DIRECTIVE
+     Do not evaluate _Pragma() inside #if, #include, #include_next and #line
+     directives; instead, emit an error (since the remaining _Pragma will
+     surely imply a syntax error).
+  INMACRO_FLAG
+     In lexer mode, set the inmacro flag to 1 if the current token comes
+     from a macro replacement, 0 otherwise. macro_count maintains an
+     increasing counter of such replacements. CONTEXT tokens count as
+     one macro replacement each. #pragma, and _Pragma() that do not come
+     from a macro replacement, also count as one macro replacement each.
+     This setting is irrelevant in non-lexer mode.
+  STD_INCLUDE_PATH
+     Default include path in stand-alone ucpp.
+  STD_MACROS
+     Default predefined macros in stand-alone ucpp.
+  STD_ASSERT
+     Default assertions in stand-alone ucpp.
+  NATIVE_INTMAX
+  NATIVE_UINTMAX
+  SIMUL_UINTMAX
+  WCHAR_SIGNEDNESS
+     Those options define how #if expressions are evaluated; see the
+     cross-compilation section of this file for more info.
+  DEFAULT_LEXER_FLAGS
+  DEFAULT_CPP_FLAGS
+     Default flags in respectively lexer and non-lexer modes.
+  POSIX_JMP
+     Define this if your architecture defines sigsetjmp() and
+     siglongjmp(); it is known to (very slightly) improve performance
+     on AIX systems.
+  MAX_CHAR_VAL
+     Ucpp will consider characters whose value is equal or above
+     MAX_CHAR_VAL as outside the C source charset (so they will be
+     treated just like '@', for instance). For ASCII systems, 128
+     is fine. 256 is a safer value, but uses more (static) memory.
+     For performance reasons, use a power of two. If MAX_CHAR_VAL is
+     correctly adjusted, ucpp should be compatible with any character
+     set.
+  UNBREAKABLE_SPACE
+     If you want an extra-whitespace character, define this macro to that
+     character. For instance, define this to 160 on an ISO-8859-1 system
+     if you want the 'unbreakable space' to be considered as whitespace.
+  SEMPER_FIDELIS
+     With this option set, ucpp, when used as a lexer, will pass
+     whitespace tokens to its caller, and those tokens will have their
+     true content; this is intended for reconstruction of the source
+     line. Beware that some comments may have embedded newlines.
+  COPY_LINE_LENGTH
+     Ucpp can maintain a copy of the current source line, up to that
+     length. Irrelevant to stand-alone version.
+  *_MEMG
+     Those settings modify ucpp behaviour, wrt memory allocations. With
+     higher values, ucpp will perform less malloc() calls and will run
+     faster, but it will use more memory. Reduce INPUT_BUF_MEMG and
+     OUTPUT_BUF_MEMG on low-memory systems, if you kept ucpp buffering
+     (see NO_UCPP_BUF option).
+
+3. Edit the Makefile. You should define the variables CC and FLAGS;
+   there are the following options:
+
+  -DAUDIT
+     Enable internal sanity checks; this slows down a bit ucpp. Do not
+     define unless you plan to debug ucpp.
+  -DMEM_CHECK
+     With this setting, ucpp will check for the return value of malloc()
+     and exit with a diagnostic when out of memory. MEM_CHECK is implied
+     by AUDIT.
+  -DINLINE=foobar
+     The ucpp code uses "inline" qualifier for some functions; by
+     default, that qualifier is macro-replaced with nothing. Define
+     INLINE to the correct replacement for your compiler, if supported.
+     Note that all "inline" functions in ucpp are also "static". For any
+     C99-compliant compiler, the GNU compiler (gcc), and the Compaq C
+     compiler under Linux/Alpha, no -DINLINE is needed (see tune.h for
+     details).
+
+4. Compile by typing "make". This should produce the ucpp executable
+   file.
+
+5. Install wherever you want the binary and the man page ucpp.1.
+
+6. If you do not have the make utility, compile each file seperately
+   and link them together. The exact details depend on your compiler.
+   You must define the macro STAND_ALONE when compiling cpp.c (there
+   is such a definition, commented out, in cpp.c, line 34).
+
+There is no "configure" script since:
+-- I do not like the very idea of a "configure" script.
+-- Ucpp is written in ANSI-C and should be fairly portable.
+-- There is no such thing as "standard" settings for a C preprocessor.
+   The predefined system macros, standard assertions,... must be tuned
+   by the sysadmin.
+-- The primary goal of ucpp is to be included in compilers. The
+   stand-alone version is mainly a debugging tool.
+
+Please note that you need an ISO-C90 (formerly ANSI) C compiler suite
+(including the standard library) to compile ucpp. If your compiler is
+not C99 (or later), read the cross-compilation section in this README
+file.
+
+The C90 and C99 standards state that external linkage names might
+be considered equal or different based upon only their first 6
+characters; this rule might make ucpp not to compile on a conformant C
+implementation. I have yet to see such an implementation, however.
+
+If you want to use ucpp as an integrated preprocessor and lexer, see the
+section REUSE. Compiling ucpp as a library is an exercise left to the
+reader.
+
+With the LOW_MEM code enabled, ucpp can run on a Minix-86 or Msdos
+16-bit small-memory-model machine. It will not be fully compliant
+on such an architecture to C99, since C99 states that at least one
+source code with 4095 simultaneously defined macros must be processed;
+ucpp will be limited to about 1500 macros (at most) due to memory
+restrictions. At least ucpp can preprocess its own code in these
+conditions. LOW_MEM is on by default because it seems to improve
+performance on large systems.
+
+
+
+LICENSE
+-------
+
+The copyright notice and license is at the beginning of the Makefile and
+each source file. It is basically a BSD license, without the advertising
+subclause (which BSD dropped recently anyway) and with no reference to
+Berkeley (since the code is all mine, written from scratch). Informally,
+this means that you can reuse and redistribute the code as you want,
+provided that you states in the documentation (or any substantial part
+of the software) of redistributed code that I am the original author.
+(If you press a cdrom with 200 software packages, I do not insist on
+having my name on the cover of the cdrom -- just keep a Readme file
+somewhere on the cdrom, with the copyright notice included)
+
+As a courteous gesture, if you reuse my code, please drop me a mail.
+It raises my self-esteem.
+
+
+
+REUSE
+-----
+
+The code has been thought as part of a bigger project; it might be
+used as an integrated lexer, that will read files, process them as a
+C preprocessor, and output a stream of C tokens. To include this code
+into a project, compile with STAND_ALONE undefined.
+
+To use the preprocessor and lexer, several steps should be performed.
+See the file 'sample.c' for an example.
+
+1. call init_cpp(). This function initializes the lexer automaton.
+
+2. set the following global variables:
+	no_special_macros
+		non-zero if the special macros (__FILE__ and others)
+		should not be defined. This is a global flag since
+		it affects the redefinition of such macros (which are
+		allowed if the special macros are not defined)
+	c99_compliant
+		if non-zero, define __STDC_VERSION__ to 199901L; this
+		is the default; otherwise, do not define __STDC_VERSION__.
+		Note that ucpp will accept to undefine __STDC_VERSION__
+		with a #undef directive.
+	c99_hosted
+		if strictly positive, define __STDC_HOSTED__ to 1.
+		If zero, define __STDC_HOSTED__ to 0. If negative,
+		do not define __STDC_HOSTED__. The default is 1.
+	emit_defines and emit_assertions should be set to 0 for
+	the step 3.
+
+3. call init_tables(). This function initializes the macro table
+   and other things; it will intialize assertions if it has a non-zero
+   argument.
+
+4. call init_include_path(). This function will reset the include
+   path to the list of paths given as argument.
+
+5. set the following global variables
+	emit_dependencies
+		set to 1 if dependencies should be emitted during
+		preprocessing
+		set to 2 if dependencies should also be emitted for
+		system include files
+	emit_defines
+		set to non-zero if #define macro definitions should be
+		emitted when macros are defined
+	emit_assertions
+		set to non-zero if #define macro definitions should be
+		emitted when macros are defined
+	emit_output
+		the FILE * where the above items are sent if one of the
+		three emit_ variables is set to non zero
+	transient_characters
+		this is for some cross-compilation; see the relevant
+		part in this README file for details
+
+6. call set_init_filename() with the initial filename as argument;
+   the second argument indicates whether the filename is real or
+   conventional ("real" means "an fopen() on it will work").
+
+7. initialize your struct lexer_state:
+	call init_lexer_state()
+	call init_lexer_mode() if the preprocessor is supposed to
+	   output a list of tokens, otherwise set the flags field
+	   to DEFAULT_CPP_FLAGS and set the output field to the
+	   FILE * where output should be sent
+	(init_lexer_mode(), if called at all, must be called after
+	 init_lexer_state())
+	adjust the flags field; here is the meaning of flags:
+
+WARN_STANDARD
+	emit the standard warnings
+WARN_ANNOYING
+	emit the useless and annoying warnings
+WARN_TRIGRAPHS
+	count trigraphs encountered; it is up to the caller to emit
+	a warning if some trigraphs were indeed encountered; the count
+	is stored in the count_trigraphs field of the struct lexer_state
+WARN_TRIGRAPHS_MORE
+	emit a warning for every trigraph encountered
+WARN_PRAGMA
+	emit a warning for each non-void _Pragma encountered in non-lexer
+	mode (because these are not dumped in the output) and for each
+	#pragma too, if ucpp was compiled without PRAGMA_DUMP
+FAIL_SHARP
+	emit errors on '#' tokens beginning a line and not followed
+	by a valid cpp directive
+CCHARSET
+	emit errors when non-C characters are encountered; if this flag
+	is not set, each non-C character will be considered as a BUNCH
+	token (since C99 states that non-C characters are allowed as
+	long as they "disappear" during preprocessing [through macro
+	replacement and stringification for instance], this flag must
+	not be set, for maximum C99 compliance)
+DISCARD_COMMENTS
+	do not keep comments in output (irrelevant in lexer mode)
+CPLUSPLUS_COMMENTS
+	understand new style comments (//) (mandatory for C99)
+LINE_NUM
+	emit #line directives when entering a file, if not in lexer mode;
+	emit CONTEXT token in lexer mode for #line and new files
+GCC_LINE_NUM
+	if LINE_NUM is set, emit gcc-like directives instead of #line
+HANDLE_ASSERTIONS
+	understand assertions in #if expressions (and #assert, #unassert)
+HANDLE_PRAGMA
+	make PRAGMA tokens for #pragma; irrelevant in non-lexer mode
+	(handling of some pragmas is required in C99 but is not of
+	the competence of the preprocessor; without this flag, ucpp will
+	ignore the contents of #pragma and _Pragma directives)
+MACRO_VAARG
+	understand macros with a variable number of arguments (mandatory
+	for C99)
+UTF8_SOURCE
+	understand UTF-8 encoding: multibyte characters are considered
+	equivalent to letters as far as syntax is concerned (they can
+	be used in identifiers)
+LEXER
+	act as a lexer, outputting tokens
+TEXT_OUTPUT
+	this flag should be set to 0 if ucpp works as a lexer, 1 otherwise.
+	It is somehow redundant with the LEXER flag, but the presence of
+	those two different flags is needed in ucpp.
+KEEP_OUTPUT
+	in non-lexer mode, emit the result of preprocessing
+COPY_LINE
+	maintain a copy of the last read line in the copy_line field of
+	the struct lexer_state ; see below for how to use this buffer
+HANDLE_TRIGRAPHS
+	understand trigraphs, such as ??/ for \. This option should be
+	set by default, except for some legacy code.
+
+	There are other flags, but they are for private usage of ucpp.
+
+8. adjust the input field in the lexer_state to the FILE * from where
+   source file is read. If you use the UCPP_MMAP compile-time option,
+   and your input file is eligible to mmap(), then you can call
+   fopen_mmap_file() to open it, then set_input_file() to set ls->input
+   and some other internal options. Do not call set_input_file() unless
+   you just called fopen_mmap_file() just before on the same file.
+
+9. call add_incpath() to add an include path, define_macro() and
+   undef_macro() to add or remove macros, make_assertion() and
+   destroy_assertion() to add or remove assertions.
+
+10. call enter_file() (this is needed only in non-lexer mode, or if
+    LINE_NUM is set).
+
+
+Afterwards:
+-- if you are in lexer mode, call lex(); each call will make the ctok
+   field point to the next token. A non-zero return value is an error.
+   lex() skips whitespace tokens. The memory used by the string value
+   of some tokens (identifiers, numbers...) is automatically freed,
+   so copy the contents of each such token if you want to keep it
+   (tokens with a string content are identified by the STRING_TOKEN
+   macro applied to their type).
+   When lex() returned a non-zero value: if it is CPPERR_EOF, then
+   end-of-input was reached. Otherwise, it is a genuine error and
+   ls->ctok is an undefined token; skip it and call lex() again to
+   ignore the error.
+
+-- otherwise, call cpp(); each call will analyze one or more tokens
+   (one token if it did not found a cpp directive, or a macro name).
+   A positive return value is an error.
+
+For both functions, if the return value is CPPERR_EOF (which is a
+strictly positive value), then it means that the end of file was
+reached. Call check_cpp_errors() after end of file for pending errors
+(unfinished #if constructions for instance). In non-lexer mode,
+call flush_output().
+
+In the struct lexer_state, the following fields might be read:
+	line		   the current input line number
+	oline		   the current output line number (in non-lexer mode)
+	flags		   the flags described above
+	count_trigraphs	   the number of trigraphs encountered
+	inmacro		   the current token comes from a macro
+	macro_count	   the current macro counter
+"flags" is an unsigned long and might be modified; the three others
+are of long type.
+
+
+To perform another preprocessing: use free_lexer_state() to release
+memory used by the buffers referenced in lexer_state, and go back to
+step 2. The different tables (macros, assertions...) should be reset to
+their respective initial contents. (Warning: this is currently untested)
+
+
+The COPY_LINE buffer: the struct lexer_state contains two interesting
+fields, copy_line[] and cli. If the COPY_LINE flag is on, each read
+line is stored in this buffer, up to (at most) COPY_LINE_LENGTH - 1
+characters (COPY_LINE_LENGTH is defined in tune.h). The last character
+of the buffer is always a zero, and if the line was read entirely, it is
+zero terminated; the trailing newline is not included.
+
+The purpose of this buffer is error-reporting. When an error occurs
+(cpp() returns a strictly positive value, or lex() returns a non-zero
+value), if your struct lexer_state is called ls, use this code:
+
+	if (ls.cli != 0) ls.copy_line[ls.cli] = 0;
+
+This will add a trailing 0 if the line was not read entirely.
+
+
+
+COMPATIBILITY NOTES
+-------------------
+
+The C language has a lengthening history. Nowadays, C comes in three
+flavours:
+
+-- Traditional C, aka "K&R". This is the language first described by
+Brian Kernighan and Dennis Ritchie, and implemented in the first C
+compiler that was ever coded. There are actually several dialects of
+K&R, and all of them are considered as deprecated.
+
+-- ISO 9899:1990, aka C90, aka C89, aka ANSI-C. Formalized by ANSI
+in 1989 and adopted by ISO the next year, it is the C flavour many C
+compilers understand. It is mostly backward compatible with K&R C, but
+with enhancements, clarifications and several new features.
+
+-- ISO 9899:1999, aka C99. This is an evolution on C90, almost fully
+backward compatible with C90 (exhibitting a code that makes a difference
+is a tricky exercise). C99 introduces many new and useful features,
+however, including in the preprocessor.
+
+There was also a normative addendum in 1995, that added a few features
+to C90 (for instance, digraphs) that are also present in C99.
+
+
+Ucpp implements the C99 standard, but can be used in a stricter mode,
+to enforce C90 compatibility (it will, however, still recognize some
+constructions that are not in plain C90).
+
+Ucpp also knows several extensions to C99:
+
+-- Assertions: this is an extension to the defined() operator, with
+   its own namespace. Assertions seem to be used in several places,
+   therefore ucpp knows about them. It is recommended to enable
+   assertions by default on Solaris systems.
+-- Unicode: the C99 norm specifies that extended characters, from
+   the ISO-10646 charset (aka "unicode") can be used in identifiers
+   with the notations \u and \U. ucpp also accepts (with the proper
+   flag) the UTF-8 encoding in the source file for such characters.
+-- #include_next directive: it works as a #include, but will look
+   for files only in the directories specified in the include path
+   after the one the current file was found. This is a GNU-ism that
+   is useful for writing transparent wrappers around header files.
+
+Assertions and unicode are activated by specific flags; the #include_next
+support is always active.
+
+The ucpp code itself should be compatible with any ISO-C90 compiler.
+The cpp.c file is rather big (~ 53kB), it might confuse old 16-bit C
+compilers; the macro.c file is somewhat large also (~ 43kB).
+
+The evaluation of #if expressions is subject to some subtleties, see the
+section "cross-compilation".
+
+The lexer code makes no assumption about the source character set, but
+the following: source characters (those which have a syntactic value in
+C; comment and string literal contents are not concerned) must have a
+strictly positive value that is strictly lower than MAX_CHAR_VAL. The
+strict positivity is already assured by the C standard, so you just need
+to adjust MAX_CHAR_VAL.
+
+Ucpp has been tested succesfully on ASCII/ISO-8859-1 and EBCDIC systems.
+Beware that UTF-8 is NOT compatible with EBCDIC.
+
+Pragma handling: when used in non-lexer mode, ucpp tries to output
+a source text that, read again, will give the exact same stream of
+tokens. This is not completely true with regards to line numbering in
+some tricky macro replacements, but it should work correctly otherwise,
+especially with pragma directives if the compile-time option PRAGMA_DUMP
+was set: #pragma are dumped, non-void _Pragma() are converted to the
+corresponding #pragma and dumped also.
+
+Ucpp does not macro-replace the contents of #pragma and _Pragma();
+If you want a macro-replaced pragma, use this:
+
+#define pragma_(x)	_Pragma(#x)
+#define pragma(x)	pragma_(x)
+
+Anyway, pragmas do not nest (an _Pragma() cannot be evaluated if it is
+inside a #pragma or another _Pragma).
+
+
+I wrote ucpp according to what is found in "The Language C" from Brian
+Kernighan and Dennis Ritchie (2nd edition) and the C99 standard; but I
+could have misinterpreted some points. On some tricky points I got help
+from the helpful people from the comp.std.c newsgroup. For assertions
+and #include_next, I mimicked the behaviour of GNU cpp, as is stated
+in the GNU cpp info documentation. An open question is related to the
+following code:
+
+#define undefined	!
+#define makeun(x)	un ## x
+#if makeun(defined foo)
+qux
+#else
+bar
+#endif
+
+Ucpp will replace 'defined foo' with 0 first (since foo is not defined),
+then it will replace the macro makeun, and the expression will become
+'un0', which is replaced by 0 since this is a remaining identifier. The
+expression evaluates to false, and 'bar' is emitted.
+However, some other preprocessors will replace makeun first, considering
+that it is not part of a 'defined' operator application; this will
+produce the macro 'undefined', which is replaced, and the expression
+becomes '!foo'. 'foo' is replaced by 0, the expression evaluates to
+true, and 'qux' is emitted.
+
+My opinion is that the behaviour is undefined, because use of the
+'defined' operator does not match an allowed form prior to macro
+replacement (I mean, its syntax matches, but its use is reconverted
+to inexistant and therefore is not anymore matching). Other people
+think that the behaviour is well-specified, and contrary to what ucpp
+does. The only thing clear to me is that the wording of the standard
+(paragraph 6.10.1.3) is unclear.
+
+Since the ucpp behaviour makes ucpp code simpler and cleaner, and
+that it is unlikely that any real-life code would ever be disturbed
+by that interpretation of the standard, ucpp will keep its current
+behaviour until convincing evidence of my misinterpretation of the
+standard is given to me. The problem can only occur is one uses ## to
+make a 'defined' operator disappear from a #if expression (everybody
+agrees that the generation of a 'defined' operator triggers undefined
+behaviour).
+
+
+About _Pragma: the standard is not clear about when this operator is
+evaluated, and if it is allowed inside #if directives and such. For
+ucpp, I coded _Pragma as a special macro with lazy replacement: it will
+be evaluated wherever a macro could be replaced, and only at the end of
+the macro replacement (for practical purposes, _Pragma can be considered
+as a macro taking one argument, and being replaced by nothing, except
+for some tricky uses of the # and ## operators). This means that, by
+default, ucpp will evaluate _Pragma inside some directives (mainly, #if,
+#include, #include_next and #line), but it can be taught not to do so by
+defining NO_PRAGMA_IN_DIRECTIVE in tune.h.
+
+
+
+CROSS-COMPILATION
+-----------------
+
+If compiled with a C99 development suite, ucpp should be fully
+C99-compliant on the host platform (up to my own understanding of the
+standard -- remember that this software is distributed as-is, without
+any guarantee). However, if a pre-C99 compiler is used, or if the
+target machine is not the host machine (for instance when you build a
+cross-compiler), the evaluation of #if expressions is subject to some
+cross-compiling issues:
+
+
+-- character constants: when evaluating expressions, character constants
+are interpreted in the source character set context; this is allowed
+by the standard but this can lead to problems with code that expects
+this interpretation to match the one made in the C code. To ease
+cross-compilation, you can define a conversion array, and make the
+global variable transient_characters point to it. The array should
+contain 256 int; transient_characters[x] is the value of the character
+whose value is x in the source character set.
+
+This facility is provided for inclusion of ucpp inside another code;
+if you want a stand-alone ucpp with that conversion, hard-code the
+conversion table into eval.c and make transient_characters[] statically
+point to it. Alternatively, you could provide an option syntax to
+provide such a table on command-line, if you feel like it.
+
+
+-- wide character constants signedness: by default, ucpp makes wide
+characters as signed as what plain chars are on the build host. To
+force wide character constant signedness, define WCHAR_SIGNEDNESS to 0
+(for unsigned) or 1 (for signed). Beware, however, that "native" wide
+character constants, even signed, are considered positive. Non-wide
+character constants are, according to the C99 standard, of type int, and
+therefore always signed.
+
+
+-- evaluation type: C90 states that all constants in #if expressions
+are considered as either long or unsigned long, and that the evaluation
+is performed with operands of that size. In C99, the situation is
+equivalent, except that the types used are intmax_t and uintmax_t, as
+defined in <stdint.h>.
+
+Ucpp can use two expression evaluators: one uses native integer types
+(one signed and one unsigned), the other evaluator emulates big integer
+numbers by representing them with two "unsigned long". By default, it
+will use the first evaluator, using (u)intmax_t as native types if the
+compiler is C99-compliant, or (unsigned) long otherwise. If you want
+another behaviour, modify the relevant section in tune.h. Here are
+examples of definitions:
+
+/* evaluate natively with type "long long" */
+#define NATIVE_UINTMAX	unsigned long long
+#define NATIVE_INTMAX	long long
+
+/* evaluate natively with type "long" (even if bigger is available) */
+#define MATIVE_UINTMAX	unsigned long
+#define MATIVE_INTMAX	long
+
+/* evaluate with bignum evaluation */
+#undef NATIVE_UINTMAX
+#define SIMUL_UINTMAX
+
+The bignum evaluation handles signed integers in two's complement
+representation, whether this is the native integer representation or
+not. The code makes the non-standard assumption that unsigned long are
+represented unpadded in memory, that is, unsigned long are made up of
+exactly sizeof(unsigned long) * CHAR_BIT bits. I have never heard of any
+architecture where this assumption would be false.
+
+
+
+FUTURE EVOLUTIONS
+-----------------
+
+Ucpp is quite complete now. There was a longstanding project of
+"traditional" preprocessing, but I dropped it because it would not
+map cleanly on the token-based ucpp structure. Maybe I will code a
+string-based preprocessor one day; it would certainly use some of the
+code from lexer.c, eval.c, mem.c and hash.c. However, making such a tool
+is almost irrelevant nowadays. If one wants to handle such project,
+using ucpp as code base, I would happily provide some help, if needed.
+
+
+
+CHANGES
+-------
+
+From 0.9 to 1.0:
+
+* bugfix: crash after erroneous #assert
+* changed ERR_SHARP to FAIL_SHARP, EMUL_UINTMAX to SIMUL_UINTMAX
+* made "inline" default on gcc and DEC ccc (Linux/Alpha)
+* semantic of -I is now Unix-like (added directories are looked first)
+* added -J flag (to add include directories after the system ones)
+* cleaned up non-ascii issues
+* bugfix: missing brace in no-LOW_MEM code
+* bugfix: argument number check in variadic macros
+* bugfix: crash in non-lexer mode after some cases of unreplaced macro
+* bugfix: _Pragma() handling wrt # and ##
+* made evaluation of _Pragma() optional in #if, #include and #line
+* bugfix: re-dump of multiline #pragma
+* added the inmacro and macro_count flags
+* added mmap() support
+* added option to retain whitespace content in lexer mode
+
+From 0.8 to 0.9:
+
+* added check for division by 0 in #if evaluation
+* added check for non-standard line numbers
+* added check for trailing garbage in most directives
+* corrected signedness of char constants (always int, therefore always signed)
+* made LOW_MEM code, so that ucpp runs smoothly on low memory architectures
+* multiple bugfixes (using the GNU cpp testsuite)
+* added handling of _Pragma (as a macro)
+* added tokenization of pragma directives
+* added conservation of pragma directives in text output
+* produced Msdos 16-bit small memory model executable
+* produced Minix-86 executable
+
+From 0.7 to 0.8:
+
+* added some support for Amiga systems
+* fixed extra spacing in stringified tokens
+* fixed bug related to %:% and tolerated rogue sharps
+* namespace cleanup
+* bugfix for macro redefinition
+* added warning for evaluated comma operators in #if (ISO requirement)
+* -Dfoo now defines foo with content 1 (and not void content)
+* trigraphs can be disabled (for incorrect but legacy code)
+* fixed semantics for #include "file" (local directory)
+* fixed detection of protected files
+* produced a Msdos 16-bit executable
+
+From 0.6 to 0.7:
+
+* officially changed the goal to full C99 compliance
+* added the CONTEXT token and let NEWLINE tokens go
+* added report_context() for error reporting
+* enforced matching of #if/#endif (file-global nesting level = 0)
+* added support of C99 digraphs
+* added UTF-8 encoding support
+* added universal character names
+* rewrote #if expressions (sizes fixed, bignum, signed/unsigned fixed)
+* fixed incomplete evaluation of #if expressions
+* added transient_characters[]
+
+From 0.5 to 0.6:
+
+* disappearance of error_nonl()
+* added extra optional warnings for trigraphs
+* some bugfixes, especially in lexer mode
+* handled MacIntosh files correctly
+
+From 0.4 to 0.5:
+
+* nicer #pragma handling (a token can be emitted)
+* bugfix in lexer mode after #line and #error
+* sample.c   an example of code linked with ucpp
+* made #if expressions conforming to standard signed/unsigned handling
+* added the copy_line[] buffer feature
+
+From 0.3 to 0.4:
+
+* relaxed interpretation of '#include foo' when foo ends up, after macro
+  substitution, with a '<bar>' content
+* corrected the 'double-dot' bug
+* corrected two bugs related to the treatment of macro aborted calls (due
+  to lack of arguments)
+* some namespaces cleanup, to ease integration into other code
+* documented the way to include ucpp into another program
+* made newlines embedded into strings illegal (and reported as such)
+
+From 0.2 to 0.3:
+
+* added support for system predefined macros
+* made several bugfixes
+* checked C99 compliance for most of the features
+* ucpp now accepts non-C characters on standard when used stand-alone
+* removed many useless spaces in the output
+
+From 0.1 to 0.2:
+
+* added support for assertions
+* added support for macros with variable arguments
+* split the pharaonic cpp.c file into many
+* made several bugfixes
+* relaxed the behaviour with regards to the void arguments
+* made C++-like comments an option
+
+
+
+THANKS TO
+---------
+
+Volker Barthelmann, Neil Booth, Stéphane Ecolivet, Antoine Leca, Cyrille
+Lefevre, Dave Rivers, Loic Tortay and Laurent Wacrenier, for suggestions
+and beta-testing.
+
+Paul Eggert, Douglas A. Gwyn, Clive D.W. Feather, and the other guys from
+comp.std.c, for explanations about the standard.
+
+Dave Brolley, Jamie Lokier and Neil Booth, for discussion about tricky
+points on nesting macros.
+
+Brian Kernighan and Dennis Ritchie, for bringing C to mortal Men.
diff --git a/ucpp/assert.c b/ucpp/assert.c
new file mode 100755
index 0000000..51f5710
--- /dev/null
+++ b/ucpp/assert.c
@@ -0,0 +1,397 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <time.h>
+#include "ucppi.h"
+#include "mem.h"
+#include "hash.h"
+#include "tune.h"
+
+/*
+ * Assertion support. Each assertion is indexed by its predicate, and
+ * the list of 'questions' which yield a true answer.
+ */
+
+static struct HT *assertions;
+
+static struct assert *new_assertion(void)
+{
+	struct assert *a = getmem(sizeof(struct assert));
+
+	a->nbval = 0;
+	return a;
+}
+
+static void del_assertion(void *va)
+{
+	struct assert *a = va;
+	size_t i, j;
+
+	if (a->name) freemem(a->name);
+	for (i = 0; i < a->nbval; i ++) {
+		for (j = 0; j < a->val[i].nt; j ++)
+			if (S_TOKEN(a->val[i].t[j].type))
+				freemem(a->val[i].t[j].name);
+		if (a->val[i].nt) freemem(a->val[i].t);
+	}
+	if (a->nbval) freemem(a->val);
+}
+
+/*
+ * print the contents of a token list
+ */
+static void print_token_fifo(struct token_fifo *tf)
+{
+	size_t i;
+
+	for (i = 0; i < tf->nt; i ++)
+		if (ttMWS(tf->t[i].type)) fputc(' ', emit_output);
+		else fputs(token_name(tf->t + i), emit_output);
+}
+
+/*
+ * print all assertions related to a given name
+ */
+static void print_assert(void *va)
+{
+	struct assert *a = va;
+	size_t i;
+
+	for (i = 0; i < a->nbval; i ++) {
+		fprintf(emit_output, "#assert %s(", a->name);
+		print_token_fifo(a->val + i);
+		fprintf(emit_output, ")\n");
+	}
+}
+
+/*
+ * compare two token_fifo, return 0 if they are identical, 1 otherwise.
+ * All whitespace tokens are considered identical, but sequences of
+ * whitespace are not shrinked.
+ */
+int cmp_token_list(struct token_fifo *f1, struct token_fifo *f2)
+{
+	size_t i;
+
+	if (f1->nt != f2->nt) return 1;
+	for (i = 0; i < f1->nt; i ++) {
+		if (ttMWS(f1->t[i].type) && ttMWS(f2->t[i].type)) continue;
+		if (f1->t[i].type != f2->t[i].type) return 1;
+		if (f1->t[i].type == MACROARG
+			&& f1->t[i].line != f2->t[i].line) return 1;
+		if (S_TOKEN(f1->t[i].type)
+			&& strcmp(f1->t[i].name, f2->t[i].name)) return 1;
+	}
+	return 0;
+}
+
+/*
+ * for #assert
+ * Assertions are not part of the ISO-C89 standard, but they are sometimes
+ * encountered, for instance in Solaris standard include files.
+ */
+int handle_assert(struct lexer_state *ls)
+{
+	int ina = 0, ltww;
+	struct token t;
+	struct token_fifo *atl = 0;
+	struct assert *a;
+	int ret = -1;
+	long l = ls->line;
+	int nnp;
+	size_t i;
+
+	while (!next_token(ls)) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type == NAME) {
+			if (!(a = getHT(assertions, &(ls->ctok->name)))) {
+				a = new_assertion();
+				a->name = sdup(ls->ctok->name);
+				ina = 1;
+			}
+			goto handle_assert_next;
+		}
+		error(l, "illegal assertion name for #assert");
+		goto handle_assert_warp_ign;
+	}
+	goto handle_assert_trunc;
+
+handle_assert_next:
+	while (!next_token(ls)) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type != LPAR) {
+			error(l, "syntax error in #assert");
+			goto handle_assert_warp_ign;
+		}
+		goto handle_assert_next2;
+	}
+	goto handle_assert_trunc;
+
+handle_assert_next2:
+	atl = getmem(sizeof(struct token_fifo));
+	atl->art = atl->nt = 0;
+	for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ltww && ttMWS(ls->ctok->type)) continue;
+		ltww = ttMWS(ls->ctok->type);
+		if (ls->ctok->type == LPAR) nnp ++;
+		else if (ls->ctok->type == RPAR) {
+			if (!(-- nnp)) goto handle_assert_next3;
+		}
+		t.type = ls->ctok->type;
+		if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+		aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
+	}
+	goto handle_assert_trunc;
+
+handle_assert_next3:
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
+			warning(l, "trailing garbage in #assert");
+		}
+	}
+	if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
+		freemem(atl->t);
+	if (atl->nt == 0) {
+		error(l, "void assertion in #assert");
+		freemem(atl);
+		return ret;
+	}
+	for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
+	if (i != a->nbval) {
+		/* we already have it */
+		ret = 0;
+		goto handle_assert_error;
+	}
+
+	/* This is a new assertion. Let's keep it. */
+	aol(a->val, a->nbval, *atl, TOKEN_LIST_MEMG);
+	if (ina) putHT(assertions, a);
+	if (emit_assertions) {
+		fprintf(emit_output, "#assert %s(", a->name);
+		print_token_fifo(atl);
+		fputs(")\n", emit_output);
+	}
+	return 0;
+
+handle_assert_trunc:
+	error(l, "unfinished #assert");
+handle_assert_error:
+	if (atl && atl->nt) {
+		for (i = 0; i < atl->nt; i ++)
+			if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name);
+		freemem(atl->t);
+	}
+	return ret;
+handle_assert_warp_ign:
+	while (!next_token(ls) && ls->ctok->type != NEWLINE);
+	return ret;
+}
+
+/*
+ * for #unassert
+ */
+int handle_unassert(struct lexer_state *ls)
+{
+	int ltww;
+	struct token t;
+	struct token_fifo *atl = 0;
+	struct assert *a;
+	int ret = -1;
+	long l = ls->line;
+	int nnp;
+	size_t i;
+
+	while (!next_token(ls)) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type == NAME) {
+			if (!(a = getHT(assertions, &(ls->ctok->name)))) {
+				ret = 0;
+				goto handle_unassert_warp;
+			}
+			goto handle_unassert_next;
+		}
+		error(l, "illegal assertion name for #unassert");
+		goto handle_unassert_warp;
+	}
+	goto handle_unassert_trunc;
+
+handle_unassert_next:
+	while (!next_token(ls)) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type != LPAR) {
+			error(l, "syntax error in #unassert");
+			goto handle_unassert_warp;
+		}
+		goto handle_unassert_next2;
+	}
+	if (emit_assertions) fprintf(emit_output, "#unassert %s\n", a->name);
+	delHT(assertions, a);
+	return 0;
+
+handle_unassert_next2:
+	atl = getmem(sizeof(struct token_fifo));
+	atl->art = atl->nt = 0;
+	for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ltww && ttMWS(ls->ctok->type)) continue;
+		ltww = ttMWS(ls->ctok->type);
+		if (ls->ctok->type == LPAR) nnp ++;
+		else if (ls->ctok->type == RPAR) {
+			if (!(-- nnp)) goto handle_unassert_next3;
+		}
+		t.type = ls->ctok->type;
+		if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+		aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
+	}
+	goto handle_unassert_trunc;
+
+handle_unassert_next3:
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
+			warning(l, "trailing garbage in #unassert");
+		}
+	}
+	if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
+		freemem(atl->t);
+	if (atl->nt == 0) {
+		error(l, "void assertion in #unassert");
+		freemem(atl);
+		return ret;
+	}
+	for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
+	if (i != a->nbval) {
+		/* we have it, undefine it */
+		if (i < (a->nbval - 1))
+			mmvwo(a->val + i, a->val + i + 1, (a->nbval - i - 1)
+				* sizeof(struct token_fifo));
+		a->nbval --;
+		if (emit_assertions) {
+			fprintf(emit_output, "#unassert %s(", a->name);
+			print_token_fifo(atl);
+			fputs(")\n", emit_output);
+		}
+	}
+	ret = 0;
+	goto handle_unassert_finish;
+
+handle_unassert_trunc:
+	error(l, "unfinished #unassert");
+handle_unassert_finish:
+	if (atl && atl->nt) {
+		for (i = 0; i < atl->nt; i ++)
+			if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name);
+		freemem(atl->t);
+	}
+	return ret;
+handle_unassert_warp:
+	while (!next_token(ls) && ls->ctok->type != NEWLINE);
+	return ret;
+}
+
+/*
+ * Add the given assertion (as string).
+ */
+int make_assertion(char *aval)
+{
+	struct lexer_state lls;
+	size_t n = strlen(aval) + 1;
+	char *c = sdup(aval);
+	int ret;
+
+	*(c + n - 1) = '\n';
+	init_buf_lexer_state(&lls, 0);
+	lls.flags = DEFAULT_LEXER_FLAGS;
+	lls.input = 0;
+	lls.input_string = (unsigned char *)c;
+	lls.pbuf = 0;
+	lls.ebuf = n;
+	lls.line = -1;
+	ret = handle_assert(&lls);
+	freemem(c);
+	free_lexer_state(&lls);
+	return ret;
+}
+
+/*
+ * Remove the given assertion (as string).
+ */
+int destroy_assertion(char *aval)
+{
+	struct lexer_state lls;
+	size_t n = strlen(aval) + 1;
+	char *c = sdup(aval);
+	int ret;
+
+	*(c + n - 1) = '\n';
+	init_buf_lexer_state(&lls, 0);
+	lls.flags = DEFAULT_LEXER_FLAGS;
+	lls.input = 0;
+	lls.input_string = (unsigned char *)c;
+	lls.pbuf = 0;
+	lls.ebuf = n;
+	lls.line = -1;
+	ret = handle_unassert(&lls);
+	freemem(c);
+	free_lexer_state(&lls);
+	return ret;
+}
+
+/*
+ * initialize the assertion table
+ */
+void init_assertions(void)
+{
+	if (assertions) killHT(assertions);
+	assertions = newHT(128, cmp_struct, hash_struct, del_assertion);
+}
+
+/*
+ * retrieve an assertion from the hash table
+ */
+struct assert *get_assertion(char *name)
+{
+	return getHT(assertions, &name);
+}
+
+/*
+ * print already defined assertions
+ */
+void print_assertions(void)
+{
+	scanHT(assertions, print_assert);
+}
diff --git a/ucpp/cpp.c b/ucpp/cpp.c
new file mode 100644
index 0000000..4dcca13
--- /dev/null
+++ b/ucpp/cpp.c
@@ -0,0 +1,2265 @@
+/*
+ * C and T preprocessor, and integrated lexer
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*vb*/
+#ifdef HAVE_MISRA
+void misra(int,...);
+#endif
+extern void handle_deps(char *,int);
+
+#define VERS_MAJ	1
+#define VERS_MIN	0
+/* uncomment the following if you cannot set it with a compiler flag */
+/* #define STAND_ALONE */
+
+#include "tune.h"
+#ifdef UCPP_MMAP
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE	1
+#endif
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <limits.h>
+#include <time.h>
+#include "ucppi.h"
+#include "mem.h"
+#include "hash.h"
+#ifdef UCPP_MMAP
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#endif
+
+/*
+ * The standard path where includes are looked for.
+ */
+#ifdef STAND_ALONE
+static char *include_path_std[] = { STD_INCLUDE_PATH, 0 };
+#endif
+static char **include_path;
+static size_t include_path_nb = 0;
+
+int no_special_macros = 0;
+int emit_dependencies = 0, emit_defines = 0, emit_assertions = 0;
+FILE *emit_output;
+
+#ifdef STAND_ALONE
+static char *system_macros_def[] = { STD_MACROS, 0 };
+static char *system_assertions_def[] = { STD_ASSERT, 0 };
+#endif
+
+char *current_filename, *current_long_filename = 0;
+static int current_incdir = -1;
+
+#ifndef NO_UCPP_ERROR_FUNCTIONS
+/*
+ * "ouch" is the name for an internal ucpp error. If AUDIT is not defined,
+ * no code calling this function will be generated; a "ouch" may still be
+ * emitted by getmem() (in mem.c) if MEM_CHECK is defined, but this "ouch"
+ * does not use this function.
+ */
+#endif	/* NO_UCPP_ERROR_FUNCTIONS */
+
+/*
+ * Some memory allocations are manually garbage-collected; essentially,
+ * strings duplicated in the process of macro replacement. Each such
+ * string is referenced in the garbage_fifo, which is cleared when all
+ * nested macros have been resolved.
+ */
+
+struct garbage_fifo {
+	char **garbage;
+	size_t ngarb, memgarb;
+};
+
+/*
+ * throw_away() marks a string to be collected later
+ */
+void throw_away(struct garbage_fifo *gf, char *n)
+{
+	wan(gf->garbage, gf->ngarb, n, gf->memgarb);
+}
+
+/*
+ * free marked strings
+ */
+void garbage_collect(struct garbage_fifo *gf)
+{
+	size_t i;
+
+	for (i = 0; i < gf->ngarb; i ++) freemem(gf->garbage[i]);
+	gf->ngarb = 0;
+}
+
+static void init_garbage_fifo(struct garbage_fifo *gf)
+{
+	gf->garbage = getmem((gf->memgarb = GARBAGE_LIST_MEMG)
+		* sizeof(char *));
+	gf->ngarb = 0;
+}
+
+/*
+ * order is important: it must match the token-constants declared as an
+ * enum in the header file.
+ */
+char *operators_name[] = {
+	" ", "\n", " ",
+	"0000", "name", "bunch", "pragma", "context",
+	"\"dummy string\"", "'dummy char'",
+	"/", "/=", "-", "--", "-=", "->", "+", "++", "+=", "<", "<=", "<<",
+	"<<=", ">", ">=", ">>", ">>=", "=", "==",
+#ifdef CAST_OP
+	"=>",
+#endif
+	"~", "!=", "&", "&&", "&=", "|", "||", "|=", "%", "%=", "*", "*=",
+	"^", "^=", "!", "~=", "{", "}", "[", "]", "(", ")", ",", "?", ";",
+	":", ".", "...", "#", "##", " ", "ouch", "<:", ":>", "<%", "%>",
+	"%:", "%:%:"
+};
+
+/* the ascii representation of a token */
+#ifdef SEMPER_FIDELIS
+#define tname(x)	(ttWHI((x).type) ? " " : S_TOKEN((x).type) \
+			? (x).name : operators_name[(x).type])
+#else
+#define tname(x)	(S_TOKEN((x).type) ? (x).name \
+			: operators_name[(x).type])
+#endif
+
+char *token_name(struct token *t)
+{
+	return tname(*t);
+}
+
+/*
+ * To speed up deeply nested and repeated inclusions, we:
+ * -- use a hash table to remember where we found each file
+ * -- remember when the file is protected by a #ifndef/#define/#endif
+ *    construction; we can then avoid including several times a file
+ *    when this is not necessary.
+ * -- remember in which directory, in the include path, the file was found.
+ */
+struct found_file {
+	char *name;		/* first field */
+	char *long_name;
+	char *protect;
+	int incdir;
+};
+
+static struct HT *found_files = 0, *found_files_loc = 0;
+
+static struct found_file *new_found_file(void)
+{
+	struct found_file *ff = getmem(sizeof(struct found_file));
+
+	ff->protect = 0;
+	ff->incdir = -1;
+	return ff;
+}
+
+static void del_found_file(void *m)
+{
+	struct found_file *ff = (struct found_file *)m;
+
+	freemem(ff->name);
+	freemem(ff->long_name);
+	if (ff->protect) freemem(ff->protect);
+}
+
+/*
+ * To keep up with the #ifndef/#define/#endif protection mechanism
+ * detection.
+ */
+struct protect protect_detect;
+static struct protect *protect_detect_stack = 0;
+
+/*
+ * "current_filename" is used for error reporting, and the __FILE__ macro
+ */
+static void set_current_filename(char *x)
+{
+	current_filename = x;
+}
+
+void set_init_filename(char *x, int real_file)
+{
+	set_current_filename(sdup(x));
+	current_long_filename = 0;
+	current_incdir = -1;
+	if (real_file) {
+		protect_detect.macro = 0;
+		protect_detect.state = 1;
+		protect_detect.ff = new_found_file();
+		protect_detect.ff->name = sdup(x);
+		protect_detect.ff->long_name = sdup(x);
+		putHT(found_files_loc, protect_detect.ff);
+	} else {
+		protect_detect.state = 0;
+	}
+}
+
+static void init_found_files(void)
+{
+	if (found_files) killHT(found_files);
+	found_files = newHT(128, cmp_struct, hash_struct, del_found_file);
+	if (found_files_loc) killHT(found_files_loc);
+	found_files_loc = newHT(128, cmp_struct, hash_struct, del_found_file);
+}
+
+/*
+ * convert a Unix-style path for the host architecture
+ */
+#if defined(MSDOS) || defined(ATARI) || defined(_WIN32)
+static char *convert_path(char *path)
+{
+	/* on msdos systems, replace all / by \ */
+	char *c, *newp = sdup(path);
+
+	for (c = newp; *c; c ++) if (*c == '/') *c = '\\';
+	return newp;
+}
+
+#elif defined AMIGA
+static char *convert_path(char *path)
+{
+	char *newp = getmem(1 + strlen(path));
+	char *s = path, *d = newp;
+
+	if (*s == '.') {					/* convert "." to "" */
+		if (*(s+1) == '\0')
+			s++;
+	}
+	while (*s) {
+		if (*s == '.') {
+			if (*(s+1) == '/') {
+				s += 2;							/* "./" is discarded */
+				continue;
+			}
+			else if (*(s+1) == '.') {
+				if (*(s+2) == '/')
+					s += 2;						/* "../" is converted to "/" */
+			}
+		}
+		*d++ = *s++;
+	}
+	*d = '\0';
+
+	return newp;
+}
+
+#else  /* no conversion */
+static char *convert_path(char *path)
+{
+	return sdup(path);
+}
+#endif
+
+/*
+ * Set the lexer state at the beginning of a file.
+ */
+static void reinit_lexer_state(struct lexer_state *ls, int wb)
+{
+#ifndef NO_UCPP_BUF
+	ls->input_buf = wb ? getmem(INPUT_BUF_MEMG) : 0;
+#ifdef UCPP_MMAP
+	ls->from_mmap = 0;
+#endif
+#endif
+	ls->ebuf = ls->pbuf = 0;
+	ls->nlka = 0;
+	ls->macfile = 0;
+	ls->discard = 1;
+	ls->last = 0;		/* we suppose '\n' is not 0 */
+	ls->line = 1;
+	ls->ltwnl = 1;
+	ls->oline = 1;
+	ls->pending_token = 0;
+	ls->cli = 0;
+	ls->copy_line[COPY_LINE_LENGTH - 1] = 0;
+	ls->ifnest = 0;
+	ls->condf[0] = ls->condf[1] = 0;
+}
+
+/*
+ * Initialize the struct lexer_state, with optional input and output buffers.
+ */
+void init_buf_lexer_state(struct lexer_state *ls, int wb)
+{
+	reinit_lexer_state(ls, wb);
+#ifndef NO_UCPP_BUF
+	ls->output_buf = wb ? getmem(OUTPUT_BUF_MEMG) : 0;
+#endif
+	ls->sbuf = 0;
+
+	ls->ctok = getmem(sizeof(struct token));
+	ls->ctok->name = getmem(ls->tknl = TOKEN_NAME_MEMG);
+	ls->pending_token = 0;
+
+	ls->flags = 0;
+	ls->count_trigraphs = 0;
+	ls->gf = getmem(sizeof(struct garbage_fifo));
+	init_garbage_fifo(ls->gf);
+	ls->condcomp = 1;
+	ls->condnest = 0;
+#ifdef INMACRO_FLAG
+	ls->inmacro = 0;
+	ls->macro_count = 0;
+#endif
+}
+
+/*
+ * Initialize the (complex) struct lexer_state.
+ */
+void init_lexer_state(struct lexer_state *ls)
+{
+	init_buf_lexer_state(ls, 1);
+}
+
+/*
+ * Restore what is needed from a lexer_state. This is used for #include.
+ */
+static void restore_lexer_state(struct lexer_state *ls,
+	struct lexer_state *lsbak)
+{
+#ifndef NO_UCPP_BUF
+	freemem(ls->input_buf);
+	ls->input_buf = lsbak->input_buf;
+#ifdef UCPP_MMAP
+	ls->from_mmap = lsbak->from_mmap;
+	ls->input_buf_sav = lsbak->input_buf_sav;
+#endif
+#endif
+	ls->input = lsbak->input;
+	ls->ebuf = lsbak->ebuf;
+	ls->pbuf = lsbak->pbuf;
+	ls->nlka = lsbak->nlka;
+	ls->macfile = lsbak->macfile;
+	ls->discard = lsbak->discard;
+	ls->line = lsbak->line;
+	ls->oline = lsbak->oline;
+	ls->ifnest = lsbak->ifnest;
+	ls->condf[0] = lsbak->condf[0];
+	ls->condf[1] = lsbak->condf[1];
+}
+
+/*
+ * file_context (and the two functions push_ and pop_) are used to save
+ * all that is needed when including a file.
+ */
+static struct file_context {
+	struct lexer_state ls;
+	char *name, *long_name;
+	int incdir;
+} *ls_stack;
+static size_t ls_depth = 0;
+
+static void push_file_context(struct lexer_state *ls)
+{
+	struct file_context fc;
+
+	if (ls_depth > 1023)
+		error(ls->line - 1, "too many nested includes");
+	fc.name = current_filename;
+	fc.long_name = current_long_filename;
+	fc.incdir = current_incdir;
+	mmv(&(fc.ls), ls, sizeof(struct lexer_state));
+	aol(ls_stack, ls_depth, fc, LS_STACK_MEMG);
+	ls_depth --;
+	aol(protect_detect_stack, ls_depth, protect_detect, LS_STACK_MEMG);
+	protect_detect.macro = 0;
+}
+
+static void pop_file_context(struct lexer_state *ls)
+{
+#ifdef AUDIT
+	if (ls_depth <= 0) ouch("prepare to meet thy creator");
+#endif
+	restore_lexer_state(ls, &(ls_stack[-- ls_depth].ls));
+	if (protect_detect.macro) freemem(protect_detect.macro);
+	protect_detect = protect_detect_stack[ls_depth];
+	set_current_filename(ls_stack[ls_depth].name);
+	current_long_filename = ls_stack[ls_depth].long_name;
+	current_incdir = ls_stack[ls_depth].incdir;
+}
+
+/*
+ * report_context() returns the list of successive includers of the
+ * current file, ending with a dummy entry with a negative line number.
+ * The caller is responsible for freeing the returned pointer.
+ */
+struct stack_context *report_context(void)
+{
+	struct stack_context *sc;
+	size_t i;
+
+	sc = getmem((ls_depth + 1) * sizeof(struct stack_context));
+	for (i = 0; i < ls_depth; i ++) {
+		sc[i].name = ls_stack[ls_depth - i - 1].name;
+		sc[i].long_name = ls_stack[ls_depth - i - 1].long_name;
+		sc[i].line = ls_stack[ls_depth - i - 1].ls.line - 1;
+	}
+	sc[ls_depth].line = -1;
+	return sc;
+}
+
+/*
+ * init_lexer_mode() is used to end initialization of a struct lexer_state
+ * if it must be used for a lexer
+ */
+void init_lexer_mode(struct lexer_state *ls)
+{
+	ls->flags = DEFAULT_LEXER_FLAGS;
+	ls->output_fifo = getmem(sizeof(struct token_fifo));
+	ls->output_fifo->art = ls->output_fifo->nt = 0;
+	ls->toplevel_of = ls->output_fifo;
+	ls->save_ctok = ls->ctok;
+}
+
+/*
+ * release memory used by a struct lexer_state
+ */
+void free_lexer_state(struct lexer_state *ls)
+{
+#ifndef NO_UCPP_BUF
+	if (ls->input_buf) freemem(ls->input_buf);
+	if (ls->output_buf) freemem(ls->output_buf);
+#endif
+	freemem(ls->ctok->name);
+	freemem(ls->ctok);
+	if (!(ls->flags & LEXER)) garbage_collect(ls->gf);
+	freemem(ls->gf);
+}
+
+/*
+ * Print line information.
+ */
+static void print_line_info(struct lexer_state *ls, unsigned long flags)
+{
+	char *fn = current_long_filename ?
+		current_long_filename : current_filename;
+	char *b, *d;
+
+	b = getmem(50 + strlen(fn));
+	if (flags & GCC_LINE_NUM) {
+		sprintf(b, "# %ld \"%s\"\n", ls->line, fn);
+	} else {
+		sprintf(b, "#line %ld \"%s\"\n", ls->line, fn);
+	}
+	for (d = b; *d; d ++) put_char(ls, (unsigned char)(*d));
+	freemem(b);
+}
+
+/*
+ * Enter a file; this implies the possible emission of a #line directive.
+ * The flags used are passed as second parameter instead of being
+ * extracted from the struct lexer_state.
+ *
+ * As a command-line option, gcc-like directives (with only a '#',
+ * without 'line') may be produced.
+ */
+void enter_file(struct lexer_state *ls, unsigned long flags)
+{
+	char *fn = current_long_filename ?
+		current_long_filename : current_filename;
+
+	if (!(flags & LINE_NUM)) return;
+	if ((flags & LEXER) && !(flags & TEXT_OUTPUT)) {
+		struct token t;
+
+		t.type = CONTEXT;
+		t.line = ls->line;
+		t.name = fn;
+		print_token(ls, &t, 0);
+		return;
+	}
+	print_line_info(ls, flags);
+	ls->oline --;	/* emitted #line troubled oline */
+}
+
+#ifdef UCPP_MMAP
+/*
+ * We open() the file, then fdopen() it and fseek() to its end. If the
+ * fseek() worked, we try to mmap() the file, up to the point where we
+ * arrived.
+ * On an architecture where end-of-lines are multibytes and translated
+ * into single '\n', bad things could happen. We strongly hope that, if
+ * we could fseek() to the end but could not mmap(), then we can get back.
+ */
+static void *find_file_map;
+static size_t map_length;
+
+FILE *fopen_mmap_file(char *name)
+{
+	FILE *f;
+	int fd;
+	long l;
+
+	find_file_map = 0;
+	fd = open(name, O_RDONLY, 0);
+	if (fd < 0) return 0;
+	l = lseek(fd, 0, SEEK_END);
+	f = fdopen(fd, "r");
+	if (!f) {
+		close(fd);
+		return 0;
+	}
+	if (l < 0) return f;	/* not seekable */
+	map_length = l;
+	if ((find_file_map = mmap(0, map_length, PROT_READ,
+		MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+		/* we could not mmap() the file; get back */
+		find_file_map = 0;
+		if (fseek(f, 0, SEEK_SET)) {
+			/* bwaah... can't get back. This file is cursed. */
+			fclose(f);
+			return 0;
+		}
+	}
+	return f;
+}
+
+void set_input_file(struct lexer_state *ls, FILE *f)
+{
+	ls->input = f;
+	if (find_file_map) {
+		ls->from_mmap = 1;
+		ls->input_buf_sav = ls->input_buf;
+		ls->input_buf = find_file_map;
+		ls->pbuf = 0;
+		ls->ebuf = map_length;
+	} else {
+		ls->from_mmap = 0;
+	}
+}
+#endif
+
+/*
+ * Find a file by looking through the include path.
+ * return value: a FILE * on the file, opened in "r" mode, or 0.
+ *
+ * find_file_error will contain:
+ *   FF_ERROR      on error (file not found or impossible to read)
+ *   FF_PROTECT    file is protected and therefore useless to read
+ *   FF_KNOWN      file is already known
+ *   FF_UNKNOWN    file was not already known
+ */
+static int find_file_error;
+
+enum { FF_ERROR, FF_PROTECT, FF_KNOWN, FF_UNKNOWN };
+
+static FILE *find_file(char *name, int localdir)
+{
+	FILE *f;
+	int i, incdir = -1;
+	size_t nl = strlen(name);
+	char *s = 0;
+	struct found_file *ff = 0;
+	int lf = 0;
+
+	find_file_error = FF_ERROR;
+	protect_detect.state = -1;
+	protect_detect.macro = 0;
+	if (localdir) {
+		int i;
+		char *rfn = current_long_filename ? current_long_filename
+			: current_filename;
+
+		for (i = strlen(rfn) - 1; i >= 0; i --)
+#if defined(MSDOS) || defined(ATARI) || defined(_WIN32)
+			if (rfn[i] == '\\') break;
+#elif defined AMIGA
+			if (rfn[i] == '/' || rfn[i] == ':') break;
+#else
+			if (rfn[i] == '/') break;
+#endif
+
+#if defined(MSDOS) || defined(ATARI) || defined(_WIN32)
+		if (i >= 0 && *name != '\\' && (nl < 2 || name[1] != ':'))
+#elif defined AMIGA
+		if (i >= 0 && strchr(name,':') == 0)
+#else
+		if (i >= 0 && *name != '/')
+#endif
+		{
+			/*
+			 * current file is somewhere else, and the provided
+			 * file name is not absolute, so we must adjust the
+			 * base for looking for the file; besides,
+			 * found_files and found_files_loc are irrelevant
+			 * for this search.
+			 */
+			s = getmem(i + 2 + nl);
+			mmv(s, rfn, i + 1);
+			mmv(s + i + 1, name, nl);
+			s[i + 1 + nl] = 0;
+			ff = getHT(found_files_loc, &s);
+		} else ff = getHT(found_files_loc, &name);
+
+		if (!ff) {
+#ifdef UCPP_MMAP
+			if (f = fopen_mmap_file(s ? s : name)) {
+#else
+			if (f = fopen(s ? s : name, "r")) {
+#endif
+				lf = 1;
+				protect_detect.ff = new_found_file();
+				goto found_file;
+			}
+		}
+	}
+
+	if (!ff) ff = getHT(found_files, s ? &s : &name);
+	if (ff) {
+		if (ff->protect && get_macro(ff->protect)) {
+			/* file is protected, do not include it */
+			find_file_error = FF_PROTECT;
+			return 0;
+		}
+		protect_detect.ff = ff;
+#ifdef UCPP_MMAP
+		f = fopen_mmap_file(ff->long_name);
+#else
+		f = fopen(ff->long_name, "r");
+#endif
+		if (!f) return 0;
+		goto found_file_2;
+	} else {
+		protect_detect.ff = new_found_file();
+	}
+	/*
+	 * This is the first time we find the file, or it was not protected.
+	 */
+	if (s) freemem(s);
+	for (i = 0; i < include_path_nb; i ++) {
+		size_t ni = strlen(include_path[i]);
+
+		s = getmem(ni + nl + 2);
+		mmv(s, include_path[i], ni);
+#ifdef AMIGA
+		/* contributed by Volker Barthelmann */
+		if (ni > 0 && s[ni - 1] != ':' && s[ni - 1] != '/') {
+			s[ni] = '/';
+			mmv(s + ni + 1, name, nl + 1);
+		} else {
+			mmv(s + ni, name, nl + 1);
+		}
+#else
+		s[ni] = '/';
+		mmv(s + ni + 1, name, nl + 1);
+#endif
+		incdir = i;
+#ifdef UCPP_MMAP
+		f = fopen_mmap_file(s);
+#else
+		f = fopen(s, "r");
+#endif
+		if (f) goto found_file;
+		freemem(s);
+	}
+	return 0;
+found_file:
+	if (f && ((emit_dependencies == 1 && lf)
+		|| emit_dependencies == 2)) {
+		fprintf(emit_output, " %s", s ? s : name);
+	}
+	if (!ff) {
+		struct found_file *nff = protect_detect.ff;
+
+		nff->name = sdup(name);
+		nff->long_name = s ? s : sdup(name);
+		nff->incdir = incdir;
+#if 0
+		putHT(lf ? found_files_loc : found_files, nff);
+#endif
+		s = 0;
+		find_file_error = FF_UNKNOWN;
+		ff = nff;
+	} else find_file_error = FF_KNOWN;
+found_file_2:
+	if (s) freemem(s);
+	current_long_filename = ff->long_name;
+#ifdef NO_LIBC_BUF
+	setbuf(f, 0);
+#endif
+	current_incdir = ff->incdir;
+	return f;
+}
+
+/*
+ * Find the named file by looking through the end of the include path.
+ * This one is not as optimized as find_file() since it is rarely used.
+ */
+static FILE *find_file_next(char *name)
+{
+	int i;
+	size_t nl = strlen(name);
+	FILE *f;
+
+	for (i = current_incdir + 1; i < include_path_nb; i ++) {
+		char *s;
+		size_t ni = strlen(include_path[i]);
+
+		s = getmem(ni + nl + 2);
+		mmv(s, include_path[i], ni);
+#ifdef AMIGA
+		/* contributed by Volker Barthelmann */
+		if (ni > 0 && s[ni - 1] != ':' && s[ni - 1] != '/') {
+			s[ni] = '/';
+			mmv(s + ni + 1, name, nl + 1);
+		} else {
+			mmv(s + ni, name, nl + 1);
+		}
+#else
+		s[ni] = '/';
+		mmv(s + ni + 1, name, nl + 1);
+#endif
+
+#ifdef UCPP_MMAP
+		f = fopen_mmap_file(s);
+#else
+		f = fopen(s, "r");
+#endif
+		if (f) {
+			if (emit_dependencies == 2) {
+				fprintf(emit_output, " %s", s ? s : name);
+			}
+			current_long_filename = s;
+			current_incdir = i;
+			return f;
+		}
+		freemem(s);
+	}
+	return 0;
+}
+
+/*
+ * The #if directive. This function parse the expression, performs macro
+ * expansion (and handles the "defined" operator), and call eval_expr.
+ * return value: 1 if the expression is true, 0 if it is false, -1 on error.
+ */
+static int handle_if(struct lexer_state *ls)
+{
+	struct token_fifo tf, tf1, tf2, tf3, *save_tf;
+	long l = ls->line;
+	unsigned long z;
+	int ret = 0, ltww = 1;
+
+	/* first, get the whole line */
+	tf.art = tf.nt = 0;
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		struct token t;
+
+		if (ltww && ttMWS(ls->ctok->type)) continue;
+		ltww = ttMWS(ls->ctok->type);
+		t.type = ls->ctok->type;
+		t.line = l;
+		if (S_TOKEN(ls->ctok->type)) {
+			t.name = sdup(ls->ctok->name);
+			throw_away(ls->gf, t.name);
+		}
+		aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+	}
+	if (ltww && tf.nt) if ((-- tf.nt) == 0) freemem(tf.t);
+	if (tf.nt == 0) {
+		error(l, "void condition for a #if/#elif");
+		return -1;
+	}
+	/* handle the "defined" operator */
+	tf1.art = tf1.nt = 0;
+	while (tf.art < tf.nt) {
+		struct token *ct, rt;
+		struct macro *m;
+		size_t nidx, eidx;
+
+		ct = tf.t + (tf.art ++);
+		if (ct->type == NAME && !strcmp(ct->name, "defined")) {
+			if (tf.art >= tf.nt) goto store_token;
+			nidx = tf.art;
+			if (ttMWS(tf.t[nidx].type))
+			  if (++ nidx >= tf.nt) goto store_token;
+			if (tf.t[nidx].type == NAME) {
+				eidx = nidx;
+				goto check_macro;
+			}
+			if (tf.t[nidx].type != LPAR) {
+#ifdef HAVE_MISRA
+				misra_neu(100,19,14,0);
+#endif
+				goto store_token;}
+			if (++ nidx >= tf.nt) goto store_token;
+			if (ttMWS(tf.t[nidx].type))
+				if (++ nidx >= tf.nt) goto store_token;
+			if (tf.t[nidx].type != NAME) {
+#ifdef HAVE_MISRA
+				misra_neu(100,19,14,0);
+#endif
+				goto store_token;}
+			eidx = nidx + 1;
+			if (eidx >= tf.nt) goto store_token;
+			if (ttMWS(tf.t[eidx].type))
+				if (++ eidx >= tf.nt) goto store_token;
+			if (tf.t[eidx].type != RPAR) goto store_token;
+			goto check_macro;
+		}
+	store_token:
+		aol(tf1.t, tf1.nt, *ct, TOKEN_LIST_MEMG);
+		continue;
+
+	check_macro:
+		m = get_macro(tf.t[nidx].name);
+		rt.type = NUMBER;
+		rt.name = m ? "1L" : "0L";
+		aol(tf1.t, tf1.nt, rt, TOKEN_LIST_MEMG);
+		tf.art = eidx + 1;
+	}
+	freemem(tf.t);
+	if (tf1.nt == 0) {
+		error(l, "void condition (after expansion) for a #if/#elif");
+		return -1;
+	}
+
+	/* perform all macro substitutions */
+	tf2.art = tf2.nt = 0;
+	save_tf = ls->output_fifo;
+	ls->output_fifo = &tf2;
+	while (tf1.art < tf1.nt) {
+		struct token *ct;
+
+		ct = tf1.t + (tf1.art ++);
+		if (ct->type == NAME) {
+			struct macro *m = get_macro(ct->name);
+
+			if (m) {
+				if (substitute_macro(ls, m, &tf1, 0,
+#ifdef NO_PRAGMA_IN_DIRECTIVE
+					1,
+#else
+					0,
+#endif
+					ct->line)) {
+					ls->output_fifo = save_tf;
+					return -1;
+				}
+				continue;
+			}
+		} else if ((ct->type == SHARP || ct->type == DIG_SHARP)
+			&& (ls->flags & HANDLE_ASSERTIONS)) {
+			/* we have an assertion; parse it */
+			int nnp, ltww = 1;
+			size_t i = tf1.art;
+			struct token_fifo atl;
+			char *aname;
+			struct assert *a;
+			int av = 0;
+			struct token rt;
+
+			atl.art = atl.nt = 0;
+			while (i < tf1.nt && ttMWS(tf1.t[i].type)) i ++;
+			if (i >= tf1.nt) goto assert_error;
+			if (tf1.t[i].type != NAME) goto assert_error;
+			aname = tf1.t[i ++].name;
+			while (i < tf1.nt && ttMWS(tf1.t[i].type)) i ++;
+			if (i >= tf1.nt) goto assert_generic;
+			if (tf1.t[i].type != LPAR) goto assert_generic;
+			i ++;
+			for (nnp = 1; nnp && i < tf1.nt; i ++) {
+				if (ltww && ttMWS(tf1.t[i].type)) continue;
+				if (tf1.t[i].type == LPAR) nnp ++;
+				else if (tf1.t[i].type == RPAR
+					&& (-- nnp) == 0) {
+					tf1.art = i + 1;
+					break;
+				}
+				ltww = ttMWS(tf1.t[i].type);
+				aol(atl.t, atl.nt, tf1.t[i], TOKEN_LIST_MEMG);
+			}
+			if (nnp) goto assert_error;
+			if (ltww && atl.nt && (-- atl.nt) == 0) freemem(atl.t);
+			if (atl.nt == 0) goto assert_error;
+
+			/* the assertion is in aname and atl; check it */
+			a = get_assertion(aname);
+			if (a) for (i = 0; i < a->nbval; i ++)
+				if (!cmp_token_list(&atl, a->val + i)) {
+					av = 1;
+					break;
+				}
+			rt.type = NUMBER;
+			rt.name = av ? "1" : "0";
+			aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG);
+			continue;
+
+		assert_generic:
+			tf1.art = i;
+			rt.type = NUMBER;
+			rt.name = get_assertion(aname) ? "1" : "0";
+			aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG);
+			continue;
+
+		assert_error:
+			error(l, "syntax error for assertion in #if");
+			ls->output_fifo = save_tf;
+			return -1;
+		}
+		aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
+	}
+	ls->output_fifo = save_tf;
+	freemem(tf1.t);
+	if (tf2.nt == 0) {
+		error(l, "void condition (after expansion) for a #if/#elif");
+		return -1;
+	}
+
+	/*
+	 * suppress whitespace and replace rogue identifiers by 0
+	 */
+	tf3.art = tf3.nt = 0;
+	while (tf2.art < tf2.nt) {
+		struct token *ct = tf2.t + (tf2.art ++);
+
+		if (ttMWS(ct->type)) continue;
+		if (ct->type == NAME) {
+			/*
+			 * a rogue identifier; we replace it with "0".
+			 */
+			struct token rt;
+#ifdef HAVE_MISRA
+			misra_neu(97,19,11,0);
+#endif
+
+			rt.type = NUMBER;
+			rt.name = "0";
+			aol(tf3.t, tf3.nt, rt, TOKEN_LIST_MEMG);
+			continue;
+		}
+		aol(tf3.t, tf3.nt, *ct, TOKEN_LIST_MEMG);
+	}
+	freemem(tf2.t);
+
+	if (tf3.nt == 0) {
+		error(l, "void condition (after expansion) for a #if/#elif");
+		return -1;
+	}
+	eval_line = l;
+	z = eval_expr(&tf3, &ret, (ls->flags & WARN_STANDARD) != 0);
+	freemem(tf3.t);
+	if (ret) return -1;
+	return (z != 0);
+}
+
+/*
+ * A #include was found; parse the end of line, replace macros if
+ * necessary.
+ *
+ * If nex is set to non-zero, the directive is considered as a #include_next
+ * (extension to C99)
+ */
+static int handle_include(struct lexer_state *ls, unsigned long flags, int nex)
+{
+	int c, string_fname = 0;
+	char *fname;
+	size_t fname_ptr = 0;
+	long l = ls->line;
+	int x, y;
+	FILE *f;
+	struct token_fifo tf, tf2, *save_tf;
+	size_t nl;
+	int tgd;
+
+#define left_angle(t)	((t) == LT || (t) == LEQ || (t) == LSH \
+			|| (t) == ASLSH || (t) == DIG_LBRK || (t) == LBRA)
+#define right_angle(t)	((t) == GT || (t) == RSH || (t) == ARROW \
+			|| (t) == DIG_RBRK || (t) == DIG_RBRA)
+
+#ifdef HAVE_MISRA
+	extern int misracheck,misratok;
+
+	if(misracheck&&misratok) misra_neu(87,19,1,0);
+#endif
+	tf.t=0; /*vb*/
+	while ((c = grap_char(ls)) >= 0 && c != '\n') {
+		if (space_char(c)) {
+			discard_char(ls);
+			continue;
+		}
+		if (c == '<') {
+			discard_char(ls);
+			while ((c = grap_char(ls)) >= 0) {
+				discard_char(ls);
+				if (c == '\n') goto include_error;
+				if (c == '>') break;
+				aol(fname, fname_ptr, (char)c, FNAME_MEMG);
+			}
+			aol(fname, fname_ptr, (char)0, FNAME_MEMG);
+			string_fname = 0;
+			goto do_include;
+		} else if (c == '"') {
+			discard_char(ls);
+			while ((c = grap_char(ls)) >= 0) {
+				discard_char(ls);
+				if (c == '\n') goto include_error;
+				if (c == '"') break;
+				aol(fname, fname_ptr, (char)c, FNAME_MEMG);
+			}
+			aol(fname, fname_ptr, (char)0, FNAME_MEMG);
+			string_fname = 1;
+			goto do_include;
+		}
+		goto include_macro;
+	}
+
+include_error:
+	error(l, "invalid '#include'");
+	return 1;
+
+include_macro:
+#ifdef HAVE_MISRA
+	misra(90);
+#endif
+	tf.art = tf.nt = 0;
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		if (!ttMWS(ls->ctok->type)) {
+			struct token t;
+
+			t.type = ls->ctok->type;
+			t.line = l;
+			if (S_TOKEN(ls->ctok->type)) {
+				t.name = sdup(ls->ctok->name);
+				throw_away(ls->gf, t.name);
+			}
+			aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+		}
+	}
+	tf2.art = tf2.nt = 0;
+	save_tf = ls->output_fifo;
+	ls->output_fifo = &tf2;
+	while (tf.art < tf.nt) {
+		struct token *ct;
+
+		ct = tf.t + (tf.art ++);
+		if (ct->type == NAME) {
+			struct macro *m = get_macro(ct->name);
+			if (m) {
+				if (substitute_macro(ls, m, &tf, 0,
+#ifdef NO_PRAGMA_IN_DIRECTIVE
+					1,
+#else
+					0,
+#endif
+					ct->line)) {
+					ls->output_fifo = save_tf;
+					return -1;
+				}
+				continue;
+			}
+		}
+		aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
+	}
+	freemem(tf.t);
+	ls->output_fifo = save_tf;
+	for (x = 0; x < tf2.nt && ttWHI(tf2.t[x].type); x ++);
+	for (y = tf2.nt - 1; y >= 0 && ttWHI(tf2.t[y].type); y --);
+	if (x >= tf2.nt) goto include_macro_err;
+	if (tf2.t[x].type == STRING) {
+		if (y != x) goto include_macro_err;
+		if (tf2.t[x].name[0] == 'L') {
+			if (ls->flags & WARN_STANDARD)
+				warning(l, "wide string for #include");
+			fname = sdup(tf2.t[x].name);
+			nl = strlen(fname);
+			*(fname + nl - 1) = 0;
+			mmvwo(fname, fname + 2, nl - 2);
+		} else {
+			fname = sdup(tf2.t[x].name);
+			nl = strlen(fname);
+			*(fname + nl - 1) = 0;
+			mmvwo(fname, fname + 1, nl - 1);
+		}
+		string_fname = 1;
+	} else if (left_angle(tf2.t[x].type) && right_angle(tf2.t[y].type)) {
+		int i, j;
+
+		if (ls->flags & WARN_ANNOYING) warning(l, "reconstruction "
+			"of <foo> in #include");
+		for (j = 0, i = x; i <= y; i ++) if (!ttWHI(tf2.t[i].type))
+			j += strlen(tname(tf2.t[i]));
+		fname = getmem(j + 1);
+		for (j = 0, i = x; i <= y; i ++) {
+			if (ttWHI(tf2.t[i].type)) continue;
+			strcpy(fname + j, tname(tf2.t[i]));
+			j += strlen(tname(tf2.t[i]));
+		}
+		*(fname + j - 1) = 0;
+		mmvwo(fname, fname + 1, j);
+		string_fname = 0;
+	} else goto include_macro_err;
+	freemem(tf2.t);
+	goto do_include_next;
+
+include_macro_err:
+	error(l, "macro expansion did not produce a valid filename "
+		"for #include");
+	if (tf2.nt) freemem(tf2.t);
+	return 1;
+
+do_include:
+	tgd = 1;
+	while (!next_token(ls)) {
+		if (tgd && !ttWHI(ls->ctok->type)
+			&& (ls->flags & WARN_STANDARD)) {
+			warning(l, "trailing garbage in #include");
+			tgd = 0;
+		}
+		if (ls->ctok->type == NEWLINE) break;
+	}
+
+	/* the increment of ls->line is intended so that the line
+	   numbering is reported correctly in report_context() even if
+	   the #include is at the end of the line with no trailing newline */
+	if (ls->ctok->type != NEWLINE) ls->line ++;
+do_include_next:
+	if (!(ls->flags & LEXER) && (ls->flags & KEEP_OUTPUT))
+		put_char(ls, '\n');
+	push_file_context(ls);
+	reinit_lexer_state(ls, 1);
+#ifdef HAVE_MISRA
+	if(misracheck){
+	  char *p;
+	  for(p=fname;*p;p++)
+	    if(*p=='\''||*p=='\\'||*p=='\"'||(*p=='/'&&p[1]=='*'))
+	      misra_neu(88,19,2,-1);
+	}
+#endif
+	{
+		char *conv_fname = convert_path(fname);
+		freemem(fname);
+		fname = conv_fname;
+	}
+	f = nex ? find_file_next(fname) : find_file(fname, string_fname);
+	if (!f) {
+		pop_file_context(ls);
+		if (find_file_error == FF_ERROR) {
+			error(l, "file '%s' not found", fname);
+			return 1;
+		}
+		/* file was found, but it is useless to include it again */
+		return 0;
+	}
+#ifdef UCPP_MMAP
+	set_input_file(ls, f);
+#else
+	ls->input = f;
+#endif
+#ifdef HAVE_MISRA
+	if (!strcmp("signal.h",fname)) misra_neu(123,20,8,-1);
+	if (!strcmp("stdio.h",fname)) misra_neu(124,20,9,-1);
+	if (!strcmp("time.h",fname)) misra(127,20,12,-1);
+#endif
+	set_current_filename(fname);
+	handle_deps(current_long_filename,string_fname);
+	enter_file(ls, flags);
+	return 0;
+
+#undef left_angle
+#undef right_angle
+}
+
+/*
+ * for #line directives
+ */
+static int handle_line(struct lexer_state *ls, unsigned long flags)
+{
+	char *fname;
+	long l = ls->line;
+	struct token_fifo tf, tf2, *save_tf;
+	size_t nl, j;
+	unsigned long z;
+
+	tf.art = tf.nt = 0;
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		if (!ttMWS(ls->ctok->type)) {
+			struct token t;
+
+			t.type = ls->ctok->type;
+			t.line = l;
+			if (S_TOKEN(ls->ctok->type)) {
+				t.name = sdup(ls->ctok->name);
+				throw_away(ls->gf, t.name);
+			}
+			aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+		}
+	}
+	tf2.art = tf2.nt = 0;
+	save_tf = ls->output_fifo;
+	ls->output_fifo = &tf2;
+	while (tf.art < tf.nt) {
+		struct token *ct;
+
+		ct = tf.t + (tf.art ++);
+		if (ct->type == NAME) {
+			struct macro *m = get_macro(ct->name);
+			if (m) {
+				if (substitute_macro(ls, m, &tf, 0,
+#ifdef NO_PRAGMA_IN_DIRECTIVE
+					1,
+#else
+					0,
+#endif
+					ct->line)) {
+					ls->output_fifo = save_tf;
+					return -1;
+				}
+				continue;
+			}
+		}
+		aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
+	}
+	freemem(tf.t);
+	for (tf2.art = 0; tf2.art < tf2.nt && ttWHI(tf2.t[tf2.art].type);
+		tf2.art ++);
+	ls->output_fifo = save_tf;
+	if (tf2.art == tf2.nt || (tf2.t[tf2.art].type != NUMBER
+		&& tf2.t[tf2.art].type != CHAR)) {
+		error(l, "not a valid number for #line");
+		goto line_macro_err;
+	}
+	for (j = 0; tf2.t[tf2.art].name[j]; j ++)
+		if (tf2.t[tf2.art].name[j] < '0'
+			|| tf2.t[tf2.art].name[j] > '9')
+			if (ls->flags & WARN_STANDARD)
+				warning(l, "non-standard line number in #line");
+	if (catch(eval_exception)) goto line_macro_err;
+	z = strtoconst(tf2.t[tf2.art].name);
+	if (j > 10 || z > 2147483647U) {
+		error(l, "out-of-bound line number for #line");
+		goto line_macro_err;
+	}
+	ls->oline = ls->line = z;
+	if ((++ tf2.art) < tf2.nt) {
+		int i;
+
+		for (i = tf2.art; i < tf2.nt && ttMWS(tf2.t[i].type); i ++);
+		if (i < tf2.nt) {
+			if (tf2.t[i].type != STRING) {
+				error(l, "not a valid filename for #line");
+				goto line_macro_err;
+			}
+			if (tf2.t[i].name[0] == 'L') {
+				if (ls->flags & WARN_STANDARD) {
+					warning(l, "wide string for #line");
+				}
+				fname = sdup(tf2.t[i].name);
+				nl = strlen(fname);
+				*(fname + nl - 1) = 0;
+				mmvwo(fname, fname + 2, nl - 2);
+			} else {
+				fname = sdup(tf2.t[i].name);
+				nl = strlen(fname);
+				*(fname + nl - 1) = 0;
+				mmvwo(fname, fname + 1, nl - 1);
+			}
+			set_current_filename(fname);
+		}
+		for (i ++; i < tf2.nt && ttMWS(tf2.t[i].type); i ++);
+		if (i < tf2.nt && (ls->flags & WARN_STANDARD)) {
+			warning(l, "trailing garbage in #line");
+		}
+	}
+	freemem(tf2.t);
+	enter_file(ls, flags);
+	return 0;
+
+line_macro_err:
+	if (tf2.nt) freemem(tf2.t);
+	return 1;
+}
+
+/*
+ * a #error or #warning directive: we emit the message without any
+ * modification (except the usual backslash+newline and trigraphs)
+ */
+static void handle_error(struct lexer_state *ls,int warnflag)
+{
+	int c;
+	size_t p = 0, lp = 128;
+	long l = ls->line;
+	unsigned char *buf = getmem(lp);
+
+	while ((c = grap_char(ls)) >= 0 && c != '\n') {
+		discard_char(ls);
+		wan(buf, p, (unsigned char)c, lp);
+	}
+	wan(buf, p, 0, lp);
+	if (warnflag)
+		warning(l, "#warning%s", buf);
+	else
+		error(l, "#error%s", buf);
+	freemem(buf);
+}
+
+/*
+ * convert digraph tokens to their standard equivalent.
+ */
+static int undig(int type)
+{
+	static int ud[6] = { LBRK, RBRK, LBRA, RBRA, SHARP, DSHARP };
+
+	return ud[type - DIG_LBRK];
+}
+
+#ifdef PRAGMA_TOKENIZE
+/*
+ * Make a compressed representation of a token list; the contents of
+ * the token_fifo are freed. Values equal to 0 are replaced by
+ * PRAGMA_TOKEN_END (by default, (unsigned char)'\n') and the compressed
+ * string is padded by a 0 (so that it may be * handled like a string).
+ * Digraph tokens are replaced by their non-digraph equivalents.
+ */
+struct comp_token_fifo compress_token_list(struct token_fifo *tf)
+{
+	struct comp_token_fifo ct;
+	size_t l;
+
+	for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
+		l ++;
+		if (S_TOKEN(tf->t[tf->art].type))
+			l += strlen(tf->t[tf->art].name) + 1;
+	}
+	ct.t = getmem((ct.length = l) + 1);
+	for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
+		int tt = tf->t[tf->art].type;
+
+		if (tt == 0) tt = PRAGMA_TOKEN_END;
+		if (tt > DIGRAPH_TOKENS && tt < DIGRAPH_TOKENS_END)
+			tt = undig(tt);
+		ct.t[l ++] = tt;
+		if (S_TOKEN(tt)) {
+			char *tn = tf->t[tf->art].name;
+			size_t sl = strlen(tn);
+
+			mmv(ct.t + l, tn, sl);
+			l += sl;
+			ct.t[l ++] = PRAGMA_TOKEN_END;
+			freemem(tn);
+		}
+	}
+	ct.t[l] = 0;
+	if (tf->nt) freemem(tf->t);
+	ct.rp = 0;
+	return ct;
+}
+#endif
+
+/*
+ * A #pragma directive: we make a PRAGMA token containing the rest of
+ * the line.
+ *
+ * We strongly hope that we are called only in LEXER mode.
+ */
+static void handle_pragma(struct lexer_state *ls)
+{
+	unsigned char *buf;
+	struct token t;
+	long l = ls->line;
+
+#ifdef PRAGMA_TOKENIZE
+	struct token_fifo tf;
+
+	tf.art = tf.nt = 0;
+	while (!next_token(ls) && ls->ctok->type != NEWLINE)
+		if (!ttMWS(ls->ctok->type)) break;
+	if (ls->ctok->type != NEWLINE) {
+		do {
+			struct token t;
+
+			t.type = ls->ctok->type;
+			if (ttMWS(t.type)) continue;
+			if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+			aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+		} while (!next_token(ls) && ls->ctok->type != NEWLINE);
+	}
+	if (tf.nt == 0) {
+		/* void pragma are silently ignored */
+		return;
+	}
+	buf = (compress_token_list(&tf)).t;
+#else
+	int c, x = 1, y = 32;
+
+	while ((c = grap_char(ls)) >= 0 && c != '\n') {
+		discard_char(ls);
+		if (!space_char(c)) break;
+	}
+	/* void #pragma are ignored */
+	if (c == '\n') return;
+	buf = getmem(y);
+	buf[0] = c;
+	while ((c = grap_char(ls)) >= 0 && c != '\n') {
+		discard_char(ls);
+		wan(buf, x, c, y);
+	}
+	for (x --; x >= 0 && space_char(buf[x]); x --);
+	x ++;
+	wan(buf, x, 0, y);
+#endif
+	t.type = PRAGMA;
+	t.line = l;
+	t.name = (char *)buf;
+	aol(ls->output_fifo->t, ls->output_fifo->nt, t, TOKEN_LIST_MEMG);
+	throw_away(ls->gf, (char *)buf);
+}
+
+/*
+ * We saw a # at the beginning of a line (or preceeded only by whitespace).
+ * We check the directive name and act accordingly.
+ */
+static int handle_cpp(struct lexer_state *ls, int sharp_type)
+{
+#define condfset(x)	do { \
+		ls->condf[(x) / 32] |= 1UL << ((x) % 32); \
+	} while (0)
+#define condfclr(x)	do { \
+		ls->condf[(x) / 32] &= ~(1UL << ((x) % 32)); \
+	} while (0)
+#define condfval(x)	((ls->condf[(x) / 32] & (1UL << ((x) % 32))) != 0)
+
+	long l = ls->line;
+	unsigned long save_flags = ls->flags;
+	int ret = 0;
+
+	save_flags = ls->flags;
+	ls->flags |= LEXER;
+	while (!next_token(ls)) {
+		int t = ls->ctok->type;
+
+		switch (t) {
+		case COMMENT:
+			if (ls->flags & WARN_ANNOYING) {
+				warning(l, "comment in the middle of "
+					"a cpp directive");
+			}
+			/* fall through */
+		case NONE:
+			continue;
+		case NEWLINE:
+			/* null directive */
+			if (ls->flags & WARN_ANNOYING) {
+				/* truly an annoying warning; null directives
+				   are rare but may increase readability of
+				   some source files, and they are legal */
+				warning(l, "null cpp directive");
+			}
+			if (!(ls->flags & LEXER)) put_char(ls, '\n');
+			goto handle_exit2;
+		case NAME:
+			break;
+		default:
+			if (ls->flags & FAIL_SHARP) {
+				if (ls->condcomp) {
+					error(l, "rogue '#'");
+					ret = 1;
+				} else {
+					if (ls->flags & WARN_STANDARD) {
+						warning(l, "rogue '#' in code "
+							"compiled out");
+						ret = 0;
+					}
+				}
+				ls->flags = save_flags;
+				goto handle_warp_ign;
+			} else {
+				struct token u;
+
+				u.type = sharp_type;
+				u.line = l;
+				ls->flags = save_flags;
+				print_token(ls, &u, 0);
+				print_token(ls, ls->ctok, 0);
+				if (ls->flags & WARN_ANNOYING) {
+					warning(l, "rogue '#' dumped");
+				}
+				goto handle_exit3;
+			}
+		}
+		if (ls->condcomp) {
+			if (!strcmp(ls->ctok->name, "define")) {
+				ret = handle_define(ls);
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "undef")) {
+				ret = handle_undef(ls);
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "if")) {
+				if ((++ ls->ifnest) > 63) goto too_many_if;
+				condfclr(ls->ifnest - 1);
+				ret = handle_if(ls);
+				if (ret > 0) ret = 0;
+				else if (ret == 0) {
+					ls->condcomp = 0;
+					ls->condmet = 0;
+					ls->condnest = ls->ifnest - 1;
+				}
+				else ret = 1;
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "ifdef")) {
+				if ((++ ls->ifnest) > 63) goto too_many_if;
+				condfclr(ls->ifnest - 1);
+
+				ret = handle_ifdef(ls);
+				if (ret > 0) ret = 0;
+				else if (ret == 0) {
+					ls->condcomp = 0;
+					ls->condmet = 0;
+					ls->condnest = ls->ifnest - 1;
+				}
+				else ret = 1;
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "ifndef")) {
+				if ((++ ls->ifnest) > 63) goto too_many_if;
+				condfclr(ls->ifnest - 1);
+				ret = handle_ifndef(ls);
+				if (ret > 0) ret = 0;
+				else if (ret == 0) {
+					ls->condcomp = 0;
+					ls->condmet = 0;
+					ls->condnest = ls->ifnest - 1;
+				}
+				else ret = 1;
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "else")) {
+				if (ls->ifnest == 0
+					|| condfval(ls->ifnest - 1)) {
+					error(l, "rogue #else");
+					ret = 1;
+					goto handle_warp;
+				}
+				condfset(ls->ifnest - 1);
+				if (ls->ifnest == 1) protect_detect.state = 0;
+				ls->condcomp = 0;
+				ls->condmet = 1;
+				ls->condnest = ls->ifnest - 1;
+				goto handle_warp;
+			} else if (!strcmp(ls->ctok->name, "elif")) {
+				if (ls->ifnest == 0
+					|| condfval(ls->ifnest - 1)) {
+					error(l, "rogue #elif");
+					ret = 1;
+					goto handle_warp_ign;
+				}
+				if (ls->ifnest == 1) protect_detect.state = 0;
+				ls->condcomp = 0;
+				ls->condmet = 1;
+				ls->condnest = ls->ifnest - 1;
+				goto handle_warp_ign;
+			} else if (!strcmp(ls->ctok->name, "endif")) {
+				if (ls->ifnest == 0) {
+					error(l, "unmatched #endif");
+					ret = 1;
+					goto handle_warp;
+				}
+				if ((-- ls->ifnest) == 0
+					&& protect_detect.state == 2) {
+					protect_detect.state = 3;
+				}
+				goto handle_warp;
+			} else if (!strcmp(ls->ctok->name, "include")) {
+				ret = handle_include(ls, save_flags, 0);
+				goto handle_exit3;
+			} else if (!strcmp(ls->ctok->name, "include_next")) {
+				ret = handle_include(ls, save_flags, 1);
+				goto handle_exit3;
+			} else if (!strcmp(ls->ctok->name, "pragma")) {
+				if (!(save_flags & LEXER)) {
+#ifdef PRAGMA_DUMP
+					/* dump #pragma in output */
+					struct token u;
+
+					u.type = sharp_type;
+					u.line = l;
+					ls->flags = save_flags;
+					print_token(ls, &u, 0);
+					print_token(ls, ls->ctok, 0);
+					while (ls->flags |= LEXER,
+						!next_token(ls)) {
+						long save_line;
+
+						ls->flags &= ~LEXER;
+						save_line = ls->line;
+						ls->line = l;
+						print_token(ls, ls->ctok, 0);
+						ls->line = save_line;
+						if (ls->ctok->type == NEWLINE)
+							break;
+					}
+					goto handle_exit3;
+#else
+					if (ls->flags & WARN_PRAGMA)
+						warning(l, "#pragma ignored "
+							"and not dumped");
+					goto handle_warp_ign;
+#endif
+				}
+				if (!(ls->flags & HANDLE_PRAGMA))
+					goto handle_warp_ign;
+				handle_pragma(ls);
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "error")) {
+				ret = 1;
+				handle_error(ls,0);
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "warning")) {
+				ret = 0;
+				handle_error(ls,1);
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "line")) {
+				ret = handle_line(ls, save_flags);
+				goto handle_exit;
+			} else if ((ls->flags & HANDLE_ASSERTIONS)
+				&& !strcmp(ls->ctok->name, "assert")) {
+				ret = handle_assert(ls);
+				goto handle_exit;
+			} else if ((ls->flags & HANDLE_ASSERTIONS)
+				&& !strcmp(ls->ctok->name, "unassert")) {
+				ret = handle_unassert(ls);
+				goto handle_exit;
+			}
+		} else {
+			if (!strcmp(ls->ctok->name, "else")) {
+				if (condfval(ls->ifnest - 1)
+					&& (ls->flags & WARN_STANDARD)) {
+					warning(l, "rogue #else in code "
+						"compiled out");
+				}
+				if (ls->condnest == ls->ifnest - 1) {
+					if (!ls->condmet) ls->condcomp = 1;
+				}
+				condfset(ls->ifnest - 1);
+				if (ls->ifnest == 1) protect_detect.state = 0;
+				goto handle_warp;
+			} else if (!strcmp(ls->ctok->name, "elif")) {
+				if (condfval(ls->ifnest - 1)
+					&& (ls->flags & WARN_STANDARD)) {
+					warning(l, "rogue #elif in code "
+						"compiled out");
+				}
+				if (ls->condnest != ls->ifnest - 1
+					|| ls->condmet)
+					goto handle_warp_ign;
+				if (ls->ifnest == 1) protect_detect.state = 0;
+				ret = handle_if(ls);
+				if (ret > 0) {
+					ls->condcomp = 1;
+					ls->condmet = 1;
+					ret = 0;
+				} else if (ret < 0) ret = 1;
+				goto handle_exit;
+			} else if (!strcmp(ls->ctok->name, "endif")) {
+				if ((-- ls->ifnest) == ls->condnest) {
+					if (ls->ifnest == 0 &&
+						protect_detect.state == 2)
+						protect_detect.state = 3;
+					ls->condcomp = 1;
+				}
+				goto handle_warp;
+			} else if (!strcmp(ls->ctok->name, "if")
+				|| !strcmp(ls->ctok->name, "ifdef")
+				|| !strcmp(ls->ctok->name, "ifndef")) {
+				if ((++ ls->ifnest) > 63) goto too_many_if;
+				condfclr(ls->ifnest - 1);
+			}
+			goto handle_warp_ign;
+		}
+		/*
+		 * Unrecognized directive. We emit either an error or
+		 * an annoying warning, depending on a command-line switch.
+		 */
+		if (ls->flags & FAIL_SHARP) {
+			error(l, "unknown cpp directive '#%s'",
+				ls->ctok->name);
+			goto handle_warp_ign;
+		} else {
+			struct token u;
+
+			u.type = sharp_type;
+			u.line = l;
+			ls->flags = save_flags;
+			print_token(ls, &u, 0);
+			print_token(ls, ls->ctok, 0);
+			if (ls->flags & WARN_ANNOYING) {
+				warning(l, "rogue '#' dumped");
+			}
+		}
+	}
+	return 1;
+
+handle_warp_ign:
+	while (!next_token(ls)) if (ls->ctok->type == NEWLINE) break;
+	goto handle_exit;
+handle_warp:
+	while (!next_token(ls)) {
+		if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
+			warning(l, "trailing garbage in "
+				"preprocessing directive");
+		}
+		if (ls->ctok->type == NEWLINE) break;
+	}
+handle_exit:
+	if (!(ls->flags & LEXER)) put_char(ls, '\n');
+handle_exit3:
+	if (protect_detect.state == 1) {
+		protect_detect.state = 0;
+	} else if (protect_detect.state == -1) {
+		/* just after the #include */
+		protect_detect.state = 1;
+	}
+handle_exit2:
+	ls->flags = save_flags;
+	return ret;
+too_many_if:
+	error(l, "too many levels of conditional inclusion (max 63)");
+	ret = 1;
+	goto handle_warp;
+#undef condfset
+#undef condfclr
+#undef condfval
+}
+
+/*
+ * This is the main entry function. It maintains count of #, and call the
+ * appropriate functions when it encounters a cpp directive or a macro
+ * name.
+ * return value: positive on error; CPPERR_EOF means "end of input reached"
+ */
+int cpp(struct lexer_state *ls)
+{
+	int r = 0;
+
+	while (next_token(ls)) {
+		if (protect_detect.state == 3) {
+			/* Cool ! A protection mechanism has been detected */
+			protect_detect.ff->protect = protect_detect.macro;
+			protect_detect.macro = 0;
+		}
+		if (ls->ifnest) {
+			error(ls->line, "unterminated #if construction "
+				"(depth %ld)", (long)ls->ifnest);
+			r = CPPERR_NEST;
+		}
+		if (ls_depth == 0) return CPPERR_EOF;
+		fclose(ls->input);
+		freemem(current_filename);
+		pop_file_context(ls);
+		if (!(ls->flags & LEXER) && !ls->ltwnl) put_char(ls, '\n');
+		enter_file(ls, ls->flags);
+	}
+	if (!(ls->ltwnl && (ls->ctok->type == SHARP
+		|| ls->ctok->type == DIG_SHARP))
+		&& protect_detect.state == 1 && !ttWHI(ls->ctok->type)) {
+		/* the first non-whitespace token encountered is not
+		   a sharp introducing a cpp directive */
+		protect_detect.state = 0;
+	}
+	if (protect_detect.state == 3 && !ttWHI(ls->ctok->type)) {
+		/* a non-whitespace token encountered after the #endif */
+		protect_detect.state = 0;
+	}
+	if (ls->condcomp) {
+		if (ls->ltwnl && (ls->ctok->type == SHARP
+			|| ls->ctok->type == DIG_SHARP)) {
+			int x = handle_cpp(ls, ls->ctok->type);
+
+			ls->ltwnl = 1;
+			return r ? r : x;
+		}
+		if (ls->ctok->type == NAME) {
+			struct macro *m;
+
+			if ((m = get_macro(ls->ctok->name)) != 0) {
+				int x;
+
+				x = substitute_macro(ls, m, 0, 1, 0,
+					ls->ctok->line);
+				if (!(ls->flags & LEXER))
+					garbage_collect(ls->gf);
+				return r ? r : x;
+			}
+			if (!(ls->flags & LEXER))
+				print_token(ls, ls->ctok, 0);
+		}
+	} else {
+		if (ls->ltwnl && (ls->ctok->type == SHARP
+			|| ls->ctok->type == DIG_SHARP)) {
+			int x = handle_cpp(ls, ls->ctok->type);
+
+			ls->ltwnl = 1;
+			return r ? r : x;
+		}
+	}
+	if (ls->ctok->type == NEWLINE) ls->ltwnl = 1;
+	else if (!ttWHI(ls->ctok->type)) ls->ltwnl = 0;
+	return r ? r : -1;
+}
+
+#ifndef STAND_ALONE
+/*
+ * llex() and lex() are the lexing functions, when the preprocessor is
+ * linked to another code. llex() should be called only by lex().
+ */
+static int llex(struct lexer_state *ls)
+{
+	struct token_fifo *tf = ls->output_fifo;
+	int r;
+
+	if (tf->nt != 0) {
+		if (tf->art < tf->nt) {
+#ifdef INMACRO_FLAG
+			if (!ls->inmacro) {
+				ls->inmacro = 1;
+				ls->macro_count ++;
+			}
+#endif
+			ls->ctok = tf->t + (tf->art ++);
+			if (ls->ctok->type > DIGRAPH_TOKENS
+				&& ls->ctok->type < DIGRAPH_TOKENS_END) {
+				ls->ctok->type = undig(ls->ctok->type);
+			}
+			return 0;
+		} else {
+#ifdef INMACRO_FLAG
+			ls->inmacro = 0;
+#endif
+			if (tf->nt) freemem(tf->t);
+			tf->art = tf->nt = 0;
+			garbage_collect(ls->gf);
+			ls->ctok = ls->save_ctok;
+		}
+
+	}
+	r = cpp(ls);
+	if (ls->ctok->type > DIGRAPH_TOKENS
+		&& ls->ctok->type < LAST_MEANINGFUL_TOKEN) {
+		ls->ctok->type = undig(ls->ctok->type);
+	}
+	if (r > 0) return r;
+	if (r < 0) return 0;
+	return llex(ls);
+}
+
+/*
+ * lex() reads the next token from the processed stream and stores it
+ * into ls->ctok.
+ * return value: non zero on error (including CPPERR_EOF, which is not
+ * quite an error)
+ */
+int lex(struct lexer_state *ls)
+{
+	int r;
+
+	do {
+		r = llex(ls);
+#ifdef SEMPER_FIDELIS
+	} while (!r && !ls->condcomp);
+#else
+	} while (!r && (!ls->condcomp || (ttWHI(ls->ctok->type) &&
+		(!(ls->flags & LINE_NUM) || ls->ctok->type != NEWLINE))));
+#endif
+	return r;
+}
+#endif
+
+/*
+ * check_cpp_errors() must be called when the end of input is reached;
+ * it checks pending errors due to truncated constructs (actually none,
+ * this is reserved for future evolutions).
+ */
+int check_cpp_errors(struct lexer_state *ls)
+{
+	return 0;
+}
+
+/*
+ * init_cpp() initializes everything that should be initialized.
+ * If standard_inc is non-zero, the standard include directories are
+ * added to the search path.
+ */
+void init_cpp(void)
+{
+	init_cppm();
+	init_buf_lexer_state(&dsharp_lexer, 0);
+#ifdef PRAGMA_TOKENIZE
+	init_buf_lexer_state(&tokenize_lexer, 0);
+#endif
+}
+
+/*
+ * (re)init the global tables.
+ * If standard_assertions is non 0, init the assertions table.
+ */
+void init_tables(int with_assertions)
+{
+	time_t t;
+	struct tm *ct;
+
+	time(&t);
+	ct = localtime(&t);
+#ifdef MSDOS
+	/* no function strftime() in TurboC 2.01 */
+	{
+		char *c = asctime(ct);
+
+		compile_time[0] = '"';
+		mmv(compile_time + 1, c + 11, 8);
+		compile_time[9] = '"';
+		compile_time[10] = 0;
+		compile_date[0] = '"';
+		mmv(compile_date + 1, c + 4, 7);
+		mmv(compile_date + 8, c + 20, 4);
+		compile_date[12] = '"';
+		compile_date[13] = 0;
+	}
+#else
+	strftime(compile_time, 12, "\"%H:%M:%S\"", ct);
+	strftime(compile_date, 24, "\"%b %d %Y\"", ct);
+#endif
+  sprintf(compile_adate,"\"(%02d.%02d.%02d)\"",
+          ct->tm_mday,ct->tm_mon+1,ct->tm_year%100);
+  init_macros();
+	if (with_assertions) init_assertions();
+	init_found_files();
+}
+
+/*
+ * Resets the include path.
+ */
+void init_include_path(char *incpath[])
+{
+	if (include_path_nb) {
+		int i;
+
+		for (i = 0; i < include_path_nb; i ++)
+			freemem(include_path[i]);
+		freemem(include_path);
+		include_path_nb = 0;
+	}
+	if (incpath) {
+		int i;
+
+		for (i = 0; incpath[i]; i ++)
+			aol(include_path, include_path_nb, convert_path(incpath[i]), INCPATH_MEMG);
+	}
+}
+
+/*
+ * add_incpath() adds "path" to the standard include path.
+ */
+void add_incpath(char *path)
+{
+	aol(include_path, include_path_nb, convert_path(path), INCPATH_MEMG);
+}
+
+#ifdef STAND_ALONE
+/*
+ * print some help
+ */
+static void usage(char *command_name)
+{
+	fprintf(stderr,
+	"Usage: %s [options] [file]\n"
+	"language options:\n"
+	"  -C              keep comments in output\n"
+	"  -s              keep '#' when no cpp directive is recognized\n"
+	"  -l              do not emit line numbers\n"
+	"  -lg             emit gcc-like line numbers\n"
+	"  -CC             disable C++-like comments\n"
+	"  -a, -na, -a0    handle (or not) assertions\n"
+	"  -V              disable macros with extra arguments\n"
+	"  -u              understand UTF-8 in source\n"
+	"  -X              enable -a, -u and -Y\n"
+	"  -c90            mimic C90 behaviour\n"
+	"  -t              disable trigraph support\n"
+	"warning options:\n"
+	"  -wt             emit a final warning when trigaphs are encountered\n"
+	"  -wtt            emit warnings for each trigaph encountered\n"
+	"  -wa             emit warnings that are usually useless\n"
+	"  -w0             disable standard warnings\n"
+	"directory options:\n"
+	"  -I directory    add 'directory' before the standard include path\n"
+	"  -J directory    add 'directory' after the standard include path\n"
+	"  -zI             do not use the standard include path\n"
+	"  -M              emit Makefile-like dependencies instead of normal "
+			"output\n"
+	"  -Ma             emit also dependancies for system files\n"
+	"  -o file         store output in file\n"
+	"macro and assertion options:\n"
+	"  -Dmacro         predefine 'macro'\n"
+	"  -Dmacro=def     predefine 'macro' with 'def' content\n"
+	"  -Umacro         undefine 'macro'\n"
+	"  -Afoo(bar)      assert foo(bar)\n"
+	"  -Bfoo(bar)      unassert foo(bar)\n"
+	"  -Y              predefine system-dependant macros\n"
+	"  -Z              do not predefine special macros\n"
+	"  -d              emit defined macros\n"
+	"  -e              emit assertions\n"
+	"misc options:\n"
+	"  -v              print version number and settings\n"
+	"  -h              show this help\n",
+	command_name);
+}
+
+/*
+ * print version and compile-time settings
+ */
+static void version(void)
+{
+	size_t i;
+
+	fprintf(stderr, "ucpp version %d.%d\n", VERS_MAJ, VERS_MIN);
+	fprintf(stderr, "search path:\n");
+	for (i = 0; i < include_path_nb; i ++)
+		fprintf(stderr, "  %s\n", include_path[i]);
+}
+
+/*
+ * parse_opt() initializes many things according to the command-line
+ * options.
+ * Return values:
+ * 0  on success
+ * 1  on semantic error (redefinition of a special macro, for instance)
+ * 2  on syntaxic error (unknown options for instance)
+ */
+static int parse_opt(int argc, char *argv[], struct lexer_state *ls)
+{
+	int i, ret = 0;
+	char *filename = 0;
+	int with_std_incpath = 1;
+	int print_version = 0, print_defs = 0, print_asserts = 0;
+	int system_macros = 0, standard_assertions = 1;
+
+	init_lexer_state(ls);
+	ls->flags = DEFAULT_CPP_FLAGS;
+	emit_output = ls->output = stdout;
+	for (i = 1; i < argc; i ++) if (argv[i][0] == '-') {
+		if (!strcmp(argv[i], "-h")) {
+			return 2;
+		} else if (!strcmp(argv[i], "-C")) {
+			ls->flags &= ~DISCARD_COMMENTS;
+		} else if (!strcmp(argv[i], "-CC")) {
+			ls->flags &= ~CPLUSPLUS_COMMENTS;
+		} else if (!strcmp(argv[i], "-a")) {
+			ls->flags |= HANDLE_ASSERTIONS;
+		} else if (!strcmp(argv[i], "-na")) {
+			ls->flags |= HANDLE_ASSERTIONS;
+			standard_assertions = 0;
+		} else if (!strcmp(argv[i], "-a0")) {
+			ls->flags &= ~HANDLE_ASSERTIONS;
+		} else if (!strcmp(argv[i], "-V")) {
+			ls->flags &= ~MACRO_VAARG;
+		} else if (!strcmp(argv[i], "-u")) {
+			ls->flags |= UTF8_SOURCE;
+		} else if (!strcmp(argv[i], "-X")) {
+			ls->flags |= HANDLE_ASSERTIONS;
+			ls->flags |= UTF8_SOURCE;
+			system_macros = 1;
+		} else if (!strcmp(argv[i], "-c90")) {
+			ls->flags &= ~MACRO_VAARG;
+			ls->flags &= ~CPLUSPLUS_COMMENTS;
+			c99_compliant = 0;
+			c99_hosted = -1;
+		} else if (!strcmp(argv[i], "-t")) {
+			ls->flags &= ~HANDLE_TRIGRAPHS;
+		} else if (!strcmp(argv[i], "-wt")) {
+			ls->flags |= WARN_TRIGRAPHS;
+		} else if (!strcmp(argv[i], "-wtt")) {
+			ls->flags |= WARN_TRIGRAPHS_MORE;
+		} else if (!strcmp(argv[i], "-wa")) {
+			ls->flags |= WARN_ANNOYING;
+		} else if (!strcmp(argv[i], "-w0")) {
+			ls->flags &= ~WARN_STANDARD;
+			ls->flags &= ~WARN_PRAGMA;
+		} else if (!strcmp(argv[i], "-s")) {
+			ls->flags &= ~FAIL_SHARP;
+		} else if (!strcmp(argv[i], "-l")) {
+			ls->flags &= ~LINE_NUM;
+		} else if (!strcmp(argv[i], "-lg")) {
+			ls->flags |= GCC_LINE_NUM;
+		} else if (!strcmp(argv[i], "-M")) {
+			ls->flags &= ~KEEP_OUTPUT;
+			emit_dependencies = 1;
+		} else if (!strcmp(argv[i], "-Ma")) {
+			ls->flags &= ~KEEP_OUTPUT;
+			emit_dependencies = 2;
+		} else if (!strcmp(argv[i], "-Y")) {
+			system_macros = 1;
+		} else if (!strcmp(argv[i], "-Z")) {
+			no_special_macros = 1;
+		} else if (!strcmp(argv[i], "-d")) {
+			ls->flags &= ~KEEP_OUTPUT;
+			print_defs = 1;
+		} else if (!strcmp(argv[i], "-e")) {
+			ls->flags &= ~KEEP_OUTPUT;
+			print_asserts = 1;
+		} else if (!strcmp(argv[i], "-zI")) {
+			with_std_incpath = 0;
+		} else if (!strcmp(argv[i], "-I") || !strcmp(argv[i], "-J")) {
+			i ++;
+		} else if (!strcmp(argv[i], "-o")) {
+			if ((++ i) >= argc) {
+				error(-1, "missing filename after -o");
+				return 2;
+			}
+			if (argv[i][0] == '-' && argv[i][1] == 0) {
+				emit_output = ls->output = stdout;
+			} else {
+				ls->output = fopen(argv[i], "w");
+				if (!ls->output) {
+					error(-1, "failed to open for "
+						"writing: %s", argv[i]);
+					return 2;
+				}
+				emit_output = ls->output;
+			}
+		} else if (!strcmp(argv[i], "-v")) {
+			print_version = 1;
+		} else if (argv[i][1] != 'I' && argv[i][1] != 'J'
+			&& argv[i][1] != 'D' && argv[i][1] != 'U'
+			&& argv[i][1] != 'A' && argv[i][1] != 'B')
+			warning(-1, "unknown option '%s'", argv[i]);
+	} else {
+		if (filename != 0) {
+			error(-1, "spurious filename '%s'", argv[i]);
+			return 2;
+		}
+		filename = argv[i];
+	}
+	init_tables(ls->flags & HANDLE_ASSERTIONS);
+	init_include_path(0);
+	if (filename) {
+#ifdef UCPP_MMAP
+		FILE *f = fopen_mmap_file(filename);
+
+		ls->input = 0;
+		if (f) set_input_file(ls, f);
+#else
+		ls->input = fopen(filename, "r");
+#endif
+		if (!ls->input) {
+			error(-1, "file '%s' not found", filename);
+			return 1;
+		}
+#ifdef NO_LIBC_BUF
+		setbuf(ls->input, 0);
+#endif
+		set_init_filename(filename, 1);
+	} else {
+		ls->input = stdin;
+		set_init_filename("<stdin>", 0);
+	}
+	for (i = 1; i < argc; i ++)
+		if (argv[i][0] == '-' && argv[i][1] == 'I')
+			add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
+	if (system_macros) for (i = 0; system_macros_def[i]; i ++)
+		ret = ret || define_macro(ls, system_macros_def[i]);
+	for (i = 1; i < argc; i ++)
+		if (argv[i][0] == '-' && argv[i][1] == 'D')
+			ret = ret || define_macro(ls, argv[i] + 2);
+	for (i = 1; i < argc; i ++)
+		if (argv[i][0] == '-' && argv[i][1] == 'U')
+			ret = ret || undef_macro(ls, argv[i] + 2);
+	if (ls->flags & HANDLE_ASSERTIONS) {
+		if (standard_assertions)
+			for (i = 0; system_assertions_def[i]; i ++)
+				make_assertion(system_assertions_def[i]);
+		for (i = 1; i < argc; i ++)
+			if (argv[i][0] == '-' && argv[i][1] == 'A')
+				ret = ret || make_assertion(argv[i] + 2);
+		for (i = 1; i < argc; i ++)
+			if (argv[i][0] == '-' && argv[i][1] == 'B')
+				ret = ret || destroy_assertion(argv[i] + 2);
+	} else {
+		for (i = 1; i < argc; i ++)
+			if (argv[i][0] == '-'
+				&& (argv[i][1] == 'A' || argv[i][1] == 'B'))
+				warning(-1, "assertions disabled");
+	}
+	if (with_std_incpath) {
+		for (i = 0; include_path_std[i]; i ++)
+			add_incpath(include_path_std[i]);
+	}
+	for (i = 1; i < argc; i ++)
+		if (argv[i][0] == '-' && argv[i][1] == 'J')
+			add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
+
+	if (print_version) {
+		version();
+		return 1;
+	}
+	if (print_defs) {
+		print_defines();
+		emit_defines = 1;
+	}
+	if (print_asserts && (ls->flags & HANDLE_ASSERTIONS)) {
+		print_assertions();
+		emit_assertions = 1;
+	}
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	struct lexer_state ls;
+	int r, fr = 0;
+
+	init_cpp();
+	if ((r = parse_opt(argc, argv, &ls)) != 0) {
+		if (r == 2) usage(argv[0]);
+		return EXIT_FAILURE;
+	}
+	enter_file(&ls, ls.flags);
+	while ((r = cpp(&ls)) < CPPERR_EOF) fr = fr || (r > 0);
+	fr = fr || check_cpp_errors(&ls);
+	if (ls.flags & KEEP_OUTPUT) {
+		/* while (ls.line > ls.oline) put_char(&ls, '\n'); */
+		put_char(&ls, '\n');
+	}
+	if (emit_dependencies) fputc('\n', emit_output);
+#ifndef NO_UCPP_BUF
+	if (!(ls.flags & LEXER)) {
+		flush_output(&ls);
+	}
+#endif
+	if (ls.flags & WARN_TRIGRAPHS && ls.count_trigraphs)
+		warning(0, "%ld trigraphs encountered", ls.count_trigraphs);
+	return fr ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+#endif
diff --git a/ucpp/cpp.h b/ucpp/cpp.h
new file mode 100755
index 0000000..4f0a709
--- /dev/null
+++ b/ucpp/cpp.h
@@ -0,0 +1,316 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__CPP__
+#define UCPP__CPP__
+
+/*
+ * Uncomment the following if you want ucpp to use externally provided
+ * error-reporting functions (ucpp_warning(), ucpp_error() and ucpp_ouch())
+ */
+/* #define NO_UCPP_ERROR_FUNCTIONS */
+
+/*
+ * Tokens (do not change the order unless checking operators_name[] in cpp.c)
+ *
+ * It is important that the token NONE is 0
+ * Check the STRING_TOKEN macro
+ */
+#define CPPERR	512
+enum {
+	NONE,		/* whitespace */
+	NEWLINE,	/* newline */
+	COMMENT,	/* comment */
+	NUMBER,		/* number constant */
+	NAME,		/* identifier */
+	BUNCH,		/* non-C characters */
+	PRAGMA,		/* a #pragma directive */
+	CONTEXT,	/* new file or #line */
+	STRING,		/* constant "xxx" */
+	CHAR,		/* constant 'xxx' */
+	SLASH,		/*	/	*/
+	ASSLASH,	/*	/=	*/
+	MINUS,		/*	-	*/
+	MMINUS,		/*	--	*/
+	ASMINUS,	/*	-=	*/
+	ARROW,		/*	->	*/
+	PLUS,		/*	+	*/
+	PPLUS,		/*	++	*/
+	ASPLUS,		/*	+=	*/
+	LT,		/*	<	*/
+	LEQ,		/*	<=	*/
+	LSH,		/*	<<	*/
+	ASLSH,		/*	<<=	*/
+	GT,		/*	>	*/
+	GEQ,		/*	>=	*/
+	RSH,		/*	>>	*/
+	ASRSH,		/*	>>=	*/
+	ASGN,		/*	=	*/
+	SAME,		/*	==	*/
+#ifdef CAST_OP
+	CAST,		/*	=>	*/
+#endif
+	NOT,		/*	~	*/
+	NEQ,		/*	!=	*/
+	AND,		/*	&	*/
+	LAND,		/*	&&	*/
+	ASAND,		/*	&=	*/
+	OR,		/*	|	*/
+	LOR,		/*	||	*/
+	ASOR,		/*	|=	*/
+	PCT,		/*	%	*/
+	ASPCT,		/*	%=	*/
+	STAR,		/*	*	*/
+	ASSTAR,		/*	*=	*/
+	CIRC,		/*	^	*/
+	ASCIRC,		/*	^=	*/
+	LNOT,		/*	!	*/
+	ASNOT,		/*	~=	*/
+	LBRA,		/*	{	*/
+	RBRA,		/*	}	*/
+	LBRK,		/*	[	*/
+	RBRK,		/*	]	*/
+	LPAR,		/*	(	*/
+	RPAR,		/*	)	*/
+	COMMA,		/*	,	*/
+	QUEST,		/*	?	*/
+	SEMIC,		/*	;	*/
+	COLON,		/*	:	*/
+	DOT,		/*	.	*/
+	MDOTS,		/*	...	*/
+	SHARP,		/*	#	*/
+	DSHARP,		/*	##	*/
+
+	OPT_NONE,	/* optional space to separate tokens in text output */
+
+	DIGRAPH_TOKENS,			/* there begin digraph tokens */
+
+	/* for DIG_*, do not change order, unless checking undig() in cpp.c */
+	DIG_LBRK,	/*	<:	*/
+	DIG_RBRK,	/*	:>	*/
+	DIG_LBRA,	/*	<%	*/
+	DIG_RBRA,	/*	%>	*/
+	DIG_SHARP,	/*	%:	*/
+	DIG_DSHARP,	/*	%:%:	*/
+
+	DIGRAPH_TOKENS_END,		/* digraph tokens end here */
+
+	LAST_MEANINGFUL_TOKEN,		/* reserved words will go there */
+
+	MACROARG,	/* special token for representing macro arguments */
+
+	UPLUS = CPPERR,	/* unary + */
+	UMINUS		/* unary - */
+};
+
+#include <stdio.h>
+#include <setjmp.h>
+#include "tune.h"
+
+struct token {
+	int type;
+	long line;
+	char *name;
+};
+
+struct token_fifo {
+	struct token *t;
+	size_t nt, art;
+};
+
+struct lexer_state {
+	/* input control */
+	FILE *input;
+#ifndef NO_UCPP_BUF
+	unsigned char *input_buf;
+#ifdef UCPP_MMAP
+	int from_mmap;
+	unsigned char *input_buf_sav;
+#endif
+#endif
+	unsigned char *input_string;
+	size_t ebuf;
+	size_t pbuf;
+	int lka[2];
+	int nlka;
+	int macfile;
+	int last;
+	int discard;
+	unsigned long utf8;
+	unsigned char copy_line[COPY_LINE_LENGTH];
+	int cli;
+
+	/* output control */
+
+	FILE *output;
+	struct token_fifo *output_fifo, *toplevel_of;
+#ifndef NO_UCPP_BUF
+	unsigned char *output_buf;
+#endif
+	size_t sbuf;
+
+	/* token control */
+	struct token *ctok;
+	struct token *save_ctok;
+	int tknl;
+	int ltwnl;
+	int pending_token;
+#ifdef INMACRO_FLAG
+	int inmacro;
+	long macro_count;
+#endif
+
+	/* lexer options */
+	long line;
+	long oline;
+	unsigned long flags;
+	long count_trigraphs;
+	struct garbage_fifo *gf;
+	int ifnest;
+	int condnest;
+	int condcomp;
+	int condmet;
+	unsigned long condf[2];
+};
+
+/*
+ * Flags for struct lexer_state
+ */
+/* warning flags */
+#define WARN_STANDARD	     0x000001UL	/* emit standard warnings */
+#define WARN_ANNOYING	     0x000002UL	/* emit annoying warnings */
+#define WARN_TRIGRAPHS	     0x000004UL	/* warn when trigraphs are used */
+#define WARN_TRIGRAPHS_MORE  0x000008UL	/* extra-warn for trigraphs */
+#define WARN_PRAGMA	     0x000010UL	/* warn for pragmas in non-lexer mode */
+
+/* error flags */
+#define FAIL_SHARP	     0x000020UL	/* emit errors on rogue '#' */
+#define CCHARSET	     0x000040UL	/* emit errors on non-C characters */
+
+/* emission flags */
+#define DISCARD_COMMENTS     0x000080UL	/* discard comments from text output */
+#define CPLUSPLUS_COMMENTS   0x000100UL	/* understand C++-like comments */
+#define LINE_NUM	     0x000200UL	/* emit #line directives in output */
+#define GCC_LINE_NUM	     0x000400UL	/* same as #line, with gcc-syntax */
+
+/* language flags */
+#define HANDLE_ASSERTIONS    0x000800UL	/* understand assertions */
+#define HANDLE_PRAGMA	     0x001000UL	/* emit PRAGMA tokens in lexer mode */
+#define MACRO_VAARG	     0x002000UL	/* understand macros with '...' */
+#define UTF8_SOURCE	     0x004000UL	/* identifiers are in UTF8 encoding */
+#define HANDLE_TRIGRAPHS     0x008000UL	/* handle trigraphs */
+
+/* global ucpp behaviour */
+#define LEXER		     0x010000UL	/* behave as a lexer */
+#define KEEP_OUTPUT	     0x020000UL	/* emit the result of preprocessing */
+#define COPY_LINE	     0x040000UL /* make a copy of the parsed line */
+
+/* internal flags */
+#define READ_AGAIN	     0x080000UL	/* emit again the last token */
+#define TEXT_OUTPUT	     0x100000UL	/* output text */
+
+/*
+ * Public function prototypes
+ */
+
+#ifndef NO_UCPP_BUF
+void flush_output(struct lexer_state *);
+#endif
+
+void init_assertions(void);
+int make_assertion(char *);
+int destroy_assertion(char *);
+void print_assertions(void);
+
+void init_macros(void);
+int define_macro(struct lexer_state *, char *);
+int undef_macro(struct lexer_state *, char *);
+void print_defines(void);
+
+void set_init_filename(char *, int);
+void init_cpp(void);
+void init_include_path(char *[]);
+void init_lexer_state(struct lexer_state *);
+void init_lexer_mode(struct lexer_state *);
+void free_lexer_state(struct lexer_state *);
+int lex(struct lexer_state *);
+int check_cpp_errors(struct lexer_state *);
+void add_incpath(char *);
+void init_tables(int);
+void enter_file(struct lexer_state *, unsigned long);
+int cpp(struct lexer_state *);
+
+#ifdef UCPP_MMAP
+FILE *fopen_mmap_file(char *);
+void set_input_file(struct lexer_state *, FILE *);
+#endif
+
+struct stack_context {
+	char *long_name, *name;
+	long line;
+};
+struct stack_context *report_context(void);
+
+extern int no_special_macros, system_macros,
+	emit_dependencies, emit_defines, emit_assertions;
+extern int c99_compliant, c99_hosted;
+extern FILE *emit_output;
+extern char *current_filename, *current_long_filename;
+extern char *operators_name[];
+extern struct protect {
+	char *macro;
+	int state;
+	struct found_file *ff;
+} protect_detect;
+
+void ucpp_ouch(char *, ...);
+void ucpp_error(long, char *, ...);
+void ucpp_warning(long, char *, ...);
+
+extern int *transient_characters;
+
+/*
+ * Errors from CPPERR_EOF and above are not real erros, only show-stoppers.
+ * Errors below CPPERR_EOF are real ones.
+ */
+#define CPPERR_NEST	 900
+#define CPPERR_EOF	1000
+
+/*
+ * This macro tells whether the name field of a given token type is
+ * relevant, or not. Irrelevant name field means that it might point
+ * to outerspace.
+ */
+#ifdef SEMPER_FIDELIS
+#define STRING_TOKEN(x)    ((x) == NONE || ((x) >= COMMENT && (x) <= CHAR))
+#else
+#define STRING_TOKEN(x)    ((x) >= NUMBER && (x) <= CHAR)
+#endif
+
+#endif
diff --git a/ucpp/eval.c b/ucpp/eval.c
new file mode 100755
index 0000000..9319b09
--- /dev/null
+++ b/ucpp/eval.c
@@ -0,0 +1,1087 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <limits.h>
+#include "ucppi.h"
+#include "tune.h"
+#include "mem.h"
+
+JMP_BUF eval_exception;
+long eval_line;
+static int emit_eval_warnings;
+
+/*
+ * If you want to hardcode a conversion table, define a static array
+ * of 256 int, and make transient_characters point to it.
+ */
+int *transient_characters = 0;
+
+#define OCTAL(x)	((x) >= '0' && (x) <= '7')
+#define DECIM(x)	((x) >= '0' && (x) <= '9')
+#define HEXAD(x)	(((x) >= '0' && (x) <= '9') \
+			|| (x) == 'a' || (x) == 'b' || (x) == 'c' \
+			|| (x) == 'd' || (x) == 'e' || (x) == 'f' \
+			|| (x) == 'A' || (x) == 'B' || (x) == 'C' \
+			|| (x) == 'D' || (x) == 'E' || (x) == 'F')
+#define OVAL(x)		((int)((x) - '0'))
+#define DVAL(x)		((int)((x) - '0'))
+#define HVAL(x)		(DECIM(x) ? DVAL(x) \
+			: (x) == 'a' || (x) == 'A' ? 10 \
+			: (x) == 'b' || (x) == 'B' ? 11 \
+			: (x) == 'c' || (x) == 'C' ? 12 \
+			: (x) == 'd' || (x) == 'D' ? 13 \
+			: (x) == 'e' || (x) == 'E' ? 14 : 15)
+
+#if !defined(NATIVE_UINTMAX) && !defined(SIMUL_UINTMAX)
+#  if __STDC__ && __STDC_VERSION__ >= 199901L
+#    include <stdint.h>
+#    define NATIVE_UINTMAX uintmax_t
+#    define NATIVE_INTMAX intmax_t
+#  else
+#    define NATIVE_UINTMAX unsigned long
+#    define NATIVE_INTMAX long
+#  endif
+#endif
+
+#ifdef NATIVE_UINTMAX
+
+typedef NATIVE_UINTMAX ucppulong;
+typedef NATIVE_INTMAX ucppslong;
+
+#define to_ulong(x)		((ucppulong)(x))
+#define to_slong(x)		((ucppslong)(x))
+
+#define op_star_u(x, y)		((x) * (y))
+
+static inline ucppulong op_slash_u(ucppulong x, ucppulong y)
+{
+	if (y == 0) {
+		error(eval_line, "division by 0");
+		throw(eval_exception);
+	}
+	return x / y;
+}
+
+static inline ucppulong op_pct_u(ucppulong x, ucppulong y)
+{
+	if (y == 0) {
+		error(eval_line, "division by 0");
+		throw(eval_exception);
+	}
+	return x % y;
+}
+
+#define op_plus_u(x, y)		((x) + (y))
+#define op_minus_u(x, y)	((x) - (y))
+#define op_neg_u(x)		(-(x))
+#define op_lsh_u(x, y)		((x) << (y))
+#define op_rsh_u(x, y)		((x) >> (y))
+#define op_lt_u(x, y)		((x) < (y))
+#define op_leq_u(x, y)		((x) <= (y))
+#define op_gt_u(x, y)		((x) > (y))
+#define op_geq_u(x, y)		((x) >= (y))
+#define op_same_u(x, y)		((x) == (y))
+#define op_neq_u(x, y)		((x) != (y))
+#define op_and_u(x, y)		((x) & (y))
+#define op_circ_u(x, y)		((x) ^ (y))
+#define op_or_u(x, y)		((x) | (y))
+#define op_lval_u(x)		((x) != 0)
+#define op_lnot_u(x)		(!(x))
+#define op_not_u(x)		(~(x))
+#define op_uplus_u(x)		(x)
+#define op_uminus_u(x)		op_neg_u(x)
+
+#define op_star_s(x, y)		((x) * (y))
+
+static inline ucppslong op_slash_s(ucppslong x, ucppslong y)
+{
+	if (y == 0) {
+		error(eval_line, "division by 0");
+		throw(eval_exception);
+	}
+	return x / y;
+}
+
+static inline ucppslong op_pct_s(ucppslong x, ucppslong y)
+{
+	if (y == 0) {
+		error(eval_line, "division by 0");
+		throw(eval_exception);
+	}
+	return x % y;
+}
+
+#define op_plus_s(x, y)		((x) + (y))
+#define op_minus_s(x, y)	((x) - (y))
+#define op_neg_s(x)		(-(x))
+#define op_lsh_s(x, y)		((x) << (y))
+#define op_rsh_s(x, y)		((x) >> (y))
+#define op_lt_s(x, y)		((x) < (y))
+#define op_leq_s(x, y)		((x) <= (y))
+#define op_gt_s(x, y)		((x) > (y))
+#define op_geq_s(x, y)		((x) >= (y))
+#define op_same_s(x, y)		((x) == (y))
+#define op_neq_s(x, y)		((x) != (y))
+#define op_and_s(x, y)		((x) & (y))
+#define op_circ_s(x, y)		((x) ^ (y))
+#define op_or_s(x, y)		((x) | (y))
+#define op_lval_s(x)		((x) != 0)
+#define op_lnot_s(x)		(!(x))
+#define op_not_s(x)		(~(x))
+#define op_uplus_s(x)		(x)
+#define op_uminus_s(x)		op_neg_s(x)
+
+#define op_promo(x)		((ucppulong)x)
+#define back_ulong(x)		((unsigned long)x)
+
+#else
+
+/*
+ * We suppose that the unsigned long is not padded in its memory
+ * representation, and that it has an even binary length.
+ *
+ * We could explore the size of ULONG_MAX with some dichotomic
+ * trick using a recursive #include, but this would be really ugly.
+ */
+#define LONGSIZE	(CHAR_BIT * sizeof(unsigned long))
+#define HALFLONGSIZE	(LONGSIZE / 2)
+#define HUL_MASK	((1UL << HALFLONGSIZE) - 1)
+#define UL_MS(x)	(((x) >> HALFLONGSIZE) & HUL_MASK)
+#define UL_LS(x)	((x) & HUL_MASK)
+#define SIGNBIT(x)	((x) & (1UL << (LONGSIZE - 1)))
+
+typedef struct {
+	unsigned long msw, lsw;
+} ucppulong;
+
+#define ucppslong	ucppulong
+
+static ucppulong to_ulong(unsigned long x)
+{
+	ucppulong y;
+
+	y.msw = 0;
+	y.lsw = x;
+	return y;
+}
+
+static ucppslong to_slong(long x)
+{
+	ucppslong y;
+
+	y.lsw = x;
+	y.msw = x >= 0 ? 0 : (unsigned long)(-1);
+	return y;
+}
+
+static ucppulong op_plus_u(ucppulong x, ucppulong y)
+{
+	ucppulong z;
+
+	z.lsw = x.lsw + y.lsw;
+	z.msw = x.msw + y.msw;
+	if (z.lsw < x.lsw) z.msw ++;
+	return z;
+}
+
+static ucppulong op_neg_u(ucppulong x)
+{
+	ucppulong z;
+
+	z.lsw = ~x.lsw;
+	z.msw = ~x.msw;
+	if (!(++ z.lsw)) z.msw ++;
+	return z;
+}
+
+#define op_minus_u(x, y)	op_plus_u(x, op_neg_u(y))
+
+static ucppulong op_lsh_u(ucppulong x, int s)
+{
+	ucppulong z;
+
+	s %= (2 * LONGSIZE);
+	if (s == 0) return x;
+	if (s >= LONGSIZE) {
+		z.lsw = 0;
+		z.msw = x.lsw;
+		return op_lsh_u(z, s - LONGSIZE);
+	}
+	z.lsw = (x.lsw << s);
+	z.msw = (x.msw << s) | (x.lsw >> (LONGSIZE - s));
+	return z;
+}
+
+static ucppulong op_rsh_u(ucppulong x, int s)
+{
+	ucppulong z;
+
+	s %= (2 * LONGSIZE);
+	if (s == 0) return x;
+	if (s >= LONGSIZE) {
+		z.msw = 0;
+		z.lsw = x.msw;
+		return op_rsh_u(z, s - LONGSIZE);
+	}
+	z.lsw = (x.lsw >> s) | (x.msw << (LONGSIZE - s));
+	z.msw = (x.msw >> s);
+	return z;
+}
+
+static int op_lt_u(ucppulong x, ucppulong y)
+{
+	if (x.msw < y.msw) return 1;
+	if (x.msw > y.msw) return 0;
+	if (x.lsw < y.lsw) return 1;
+	return 0;
+}
+
+static int op_leq_u(ucppulong x, ucppulong y)
+{
+	if (x.msw < y.msw) return 1;
+	if (x.msw > y.msw) return 0;
+	if (x.lsw <= y.lsw) return 1;
+	return 0;
+}
+
+#define op_gt_u(x, y)	op_lt_u(y, x)
+#define op_geq_u(x, y)	op_leq_u(y, x)
+
+static int op_same_u(ucppulong x, ucppulong y)
+{
+	return x.msw == y.msw && x.lsw == y.lsw;
+}
+
+#define op_neq_u(x, y)	(!op_same_u(x, y))
+
+static ucppulong op_and_u(ucppulong x, ucppulong y)
+{
+	ucppulong z;
+
+	z.lsw = x.lsw & y.lsw;
+	z.msw = x.msw & y.msw;
+	return z;
+}
+
+static ucppulong op_circ_u(ucppulong x, ucppulong y)
+{
+	ucppulong z;
+
+	z.lsw = x.lsw ^ y.lsw;
+	z.msw = x.msw ^ y.msw;
+	return z;
+}
+
+static ucppulong op_or_u(ucppulong x, ucppulong y)
+{
+	ucppulong z;
+
+	z.lsw = x.lsw | y.lsw;
+	z.msw = x.msw | y.msw;
+	return z;
+}
+
+#define op_lval_u(x)	op_neq_u(x, to_ulong(0))
+#define op_lnot_u(x)	(!op_lval_u(x))
+
+static ucppulong op_not_u(ucppulong x)
+{
+	ucppulong z;
+
+	z.lsw = ~x.lsw;
+	z.msw = ~x.msw;
+	return z;
+}
+
+#define op_uplus_u(x)	(x)
+#define op_uminus_u(x)	op_neg_u(x)
+
+static ucppulong umul(unsigned long x, unsigned long y)
+{
+	ucppulong z;
+	unsigned long t00, t01, t10, t11, c = 0, t;
+
+	t00 = UL_LS(x) * UL_LS(y);
+	t01 = UL_LS(x) * UL_MS(y);
+	t10 = UL_MS(x) * UL_LS(y);
+	t11 = UL_MS(x) * UL_MS(y);
+	t = z.lsw = t00;
+	if (t > (z.lsw += (UL_LS(t01) << HALFLONGSIZE))) c ++;
+	t = z.lsw;
+	if (t > (z.lsw += (UL_LS(t10) << HALFLONGSIZE))) c ++;
+	z.msw = t11 + UL_MS(t10) + UL_MS(t01) + c;
+	return z;
+}
+
+static ucppulong op_star_u(ucppulong x, ucppulong y)
+{
+	ucppulong z1, z2;
+
+	z1.lsw = z2.lsw = 0;
+	z1.msw = x.lsw * y.msw;
+	z2.msw = x.msw * y.lsw;
+	return op_plus_u(umul(x.lsw, y.lsw), op_plus_u(z1, z2));
+}
+
+static void udiv(ucppulong x, ucppulong y, ucppulong *q, ucppulong *r)
+{
+	int i, j;
+
+	*q = to_ulong(0);
+	for (i = 2 * LONGSIZE - 1; i >= 0; i --) {
+		if (i >= LONGSIZE && (y.msw & (1UL << (i - LONGSIZE)))) break;
+		if (i < LONGSIZE && (y.lsw & (1UL << i))) break;
+	}
+	if (i < 0) {
+		error(eval_line, "division by 0");
+		throw(eval_exception);
+	}
+	for (j = 2 * LONGSIZE - 1 - i; j >= 0; j --) {
+		ucppulong a = op_lsh_u(y, j);
+
+		if (op_leq_u(a, x)) {
+			x = op_minus_u(x, a);
+			if (j >= LONGSIZE)
+				q->msw |= (1UL << (j - LONGSIZE));
+			else
+				q->lsw |= (1UL << j);
+		}
+	}
+	*r = x;
+}
+
+static ucppulong op_slash_u(ucppulong x, ucppulong y)
+{
+	ucppulong q, r;
+
+	udiv(x, y, &q, &r);
+	return q;
+}
+
+static ucppulong op_pct_u(ucppulong x, ucppulong y)
+{
+	ucppulong q, r;
+
+	udiv(x, y, &q, &r);
+	return r;
+}
+
+
+static ucppslong op_star_s(ucppslong x, ucppslong y)
+{
+	ucppulong a = x, b = y, c;
+	int xn = 0, yn = 0;
+
+	if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; }
+	if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; }
+	c = op_star_u(a, b);
+	/* Turbo C seems to miscompile the ?: operators when operands
+	   are ulong/slong structures */
+	if (xn ^ yn) return op_neg_u(c);
+	return c;
+}
+
+static void sdiv(ucppslong x, ucppslong y, ucppslong *q, ucppslong *r)
+{
+	ucppulong a = x, b = y, c, d;
+	int xn = 0, yn = 0;
+
+	if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; }
+	if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; }
+	udiv(a, b, &c, &d);
+	if (xn ^ yn) *q = op_neg_u(c); else *q = c;
+	if (xn ^ yn) *r = op_neg_u(d); else *r = d;
+}
+
+static ucppslong op_slash_s(ucppslong x, ucppslong y)
+{
+	ucppslong q, r;
+
+	sdiv(x, y, &q, &r);
+	return q;
+}
+
+static ucppslong op_pct_s(ucppslong x, ucppslong y)
+{
+	ucppslong q, r;
+
+	sdiv(x, y, &q, &r);
+	return r;
+}
+
+#define op_plus_s(x, y)		op_plus_u(x, y)
+#define op_minus_s(x, y)	op_minus_u(x, y)
+#define op_neg_s(x)		op_neg_u(x)
+#define op_lsh_s(x, y)		op_lsh_u(x, y)
+
+/*
+ * What happens if x represents a negative value, is implementation
+ * specified. We emit a warning, and extend the sign (which is what
+ * most implementations do).
+ */
+static ucppslong op_rsh_s(ucppslong x, int y)
+{
+	int xn = (SIGNBIT(x.msw) != 0);
+	ucppulong q = op_rsh_u(x, y);
+
+	if (xn && y > 0) {
+		if (emit_eval_warnings)
+			warning(eval_line, "right shift of a signed negative "
+				"value in #if");
+		q = op_or_u(q, op_lsh_u(op_not_u(to_ulong(0)),
+			2 * LONGSIZE - y));
+	}
+	return q;
+}
+
+static int op_lt_s(ucppslong x, ucppslong y)
+{
+	int xn = (SIGNBIT(x.msw) != 0);
+	int yn = (SIGNBIT(y.msw) != 0);
+
+	if (xn && !yn) return 1;
+	if (!xn && yn) return 0;
+	if (xn) return op_lt_u(op_neg_u(y), op_neg_u(x));
+	return op_lt_u(x, y);
+}
+
+static int op_leq_s(ucppslong x, ucppslong y)
+{
+	int xn = (SIGNBIT(x.msw) != 0);
+	int yn = (SIGNBIT(y.msw) != 0);
+
+	if (xn && !yn) return 1;
+	if (!xn && yn) return 0;
+	if (xn) return op_leq_u(op_neg_u(y), op_neg_u(x));
+	return op_leq_u(x, y);
+}
+
+#define op_gt_s(x, y)		op_lt_s(y, x)
+#define op_geq_s(x, y)		op_leq_s(y, x)
+#define op_same_s(x, y)		op_same_u(x, y)
+#define op_neq_s(x, y)		(!op_same_s(x, y))
+
+#define op_and_s(x, y)		op_and_u(x, y)
+#define op_circ_s(x, y)		op_circ_u(x, y)
+#define op_or_s(x, y)		op_or_u(x, y)
+
+#define op_lval_s(x)		op_neq_s(x, to_slong(0))
+#define op_lnot_s(x)		(!op_lval_s(x))
+#define op_not_s(x)		op_not_u(x)
+#define op_uplus_s(x)		(x)
+#define op_uminus_s(x)		op_neg_s(x)
+
+#define op_promo(x)		(x)
+#define back_ulong(x)		((x).lsw)
+
+#endif
+
+typedef struct {
+	int sign;
+	union {
+		ucppulong uv;
+		ucppslong sv;
+	} u;
+} ppval;
+
+static int boolval(ppval x)
+{
+	return x.sign ? op_lval_s(x.u.sv) : op_lval_u(x.u.uv);
+}
+
+#if !defined(WCHAR_SIGNEDNESS)
+#  if CHAR_MIN == 0
+#    define WCHAR_SIGNEDNESS	0
+#  else
+#    define WCHAR_SIGNEDNESS	1
+#  endif
+#endif
+
+/*
+ * Check the suffix, return 1 if it is signed, 0 otherwise.
+ * u, l, ll, ul, lu, ull, llu, and variations with uppercase letters
+ * are legal, no suffix either; other suffixes are not legal.
+ */
+static int pp_suffix(char *d, char *refc)
+{
+	if (!*d) return 1;
+	if (*d == 'u' || *d == 'U') {
+		d ++;
+		if (!*d) return 0;
+		if (*d == 'l' || *d == 'L') {
+			d ++;
+			if (*d == 'l' || *d == 'L') d ++;
+			if (!*d) return 0;
+			goto suffix_error;
+		}
+		goto suffix_error;
+	}
+	if (*d == 'l' || *d == 'L') {
+		d ++;
+		if (*d == 'l' || *d == 'L') d ++;
+		if (!*d) return 1;
+		if (*d == 'u' || *d == 'U') {
+			d ++;
+			if (!*d) return 0;
+		}
+		goto suffix_error;
+	}
+suffix_error:
+	error(eval_line, "invalid integer constant '%s'", refc);
+	throw(eval_exception);
+	return 666;
+}
+
+static ppval pp_decconst(char *c, int sign, char *refc)
+{
+	ppval q;
+
+	q.sign = sign;
+	if (q.sign) {
+		q.u.sv = to_slong(0);
+		for (; DECIM(*c); c ++) {
+			q.u.sv = op_star_s(q.u.sv, to_slong(10));
+			q.u.sv = op_plus_s(q.u.sv, to_slong(DVAL(*c)));
+		}
+		if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+	} else {
+		q.u.uv = to_ulong(0);
+		for (; DECIM(*c); c ++) {
+			q.u.uv = op_star_u(q.u.uv, to_ulong(10));
+			q.u.uv = op_plus_u(q.u.uv, to_ulong(DVAL(*c)));
+		}
+		if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+	}
+	return q;
+const_error:
+	error(eval_line, "invalid integer constant '%s'", refc);
+	throw(eval_exception);
+	return q;
+}
+
+static ppval pp_octconst(char *c, int sign, char *refc)
+{
+	ppval q;
+
+	q.sign = sign;
+	if (q.sign) {
+		q.u.sv = to_slong(0);
+		for (; OCTAL(*c); c ++) {
+			q.u.sv = op_star_s(q.u.sv, to_slong(8));
+			q.u.sv = op_plus_s(q.u.sv, to_slong(OVAL(*c)));
+		}
+		if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+	} else {
+		q.u.uv = to_ulong(0);
+		for (; OCTAL(*c); c ++) {
+			q.u.uv = op_star_u(q.u.uv, to_ulong(8));
+			q.u.uv = op_plus_u(q.u.uv, to_ulong(OVAL(*c)));
+		}
+		if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+	}
+	return q;
+const_error:
+	error(eval_line, "invalid integer constant '%s'", refc);
+	throw(eval_exception);
+	return q;
+}
+
+static ppval pp_hexconst(char *c, int sign, char *refc)
+{
+	ppval q;
+
+	q.sign = sign;
+	if (q.sign) {
+		q.u.sv = to_slong(0);
+		for (; HEXAD(*c); c ++) {
+			q.u.sv = op_star_s(q.u.sv, to_slong(16));
+			q.u.sv = op_plus_s(q.u.sv, to_slong(HVAL(*c)));
+		}
+		if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+	} else {
+		q.u.uv = to_ulong(0);
+		for (; HEXAD(*c); c ++) {
+			q.u.uv = op_star_u(q.u.uv, to_ulong(16));
+			q.u.uv = op_plus_u(q.u.uv, to_ulong(HVAL(*c)));
+		}
+		if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+	}
+	return q;
+const_error:
+	error(eval_line, "invalid integer constant '%s'", refc);
+	throw(eval_exception);
+	return q;
+}
+
+static unsigned long pp_char(char *c, char *refc)
+{
+	unsigned long r = 0;
+
+	c ++;
+	if (*c == '\\') {
+		int i;
+
+		c ++;
+		switch (*c) {
+		case 'n': r = '\n'; c ++; break;
+		case 't': r = '\t'; c ++; break;
+		case 'v': r = '\v'; c ++; break;
+		case 'b': r = '\b'; c ++; break;
+		case 'r': r = '\r'; c ++; break;
+		case 'f': r = '\f'; c ++; break;
+		case 'a': r = '\a'; c ++; break;
+		case '\\': r = '\\'; c ++; break;
+		case '\?': r = '\?'; c ++; break;
+		case '\'': r = '\''; c ++; break;
+		case '\"': r = '\"'; c ++; break;
+		case 'u':
+			for (i = 0, c ++; i < 4 && HEXAD(*c); i ++, c ++) {
+				r = (r * 16) + HVAL(*c);
+			}
+			if (i != 4) {
+				error(eval_line, "malformed UCN in %s", refc);
+				throw(eval_exception);
+			}
+			break;
+		case 'U':
+			for (i = 0, c ++; i < 8 && HEXAD(*c); i ++, c ++) {
+				r = (r * 16) + HVAL(*c);
+			}
+			if (i != 8) {
+				error(eval_line, "malformed UCN in %s", refc);
+				throw(eval_exception);
+			}
+			break;
+		case 'x':
+			for (c ++; HEXAD(*c); c ++) r = (r * 16) + HVAL(*c);
+			break;
+		default:
+			if (OCTAL(*c)) {
+				r = OVAL(*(c ++));
+				if (OCTAL(*c)) r = (r * 8) + OVAL(*(c ++));
+				if (OCTAL(*c)) r = (r * 8) + OVAL(*(c ++));
+			} else {
+				error(eval_line, "invalid escape sequence "
+					"'\\%c'", *c);
+				throw(eval_exception);
+			}
+		}
+	} else if (*c == '\'') {
+		error(eval_line, "empty character constant");
+		throw(eval_exception);
+	} else {
+		r = *((unsigned char *)(c ++));
+	}
+
+	if (transient_characters && r < 256) {
+		r = transient_characters[(size_t)r];
+	}
+
+	if (*c != '\'' && emit_eval_warnings) {
+		warning(eval_line, "multicharacter constant");
+	}
+	return r;
+}
+
+static ppval pp_strtoconst(char *refc)
+{
+	ppval q;
+	char *c = refc, *d;
+	int sign = 1;
+
+	if (*c == '\'' || *c == 'L') {
+		q.sign = (*c == 'L') ? WCHAR_SIGNEDNESS : 1;
+		if (*c == 'L') c ++;
+		if (q.sign) {
+			q.u.sv = to_slong(pp_char(c, refc));
+		} else {
+			q.u.uv = to_ulong(pp_char(c, refc));
+		}
+		return q;
+	}
+	for (d = c; *d; d ++) {
+		if (!HEXAD(*d) && *d != 'x' && *d != 'X') {
+			sign = pp_suffix(d, refc);
+			break;
+		}
+	}
+	if (*c == '0') {
+		c ++;
+		if (*c == 'x' || *c == 'X') {
+			/* hexadecimal constant */
+			c ++;
+			return pp_hexconst(c, sign, refc);
+		}
+		return pp_octconst(c, sign, refc);
+	}
+	return pp_decconst(c, sign, refc);
+}
+
+/*
+ * Used by #line directives -- anything beyond what can be put in an
+ * unsigned long, is considered absurd.
+ */
+unsigned long strtoconst(char *c)
+{
+	ppval q = pp_strtoconst(c);
+
+	if (q.sign) q.u.uv = op_promo(q.u.sv);
+	return back_ulong(q.u.uv);
+}
+
+#define OP_UN(x)	((x) == LNOT || (x) == NOT || (x) == UPLUS \
+			|| (x) == UMINUS)
+
+static ppval eval_opun(int op, ppval v)
+{
+	if (op == LNOT) {
+		v.sign = 1;
+		v.u.sv = to_slong(op_lnot_s(v.u.sv));
+		return v;
+	}
+	if (v.sign) {
+		switch (op) {
+		case NOT: v.u.sv = op_not_s(v.u.sv); break;
+		case UPLUS: v.u.sv = op_uplus_s(v.u.sv); break;
+		case UMINUS: v.u.sv = op_uminus_s(v.u.sv); break;
+		}
+	} else {
+		switch (op) {
+		case NOT: v.u.uv = op_not_u(v.u.uv); break;
+		case UPLUS: v.u.uv = op_uplus_u(v.u.uv); break;
+		case UMINUS: v.u.uv = op_uminus_u(v.u.uv); break;
+		}
+	}
+	return v;
+}
+
+#define OP_BIN(x)	((x) == STAR || (x) == SLASH || (x) == PCT \
+			|| (x) == PLUS || (x) == MINUS || (x) == LSH \
+			|| (x) == RSH || (x) == LT || (x) == LEQ \
+			|| (x) == GT || (x) == GEQ || (x) == SAME \
+			|| (x) == NEQ || (x) == AND || (x) == CIRC \
+			|| (x) == OR || (x) == LAND || (x) == LOR \
+			|| (x) == COMMA)
+static ppval eval_opbin(int op, ppval v1, ppval v2)
+{
+	ppval r;
+
+	switch (op) {
+	case STAR:	case SLASH:	case PCT:
+	case PLUS:	case MINUS:	case AND:
+	case CIRC:	case OR:
+		/* promote operands, adjust signedness of result */
+		if (!v1.sign || !v2.sign) {
+			if (v1.sign) {
+				v1.u.uv = op_promo(v1.u.sv);
+				v1.sign = 0;
+			} else if (v2.sign) {
+				v2.u.uv = op_promo(v2.u.sv);
+				v2.sign = 0;
+			}
+			r.sign = 0;
+		} else {
+			r.sign = 1;
+		}
+		break;
+	case LT:	case LEQ:	case GT:
+	case GEQ:	case SAME:	case NEQ:
+		/* promote operands */
+		if (!v1.sign || !v2.sign) {
+			if (v1.sign) {
+				v1.u.uv = op_promo(v1.u.sv);
+				v1.sign = 0;
+			} else if (v2.sign) {
+				v2.u.uv = op_promo(v2.u.sv);
+				v2.sign = 0;
+			}
+		}
+		/* fall through */
+	case LAND:
+	case LOR:
+		/* result is signed anyway */
+		r.sign = 1;
+		break;
+	case LSH:
+	case RSH:
+		/* result is as signed as left operand; promote right
+		   operand to unsigned (this is not required by the
+		   standard) */
+		r.sign = v1.sign;
+		if (v2.sign) {
+			v2.u.uv = op_promo(v2.u.sv);
+			v2.sign = 0;
+		}
+		break;
+	case COMMA:
+		if (emit_eval_warnings) {
+			warning(eval_line, "ISO C forbids evaluated comma "
+				"operators in #if expressions");
+		}
+		r.sign = v2.sign;
+		break;
+#ifdef AUDIT
+	default: ouch("a good operator is a dead operator");
+#endif
+	}
+
+#define SBINOP(x)	if (r.sign) r.u.sv = op_ ## x ## _s(v1.u.sv, v2.u.sv); \
+			else r.u.uv = op_ ## x ## _u(v1.u.uv, v2.u.uv);
+
+#define NSSBINOP(x)	if (v1.sign) r.u.sv = to_slong(op_ ## x ## _s(v1.u.sv, \
+			v2.u.sv)); else r.u.sv = to_slong(op_ ## x ## _u \
+			(v1.u.uv, v2.u.uv));
+
+#define LBINOP(x)	if (v1.sign) r.u.sv = to_slong(op_lval_s(v1.u.sv) x \
+			op_lval_s(v2.u.sv)); else r.u.sv = \
+			to_slong(op_lval_u(v1.u.uv) x op_lval_u(v2.u.uv));
+
+#define ABINOP(x)	if (r.sign) r.u.sv = op_ ## x ## _s(v1.u.sv, \
+			back_ulong(v2.u.uv)); else r.u.uv = \
+			op_ ## x ## _u(v1.u.uv, back_ulong(v2.u.uv));
+
+	switch (op) {
+	case STAR: SBINOP(star); break;
+	case SLASH: SBINOP(slash); break;
+	case PCT: SBINOP(pct); break;
+	case PLUS: SBINOP(plus); break;
+	case MINUS: SBINOP(minus); break;
+	case LSH: ABINOP(lsh); break;
+	case RSH: ABINOP(rsh); break;
+	case LT: NSSBINOP(lt); break;
+	case LEQ: NSSBINOP(leq); break;
+	case GT: NSSBINOP(gt); break;
+	case GEQ: NSSBINOP(geq); break;
+	case SAME: NSSBINOP(same); break;
+	case NEQ: NSSBINOP(neq); break;
+	case AND: SBINOP(and); break;
+	case CIRC: SBINOP(circ); break;
+	case OR: SBINOP(or); break;
+	case LAND: LBINOP(&&); break;
+	case LOR: LBINOP(||); break;
+	case COMMA: r = v2; break;
+	}
+	return r;
+}
+
+#define ttOP(x)		(OP_UN(x) || OP_BIN(x) || (x) == QUEST || (x) == COLON)
+
+static int op_prec(int op)
+{
+	switch (op) {
+	case LNOT:
+	case NOT:
+	case UPLUS:
+	case UMINUS:
+		return 13;
+	case STAR:
+	case SLASH:
+	case PCT:
+		return 12;
+	case PLUS:
+	case MINUS:
+		return 11;
+	case LSH:
+	case RSH:
+		return 10;
+	case LT:
+	case LEQ:
+	case GT:
+	case GEQ:
+		return 9;
+	case SAME:
+	case NEQ:
+		return 8;
+	case AND:
+		return 7;
+	case CIRC:
+		return 6;
+	case OR:
+		return 5;
+	case LAND:
+		return 4;
+	case LOR:
+		return 3;
+	case QUEST:
+		return 2;
+	case COMMA:
+		return 1;
+	}
+#ifdef AUDIT
+	ouch("an unknown species should have a higher precedence");
+#endif
+	return 666;
+}
+
+/*
+ * Perform the hard work of evaluation.
+ *
+ * This function works because:
+ * -- all unary operators are right to left associative, and with
+ *    identical precedence
+ * -- all binary operators are left to right associative
+ * -- there is only one non-unary and non-binary operator: the quest-colon
+ *
+ * If do_eval is 0, the evaluation of operators is not done. This is
+ * for sequence point operators (&&, || and ?:).
+ */
+static ppval eval_shrd(struct token_fifo *tf, int minprec, int do_eval)
+{
+	ppval top;
+	struct token *ct;
+
+	top.sign = 1;
+	if (tf->art == tf->nt) goto trunc_err;
+	ct = tf->t + (tf->art ++);
+	if (ct->type == LPAR) {
+		top = eval_shrd(tf, 0, do_eval);
+		if (tf->art == tf->nt) goto trunc_err;
+		ct = tf->t + (tf->art ++);
+		if (ct->type != RPAR) {
+			error(eval_line, "a right parenthesis was expected");
+			throw(eval_exception);
+		}
+	} else if (ct->type == NUMBER || ct->type == CHAR) {
+		top = pp_strtoconst(ct->name);
+	} else if (OP_UN(ct->type)) {
+		top = eval_opun(ct->type, eval_shrd(tf,
+			op_prec(ct->type), do_eval));
+		goto eval_loop;
+	} else if (ttOP(ct->type)) goto rogue_op_err;
+	else {
+		goto invalid_token_err;
+	}
+
+eval_loop:
+	if (tf->art == tf->nt) {
+		return top;
+	}
+	ct = tf->t + (tf->art ++);
+	if (OP_BIN(ct->type)) {
+		int bp = op_prec(ct->type);
+
+		if (bp > minprec) {
+			ppval tr;
+
+			if ((ct->type == LOR && boolval(top))
+				|| (ct->type == LAND && !boolval(top))) {
+				tr = eval_shrd(tf, bp, 0);
+				if (do_eval) {
+					top.sign = 1;
+					if (ct->type == LOR)
+						top.u.sv = to_slong(1);
+					if (ct->type == LAND)
+						top.u.sv = to_slong(0);
+				}
+			} else {
+				tr = eval_shrd(tf, bp, do_eval);
+				if (do_eval)
+					top = eval_opbin(ct->type, top, tr);
+			}
+			goto eval_loop;
+		}
+	} else if (ct->type == QUEST) {
+		int bp = op_prec(QUEST);
+		ppval r1, r2;
+
+		if (bp >= minprec) {
+			int qv = boolval(top);
+
+			r1 = eval_shrd(tf, bp, qv ? do_eval : 0);
+			if (tf->art == tf->nt) goto trunc_err;
+			ct = tf->t + (tf->art ++);
+			if (ct->type != COLON) {
+				error(eval_line, "a colon was expected");
+				throw(eval_exception);
+			}
+			r2 = eval_shrd(tf, bp, qv ? 0 : do_eval);
+			if (do_eval) {
+				if (qv) top = r1; else top = r2;
+			}
+			goto eval_loop;
+		}
+	}
+	tf->art --;
+	return top;
+
+trunc_err:
+	error(eval_line, "truncated constant integral expression");
+	throw(eval_exception);
+rogue_op_err:
+	error(eval_line, "rogue operator '%s' in constant integral "
+		"expression", operators_name[ct->type]);
+	throw(eval_exception);
+invalid_token_err:
+	error(eval_line, "invalid token in constant integral expression");
+	throw(eval_exception);
+}
+
+#define UNARY(x)	((x) != NUMBER && (x) != NAME && (x) != CHAR \
+			&& (x) != RPAR)
+
+/*
+ * Evaluate the integer expression contained in the given token_fifo.
+ * Evaluation is made by precedence of operators, as described in the
+ * Dragon Book. The unary + and - are distinguished from their binary
+ * counterparts using the Fortran way: a + or a - is considered unary
+ * if it does not follow a constant, an identifier or a right parenthesis.
+ */
+unsigned long eval_expr(struct token_fifo *tf, int *ret, int ew)
+{
+	size_t sart;
+	ppval r;
+
+	emit_eval_warnings = ew;
+	if (catch(eval_exception)) goto eval_err;
+	/* first, distinguish unary + and - from binary + and - */
+	for (sart = tf->art; tf->art < tf->nt; tf->art ++) {
+		if (tf->t[tf->art].type == PLUS) {
+			if (sart == tf->art || UNARY(tf->t[tf->art - 1].type))
+				tf->t[tf->art].type = UPLUS;
+		} else if (tf->t[tf->art].type == MINUS) {
+			if (sart == tf->art || UNARY(tf->t[tf->art - 1].type))
+				tf->t[tf->art].type = UMINUS;
+		}
+	}
+	tf->art = sart;
+	r = eval_shrd(tf, 0, 1);
+	if (tf->art < tf->nt) {
+		error(eval_line, "trailing garbage in constant integral "
+			"expression");
+		goto eval_err;
+	}
+	*ret = 0;
+	return boolval(r);
+eval_err:
+	*ret = 1;
+	return 0;
+}
diff --git a/ucpp/hash.c b/ucpp/hash.c
new file mode 100755
index 0000000..0e1669c
--- /dev/null
+++ b/ucpp/hash.c
@@ -0,0 +1,301 @@
+/*
+ * Generic hash table routines.
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+#include "hash.h"
+#include "mem.h"
+
+/*
+ * hash_string() is a sample hash function for strings
+ */
+int hash_string(char *s)
+{
+	unsigned char h = 0;
+
+	for (; *s; s ++) h ^= (unsigned char)(*s);
+	return ((int)h);
+}
+
+/*
+ * struct hash_item is the basic data type to internally handle hash tables
+ */
+struct hash_item {
+	void *data;
+	struct hash_item *next;
+};
+
+/*
+ * This function adds an entry to the struct hash_item list
+ */
+static struct hash_item *add_entry(struct hash_item *blist, void *data)
+{
+	struct hash_item *t = getmem(sizeof(struct hash_item));
+
+	t->data = data;
+	t->next = blist;
+	return t;
+}
+
+/*
+ * This function finds a struct hash_item in a list, using the
+ * comparison function provided as cmpdata (*cmpdata() returns
+ * non-zero if the two parameters are to be considered identical).
+ *
+ * It returns 0 if the item is not found.
+ */
+static struct hash_item *get_entry(struct hash_item *blist, void *data,
+	int (*cmpdata)(void *, void *))
+{
+	while (blist) {
+		if ((*cmpdata)(data, blist->data)) return blist;
+		blist = blist->next;
+	}
+	return 0;
+}
+
+/*
+ * This function acts like get_entry but deletes the found item, using
+ * the provided function deldata(); it returns 0 if the given data was
+ * not found.
+ */
+static struct hash_item *del_entry(struct hash_item *blist, void *data,
+	int (*cmpdata)(void *, void *), void (*deldata)(void *))
+{
+	struct hash_item *prev = 0, *save = blist;
+
+	while (blist) {
+		if ((*cmpdata)(data, blist->data)) {
+			(*deldata)(blist->data);
+			if (prev) prev->next = blist->next;
+			if (save == blist) save = blist->next;
+			freemem(blist);
+			return save;
+		}
+		prev = blist;
+		blist = blist->next;
+	}
+	return 0;
+}
+
+/*
+ * This function creates a new hashtable, with the hashing and comparison
+ * functions given as parameters
+ */
+struct HT *newHT(int n, int (*cmpdata)(void *, void *), int (*hash)(void *),
+	void (*deldata)(void *))
+{
+	struct HT *t = getmem(sizeof(struct HT));
+	int i;
+
+	t->lists = getmem(n * sizeof(struct hash_item *));
+	for (i = 0; i < n; i ++) t->lists[i] = 0;
+	t->nb_lists = n;
+	t->cmpdata = cmpdata;
+	t->hash = hash;
+	t->deldata = deldata;
+	return t;
+}
+
+/*
+ * This function adds a new entry in the hashtable ht; it returns 0
+ * on success, or a pointer to the already present item otherwise.
+ */
+void *putHT(struct HT *ht, void *data)
+{
+	int h;
+	struct hash_item *d;
+
+	h = ((*(ht->hash))(data)) % ht->nb_lists;
+	if ((d = get_entry(ht->lists[h], data, ht->cmpdata)))
+		return d->data;
+	ht->lists[h] = add_entry(ht->lists[h], data);
+	return 0;
+}
+
+/*
+ * This function adds a new entry in the hashtable ht, even if an equal
+ * entry is already there. Exercise caution !
+ * The new entry will "hide" the old one, which means that the new will be
+ * found upon lookup/delete, not the old one.
+ */
+void *forceputHT(struct HT *ht, void *data)
+{
+	int h;
+
+	h = ((*(ht->hash))(data)) % ht->nb_lists;
+	ht->lists[h] = add_entry(ht->lists[h], data);
+	return 0;
+}
+
+/*
+ * This function finds the entry corresponding to *data in the
+ * hashtable ht (using the comparison function given as argument
+ * to newHT)
+ */
+void *getHT(struct HT *ht, void *data)
+{
+	int h;
+	struct hash_item *t;
+
+	h = ((*(ht->hash))(data)) % ht->nb_lists;
+	if ((t = get_entry(ht->lists[h], data, ht->cmpdata)) == 0)
+		return 0;
+	return (t->data);
+}
+
+/*
+ * This function finds and delete the entry corresponding to *data
+ * in the hashtable ht (using the comparison function given as
+ * argument to newHT).
+ */
+
+int delHT(struct HT *ht, void *data)
+{
+	int h;
+
+	h = ((*(ht->hash))(data)) % ht->nb_lists;
+	ht->lists[h] = del_entry(ht->lists[h], data, ht->cmpdata, ht->deldata);
+	return 1;
+}
+
+/*
+ * This function duplicates a given hash table; the data is not copied
+ */
+struct HT *copyHT(struct HT *ht)
+{
+	struct HT *nht = newHT(ht->nb_lists, ht->cmpdata, ht->hash,
+		ht->deldata);
+	struct hash_item *t;
+	int i, j;
+
+	for (i = 0; i < nht->nb_lists; i ++) {
+		j = 0;
+		t = ht->lists[i];
+		while (t) {
+			t = t->next;
+			j ++;
+		}
+		if (j != 0) {
+			nht->lists[i] = getmem(j * sizeof(struct hash_item));
+			mmv(nht->lists[i], ht->lists[i],
+				j * sizeof(struct hash_item));
+		}
+	}
+	return nht;
+}
+
+/*
+ * This function completely eradicates from memory a given hash table,
+ * releasing all objects
+ */
+void killHT(struct HT *ht)
+{
+	int i;
+	struct hash_item *t, *n;
+
+	for (i = 0; i < ht->nb_lists; i ++) for (t = ht->lists[i]; t;) {
+		n = t->next;
+		(*(ht->deldata))(t->data);
+		freemem(t);
+		t = n;
+	}
+	freemem(ht);
+}
+
+/*
+ * This function stores a backup of the hash table, for context stacking
+ */
+void saveHT(struct HT *ht, void **buffer)
+{
+	struct hash_item **b = (struct hash_item **)buffer;
+	int i;
+
+	for (i = 0; i < ht->nb_lists; i ++) b[i] = ht->lists[i];
+}
+
+/*
+ * This function restores the saved state of the hash table.
+ * Do NOT use if some of the entries that were present before the backup
+ * have been removed (even temporarily).
+ */
+void restoreHT(struct HT *ht, void **buffer)
+{
+	struct hash_item **b = (struct hash_item **)buffer;
+	int i;
+
+	for (i = 0; i < ht->nb_lists; i ++) {
+		struct hash_item *t = ht->lists[i], *n;
+
+		while (t != b[i]) {
+			n = t->next;
+			(*(ht->deldata))(t->data);
+			freemem(t);
+			t = n;
+		}
+		ht->lists[i] = b[i];
+	}
+}
+
+/*
+ * This function scans the whole table and calls the given function on
+ * each entry.
+ */
+void scanHT(struct HT *ht, void (*action)(void *))
+{
+	int i;
+
+	for (i = 0; i < ht->nb_lists; i ++) {
+		struct hash_item *t = ht->lists[i];
+
+		while (t) {
+			(*action)(t->data);
+			t = t->next;
+		}
+	}
+}
+
+/*
+ * The two following fonctions are generic for storing structures
+ * uniquely identified by their name, which must be the first
+ * field of the structure.
+ */
+int hash_struct(void *m)
+{
+	char *n = *(char **)m;
+
+	return hash_string(n) & 127;
+}
+
+int cmp_struct(void *m1, void *m2)
+{
+	char *n1 = *(char **)m1, *n2 = *(char **)m2;
+
+	return !strcmp(n1, n2);
+}
diff --git a/ucpp/hash.h b/ucpp/hash.h
new file mode 100755
index 0000000..d15cbca
--- /dev/null
+++ b/ucpp/hash.h
@@ -0,0 +1,58 @@
+/*
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__HASH__
+#define UCPP__HASH__
+
+struct hash_item;
+
+struct HT {
+	struct hash_item **lists;
+	int nb_lists;
+	int (*cmpdata)(void *, void *);
+	int (*hash)(void *);
+	void (*deldata)(void *);
+};
+
+int hash_string(char *);
+struct HT *newHT(int, int (*)(void *, void *), int (*)(void *),
+	void (*)(void *));
+void *putHT(struct HT *, void *);
+void *forceputHT(struct HT *, void *);
+void *getHT(struct HT *, void *);
+int delHT(struct HT *, void *);
+struct HT *copyHT(struct HT *);
+void killHT(struct HT *);
+void saveHT(struct HT *, void **);
+void restoreHT(struct HT *, void **);
+void scanHT(struct HT *, void (*)(void *));
+int hash_struct(void *);
+int cmp_struct(void *, void *);
+
+#endif
diff --git a/ucpp/lexer.c b/ucpp/lexer.c
new file mode 100755
index 0000000..9e5ebae
--- /dev/null
+++ b/ucpp/lexer.c
@@ -0,0 +1,1050 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*vb*/
+#ifdef HAVE_MISRA
+extern int misracheck;
+void misra(int,...);
+void misra_neu(int, int, int, int, ...);
+#endif
+
+#include "tune.h"
+#ifdef UCPP_MMAP
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE	1
+#endif
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ctype.h>
+#include "ucppi.h"
+#include "mem.h"
+#ifdef UCPP_MMAP
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#endif
+
+/*
+ * Character classes for description of the automaton.
+ * The characters used for representing classes should not appear
+ * explicitely in an automaton rule.
+ */
+#define SPC	' '	/* whitespace characters */
+#define ALP	'Z'	/* A-Z, a-z, _ */
+#define NUM	'9'	/* 0-9 */
+#define ANY	'Y'	/* any character */
+#define VCH	'F'	/* void character (for end of input) */
+
+/*
+ * flags and macros to test those flags
+ * STO: the currently read string is a complete token
+ * PUT: the currently read character must be added to the string
+ * FRZ: the currently read character must be kept and read again
+ */
+#define MOD_MK		255
+#define noMOD(x)	((x) & 255)
+#define STO(x)		((x) | 256)
+#define ttSTO(x)	((x) & 256)
+#define FRZ(x)		((x) | 512)
+#define ttFRZ(x)	((x) & 512)
+#define PUT(x)		((x) | 1024)
+#define ttPUT(x)	((x) & 1024)
+
+/* order is important */
+enum {
+	S_START, S_SPACE, S_BANG, S_STRING, S_STRING2, S_COLON,
+	S_SHARP, S_PCT, S_PCT2, S_PCT3, S_AMPER, S_CHAR, S_CHAR2, S_STAR,
+	S_PLUS, S_MINUS, S_DOT, S_DOT2, S_SLASH, S_NUMBER, S_NUMBER2, S_LT,
+	S_LT2, S_EQ, S_GT, S_GT2, S_CIRC, S_PIPE, S_TILDE, S_BACKSLASH,
+	S_COMMENT, S_COMMENT2, S_COMMENT3, S_COMMENT4, S_COMMENT5,
+	S_NAME, S_NAME_BS, S_LCHAR,
+	MSTATE,
+	S_ILL, S_DDOT, S_DDSHARP, S_BS, S_ROGUE_BS, S_BEHEAD, S_DECAY,
+	S_TRUNC, S_TRUNCC, S_OUCH
+};
+
+#define CMT(x)		((x) >= S_COMMENT && (x) <= S_COMMENT5)
+
+#define CMCR	2
+
+/*
+ * This is the description of the automaton. It is not used "as is"
+ * but copied at execution time into a table.
+ *
+ * To my utmost displeasure, there are a few hacks in read_token()
+ * (which uses the transformed automaton) about the special handling
+ * of slashes, sharps, and the letter L.
+ */
+static struct machine_state {
+	int state;
+	unsigned char input[CMCR];
+	int new_state;
+} cppms[] = {
+	/* S_START is the generic beginning state */
+	{ S_START,	{ ANY },	S_ILL			},
+#ifdef SEMPER_FIDELIS
+	{ S_START,	{ SPC },	PUT(S_SPACE)		},
+#else
+	{ S_START,	{ SPC },	S_SPACE			},
+#endif
+	{ S_START,	{ '\n' },	STO(NEWLINE)		},
+	{ S_START,	{ '!' },	S_BANG			},
+	{ S_START,	{ '"' },	PUT(S_STRING)		},
+	{ S_START,	{ '#' },	S_SHARP			},
+	{ S_START,	{ '%' },	S_PCT			},
+	{ S_START,	{ '&' },	S_AMPER			},
+	{ S_START,	{ '\'' },	PUT(S_CHAR)		},
+	{ S_START,	{ '(' },	STO(LPAR)		},
+	{ S_START,	{ ')' },	STO(RPAR)		},
+	{ S_START,	{ '*' },	S_STAR			},
+	{ S_START,	{ '+' },	S_PLUS			},
+	{ S_START,	{ ',' },	STO(COMMA)		},
+	{ S_START,	{ '-' },	S_MINUS			},
+	{ S_START,	{ '.' },	PUT(S_DOT)		},
+#ifdef SEMPER_FIDELIS
+	{ S_START,	{ '/' },	PUT(S_SLASH)		},
+#else
+	{ S_START,	{ '/' },	S_SLASH			},
+#endif
+	{ S_START,	{ NUM },	PUT(S_NUMBER)		},
+#ifdef HAVE_ECPP
+	{ S_START,	{ '@' },	S_COLON			},
+	{ S_START,	{ ':' },	PUT(S_NAME)		},
+#else
+	{ S_START,	{ ':' },	S_COLON			},
+#endif
+	{ S_START,	{ ';' },	STO(SEMIC)		},
+	{ S_START,	{ '<' },	S_LT			},
+	{ S_START,	{ '=' },	S_EQ			},
+	{ S_START,	{ '>' },	S_GT			},
+	{ S_START,	{ '?' },	STO(QUEST)		},
+	{ S_START,	{ ALP },	PUT(S_NAME)		},
+	{ S_START,	{ 'L' },	PUT(S_LCHAR)		},
+	{ S_START,	{ '[' },	STO(LBRK)		},
+	{ S_START,	{ ']' },	STO(RBRK)		},
+	{ S_START,	{ '^' },	S_CIRC			},
+	{ S_START,	{ '{' },	STO(LBRA)		},
+	{ S_START,	{ '|' },	S_PIPE			},
+	{ S_START,	{ '}' },	STO(RBRA)		},
+	{ S_START,	{ '~' },	S_TILDE			},
+	{ S_START,	{ '\\' },	S_BACKSLASH		},
+
+	/* after a space */
+	{ S_SPACE,	{ ANY },	FRZ(STO(NONE))		},
+#ifdef SEMPER_FIDELIS
+	{ S_SPACE,	{ SPC },	PUT(S_SPACE)		},
+#else
+	{ S_SPACE,	{ SPC },	S_SPACE			},
+#endif
+
+	/* after a ! */
+	{ S_BANG,	{ ANY },	FRZ(STO(LNOT))		},
+	{ S_BANG,	{ '=' },	STO(NEQ)		},
+
+	/* after a " */
+	{ S_STRING,	{ ANY },	PUT(S_STRING)		},
+	{ S_STRING,	{ VCH },	FRZ(S_TRUNC)		},
+	{ S_STRING,	{ '\n' },	FRZ(S_BEHEAD)		},
+	{ S_STRING,	{ '\\' },	PUT(S_STRING2)		},
+	{ S_STRING,	{ '"' },	PUT(STO(STRING))	},
+
+	{ S_STRING2,	{ ANY },	PUT(S_STRING)		},
+	{ S_STRING2,	{ VCH },	FRZ(S_TRUNC)		},
+
+	/* after a # */
+	{ S_SHARP,	{ ANY },	FRZ(STO(SHARP))		},
+	{ S_SHARP,	{ '#' },	STO(DSHARP)		},
+
+	/* after a : */
+	{ S_COLON,	{ ANY },	FRZ(STO(COLON))		},
+	{ S_COLON,	{ '>' },	STO(DIG_RBRK)		},
+
+	/* after a % */
+	{ S_PCT,	{ ANY },	FRZ(STO(PCT))		},
+	{ S_PCT,	{ '=' },	STO(ASPCT)		},
+	{ S_PCT,	{ '>' },	STO(DIG_RBRA)		},
+	{ S_PCT,	{ ':' },	S_PCT2			},
+
+	/* after a %: */
+	{ S_PCT2,	{ ANY },	FRZ(STO(DIG_SHARP))	},
+	{ S_PCT2,	{ '%' },	S_PCT3			},
+
+	/* after a %:% */
+	{ S_PCT3,	{ ANY },	FRZ(S_DDSHARP)		},
+	{ S_PCT3,	{ ':' },	STO(DIG_DSHARP)		},
+
+	/* after a & */
+	{ S_AMPER,	{ ANY },	FRZ(STO(AND))		},
+	{ S_AMPER,	{ '=' },	STO(ASAND)		},
+	{ S_AMPER,	{ '&' },	STO(LAND)		},
+
+	/* after a ' */
+	{ S_CHAR,	{ ANY },	PUT(S_CHAR)		},
+	{ S_CHAR,	{ VCH },	FRZ(S_TRUNC)		},
+	{ S_CHAR,	{ '\'' },	PUT(STO(CHAR))		},
+	{ S_CHAR,	{ '\\' },	PUT(S_CHAR2)		},
+
+	/* after a \ in a character constant
+	   useful only for '\'' */
+	{ S_CHAR2,	{ ANY },	PUT(S_CHAR)		},
+	{ S_CHAR2,	{ VCH },	FRZ(S_TRUNC)		},
+
+	/* after a * */
+	{ S_STAR,	{ ANY },	FRZ(STO(STAR))		},
+	{ S_STAR,	{ '=' },	STO(ASSTAR)		},
+
+	/* after a + */
+	{ S_PLUS,	{ ANY },	FRZ(STO(PLUS))		},
+	{ S_PLUS,	{ '+' },	STO(PPLUS)		},
+	{ S_PLUS,	{ '=' },	STO(ASPLUS)		},
+
+	/* after a - */
+	{ S_MINUS,	{ ANY },	FRZ(STO(MINUS))		},
+	{ S_MINUS,	{ '-' },	STO(MMINUS)		},
+	{ S_MINUS,	{ '=' },	STO(ASMINUS)		},
+	{ S_MINUS,	{ '>' },	STO(ARROW)		},
+
+	/* after a . */
+	{ S_DOT,	{ ANY },	FRZ(STO(DOT))		},
+	{ S_DOT,	{ NUM },	PUT(S_NUMBER)		},
+	{ S_DOT,	{ '.' },	S_DOT2			},
+
+	/* after .. */
+	{ S_DOT2,	{ ANY },	FRZ(S_DDOT)		},
+	{ S_DOT2,	{ '.' },	STO(MDOTS)		},
+
+	/* after a / */
+	{ S_SLASH,	{ ANY },	FRZ(STO(SLASH))		},
+	{ S_SLASH,	{ '=' },	STO(ASSLASH)		},
+#ifdef SEMPER_FIDELIS
+	{ S_SLASH,	{ '*' },	PUT(S_COMMENT)		},
+	{ S_SLASH,	{ '/' },	PUT(S_COMMENT5)		},
+#else
+	{ S_SLASH,	{ '*' },	S_COMMENT		},
+	{ S_SLASH,	{ '/' },	S_COMMENT5		},
+#endif
+	/*
+	 * There is a little hack in read_token() to disable
+	 * this last rule, if C++ (C99) comments are not enabled.
+	 */
+
+	/* after a number */
+	{ S_NUMBER,	{ ANY },	FRZ(STO(NUMBER))	},
+	{ S_NUMBER,	{ ALP, NUM },	PUT(S_NUMBER)		},
+	{ S_NUMBER,	{ '.' },	PUT(S_NUMBER)		},
+	{ S_NUMBER,	{ 'E', 'e' },	PUT(S_NUMBER2)		},
+	{ S_NUMBER,	{ 'P', 'p' },	PUT(S_NUMBER2)		},
+
+	{ S_NUMBER2,	{ ANY },	FRZ(STO(NUMBER))	},
+	{ S_NUMBER2,	{ ALP, NUM },	PUT(S_NUMBER)		},
+	{ S_NUMBER2,	{ '+', '-' },	PUT(S_NUMBER)		},
+
+	/* after a < */
+	{ S_LT,		{ ANY },	FRZ(STO(LT))		},
+	{ S_LT,		{ '=' },	STO(LEQ)		},
+	{ S_LT,		{ '<' },	S_LT2			},
+	{ S_LT,		{ ':' },	STO(DIG_LBRK)		},
+	{ S_LT,		{ '%' },	STO(DIG_LBRA)		},
+
+	{ S_LT2,	{ ANY },	FRZ(STO(LSH))		},
+	{ S_LT2,	{ '=' },	STO(ASLSH)		},
+
+	/* after a > */
+	{ S_GT,		{ ANY },	FRZ(STO(GT))		},
+	{ S_GT,		{ '=' },	STO(GEQ)		},
+	{ S_GT,		{ '>' },	S_GT2			},
+
+	{ S_GT2,	{ ANY },	FRZ(STO(RSH))		},
+	{ S_GT2,	{ '=' },	STO(ASRSH)		},
+
+	/* after a = */
+	{ S_EQ,		{ ANY },	FRZ(STO(ASGN))		},
+	{ S_EQ,		{ '=' },	STO(SAME)		},
+#ifdef CAST_OP
+	{ S_EQ,		{ '>' },	STO(CAST)		},
+#endif
+
+	/* after a \ */
+	{ S_BACKSLASH,	{ ANY },	FRZ(S_BS)		},
+	{ S_BACKSLASH,	{ 'U', 'u' },	FRZ(S_NAME_BS)		},
+
+	/* after a letter */
+	{ S_NAME,	{ ANY },	FRZ(STO(NAME))		},
+	{ S_NAME,	{ ALP, NUM },	PUT(S_NAME)		},
+	{ S_NAME,	{ '\\' },	S_NAME_BS		},
+#ifdef HAVE_ECPP
+	{ S_NAME,	{ ':' },	PUT(S_NAME)		},
+#endif
+
+	/* after a \ in an identifier */
+	{ S_NAME_BS,	{ ANY },	FRZ(S_ROGUE_BS)		},
+	{ S_NAME_BS,	{ 'u', 'U' },	PUT(S_NAME)		},
+
+	/* after a L */
+	{ S_LCHAR,	{ ANY },	FRZ(S_NAME)		},
+	{ S_LCHAR,	{ '"' },	PUT(S_STRING)		},
+	{ S_LCHAR,	{ '\'' },	PUT(S_CHAR)		},
+
+	/* after a ^ */
+	{ S_CIRC,	{ ANY },	FRZ(STO(CIRC))		},
+	{ S_CIRC,	{ '=' },	STO(ASCIRC)		},
+
+	/* after a | */
+	{ S_PIPE,	{ ANY },	FRZ(STO(OR))		},
+	{ S_PIPE,	{ '=' },	STO(ASOR)		},
+	{ S_PIPE,	{ '|' },	STO(LOR)		},
+
+	/* after a ~ */
+	{ S_TILDE,	{ ANY },	FRZ(STO(NOT))		},
+	{ S_TILDE,	{ '=' },	STO(ASNOT)		},
+
+	/* after a / and * */
+#ifdef SEMPER_FIDELIS
+	{ S_COMMENT,	{ ANY },	PUT(S_COMMENT)		},
+	{ S_COMMENT,	{ VCH },	FRZ(S_TRUNCC)		},
+	{ S_COMMENT,	{ '*' },	PUT(S_COMMENT2)		},
+
+	{ S_COMMENT2,	{ ANY },	FRZ(S_COMMENT)		},
+	{ S_COMMENT2,	{ VCH },	FRZ(S_TRUNCC)		},
+	{ S_COMMENT2,	{ '*' },	PUT(S_COMMENT2)		},
+	{ S_COMMENT2,	{ '/' },	STO(PUT(COMMENT))	},
+
+	{ S_COMMENT5,	{ ANY },	PUT(S_COMMENT5)		},
+	{ S_COMMENT5,	{ VCH },	FRZ(S_DECAY)		},
+	{ S_COMMENT5,	{ '\n' },	FRZ(STO(COMMENT))	},
+#else
+	{ S_COMMENT,	{ ANY },	S_COMMENT		},
+	{ S_COMMENT,	{ VCH },	FRZ(S_TRUNCC)		},
+	{ S_COMMENT,	{ '*' },	S_COMMENT2		},
+
+	{ S_COMMENT2,	{ ANY },	FRZ(S_COMMENT)		},
+	{ S_COMMENT2,	{ VCH },	FRZ(S_TRUNCC)		},
+	{ S_COMMENT2,	{ '*' },	S_COMMENT2		},
+	{ S_COMMENT2,	{ '/' },	STO(COMMENT)		},
+
+	{ S_COMMENT5,	{ ANY },	S_COMMENT5		},
+	{ S_COMMENT5,	{ VCH },	FRZ(S_DECAY)		},
+	{ S_COMMENT5,	{ '\n' },	FRZ(STO(COMMENT))	},
+#endif
+
+	/* dummy end of machine description */
+	{ 0,		{ 0 },		0			}
+};
+
+/*
+ * cppm is the table used to store the automaton: if we are in state s
+ * and we read character c, we apply the action cppm[s][c] (jumping to
+ * another state, or emitting a token).
+ * cppm_vch is the table for the special virtual character "end of input"
+ */
+static int cppm[MSTATE][MAX_CHAR_VAL];
+static int cppm_vch[MSTATE];
+
+/*
+ * init_cppm() fills cppm[][] with the information stored in cppms[].
+ * It must be called before beginning the lexing process.
+ */
+void init_cppm(void)
+{
+	int i, j, k, c;
+	static unsigned char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	static unsigned char lower[] = "abcdefghijklmnopqrstuvwxyz";
+	unsigned char *cp;
+
+	for (i = 0; i < MSTATE; i ++) {
+		for (j = 0; j < MAX_CHAR_VAL; j ++) cppm[i][j] = S_OUCH;
+		cppm_vch[i] = S_OUCH;
+	}
+	for (i = 0; cppms[i].input[0]; i ++) for (k = 0; k < CMCR; k ++) {
+		int s = cppms[i].state;
+		int ns = cppms[i].new_state;
+
+		switch (c = cppms[i].input[k]) {
+		case 0:
+			break;
+		case SPC:
+			/* see space_char() also */
+			cppm[s][' '] = ns;
+			cppm[s]['\t'] = ns;
+			cppm[s]['\v'] = ns;
+			cppm[s]['\f'] = ns;
+#ifdef UNBREAKABLE_SPACE
+			if (MAX_CHAR_VAL > UNBREAKABLE_SPACE)
+				cppm[s][UNBREAKABLE_SPACE] = ns;
+#endif
+			break;
+		case ALP:
+			for (cp = upper; *cp; cp ++) cppm[s][(int)*cp] = ns;
+			for (cp = lower; *cp; cp ++) cppm[s][(int)*cp] = ns;
+			cppm[s]['_'] = ns;
+			break;
+		case NUM:
+			for (j = '0'; j <= '9'; j ++) cppm[s][j] = ns;
+			break;
+		case ANY:
+			for (j = 0; j < MAX_CHAR_VAL; j ++) cppm[s][j] = ns;
+			cppm_vch[s] = ns;
+			break;
+		case VCH:
+			cppm_vch[s] = ns;
+			break;
+		default:
+			cppm[s][c] = ns;
+			break;
+		}
+	}
+}
+
+int space_char(int c)
+{
+	if (c == ' ' || c == '\t' || c == '\v' || c == '\f'
+#ifdef UNBREAKABLE_SPACE
+		|| c == UNBREAKABLE_SPACE
+#endif
+		) return 1;
+	return 0;
+}
+
+#ifndef NO_UCPP_BUF
+/*
+ * our output buffer is full, flush it
+ */
+void flush_output(struct lexer_state *ls)
+{
+	size_t x = ls->sbuf, y = 0, z;
+
+	if (ls->sbuf == 0) return;
+	do {
+		z = fwrite(ls->output_buf + y, 1, x, ls->output);
+		x -= z;
+		y += z;
+	} while (z && x > 0);
+	if (!y) {
+		error(ls->line, "could not flush output (disk full ?)");
+		die();
+	}
+	ls->sbuf = 0;
+}
+#endif
+
+/*
+ * Output one character; flush the buffer if needed.
+ * This function should not be called, except by put_char().
+ */
+static inline void write_char(struct lexer_state *ls, unsigned char c)
+{
+#ifndef NO_UCPP_BUF
+	ls->output_buf[ls->sbuf ++] = c;
+	if (ls->sbuf == OUTPUT_BUF_MEMG) flush_output(ls);
+#else
+	if (putc((int)c, ls->output) == EOF) {
+		error(ls->line, "output write error (disk full ?)");
+		die();
+	}
+#endif
+	if (c == '\n') {
+		ls->oline ++;
+	}
+}
+
+/*
+ * schedule a character for output
+ */
+void put_char(struct lexer_state *ls, unsigned char c)
+{
+	if (ls->flags & KEEP_OUTPUT) write_char(ls, c);
+}
+
+/*
+ * get next raw input character
+ */
+static inline int read_char(struct lexer_state *ls)
+{
+	unsigned char c;
+
+	if (!ls->input) {
+		return ((ls->pbuf ++) < ls->ebuf) ?
+			ls->input_string[ls->pbuf - 1] : -1;
+	}
+	while (1) {
+#ifndef NO_UCPP_BUF
+		if (ls->pbuf == ls->ebuf) {
+#ifdef UCPP_MMAP
+			if (ls->from_mmap) {
+				munmap((void *)ls->input_buf, ls->ebuf);
+				ls->from_mmap = 0;
+				ls->input_buf = ls->input_buf_sav;
+			}
+#endif
+			ls->ebuf = fread(ls->input_buf, 1,
+				INPUT_BUF_MEMG, ls->input);
+			ls->pbuf = 0;
+		}
+		if (ls->ebuf == 0) return -1;
+		c = ls->input_buf[ls->pbuf ++];
+#else
+		int x = getc(ls->input);
+
+		if (x == EOF) return -1;
+		c = x;
+#endif
+		if (ls->flags & COPY_LINE) {
+			if (c == '\n') {
+				ls->copy_line[ls->cli] = 0;
+				ls->cli = 0;
+			} else if (ls->cli < (COPY_LINE_LENGTH - 1)) {
+				ls->copy_line[ls->cli ++] = c;
+			}
+		}
+		if (ls->macfile && c == '\n') {
+			ls->macfile = 0;
+			continue;
+		}
+		ls->macfile = 0;
+		if (c == '\r') {
+			/*
+			 * We found a '\r'; we handle it as a newline
+			 * and ignore the next newline. This should work
+			 * with all combinations of Msdos, MacIntosh and
+			 * Unix files on these three platforms. On other
+			 * platforms, native file formats are always
+			 * supported.
+			 */
+			ls->macfile = 1;
+			c = '\n';
+		}
+		break;
+	}
+	/*vb*/
+#ifdef HAVE_MISRA
+	if(misracheck){
+	  if(!isspace((unsigned char)c)&&
+	     (c<'A'||c>'Z')&&
+	     (c<'a'||c>'z')&&
+	     (c<'0'||c>'9')&&
+	     c!='!'&&c!='\"'&&c!='#'&&c!='%'&&c!='&'&&c!='\''&&c!='('&&c!=')'&&
+	     c!='*'&&c!='+'&&c!=','&&c!='-'&&c!='.'&&c!='/'&&c!=':'&&
+	     c!=';'&&c!='<'&&c!='='&&c!='>'&&c!='?'&&c!='['&&c!=']'&&
+	     c!='^'&&c!='_'&&c!='{'&&c!='|'&&c!='}'&&c!='~'&&c!='\\'
+	     )
+	    misra_neu(5,4,1,ls->line,c,' ');
+	}
+#endif
+	return c;
+}
+
+/*
+ * next_fifo_char(), char_lka1() and char_lka2() give a two character
+ * look-ahead on the input stream; this is needed for trigraphs
+ */
+static inline int next_fifo_char(struct lexer_state *ls)
+{
+	int c;
+
+	if (ls->nlka != 0) {
+		c = ls->lka[0];
+		ls->lka[0] = ls->lka[1];
+		ls->nlka --;
+	} else c = read_char(ls);
+	return c;
+}
+
+static inline int char_lka1(struct lexer_state *ls)
+{
+	if (ls->nlka == 0) {
+		ls->lka[0] = read_char(ls);
+		ls->nlka ++;
+	}
+	return ls->lka[0];
+}
+
+static inline int char_lka2(struct lexer_state *ls)
+{
+#ifdef AUDIT
+	if (ls->nlka == 0) ouch("always in motion future is");
+#endif
+	if (ls->nlka == 1) {
+		ls->lka[1] = read_char(ls);
+		ls->nlka ++;
+	}
+	return ls->lka[1];
+}
+
+static struct trigraph {
+	int old, new;
+} trig[9] = {
+	{ '=', '#' },
+	{ '/', '\\' },
+	{ '\'', '^' },
+	{ '(', '[' },
+	{ ')', ']' },
+	{ '!', '|' },
+	{ '<', '{' },
+	{ '>', '}' },
+	{ '-', '~' }
+};
+
+/*
+ * Returns the next character, after treatment of trigraphs and terminating
+ * backslashes. Return value is -1 if there is no more input.
+ */
+static inline int next_char(struct lexer_state *ls)
+{
+	int c;
+
+	if (!ls->discard) return ls->last;
+	ls->discard = 0;
+	do {
+		c = next_fifo_char(ls);
+#ifdef HAVE_ECPP
+		if(c==':'){
+			if(char_lka1(ls)==':'){
+				next_fifo_char(ls);
+			}else{
+				c='@';
+			}
+		}
+#endif
+		/* check trigraphs */
+		if (c == '?' && char_lka1(ls) == '?'
+			&& (ls->flags & HANDLE_TRIGRAPHS)) {
+			int i, d;
+
+			d = char_lka2(ls);
+			for (i = 0; i < 9; i ++) if (d == trig[i].old) {
+				if (ls->flags & WARN_TRIGRAPHS) {
+					ls->count_trigraphs ++;
+				}
+				if (ls->flags & WARN_TRIGRAPHS_MORE) {
+					warning(ls->line, "trigraph ?""?%c "
+						"encountered", d);
+					/*vb*/
+#ifdef HAVE_MISRA
+					misra_neu(7,4,2,-1,d);
+#endif
+				}
+				next_fifo_char(ls);
+				next_fifo_char(ls);
+				c = trig[i].new;
+				break;
+			}
+		}
+		if (c == '\\' && char_lka1(ls) == '\n') {
+			ls->line ++;
+			next_fifo_char(ls);
+		} else {
+			ls->last = c;
+			return c;
+		}
+	} while (1);
+}
+
+/*
+ * wrapper for next_char(), to be called from outside
+ * (used by #error, #include directives)
+ */
+int grap_char(struct lexer_state *ls)
+{
+	return next_char(ls);
+}
+
+/*
+ * Discard the current character, so that the next call to next_char()
+ * will step into the input stream.
+ */
+void discard_char(struct lexer_state *ls)
+{
+#ifdef AUDIT
+	if (ls->discard) ouch("overcollecting garbage");
+#endif
+	ls->discard = 1;
+	ls->utf8 = 0;
+	if (ls->last == '\n') ls->line ++;
+}
+
+/*
+ * Convert an UTF-8 encoded character to a Universal Character Name
+ * using \u (or \U when appropriate).
+ */
+static int utf8_to_string(unsigned char buf[], unsigned long utf8)
+{
+	unsigned long val = 0;
+	static char hex[16] = "0123456789abcdef";
+
+	if (utf8 & 0x80UL) {
+		unsigned long x1, x2, x3, x4;
+
+		x1 = (utf8 >> 24) & 0x7fUL;
+		x2 = (utf8 >> 16) & 0x7fUL;
+		x3 = (utf8 >> 8) & 0x7fUL;
+		x4 = (utf8) & 0x3fUL;
+		x1 &= 0x07UL;
+		if (x2 & 0x40UL) x2 &= 0x0fUL;
+		if (x3 & 0x40UL) x3 &= 0x1fUL;
+		val = x4 | (x3 << 6) | (x2 << 12) | (x1 << 16);
+	} else val = utf8;
+	if (val < 128) {
+		buf[0] = val;
+		buf[1] = 0;
+		return 1;
+	} else if (val < 0xffffUL) {
+		buf[0] = '\\';
+		buf[1] = 'u';
+		buf[2] = hex[(size_t)(val >> 12)];
+		buf[3] = hex[(size_t)((val >> 8) & 0xfU)];
+		buf[4] = hex[(size_t)((val >> 4) & 0xfU)];
+		buf[5] = hex[(size_t)(val & 0xfU)];
+		buf[6] = 0;
+		return 6;
+	}
+	buf[0] = '\\';
+	buf[1] = 'U';
+	buf[2] = '0';
+	buf[3] = '0';
+	buf[4] = hex[(size_t)(val >> 20)];
+	buf[5] = hex[(size_t)((val >> 16) & 0xfU)];
+	buf[6] = hex[(size_t)((val >> 12) & 0xfU)];
+	buf[7] = hex[(size_t)((val >> 8) & 0xfU)];
+	buf[8] = hex[(size_t)((val >> 4) & 0xfU)];
+	buf[9] = hex[(size_t)(val & 0xfU)];
+	buf[10] = 0;
+	return 10;
+}
+
+/*
+ * Scan the identifier and put it in canonical form:
+ *  -- tranform \U0000xxxx into \uxxxx
+ *  -- inside \u and \U, make letters low case
+ *  -- report (some) incorrect use of UCN
+ */
+static void canonize_id(struct lexer_state *ls, char *id)
+{
+	char *c, *d;
+
+	for (c = d = id; *c;) {
+		if (*c == '\\') {
+			int i;
+
+			if (!*(c + 1)) goto canon_error;
+			if (*(c + 1) == 'U') {
+				for (i = 0; i < 8 && *(c + i + 2); i ++);
+				if (i != 8) goto canon_error;
+				*(d ++) = '\\';
+				c += 2;
+				for (i = 0; i < 4 && *(c + i) == '0'; i ++);
+				if (i == 4) {
+					*(d ++) = 'u';
+					c += 4;
+				} else {
+					*(d ++) = 'U';
+					i = 8;
+				}
+				for (; i > 0; i --) {
+					switch (*c) {
+					case 'A': *(d ++) = 'a'; break;
+					case 'B': *(d ++) = 'b'; break;
+					case 'C': *(d ++) = 'c'; break;
+					case 'D': *(d ++) = 'd'; break;
+					case 'E': *(d ++) = 'e'; break;
+					case 'F': *(d ++) = 'f'; break;
+					default: *(d ++) = *c; break;
+					}
+					c ++;
+				}
+			} else if (*(c + 1) == 'u') {
+				for (i = 0; i < 4 && *(c + i + 2); i ++);
+				if (i != 4) goto canon_error;
+				*(d ++) = '\\';
+				*(d ++) = 'u';
+				c += 2;
+				for (; i > 0; i --) {
+					switch (*c) {
+					case 'A': *(d ++) = 'a'; break;
+					case 'B': *(d ++) = 'b'; break;
+					case 'C': *(d ++) = 'c'; break;
+					case 'D': *(d ++) = 'd'; break;
+					case 'E': *(d ++) = 'e'; break;
+					case 'F': *(d ++) = 'f'; break;
+					default: *(d ++) = *c; break;
+					}
+					c ++;
+				}
+			} else goto canon_error;
+			continue;
+		}
+		*(d ++) = *(c ++);
+	}
+	*d = 0;
+	return;
+
+canon_error:
+	for (; *c; *(d ++) = *(c ++));
+	if (ls->flags & WARN_STANDARD) {
+		warning(ls->line, "malformed identifier with UCN: '%s'", id);
+	}
+	*d = 0;
+}
+
+/*
+ * Run the automaton, in order to get the next token.
+ * This function should not be called, except by next_token()
+ *
+ * return value: 1 on error, 2 on end-of-file, 0 otherwise.
+ */
+static inline int read_token(struct lexer_state *ls)
+{
+	int cstat = S_START, nstat;
+	size_t ltok = 0;
+	int c, outc = 0, ucn_in_id = 0;
+	int shift_state;
+	unsigned long utf8;
+	long l = ls->line;
+
+	ls->ctok->line = l;
+	if (ls->pending_token) {
+		if ((ls->ctok->type = ls->pending_token) == BUNCH) {
+			ls->ctok->name[0] = '\\';
+			ls->ctok->name[1] = 0;
+		}
+		ls->pending_token = 0;
+		return 0;
+	}
+	if (ls->flags & UTF8_SOURCE) {
+		utf8 = ls->utf8;
+		shift_state = 0;
+	}
+	if (!(ls->flags & LEXER) && (ls->flags & KEEP_OUTPUT))
+		for (; ls->line > ls->oline;) put_char(ls, '\n');
+	do {
+		c = next_char(ls);
+		if (c < 0) {
+			if ((ls->flags & UTF8_SOURCE) && shift_state) {
+				if (ls->flags & WARN_STANDARD)
+					warning(ls->line, "truncated UTF-8 "
+						"character");
+				shift_state = 0;
+				utf8 = 0;
+			}
+			if (cstat == S_START) return 2;
+			nstat = cppm_vch[cstat];
+		} else {
+			if (ls->flags & UTF8_SOURCE) {
+				if (shift_state) {
+					if ((c & 0xc0) != 0x80) {
+						if (ls->flags & WARN_STANDARD)
+							warning(ls->line,
+								"truncated "
+								"UTF-8 "
+								"character");
+						shift_state = 0;
+						utf8 = 0;
+						c = '_';
+					} else {
+						utf8 = (utf8 << 8) | c;
+						if (-- shift_state) {
+							ls->discard = 1;
+							continue;
+						}
+						c = '_';
+					}
+				} else if ((c & 0xc0) == 0xc0) {
+					if ((c & 0x30) == 0x30) {
+						shift_state = 3;
+					} else if (c & 0x20) {
+						shift_state = 2;
+					} else {
+						shift_state = 1;
+					}
+					utf8 = c;
+					ls->discard = 1;
+					continue;
+				} else utf8 = 0;
+			}
+			nstat = cppm[cstat][c < MAX_CHAR_VAL ? c : 0];
+		}
+#ifdef AUDIT
+		if (nstat == S_OUCH) {
+			ouch("bad move...");
+		}
+#endif
+		/*
+		 * disable C++-like comments
+		 */
+		if (nstat == S_COMMENT5 && !(ls->flags & CPLUSPLUS_COMMENTS))
+			nstat = FRZ(STO(SLASH));
+
+		if (noMOD(nstat) >= MSTATE && !ttSTO(nstat))
+			switch (noMOD(nstat)) {
+		case S_ILL:
+			if (ls->flags & CCHARSET) {
+				error(ls->line, "illegal character '%c'", c);
+				return 1;
+			}
+			nstat = PUT(STO(BUNCH));
+			break;
+		case S_BS:
+			ls->ctok->name[0] = '\\';
+			ltok ++;
+			nstat = FRZ(STO(BUNCH));
+			if (!(ls->flags & LEXER)) put_char(ls, '\\');
+			break;
+		case S_ROGUE_BS:
+			ls->pending_token = BUNCH;
+			nstat = FRZ(STO(NAME));
+			break;
+		case S_DDOT:
+			ls->pending_token = DOT;
+			nstat = FRZ(STO(DOT));
+			break;
+		case S_DDSHARP:
+			ls->pending_token = PCT;
+			nstat = FRZ(STO(DIG_SHARP));
+			break;
+		case S_BEHEAD:
+			error(l, "unfinished string at end of line");
+			return 1;
+		case S_DECAY:
+			warning(l, "unterminated // comment");
+			nstat = FRZ(STO(COMMENT));
+			break;
+		case S_TRUNC:
+			error(l, "truncated token");
+			return 1;
+		case S_TRUNCC:
+			error(l, "truncated comment");
+			return 1;
+#ifdef AUDIT
+		case S_OUCH:
+			ouch("machine went out of control");
+			break;
+#endif
+		}
+		if (!ttFRZ(nstat)) {
+			discard_char(ls);
+			if (!(ls->flags & LEXER) && ls->condcomp) {
+				int z = ttSTO(nstat) ? S_ILL : noMOD(nstat);
+
+				if (cstat == S_NAME || z == S_NAME
+					|| ((CMT(cstat) || CMT(z))
+					&& (ls->flags & DISCARD_COMMENTS))) {
+					outc = 0;
+				} else if (z == S_LCHAR || z == S_SLASH
+					|| (z == S_SHARP && ls->ltwnl)
+					|| (z == S_PCT && ls->ltwnl)
+					|| (z == S_BACKSLASH)) {
+					outc = c;
+				} else if (z == S_PCT2 && ls->ltwnl) {
+					outc = -1;
+				} else if (z == S_PCT3 && ls->ltwnl) {
+					/* we have %:% but this still might
+					   not be a %:%: */
+					outc = -2;
+				} else {
+					if (outc < 0) {
+						put_char(ls, '%');
+						put_char(ls, ':');
+						if (outc == -2)
+							put_char(ls, '%');
+						outc = 0;
+					} else if (outc) {
+						put_char(ls, outc);
+						outc = 0;
+					}
+					put_char(ls, c);
+				}
+			}
+		} else if (outc == '/' && !(ls->flags & LEXER)
+			&& ls->condcomp) {
+			/* this is a hack: we need to dump a pending slash */
+			put_char(ls, outc);
+			outc = 0;
+		}
+		if (ttPUT(nstat)) {
+			if (cstat == S_NAME_BS) {
+				ucn_in_id = 1;
+				wan(ls->ctok->name, ltok, '\\', ls->tknl);
+			}
+			if ((ls->flags & UTF8_SOURCE) && utf8) {
+				unsigned char buf[11];
+				int i, j;
+
+				for (i = 0, j = utf8_to_string(buf, utf8);
+					i < j; i ++)
+					wan(ls->ctok->name, ltok, buf[i],
+						ls->tknl);
+				/* if (j > 1) ucn_in_id = 1; */
+			} else wan(ls->ctok->name, ltok,
+				(unsigned char)c, ls->tknl);
+		}
+		if (ttSTO(nstat)) {
+			if (S_TOKEN(noMOD(nstat))) {
+				wan(ls->ctok->name, ltok,
+					(unsigned char)0, ls->tknl);
+			}
+			ls->ctok->type = noMOD(nstat);
+			break;
+		}
+		cstat = noMOD(nstat);
+	} while (1);
+	if (!(ls->flags & LEXER) && (ls->flags & DISCARD_COMMENTS)
+			&& ls->ctok->type == COMMENT) put_char(ls, ' ');
+	if (ucn_in_id && ls->ctok->type == NAME)
+		canonize_id(ls, ls->ctok->name);
+	return 0;
+}
+
+/*
+ * fills ls->ctok with the next token
+ */
+int next_token(struct lexer_state *ls)
+{
+	if (ls->flags & READ_AGAIN) {
+		ls->flags &= ~READ_AGAIN;
+		if (!(ls->flags & LEXER)) {
+			char *c = S_TOKEN(ls->ctok->type) ?
+				ls->ctok->name : token_name(ls->ctok);
+			if (ls->ctok->type == OPT_NONE) {
+				ls->ctok->type = NONE;
+#ifdef SEMPER_FIDELIS
+				ls->ctok->name[0] = ' ';
+				ls->ctok->name[1] = 0;
+#endif
+				put_char(ls, ' ');
+			} else if (ls->ctok->type != NAME &&
+				!(ls->ltwnl && (ls->ctok->type == SHARP
+					|| ls->ctok->type == DIG_SHARP)))
+				for (; *c; c ++) put_char(ls, *c);
+		}
+		return 0;
+	}
+	return read_token(ls);
+}
diff --git a/ucpp/macro.c b/ucpp/macro.c
new file mode 100755
index 0000000..d42e006
--- /dev/null
+++ b/ucpp/macro.c
@@ -0,0 +1,1870 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*vb*/
+#ifdef HAVE_MISRA
+void misra(int,...);
+void misra_neu(int, int, int, int, ...);
+int misra_is_reserved(const char*);
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ctype.h>
+#include "ucppi.h"
+#include "mem.h"
+#include "hash.h"
+#include "tune.h"
+
+/*vb*/
+extern int nesting;
+#ifdef HAVE_MISRA
+extern int misracheck;
+#endif
+
+/*
+ * we store macros in a hash table, and retrieve them using their name
+ * as identifier.
+ */
+static struct HT *macros = 0;
+
+static void del_macro(void *m)
+{
+	struct macro *n = m;
+	int i;
+
+	if (n->name) freemem(n->name);
+	for (i = 0; i < n->narg; i ++) freemem(n->arg[i]);
+	if (n->narg > 0) freemem(n->arg);
+#ifdef LOW_MEM
+	if (n->cval.length) freemem(n->cval.t);
+#else
+	if (n->val.nt) {
+		for (i = 0; i < n->val.nt; i ++)
+			if (S_TOKEN(n->val.t[i].type))
+				freemem(n->val.t[i].name);
+		freemem(n->val.t);
+	}
+#endif
+	freemem(n);
+}
+
+static inline struct macro *new_macro(void)
+{
+	struct macro *m = getmem(sizeof(struct macro));
+
+	m->name = 0;
+	m->narg = -1;
+	m->nest = 0;
+#ifdef LOW_MEM
+	m->cval.length = 0;
+#else
+	m->val.nt = m->val.art = 0;
+#endif
+	m->vaarg = 0;
+	return m;
+}
+
+/*
+ * for special macros, and the "defined" operator
+ */
+enum {
+	MAC_NONE, MAC_DEFINED,
+	MAC_LINE, MAC_FILE, MAC_DATE, MAC_ADATE, MAC_TIME, MAC_STDC, MAC_PRAGMA
+};
+#define MAC_SPECIAL	MAC_LINE
+
+/*
+ * returns 1 for "defined"
+ * returns x > 1 for a special macro such as __FILE__
+ * returns 0 otherwise
+ */
+static inline int check_special_macro(char *name)
+{
+	if (!strcmp(name, "defined")) return MAC_DEFINED;
+	if (*name != '_') return MAC_NONE;
+	if (*(name + 1) == 'P') {
+		if (!strcmp(name, "_Pragma")) return MAC_PRAGMA;
+		return MAC_NONE;
+	} else if (*(name + 1) != '_') return MAC_NONE;
+	if (no_special_macros) return MAC_NONE;
+	if (!strcmp(name, "__LINE__")) return MAC_LINE;
+	else if (!strcmp(name, "__FILE__")) return MAC_FILE;
+	else if (!strcmp(name, "__DATE__")) return MAC_DATE;
+	else if (!strcmp(name, "__AMIGADATE__")) return MAC_ADATE;
+	else if (!strcmp(name, "__TIME__")) return MAC_TIME;
+	else if (!strcmp(name, "__STDC__")) return MAC_STDC;
+	return MAC_NONE;
+}
+
+int c99_compliant = 1;
+int c99_hosted = 1;
+
+/*
+ * add the special macros to the macro table
+ */
+static void add_special_macros(void)
+{
+	struct macro *m;
+
+	m = new_macro(); m->name = sdup("__LINE__"); putHT(macros, m);
+	m = new_macro(); m->name = sdup("__FILE__"); putHT(macros, m);
+	m = new_macro(); m->name = sdup("__DATE__"); putHT(macros, m);
+	m = new_macro(); m->name = sdup("__AMIGADATE__"); putHT(macros, m);
+	m = new_macro(); m->name = sdup("__TIME__"); putHT(macros, m);
+	m = new_macro(); m->name = sdup("__STDC__"); putHT(macros, m);
+	m = new_macro(); m->name = sdup("_Pragma"); m->narg = 1;
+	m->arg = getmem(sizeof(char *)); m->arg[0] = sdup("foo");
+	putHT(macros, m);
+	if (c99_compliant) {
+#ifndef LOW_MEM
+		struct token t;
+#endif
+
+		m = new_macro();
+		m->name = sdup("__STDC_VERSION__");
+#ifdef LOW_MEM
+		m->cval.t = getmem(9);
+		m->cval.t[0] = NUMBER;
+		mmv(m->cval.t + 1, "199901L", 8);
+		m->cval.length = 9;
+#else
+		t.type = NUMBER;
+		t.line = 0;
+		t.name = sdup("199901L");
+		aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);
+#endif
+		putHT(macros, m);
+	}
+	if (c99_hosted) {
+#ifndef LOW_MEM
+		struct token t;
+#endif
+
+		m = new_macro();
+		m->name = sdup("__STDC_HOSTED__");
+#ifdef LOW_MEM
+		m->cval.t = getmem(3);
+		m->cval.t[0] = NUMBER;
+		mmv(m->cval.t + 1, "1", 2);
+		m->cval.length = 3;
+#else
+		t.type = NUMBER;
+		t.line = 0;
+		t.name = sdup("1");
+		aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);
+#endif
+		putHT(macros, m);
+	}
+}
+
+/*
+ * print the content of a macro, in #define form
+ */
+static void print_macro(void *vm)
+{
+	struct macro *m = vm;
+	int x = check_special_macro(m->name);
+	int i;
+
+	if (x != MAC_NONE) {
+		fprintf(emit_output, "/* #define %s */ /* special */\n",
+			m->name);
+		return;
+	}
+	fprintf(emit_output, "#define %s", m->name);
+	if (m->narg >= 0) {
+		fprintf(emit_output, "(");
+		for (i = 0; i < m->narg; i ++) {
+			fprintf(emit_output, i ? ", %s" : "%s", m->arg[i]);
+		}
+		if (m->vaarg) {
+			fputs(m->narg ? ", ..." : "...", emit_output);
+		}
+		fprintf(emit_output, ")");
+	}
+#ifdef LOW_MEM
+	if (m->cval.length == 0) {
+		fputc('\n', emit_output);
+		return;
+	}
+	fputc(' ', emit_output);
+	for (i = 0; i < m->cval.length;) {
+		int tt = m->cval.t[i ++];
+
+		if (tt == MACROARG) {
+			if (m->cval.t[i] == m->narg)
+				fputs("__VA_ARGS__", emit_output);
+			else
+				fputs(m->arg[(size_t)(m->cval.t[i])],
+					emit_output);
+			i ++;
+		}
+		else if (S_TOKEN(tt)) {
+			fputs((char *)(m->cval.t + i), emit_output);
+			i += 1 + strlen((char *)(m->cval.t + i));
+		} else fputs(operators_name[tt], emit_output);
+	}
+#else
+	if (m->val.nt == 0) {
+		fputc('\n', emit_output);
+		return;
+	}
+	fputc(' ', emit_output);
+	for (i = 0; i < m->val.nt; i ++) {
+		if (m->val.t[i].type == MACROARG) {
+			if (m->val.t[i].line == m->narg)
+				fputs("__VA_ARGS__", emit_output);
+			else
+				fputs(m->arg[(size_t)(m->val.t[i].line)],
+					emit_output);
+		} else fputs(token_name(m->val.t + i), emit_output);
+	}
+#endif
+	fputc('\n', emit_output);
+}
+
+/*
+ * Send a token to the output (a token_fifo in lexer mode, the output
+ * buffer in stand alone mode).
+ */
+void print_token(struct lexer_state *ls, struct token *t, long uz_line)
+{
+	char *x = t->name;
+
+	if (uz_line && t->line < 0) t->line = uz_line;
+	if (ls->flags & LEXER) {
+		struct token at;
+
+		at = *t;
+		if (S_TOKEN(t->type)) {
+			at.name = sdup(at.name);
+			throw_away(ls->gf, at.name);
+		}
+		aol(ls->output_fifo->t, ls->output_fifo->nt, at,
+			TOKEN_LIST_MEMG);
+		return;
+	}
+	if (ls->flags & KEEP_OUTPUT) {
+		for (; ls->oline < ls->line;) put_char(ls, '\n');
+	}
+	if (!S_TOKEN(t->type)) x = operators_name[t->type];
+	for (; *x; x ++) put_char(ls, *x);
+}
+
+/*
+ * send a reduced whitespace token to the output
+ */
+#define print_space(ls)	do { \
+		struct token lt; \
+		lt.type = OPT_NONE; \
+		lt.line = (ls)->line; \
+		print_token((ls), &lt, 0); \
+	} while (0)
+
+/*
+ * We found a #define directive; parse the end of the line, perform
+ * sanity checks, store the new macro into the "macros" hash table.
+ *
+ * In case of a redefinition of a macro: we enforce the rule that a
+ * macro should be redefined identically, including the spelling of
+ * parameters. We emit an error on offending code; dura lex, sed lex.
+ * After all, it is easy to avoid such problems, with a #undef directive.
+ */
+int handle_define(struct lexer_state *ls)
+{
+	struct macro *m, *n;
+#ifdef LOW_MEM
+	struct token_fifo mv;
+#endif
+	int ltwws = 1, redef = 0;
+	char *mname = 0;
+	int narg;
+	size_t nt;
+	long l = ls->line;
+	
+	/*vb*/
+#ifdef HAVE_MISRA
+	if(nesting!=0) misra_neu(91,19,5,0);
+#endif
+
+	/* find the next non-white token on the line, this should be
+	   the macro name */
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type == NAME) mname = sdup(ls->ctok->name);
+		break;
+	}
+	if (mname == 0) {
+		error(l, "missing macro name");
+		return 1;
+	}
+	if (check_special_macro(mname)) {
+		error(l, "trying to redefine the special macro %s", mname);
+		goto warp_error;
+	}
+	/*
+	 * If a macro with this name was already defined: the K&R
+	 * states that the new macro should be identical to the old one
+	 * (with some arcane rule of equivalence of whitespace); otherwise,
+	 * redefining the macro is an error. Most preprocessors would
+	 * only emit a warning (or nothing at all) on an unidentical
+	 * redefinition.
+	 *
+	 * Since it is easy to avoid this error (with a #undef directive),
+	 * we choose to enforce the rule and emit an error.
+	 */
+
+#ifdef HAVE_MISRA
+		if (misra_is_reserved(mname)) misra_neu(114,20,1,-1);
+#endif
+
+	if ((n = getHT(macros, &mname)) != 0) {
+		/* redefinition of a macro: we must check that we define
+		   it identical */
+		redef = 1;
+#ifdef LOW_MEM
+		n->cval.rp = 0;
+#endif
+		freemem(mname);
+	}
+	if (!redef) {
+		m = new_macro();
+		m->name = mname;
+		m->narg = -1;
+#ifdef LOW_MEM
+		mv.art = mv.nt = 0;
+#define mval	mv
+#else
+#define mval	(m->val)
+#endif
+	}
+	if (next_token(ls)) goto define_end;
+	/*
+	 * Check if the token immediately following the macro name is
+	 * a left parenthesis; if so, then this is a macro with arguments.
+	 * Collect their names and try to match the next parenthesis.
+	 */
+	if (ls->ctok->type == LPAR) {
+		int i, j;
+		int need_comma = 0, saw_mdots = 0;
+
+		narg = 0;
+		while (!next_token(ls)) {
+			if (ls->ctok->type == NEWLINE) {
+				error(l, "truncated macro definition");
+				return 1;
+			}
+			if (ls->ctok->type == COMMA) {
+				if (saw_mdots) {
+					error(l, "'...' must end the macro "
+						"argument list");
+					goto warp_error;
+				}
+				if (!need_comma) {
+					error(l, "void macro argument");
+					goto warp_error;
+				}
+				need_comma = 0;
+				continue;
+			} else if (ls->ctok->type == NAME) {
+				if (saw_mdots) {
+					error(l, "'...' must end the macro "
+						"argument list");
+					goto warp_error;
+				}
+				if (need_comma) {
+					error(l, "missing comma in "
+						"macro argument list");
+					goto warp_error;
+				}
+				if (!redef) {
+					aol(m->arg, narg,
+						sdup(ls->ctok->name), 8);
+					if (narg == 128
+						&& (ls->flags & WARN_STANDARD))
+						warning(l, "more arguments to "
+							"macro than the ISO "
+							"limit (127)");
+#ifdef LOW_MEM
+					if (narg == 254) {
+						error(l, "too many arguments "
+							"in macro definition "
+							"(max 253)");
+						goto warp_error;
+					}
+#endif
+				} else {
+					/* this is a redefinition of the
+					   macro; check equality between
+					   old and new definitions */
+					if (narg >= n->narg) goto redef_error;
+					if (strcmp(ls->ctok->name,
+						n->arg[narg ++]))
+						goto redef_error;
+				}
+				need_comma = 1;
+				continue;
+			} else if ((ls->flags & MACRO_VAARG)
+				&& ls->ctok->type == MDOTS) {
+				if (need_comma) {
+					error(l, "missing comma before '...'");
+					goto warp_error;
+				}
+				if (redef && !n->vaarg) goto redef_error;
+				if (!redef) m->vaarg = 1;
+				saw_mdots = 1;
+				need_comma = 1;
+				continue;
+			} else if (ls->ctok->type == RPAR) {
+				if (narg > 0 && !need_comma) {
+					error(l, "void macro argument");
+					goto warp_error;
+				}
+				if (redef && n->vaarg && !saw_mdots)
+					goto redef_error;
+				break;
+			} else if (ttMWS(ls->ctok->type)) {
+				continue;
+			}
+			error(l, "invalid macro argument");
+			goto warp_error;
+		}
+		if (!redef) {
+			for (i = 1; i < narg; i ++) for (j = 0; j < i; j ++)
+				if (!strcmp(m->arg[i], m->arg[j])) {
+					error(l, "duplicate macro "
+						"argument");
+					goto warp_error;
+				}
+		}
+		if (!redef) m->narg = narg;
+	} else {
+		if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD))
+			warning(ls->line, "identifier not followed by "
+				"whitespace in #define");
+		ls->flags |= READ_AGAIN;
+		narg = 0;
+	}
+	if (redef) nt = 0;
+
+	/* now, we have the arguments. Let's get the macro contents. */
+	while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+		struct token t;
+
+		t.type = ls->ctok->type;
+		if (ltwws && ttMWS(t.type)) continue;
+		t.line = 0;
+		if (t.type == NAME) {
+			int i;
+
+			if ((ls->flags & MACRO_VAARG)
+				&& !strcmp(ls->ctok->name, "__VA_ARGS__")) {
+				if (redef) {
+					if (!n->vaarg) goto redef_error;
+				} else if (!m->vaarg) {
+					error(l, "'__VA_ARGS__' is forbidden "
+						"in macros with a fixed "
+						"number of arguments");
+					goto warp_error;
+				}
+				t.type = MACROARG;
+				t.line = redef ? n->narg : m->narg;
+			}
+			for (i = 0; i < narg; i ++)
+				if (!strcmp(redef ? n->arg[i] : m->arg[i],
+					ls->ctok->name)) {
+					t.type = MACROARG;
+					/* this is a hack: we store the
+					   argument number in the line field */
+					t.line = i;
+					break;
+				}
+		}
+		if (!redef && S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+		if (ttMWS(t.type)) {
+			if (ltwws) continue;
+#ifdef SEMPER_FIDELIS
+			t.type = OPT_NONE;
+#else
+			t.type = NONE;
+#endif
+			ltwws = 1;
+		} else ltwws = 0;
+		if (!redef) {
+			/* we ensure that each macro token has a correct
+			   line number */
+			if (t.type != MACROARG) t.line = l;
+			aol(mval.t, mval.nt, t, TOKEN_LIST_MEMG);
+		} else {
+#ifdef LOW_MEM
+			int tt;
+
+			if (n->cval.rp >= n->cval.length) {
+#ifdef SEMPER_FIDELIS
+				if (t.type != OPT_NONE) goto redef_error;
+#else
+				if (t.type != NONE) goto redef_error;
+#endif
+			} else if (t.type != n->cval.t[n->cval.rp]
+				|| (t.type == MACROARG
+				    && t.line != n->cval.t[n->cval.rp + 1])
+				|| (S_TOKEN(t.type) && strcmp(ls->ctok->name,
+				   (char *)(n->cval.t + n->cval.rp + 1)))) {
+				goto redef_error;
+			}
+			tt = n->cval.t[n->cval.rp ++];
+			if (S_TOKEN(tt)) n->cval.rp += 1
+				+ strlen((char *)(n->cval.t + n->cval.rp));
+			else if (tt == MACROARG) n->cval.rp ++;
+#else
+			if (nt >= n->val.nt) {
+#ifdef SEMPER_FIDELIS
+				if (t.type != OPT_NONE) goto redef_error;
+#else
+				if (t.type != NONE) goto redef_error;
+#endif
+			} else if (t.type != n->val.t[nt].type
+				|| (t.type == MACROARG
+				    && t.line != n->val.t[nt].line)
+				|| (S_TOKEN(t.type) && strcmp(ls->ctok->name,
+				   n->val.t[nt].name))) {
+				goto redef_error;
+			}
+#endif
+			nt ++;
+		}
+	}
+
+	if (redef) {
+#ifdef LOW_MEM
+		if (n->cval.rp < n->cval.length) goto redef_error_2;
+#else
+		if (nt < n->val.nt) goto redef_error_2;
+#endif
+		return 0;
+	}
+
+	/* now we have the complete macro; perform some checks about
+	   the operators # and ##, and, if everything is ok,
+	   store the macro into the hash table */
+define_end:
+#ifdef SEMPER_FIDELIS
+	if (mval.nt && mval.t[mval.nt - 1].type == OPT_NONE) {
+#else
+	if (mval.nt && mval.t[mval.nt - 1].type == NONE) {
+#endif
+		mval.nt --;
+		if (mval.nt == 0) freemem(mval.t);
+	}
+	if (mval.nt != 0) {
+		size_t i;
+
+		/* some checks about the macro */
+		if (mval.t[0].type == DSHARP
+			|| mval.t[0].type == DIG_DSHARP
+			|| mval.t[mval.nt - 1].type == DSHARP
+			|| mval.t[mval.nt - 1].type == DIG_DSHARP) {
+			error(l, "operator '##' may neither begin "
+				"nor end a macro");
+			return 1;
+		}
+		if (m->narg >= 0) for (i = 0; i < mval.nt; i ++)
+			if ((mval.t[i].type == SHARP
+				|| mval.t[i].type == DIG_SHARP) &&
+				(i == (mval.nt - 1)
+				|| (ttMWS(mval.t[i + 1].type) &&
+				    (i == mval.nt - 2
+				     || mval.t[i + 2].type != MACROARG))
+				|| (!ttMWS(mval.t[i + 1].type)
+				     && mval.t[i + 1].type != MACROARG))) {
+				error(l, "operator '#' not followed "
+					"by a macro argument");
+				return 1;
+			}
+	}
+#ifdef LOW_MEM
+	{
+		size_t i, l;
+
+		for (i = 0, l = 0; i < mval.nt; i ++) {
+			l ++;
+			if (S_TOKEN(mval.t[i].type))
+				l += 1 + strlen(mval.t[i].name);
+			else if (mval.t[i].type == MACROARG) l ++;
+		}
+		m->cval.length = l;
+		if (l) m->cval.t = getmem(l);
+		for (i = 0, l = 0; i < mval.nt; i ++) {
+			m->cval.t[l ++] = mval.t[i].type;
+			if (S_TOKEN(mval.t[i].type)) {
+				size_t x = 1 + strlen(mval.t[i].name);
+
+				mmv(m->cval.t + l, mval.t[i].name, x);
+				l += x;
+				freemem(mval.t[i].name);
+			}
+			else if (mval.t[i].type == MACROARG)
+				m->cval.t[l ++] = mval.t[i].line;
+		}
+		if (mval.nt) freemem(mval.t);
+	}
+#endif
+
+
+#ifdef LOW_MEM
+	/*vb*/
+#ifdef HAVE_MISRA
+	if(misracheck)
+	{
+	  int i,lp=0;
+	  for(i=0;i<m->cval.length;){
+	    int tt=m->cval.t[i++];
+	    if(tt==MACROARG){
+	      i++;
+	      if(!lp||m->cval.t[i]!=RPAR) misra_neu(96,19,10,0);
+	    }else if(S_TOKEN(tt)){
+	      i += 1 + strlen((char *)(m->cval.t + i));
+	    }else{
+	      if(tt==LPAR) lp=1; else lp=0;
+	    }
+	  }
+	}
+#endif
+#else
+#error not supported
+#endif
+
+	putHT(macros, m);
+	if (emit_defines) print_macro(m);
+	return 0;
+
+redef_error:
+	while (ls->ctok->type != NEWLINE && !next_token(ls));
+redef_error_2:
+	error(l, "macro '%s' redefined unidentically", n->name);
+	return 1;
+warp_error:
+	while (ls->ctok->type != NEWLINE && !next_token(ls));
+	return 1;
+#undef mval
+}
+
+/*
+ * Get the arguments for a macro. This code is tricky because there can
+ * be multiple sources for these arguments, if we are in the middle of
+ * a macro replacement; arguments are macro-replaced before inclusion
+ * into the macro replacement.
+ *
+ * return value:
+ * 1	no argument (last token read from next_token())
+ * 2    no argument (last token read from tfi)
+ * 3    no argument (nothing read)
+ * 4	error
+ *
+ * Void arguments are allowed in C99.
+ */
+static int collect_arguments(struct lexer_state *ls, struct token_fifo *tfi,
+	int penury, struct token_fifo *atl, int narg, int vaarg, int *wr)
+{
+	int ltwws = 1, npar = 0, i;
+	struct token *ct = 0;
+	int read_from_fifo = 0;
+	long begin_line = ls->line;
+
+#define unravel(ls)	(read_from_fifo = 0, !((tfi && tfi->art < tfi->nt \
+	&& (read_from_fifo = 1) && (ct = tfi->t + (tfi->art ++))) \
+	|| ((!tfi || penury) && !next_token(ls) && (ct = (ls)->ctok))))
+
+	/*
+	 * collect_arguments() is assumed to setup correctly atl
+	 * (this is not elegant, but it works)
+	 */
+	for (i = 0; i < narg; i ++) atl[i].art = atl[i].nt = 0;
+	if (vaarg) atl[narg].art = atl[narg].nt = 0;
+	*wr = 0;
+	while (!unravel(ls)) {
+		if (!read_from_fifo && ct->type == NEWLINE) ls->ltwnl = 1;
+		if (ttWHI(ct->type)) {
+			*wr = 1;
+			continue;
+		}
+		if (ct->type == LPAR) {
+			npar = 1;
+		}
+		break;
+	}
+	if (!npar) {
+		if (ct == ls->ctok) return 1;
+		if (read_from_fifo) return 2;
+		return 3;
+	}
+	if (!read_from_fifo && ct == ls->ctok) ls->ltwnl = 0;
+	i = 0;
+	if ((narg + vaarg) == 0) {
+		while(!unravel(ls)) {
+			if (ttWHI(ct->type)) continue;
+			if (ct->type == RPAR) goto harvested;
+			npar = 1;
+			goto too_many_args;
+		}
+	}
+	while (!unravel(ls)) {
+		struct token t;
+
+		if (ct->type == LPAR) npar ++;
+		else if (ct->type == RPAR && (-- npar) == 0) {
+			if (atl[i].nt != 0
+				&& ttMWS(atl[i].t[atl[i].nt - 1].type))
+					atl[i].nt --;
+			i ++;
+			/*
+			 * C99 standard states that at least one argument
+			 * should be present for the ... part; to relax
+			 * this behaviour, change 'narg + vaarg' to 'narg'.
+			 */
+			if (i < (narg + vaarg)) {
+				error(begin_line, "not enough arguments "
+					"to macro");
+#ifdef HAVE_MISRA
+				misra_neu(94,19,8,0);
+#endif
+				return 4;
+			}
+			if (i > narg) {
+				if (!(ls->flags & MACRO_VAARG) || !vaarg)
+					goto too_many_args;
+			}
+			goto harvested;
+		} else if (ct->type == COMMA && npar <= 1 && i < narg) {
+			if (atl[i].nt != 0
+				&& ttMWS(atl[i].t[atl[i].nt - 1].type))
+					atl[i].nt --;
+			if (++ i == narg) {
+				if (!(ls->flags & MACRO_VAARG) || !vaarg)
+					goto too_many_args;
+			}
+			if (i > 30000) goto too_many_args;
+			ltwws = 1;
+			continue;
+		} else if (ltwws && ttWHI(ct->type)) continue;
+
+		t.type = ct->type;
+		if (!read_from_fifo) t.line = ls->line; else t.line = ct->line;
+		/*
+		 * Stringification applies only on macro arguments;
+		 * so we handle here OPT_NONE.
+		 * OPT_NONE is kept, but does not count as whitespace,
+		 * and merges with other whitespace to give a fully
+		 * qualified NONE token. Two OPT_NONE tokens merge.
+		 * Initial and final OPT_NONE are discarded (initial
+		 * is already done, as OPT_NONE is matched by ttWHI).
+		 */
+
+		if (ttWHI(t.type)) {
+			if (t.type != OPT_NONE) {
+				t.type = NONE;
+				ltwws = 1;
+			}
+			if (atl[i].nt > 0
+				&& atl[i].t[atl[i].nt - 1].type == OPT_NONE)
+					atl[i].nt --;
+		} else ltwws = 0;
+		if (S_TOKEN(t.type)) {
+			t.name = ct->name;
+			if (ct == (ls)->ctok) {
+				t.name = sdup(t.name);
+				throw_away(ls->gf, t.name);
+			}
+		}
+		aol(atl[i].t, atl[i].nt, t, TOKEN_LIST_MEMG);
+	}
+	error(begin_line, "unfinished macro call");
+	return 4;
+too_many_args:
+	error(begin_line, "too many arguments to macro");
+	while (npar && !unravel(ls)) {
+		if (ct->type == LPAR) npar ++;
+		else if (ct->type == RPAR) npar --;
+	}
+	return 4;
+harvested:
+	if (i > 127 && (ls->flags & WARN_STANDARD))
+		warning(begin_line, "macro call with %d arguments (ISO "
+			"specifies 127 max)", i);
+	return 0;
+#undef unravel
+}
+
+/*
+ * concat_token() is called when the ## operator is used. It uses
+ * the struct lexer_state dsharp_lexer to parse the result of the
+ * concatenation.
+ *
+ * Law enforcement: if the whole string does not produce a valid
+ * token, report an error. This also applies if only the beginning
+ * of the string gives a statement. For instance, '( ## )' will
+ * produce an error, since '()' is not a valid C token. Other
+ * preprocessors would ignore the ## operator in such instance.
+ */
+struct lexer_state dsharp_lexer;
+
+static inline int concat_token(struct token *t1, struct token *t2)
+{
+	char *n1 = token_name(t1), *n2 = token_name(t2);
+	size_t l1 = strlen(n1), l2 = strlen(n2);
+	unsigned char *x = getmem(l1 + l2 + 1);
+	int r;
+
+	mmv(x, n1, l1);
+	mmv(x + l1, n2, l2);
+	x[l1 + l2] = 0;
+	dsharp_lexer.input = 0;
+	dsharp_lexer.input_string = x;
+	dsharp_lexer.pbuf = 0;
+	dsharp_lexer.ebuf = l1 + l2;
+	dsharp_lexer.discard = 1;
+	dsharp_lexer.flags = DEFAULT_LEXER_FLAGS;
+	dsharp_lexer.pending_token = 0;
+	r = next_token(&dsharp_lexer);
+	freemem(x);
+	return (r == 1 || dsharp_lexer.pbuf < (l1 + l2)
+		|| dsharp_lexer.pending_token
+		|| (dsharp_lexer.pbuf == (l1 + l2) && !dsharp_lexer.discard));
+}
+
+#ifdef PRAGMA_TOKENIZE
+/*
+ * tokenize_string() takes a string as input, and split it into tokens,
+ * reassembling the tokens into a single compressed string generated by
+ * compress_token_list(); this function is used for _Pragma processing.
+ */
+struct lexer_state tokenize_lexer;
+
+static char *tokenize_string(struct lexer_state *ls, char *buf)
+{
+	struct token_fifo tf;
+	size_t bl = strlen(buf);
+	int r;
+
+	tokenize_lexer.input = 0;
+	tokenize_lexer.input_string = (unsigned char *)buf;
+	tokenize_lexer.pbuf = 0;
+	tokenize_lexer.ebuf = bl;
+	tokenize_lexer.discard = 1;
+	tokenize_lexer.flags = ls->flags | LEXER;
+	tokenize_lexer.pending_token = 0;
+	tf.art = tf.nt = 0;
+	while (!(r = next_token(&tokenize_lexer))) {
+		struct token t, *ct = tokenize_lexer.ctok;
+
+		if (ttWHI(ct->type)) continue;
+		t = *ct;
+		if (S_TOKEN(t.type)) t.name = sdup(t.name);
+		aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+	}
+	if (tokenize_lexer.pbuf < bl) goto tokenize_error;
+	return (char *)((compress_token_list(&tf)).t);
+
+tokenize_error:
+	if (tf.nt) {
+		for (tf.art = 0; tf.art < tf.nt; tf.art ++)
+			if (S_TOKEN(tf.t[tf.art].type))
+				freemem(tf.t[tf.art].name);
+		freemem(tf.t);
+	}
+	return 0;
+}
+#endif
+
+/*
+ * stringify_string() has a self-explanatory name. It is called when
+ * the # operator is used in a macro and a string constant must be
+ * stringified.
+ */
+static inline char *stringify_string(char *x)
+{
+	size_t l;
+	int i, inside_str = 0, inside_cc = 0, must_quote, has_quoted = 0;
+	char *y, *d;
+
+	for (i = 0; i < 2; i ++) {
+		if (i) d[0] = '"';
+		for (l = 1, y = x; *y; y ++, l ++) {
+			must_quote = 0;
+			if (inside_cc) {
+				if (*y == '\\') {
+					must_quote = 1;
+					has_quoted = 1;
+				} else if (!has_quoted && *y == '\'')
+					inside_cc = 0;
+			} else if (inside_str) {
+				if (*y == '"' || *y == '\\') must_quote = 1;
+				if (*y == '\\') has_quoted = 1;
+				else if (!has_quoted && *y == '"')
+					inside_str = 0;
+			} else if (*y == '"') {
+				inside_str = 1;
+				must_quote = 1;
+			} else if (*y == '\'') {
+				inside_cc = 1;
+			}
+			if (must_quote) {
+				if (i) d[l] = '\\';
+				l ++;
+			}
+			if (i) d[l] = *y;
+		}
+		if (!i) d = getmem(l + 2);
+		if (i) {
+			d[l] = '"';
+			d[l + 1] = 0;
+		}
+	}
+	return d;
+}
+
+/*
+ * stringify() produces a constant string, result of the # operator
+ * on a list of tokens.
+ */
+static char *stringify(struct token_fifo *tf)
+{
+	size_t tlen;
+	size_t i;
+	char *x, *y;
+
+	for (tlen = 0, i = 0; i < tf->nt; i ++)
+		if (tf->t[i].type < CPPERR && tf->t[i].type != OPT_NONE)
+			tlen += strlen(token_name(tf->t + i));
+	if (tlen == 0) return sdup("\"\"");
+	x = getmem(tlen + 1);
+	for (tlen = 0, i = 0; i < tf->nt; i ++) {
+		if (tf->t[i].type >= CPPERR || tf->t[i].type == OPT_NONE)
+			continue;
+		strcpy(x + tlen, token_name(tf->t + i));
+		tlen += strlen(token_name(tf->t + i));
+	}
+	/* no need to add a trailing 0: strcpy() did that (and the string
+	   is not empty) */
+	y = stringify_string(x);
+	freemem(x);
+	return y;
+}
+
+/*
+ * Two strings evaluated at initialization time, to handle the __TIME__
+ * and __DATE__ special macros.
+ *
+ * C99 specifies that these macros should remain constant throughout
+ * the whole preprocessing.
+ */
+char compile_time[12], compile_date[24], compile_adate[16];
+
+/*
+ * substitute_macro() performs the macro substitution. It is called when
+ * an identifier recognized as a macro name has been found; this function
+ * tries to collect the arguments (if needed), applies # and ## operators
+ * and perform recursive and nested macro expansions.
+ *
+ * In the substitution of a macro, we remove all newlines that were in the
+ * arguments. This might confuse error reporting (which could report
+ * erroneous line numbers) or have worse effect is the preprocessor is
+ * used for another language pickier than C. Since the interface between
+ * the preprocessor and the compiler is not fully specified, I believe
+ * that this is no violation of the standard. Comments welcome.
+ *
+ * We take tokens from tfi. If tfi has no more tokens to give: we may
+ * take some tokens from ls to complete a call (fetch arguments) if
+ * and only if penury is non zero.
+ */
+int substitute_macro(struct lexer_state *ls, struct macro *m,
+	struct token_fifo *tfi, int penury, int reject_nested, long l)
+{
+	struct token_fifo *atl, etl;
+	struct token t, *ct;
+	int i, save_nest = m->nest;
+	size_t save_art, save_tfi, etl_limit;
+	int ltwds, ntwds, ltwws;
+	int pragma_op = 0;
+
+	/*
+	 * Reject the replacement, if we are already inside the macro.
+	 */
+	if (m->nest > reject_nested) {
+		t.type = NAME;
+		t.line = ls->line;
+		t.name = m->name;
+		print_token(ls, &t, 0);
+		return 0;
+	}
+#ifdef HAVE_MISRA
+	if (!strcmp(m->name,"offsetof")) misra_neu(120,20,6,-1);
+	if (!strcmp(m->name,"setjmp")) misra_neu(122,20,7,-1);
+#endif
+	/*
+	 * put a separation from preceeding tokens
+	 */
+	print_space(ls);
+
+	/*
+	 * Check if the macro is a special one.
+	 */
+	if ((i = check_special_macro(m->name)) >= MAC_SPECIAL) {
+		/* we have a special macro */
+		switch (i) {
+			char buf[30], *bbuf, *cfn;
+
+		case MAC_LINE:
+			t.type = NUMBER;
+			t.line = l;
+			sprintf(buf, "%ld", l);
+			t.name = buf;
+			print_space(ls);
+			print_token(ls, &t, 0);
+			break;
+		case MAC_FILE:
+			t.type = STRING;
+			t.line = l;
+			cfn = current_long_filename ?
+				current_long_filename : current_filename;
+			bbuf = getmem(2 * strlen(cfn) + 3);
+			{
+				char *c, *d;
+				int lcwb = 0;
+
+				bbuf[0] = '"';
+				for (c = cfn, d = bbuf + 1; *c; c ++) {
+					if (*c == '\\') {
+						if (lcwb) continue;
+						*(d ++) = '\\';
+						lcwb = 1;
+					} else lcwb = 0;
+					*(d ++) = *c;
+				}
+				*(d ++) = '"';
+				*(d ++) = 0;
+			}
+			t.name = bbuf;
+			print_space(ls);
+			print_token(ls, &t, 0);
+			freemem(bbuf);
+			break;
+		case MAC_DATE:
+			t.type = STRING;
+			t.line = l;
+			t.name = compile_date;
+			print_space(ls);
+			print_token(ls, &t, 0);
+			break;
+		case MAC_ADATE:
+			t.type = STRING;
+			t.line = l;
+			t.name = compile_adate;
+			print_space(ls);
+			print_token(ls, &t, 0);
+			break;
+		case MAC_TIME:
+			t.type = STRING;
+			t.line = l;
+			t.name = compile_time;
+			print_space(ls);
+			print_token(ls, &t, 0);
+			break;
+		case MAC_STDC:
+			t.type = NUMBER;
+			t.line = l;
+			t.name = "1";
+			print_space(ls);
+			print_token(ls, &t, 0);
+			break;
+		case MAC_PRAGMA:
+			if (reject_nested > 0) {
+				/* do not replace _Pragma() unless toplevel */
+				t.type = NAME;
+				t.line = ls->line;
+				t.name = m->name;
+				print_token(ls, &t, 0);
+				return 0;
+			}
+			pragma_op = 1;
+			goto collect_args;
+#ifdef AUDIT
+		default:
+			ouch("unbekanntes fliegendes macro");
+#endif
+		}
+		return 0;
+	}
+
+	/*
+	 * If the macro has arguments, collect them.
+	 */
+collect_args:
+	if (m->narg >= 0) {
+		unsigned long save_flags = ls->flags;
+		int wr = 0;
+
+		ls->flags |= LEXER;
+		if (m->narg > 0 || m->vaarg)
+			atl = getmem((m->narg + m->vaarg)
+				* sizeof(struct token_fifo));
+		switch (collect_arguments(ls, tfi, penury, atl,
+			m->narg, m->vaarg, &wr)) {
+		case 1:
+			/* the macro expected arguments, but we did not
+			   find any; the last read token should be read
+			   again. */
+			ls->flags = save_flags | READ_AGAIN;
+			goto no_argument_next;
+		case 2:
+			tfi->art --;
+			/* fall through */
+		case 3:
+			ls->flags = save_flags;
+		no_argument_next:
+			t.type = NAME;
+			t.line = l;
+			t.name = m->name;
+			print_token(ls, &t, 0);
+			if (wr) {
+				t.type = NONE;
+				t.line = l;
+#ifdef SEMPER_FIDELIS
+				t.name = " ";
+#endif
+				print_token(ls, &t, 0);
+				goto exit_macro_2;
+			}
+			goto exit_macro_1;
+		case 4:
+			ls->flags = save_flags;
+			return 1;
+		}
+		ls->flags = save_flags;
+	}
+
+	/*
+	 * If the macro is _Pragma, and we got here, then we have
+	 * exactly one argument. We check it, unstringize it, and
+	 * emit a PRAGMA token.
+	 */
+	if (pragma_op) {
+		char *pn;
+
+		if (atl[0].nt != 1 || atl[0].t[0].type != STRING) {
+			error(ls->line, "invalid argument to _Pragma");
+			if (atl[0].nt) freemem(atl[0].t);
+			freemem(atl);
+			return 1;
+		}
+		pn = atl[0].t[0].name;
+		if ((pn[0] == '"' && pn[1] == '"') || (pn[0] == 'L'
+			&& pn[1] == '"' && pn[2] == '"')) {
+			/* void pragma -- just ignore it */
+			freemem(atl[0].t);
+			freemem(atl);
+			return 0;
+		}
+		if (ls->flags & TEXT_OUTPUT) {
+#ifdef PRAGMA_DUMP
+	/*
+	 * This code works because we actually evaluate arguments in a
+	 * lazy way: we scan a macro argument only if it appears in the
+	 * output, and exactly as many times as it appears. Therefore,
+	 * _Pragma() will get evaluated just like they should.
+	 */
+			char *c = atl[0].t[0].name, *d;
+
+			for (d = "\n#pragma "; *d; d ++) put_char(ls, *d);
+			d = (*c == 'L') ? c + 2 : c + 1;
+			for (; *d != '"'; d ++) {
+				if (*d == '\\' && (*(d + 1) == '\\'
+					|| *(d + 1) == '"')) {
+					d ++;
+				}
+				put_char(ls, *d);
+			}
+			put_char(ls, '\n');
+			ls->oline = ls->line;
+			enter_file(ls, ls->flags);
+#else
+			if (ls->flags & WARN_PRAGMA)
+				warning(ls->line,
+					"_Pragma() ignored and not dumped");
+#endif
+		} else if (ls->flags & HANDLE_PRAGMA) {
+			char *c = atl[0].t[0].name, *d, *buf;
+			struct token t;
+
+			/* a wide string is a string */
+			if (*c == 'L') c ++;
+			c ++;
+			for (buf = d = getmem(strlen(c)); *c != '"'; c ++) {
+				if (*c == '\\' && (*(c + 1) == '\\'
+					|| *(c + 1) == '"')) {
+					*(d ++) = *(++ c);
+				} else *(d ++) = *c;
+			}
+			*d = 0;
+			t.type = PRAGMA;
+			t.line = ls->line;
+#ifdef PRAGMA_TOKENIZE
+			t.name = tokenize_string(ls, buf);
+			freemem(buf);
+			buf = t.name;
+			if (!buf) {
+				freemem(atl[0].t);
+				freemem(atl);
+				return 1;
+			}
+#else
+			t.name = buf;
+#endif
+			aol(ls->toplevel_of->t, ls->toplevel_of->nt,
+				t, TOKEN_LIST_MEMG);
+			throw_away(ls->gf, buf);
+		}
+		freemem(atl[0].t);
+		freemem(atl);
+		return 0;
+	}
+
+	/*
+	 * Now we expand and replace the arguments in the macro; we
+	 * also handle '#' and '##'. If we find an argument, that has
+	 * to be replaced, we expand it in its own token list, then paste
+	 * it. Tricky point: when we paste an argument, we must scan
+	 * again the resulting list for further replacements. This
+	 * implies problems with regards to nesting self-referencing
+	 * macros.
+	 *
+	 * We do then YAUH (yet another ugly hack): if a macro is replaced,
+	 * and nested replacement exhibit the same macro, we mark it with
+	 * a negative line number. All produced negative line numbers
+	 * must be cleaned in the end.
+	 */
+
+#define ZAP_LINE(t)	do { \
+		if ((t).type == NAME) { \
+			struct macro *zlm = getHT(macros, &((t).name)); \
+			if (zlm && zlm->nest > reject_nested) \
+				(t).line = -1 - (t).line; \
+		} \
+	} while (0)
+
+#ifdef LOW_MEM
+	save_art = m->cval.rp;
+	m->cval.rp = 0;
+#else
+	save_art = m->val.art;
+	m->val.art = 0;
+#endif
+	etl.art = etl.nt = 0;
+	m->nest = reject_nested + 1;
+	ltwds = ntwds = 0;
+#ifdef LOW_MEM
+	while (m->cval.rp < m->cval.length) {
+#else
+	while (m->val.art < m->val.nt) {
+#endif
+		size_t next, z;
+#ifdef LOW_MEM
+		struct token uu;
+
+		ct = &uu;
+		ct->line = 1;
+		t.type = ct->type = m->cval.t[m->cval.rp ++];
+		if (ct->type == MACROARG) {
+			ct->line = m->cval.t[m->cval.rp ++];
+		} else if (S_TOKEN(ct->type)) {
+			t.name = ct->name = (char *)(m->cval.t + m->cval.rp);
+			m->cval.rp += 1 + strlen(ct->name);
+		}
+#ifdef SEMPER_FIDELIS
+		else if (ct->type == OPT_NONE) {
+			t.type = ct->type = NONE;
+			t.name = ct->name = " ";
+		}
+#endif
+		t.line = ls->line;
+		next = m->cval.rp;
+		if ((next < m->cval.length && (m->cval.t[z = next] == DSHARP
+			|| m->cval.t[z = next] == DIG_DSHARP))
+			|| ((next + 1) < m->cval.length
+			   && ttWHI(m->cval.t[next])
+			   && (m->cval.t[z = next + 1] == DSHARP
+			    || m->cval.t[z = next + 1] == DIG_DSHARP))) {
+			ntwds = 1;
+			m->cval.rp = z;
+		} else ntwds = 0;
+#else
+		ct = m->val.t + (m->val.art ++);
+		next = m->val.art;
+		t.type = ct->type;
+		t.line = ls->line;
+#ifdef SEMPER_FIDELIS
+		if (t.type == OPT_NONE) {
+			t.type = NONE;
+			t.name = " ";
+		} else
+#else
+		t.name = ct->name;
+#endif
+		if ((next < m->val.nt && (m->val.t[z = next].type == DSHARP
+			|| m->val.t[z = next].type == DIG_DSHARP))
+			|| ((next + 1) < m->val.nt
+			   && ttWHI(m->val.t[next].type)
+			   && (m->val.t[z = next + 1].type == DSHARP
+			    || m->val.t[z = next + 1].type == DIG_DSHARP))) {
+			ntwds = 1;
+			m->val.art = z;
+		} else ntwds = 0;
+#endif
+		if (ct->type == MACROARG) {
+			z = ct->line;	/* the argument number is there */
+			if (ltwds && atl[z].nt != 0 && etl.nt) {
+				if (concat_token(etl.t + (-- etl.nt),
+					atl[z].t)) {
+					error(ls->line, "operator '##' "
+						"produced the invalid token "
+						"'%s%s'",
+						token_name(etl.t + etl.nt),
+						token_name(atl[z].t));
+					m->nest = save_nest;
+#ifdef LOW_MEM
+					m->cval.rp = save_art;
+#else
+					m->val.art = save_art;
+#endif
+					return 1;
+				}
+				if (etl.nt == 0) freemem(etl.t);
+				else if (!ttWHI(etl.t[etl.nt - 1].type)) {
+					t.type = OPT_NONE;
+					t.line = ls->line;
+					aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+				}
+				t.type = dsharp_lexer.ctok->type;
+				t.line = ls->line;
+				if (S_TOKEN(t.type)) {
+					t.name = sdup(dsharp_lexer.ctok->name);
+					throw_away(ls->gf, t.name);
+				}
+				ZAP_LINE(t);
+				aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+				atl[z].art = 1;
+			} else atl[z].art = 0;
+			if (atl[z].art < atl[z].nt && (!etl.nt
+				|| !ttWHI(etl.t[etl.nt - 1].type))) {
+				t.type = OPT_NONE;
+				t.line = ls->line;
+				aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+			}
+			if (ltwds || ntwds) {
+				while (atl[z].art < atl[z].nt) {
+					t = atl[z].t[atl[z].art ++];
+					t.line = ls->line;
+					ZAP_LINE(t);
+					aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+				}
+			} else {
+				struct token_fifo *save_tf;
+				unsigned long save_flags;
+				int ret = 0;
+
+				atl[z].art = 0;
+				save_tf = ls->output_fifo;
+				ls->output_fifo = &etl;
+				save_flags = ls->flags;
+				ls->flags |= LEXER;
+				while (atl[z].art < atl[z].nt) {
+					struct macro *nm;
+					struct token *cct;
+
+					cct = atl[z].t + (atl[z].art ++);
+					if (cct->type == NAME
+						&& cct->line >= 0
+						&& (nm = getHT(macros,
+						    &(cct->name)))
+						&& nm->nest <=
+						    (reject_nested + 1)) {
+						ret |= substitute_macro(ls,
+							nm, atl + z, 0,
+							reject_nested + 1, l);
+						continue;
+					}
+					ZAP_LINE(t);
+					aol(etl.t, etl.nt, *cct,
+						TOKEN_LIST_MEMG);
+				}
+				ls->output_fifo = save_tf;
+				ls->flags = save_flags;
+				if (ret) {
+					m->nest = save_nest;
+#ifdef LOW_MEM
+					m->cval.rp = save_art;
+#else
+					m->val.art = save_art;
+#endif
+					return ret;
+				}
+			}
+			if (!ntwds && (!etl.nt
+				|| !ttWHI(etl.t[etl.nt - 1].type))) {
+				t.type = OPT_NONE;
+				t.line = ls->line;
+				aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+			}
+			ltwds = 0;
+			continue;
+		}
+		/*
+		 * This code is definitely cursed.
+		 *
+		 * For the extremely brave reader who tries to understand
+		 * what is happening: ltwds is a flag meaning "last token
+		 * was double-sharp" and ntwds means "next token will be
+		 * double-shar". The tokens are from the macro definition,
+		 * and scanned from left to right. Arguments that are
+		 * not implied into a #/## construction are macro-expanded
+		 * seperately, then included into the token stream.
+		 */
+		if (ct->type == DSHARP || ct->type == DIG_DSHARP) {
+			if (ltwds) {
+				error(ls->line, "quad sharp");
+				m->nest = save_nest;
+#ifdef LOW_MEM
+				m->cval.rp = save_art;
+#else
+				m->val.art = save_art;
+#endif
+				return 1;
+			}
+#ifdef LOW_MEM
+			if (m->cval.rp < m->cval.length
+				&& ttMWS(m->cval.t[m->cval.rp]))
+					m->cval.rp ++;
+#else
+			if (m->val.art < m->val.nt
+				&& ttMWS(m->val.t[m->val.art].type))
+					m->val.art ++;
+#endif
+			ltwds = 1;
+			continue;
+		} else if (ltwds && etl.nt != 0) {
+			if (concat_token(etl.t + (-- etl.nt), ct)) {
+				error(ls->line, "operator '##' produced "
+					"the invalid token '%s%s'",
+					token_name(etl.t + etl.nt),
+					token_name(ct));
+				m->nest = save_nest;
+#ifdef LOW_MEM
+				m->cval.rp = save_art;
+#else
+				m->val.art = save_art;
+#endif
+				return 1;
+			}
+			if (etl.nt == 0) freemem(etl.t);
+			t.type = dsharp_lexer.ctok->type;
+			t.line = ls->line;
+			if (S_TOKEN(t.type)) {
+				t.name = sdup(dsharp_lexer.ctok->name);
+				throw_away(ls->gf, t.name);
+			}
+			ct = &t;
+		}
+		ltwds = 0;
+#ifdef LOW_MEM
+		if ((ct->type == SHARP || ct->type == DIG_SHARP)
+			&& next < m->cval.length
+			&& (m->cval.t[next] == MACROARG
+			|| (ttMWS(m->cval.t[next])
+			&& (next + 1) < m->cval.length
+			&& m->cval.t[next + 1] == MACROARG))) {
+#else
+		if ((ct->type == SHARP || ct->type == DIG_SHARP)
+			&& next < m->val.nt
+			&& (m->val.t[next].type == MACROARG
+			|| (ttMWS(m->val.t[next].type)
+			&& (next + 1) < m->val.nt
+			&& m->val.t[next + 1].type == MACROARG))) {
+#endif
+			/*
+			 * We have a # operator followed by (an optional
+			 * whitespace and) a macro argument; this means
+			 * stringification. So be it.
+			 */
+#ifdef LOW_MEM
+			if (ttMWS(m->cval.t[next])) m->cval.rp ++;
+#else
+			if (ttMWS(m->val.t[next].type)) m->val.art ++;
+#endif
+			t.type = STRING;
+#ifdef LOW_MEM
+			m->cval.rp ++;
+			t.name = stringify(atl +
+				(size_t)(m->cval.t[m->cval.rp ++]));
+#else
+			t.name = stringify(atl +
+				(size_t)(m->val.t[m->val.art ++].line));
+#endif
+			throw_away(ls->gf, t.name);
+			ct = &t;
+			/*
+			 * There is no need for extra spaces here.
+			 */
+		}
+		t = *ct;
+		ZAP_LINE(t);
+		aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+	}
+#ifdef LOW_MEM
+	m->cval.rp = save_art;
+#else
+	m->val.art = save_art;
+#endif
+
+
+	/*
+	 * Now etl contains the expanded macro, to be parsed again for
+	 * further expansions -- much easier, since '#' and '##' have
+	 * already been handled.
+	 * However, we might need some input from tfi. So, we paste
+	 * the contents of tfi after etl, and we put back what was
+	 * not used.
+	 *
+	 * Some adjacent spaces are merged; only unique NONE, or sequences
+	 * OPT_NONE NONE are emitted.
+	 */
+	etl_limit = etl.nt;
+	if (tfi) {
+		save_tfi = tfi->art;
+		while (tfi->art < tfi->nt) aol(etl.t, etl.nt,
+			tfi->t[tfi->art ++], TOKEN_LIST_MEMG);
+	}
+	ltwws = 0;
+	while (etl.art < etl_limit) {
+		struct macro *nm;
+
+		ct = etl.t + (etl.art ++);
+		if (ct->type == NAME && ct->line >= 0
+			&& (nm = getHT(macros, &(ct->name)))) {
+			if (substitute_macro(ls, nm, &etl,
+				penury, reject_nested, l)) {
+				m->nest = save_nest;
+				return 1;
+			}
+			ltwws = 0;
+			continue;
+		}
+		if (ttMWS(ct->type)) {
+			if (ltwws == 1) {
+				if (ct->type == OPT_NONE) continue;
+				ltwws = 2;
+			} else if (ltwws == 2) continue;
+			else if (ct->type == OPT_NONE) ltwws = 1;
+			else ltwws = 2;
+		} else ltwws = 0;
+		if (ct->line >= 0) ct->line = l;
+		print_token(ls, ct, reject_nested ? 0 : l);
+	}
+	if (etl.nt) freemem(etl.t);
+	if (tfi) {
+		tfi->art = save_tfi + (etl.art - etl_limit);
+	}
+
+exit_macro_1:
+	print_space(ls);
+exit_macro_2:
+	for (i = 0; i < m->narg; i ++) if (atl[i].nt) freemem(atl[i].t);
+	if (m->narg > 0) freemem(atl);
+	m->nest = save_nest;
+	return 0;
+}
+
+/*
+ * print already defined macros
+ */
+void print_defines(void)
+{
+	scanHT(macros, print_macro);
+}
+
+/*
+ * define_macro() defines a new macro, whom definition is given in
+ * the command-line syntax: macro=def
+ * The '=def' part is optional.
+ *
+ * It returns non-zero on error.
+ */
+int define_macro(struct lexer_state *ls, char *def)
+{
+	char *c = sdup(def), *d;
+	int with_def = 0;
+	int ret = 0;
+
+	for (d = c; *d && *d != '='; d ++);
+	if (*d) {
+		*d = ' ';
+		with_def = 1;
+	}
+	if (with_def) {
+		struct lexer_state lls;
+		size_t n = strlen(c) + 1;
+
+		if (c == d) {
+			error(-1, "void macro name");
+			ret = 1;
+		} else {
+			*(c + n - 1) = '\n';
+			init_buf_lexer_state(&lls, 0);
+			lls.flags = ls->flags | LEXER;
+			lls.input = 0;
+			lls.input_string = (unsigned char *)c;
+			lls.pbuf = 0;
+			lls.ebuf = n;
+			lls.line = -1;
+			ret = handle_define(&lls);
+			free_lexer_state(&lls);
+		}
+	} else {
+		struct macro *m;
+
+		if (!*c) {
+			error(-1, "void macro name");
+			ret = 1;
+		} else if ((m = getHT(macros, &c))
+#ifdef LOW_MEM
+			&& (m->cval.length != 3
+			|| m->cval.t[0] != NUMBER
+			|| strcmp((char *)(m->cval.t + 1), "1"))) {
+#else
+			&& (m->val.nt != 1
+			|| m->val.t[0].type != NUMBER
+			|| strcmp(m->val.t[0].name, "1"))) {
+#endif
+			error(-1, "macro %s already defined", c);
+			ret = 1;
+		} else {
+#ifndef LOW_MEM
+			struct token t;
+#endif
+
+			m = new_macro();
+			m->name = sdup(c);
+#ifdef LOW_MEM
+			m->cval.length = 3;
+			m->cval.t = getmem(3);
+			m->cval.t[0] = NUMBER;
+			m->cval.t[1] = '1';
+			m->cval.t[2] = 0;
+#else
+			t.type = NUMBER;
+			t.name = sdup("1");
+			aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);
+#endif
+			putHT(macros, m);
+		}
+	}
+	freemem(c);
+	return ret;
+}
+
+/*
+ * undef_macro() undefines the macro whom name is given as "def";
+ * it is not an error to try to undef a macro that does not exist.
+ *
+ * It returns non-zero on error (undefinition of a special macro,
+ * void macro name).
+ */
+int undef_macro(struct lexer_state *ls, char *def)
+{
+	char *c = def;
+
+	if (!*c) {
+		error(-1, "void macro name");
+		return 1;
+	}
+	if (getHT(macros, &c)) {
+		if (check_special_macro(c)) {
+			error(-1, "trying to undef special macro %s", c);
+			return 1;
+		} else delHT(macros, &c);
+	}
+	return 0;
+}
+
+/*
+ * We saw a #ifdef directive. Parse the line.
+ * return value: 1 if the macro is defined, 0 if it is not, -1 on error
+ */
+int handle_ifdef(struct lexer_state *ls)
+{
+	while (!next_token(ls)) {
+		int tgd = 1;
+
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type == NAME) {
+			int x = (getHT(macros, &(ls->ctok->name)) != 0);
+			while (!next_token(ls) && ls->ctok->type != NEWLINE)
+				if (tgd && !ttWHI(ls->ctok->type)
+					&& (ls->flags & WARN_STANDARD)) {
+					warning(ls->line, "trailing garbage "
+						"in #ifdef");
+					tgd = 0;
+				}
+			return x;
+		}
+		error(ls->line, "illegal macro name for #ifdef");
+		while (!next_token(ls) && ls->ctok->type != NEWLINE)
+			if (tgd && !ttWHI(ls->ctok->type)
+				&& (ls->flags & WARN_STANDARD)) {
+				warning(ls->line, "trailing garbage in "
+					"#ifdef");
+				tgd = 0;
+			}
+		return -1;
+	}
+	error(ls->line, "unfinished #ifdef");
+	return -1;
+}
+
+/*
+ * for #undef
+ * return value: 1 on error, 0 on success. Undefining a macro that was
+ * already not defined is not an error.
+ */
+int handle_undef(struct lexer_state *ls)
+{
+  /*vb*/
+#ifdef HAVE_MISRA
+  if(nesting!=0) misra_neu(91,19,5,0);
+  misra_neu(92,19,6,0);
+#endif
+
+	while (!next_token(ls)) {
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type == NAME) {
+			struct macro *m = getHT(macros, &(ls->ctok->name));
+			int tgd = 1;
+
+			if (m != 0) {
+				if (check_special_macro(ls->ctok->name)) {
+					error(ls->line, "trying to undef "
+						"special macro %s",
+						ls->ctok->name);
+					goto undef_error;
+				}
+				if (emit_defines)
+					fprintf(emit_output, "#undef %s\n",
+						m->name);
+				delHT(macros, &(ls->ctok->name));
+			}
+			while (!next_token(ls) && ls->ctok->type != NEWLINE)
+				if (tgd && !ttWHI(ls->ctok->type)
+					&& (ls->flags & WARN_STANDARD)) {
+					warning(ls->line, "trailing garbage "
+						"in #undef");
+					tgd = 0;
+				}
+			return 0;
+		}
+		error(ls->line, "illegal macro name for #undef");
+	undef_error:
+		while (!next_token(ls) && ls->ctok->type != NEWLINE);
+		return 1;
+	}
+	error(ls->line, "unfinished #undef");
+	return 1;
+}
+
+/*
+ * for #ifndef
+ * return value: 0 if the macro is defined, 1 if it is not, -1 on error.
+ */
+int handle_ifndef(struct lexer_state *ls)
+{
+	while (!next_token(ls)) {
+		int tgd = 1;
+
+		if (ls->ctok->type == NEWLINE) break;
+		if (ttMWS(ls->ctok->type)) continue;
+		if (ls->ctok->type == NAME) {
+			int x = (getHT(macros, &(ls->ctok->name)) == 0);
+
+			while (!next_token(ls) && ls->ctok->type != NEWLINE)
+				if (tgd && !ttWHI(ls->ctok->type)
+					&& (ls->flags & WARN_STANDARD)) {
+					warning(ls->line, "trailing garbage "
+						"in #ifndef");
+					tgd = 0;
+				}
+			if (protect_detect.state == 1) {
+				protect_detect.state = 2;
+				protect_detect.macro = sdup(ls->ctok->name);
+			}
+			return x;
+		}
+		error(ls->line, "illegal macro name for #ifndef");
+		while (!next_token(ls) && ls->ctok->type != NEWLINE)
+			if (tgd && !ttWHI(ls->ctok->type)
+				&& (ls->flags & WARN_STANDARD)) {
+				warning(ls->line, "trailing garbage in "
+					"#ifndef");
+				tgd = 0;
+			}
+		return -1;
+	}
+	error(ls->line, "unfinished #ifndef");
+	return -1;
+}
+
+/*
+ * initialize the macro table
+ */
+void init_macros(void)
+{
+	if (macros) killHT(macros);
+	macros = newHT(128, cmp_struct, hash_struct, del_macro);
+	if (!no_special_macros) add_special_macros();
+}
+
+/*
+ * find a macro from its name
+ */
+struct macro *get_macro(char *name)
+{
+	return getHT(macros, &name);
+}
diff --git a/ucpp/mem.c b/ucpp/mem.c
new file mode 100755
index 0000000..db621d5
--- /dev/null
+++ b/ucpp/mem.c
@@ -0,0 +1,157 @@
+/*
+ * Memory manipulation routines
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "mem.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef AUDIT
+void die(void)
+{
+	abort();
+}
+
+static void suicide(unsigned long e)
+{
+	fprintf(stderr, "ouch: Schrodinger's beef is not dead ! %lx\n", e);
+	die();
+}
+#else
+void die(void)
+{
+	exit(1);
+}
+#endif
+
+#if defined AUDIT || defined MEM_CHECK
+/*
+ * This function is equivalent to a malloc(), but will display an error
+ * message and exit if the wanted memory is not available
+ */
+void *getmem(size_t x)
+{
+	void *m;
+
+#ifdef AUDIT
+	m = malloc(x + 8);
+#else
+	m = malloc(x);
+#endif
+	if (m == 0) {
+		fprintf(stderr, "ouch: malloc() failed\n");
+		die();
+	}
+#ifdef AUDIT
+	*((unsigned long *)m) = 0xdeadbeefUL;
+	return (void *)(((char *)m) + 8);
+#else
+	return m;
+#endif
+}
+#endif
+
+/*
+ * This function is equivalent to a realloc(); if the realloc() call
+ * fails, it will try a malloc() and a memcpy(). If not enough memory is
+ * available, the program exits with an error message
+ */
+void *incmem(void *m, size_t x, size_t nx)
+{
+	void *nm;
+
+#ifdef AUDIT
+	m = (void *)(((char *)m) - 8);
+	if (*((unsigned long *)m) != 0xdeadbeefUL)
+		suicide(*((unsigned long *)m));
+	x += 8; nx += 8;
+#endif
+	if (!(nm = realloc(m, nx))) {
+		if (x > nx) x = nx;
+		nm = getmem(nx);
+		memcpy(nm, m, x);
+		/* free() and not freemem(), because of the Schrodinger beef */
+		free(m);
+	}
+#ifdef AUDIT
+	return (void *)(((char *)nm) + 8);
+#else
+	return nm;
+#endif
+}
+
+#ifdef AUDIT
+/*
+ * This function frees the given block
+ */
+void freemem(void *x)
+{
+#ifdef AUDIT
+	void *y = (void *)(((char *)x) - 8);
+
+	if ((*((unsigned long *)y)) != 0xdeadbeefUL)
+		suicide(*((unsigned long *)y));
+	*((unsigned long *)y) = 0xfeedbabeUL;
+	free(y);
+#else
+	free(x);
+#endif
+}
+#endif
+
+#ifdef AUDIT
+/*
+ * This function copies n bytes from src to dest
+ */
+void *mmv(void *dest, void *src, size_t n)
+{
+	return memcpy(dest, src, n);
+}
+
+/*
+ * This function copies n bytes from src to dest
+ */
+void *mmvwo(void *dest, void *src, size_t n)
+{
+	return memmove(dest, src, n);
+}
+#endif
+
+/*
+ * This function creates a new char * and fills it with a copy of src
+ */
+char *sdup(char *src)
+{
+	size_t n = 1 + strlen(src);
+	char *x = getmem(n);
+
+	mmv(x, src, n);
+	return x;
+}
diff --git a/ucpp/mem.h b/ucpp/mem.h
new file mode 100755
index 0000000..6d646b7
--- /dev/null
+++ b/ucpp/mem.h
@@ -0,0 +1,133 @@
+/*
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__MEM__
+#define UCPP__MEM__
+
+#include <stdlib.h>
+
+void die(void);
+void *incmem(void *, size_t, size_t);
+char *sdup(char *);
+
+#if defined AUDIT || defined MEM_CHECK
+void *getmem(size_t);
+#else
+#define getmem		malloc
+#endif
+
+#ifdef AUDIT
+void freemem(void *);
+#else
+#define freemem		free
+#endif
+
+#ifdef AUDIT
+void *mmv(void *, void *, size_t);
+void *mmvwo(void *, void *, size_t);
+#else
+#define mmv	memcpy
+#define mmvwo	memmove
+#endif
+
+/*
+ * this macro adds the object obj at the end of the array list, handling
+ * memory allocation when needed; ptr contains the number of elements in
+ * the array, and memg is the granularity of memory allocations (a power
+ * of 2 is recommanded, for optimization reasons)
+ *
+ * list and ptr may be updated, and thus need to be lvalues
+ */
+#define aol(list,ptr,obj,memg) do { \
+		if (((ptr) % (memg)) == 0) { \
+			if ((ptr) != 0) { \
+				(list) = incmem((list), (ptr) * sizeof(obj), \
+					((ptr) + (memg)) * sizeof(obj)); \
+			} else { \
+				(list) = getmem((memg) * sizeof(obj)); \
+			} \
+		} \
+		(list)[(ptr) ++] = (obj); \
+	} while (0)
+
+/*
+ * bol() does the same as aol(), but adds the new item at the beginning
+ * of the list; beware, the computational cost is greater.
+ */
+#define bol(list,ptr,obj,memg) do { \
+		if (((ptr) % (memg)) == 0) { \
+			if ((ptr) != 0) { \
+				(list) = incmem((list), (ptr) * sizeof(obj), \
+					((ptr) + (memg)) * sizeof(obj)); \
+			} else { \
+				(list) = getmem((memg) * sizeof(obj)); \
+			} \
+		} \
+		if ((ptr) != 0) \
+			mmvwo((list) + 1, (list), (ptr) * sizeof(obj)); \
+		(ptr) ++; \
+		(list)[0] = (obj); \
+	} while (0)
+
+/*
+ * mbol() does the same as bol(), but adds the new item at the given
+ * emplacement; bol() is equivalent to mbol with 0 as last argument.
+ */
+#define mbol(list,ptr,obj,memg,n) do { \
+		if (((ptr) % (memg)) == 0) { \
+			if ((ptr) != 0) { \
+				(list) = incmem((list), (ptr) * sizeof(obj), \
+					((ptr) + (memg)) * sizeof(obj)); \
+			} else { \
+				(list) = getmem((memg) * sizeof(obj)); \
+			} \
+		} \
+		if ((ptr) > n) \
+			mmvwo((list) + n + 1, (list) + n, \
+				((ptr) - n) * sizeof(obj)); \
+		(ptr) ++; \
+		(list)[n] = (obj); \
+	} while (0)
+
+/*
+ * this macro adds the object obj at the end of the array list, doubling
+ * the size of list when needed; as for aol(), ptr and list must be
+ * lvalues, and so must be llng
+ */
+
+#define wan(list,ptr,obj,llng) do { \
+		if ((ptr) == (llng)) { \
+			(llng) += (llng); \
+			(list) = incmem((list), (ptr) * sizeof(obj), \
+				(llng) * sizeof(obj)); \
+		} \
+		(list)[(ptr) ++] = (obj); \
+	} while (0)
+
+#endif
diff --git a/ucpp/sample.c b/ucpp/sample.c
new file mode 100755
index 0000000..7903184
--- /dev/null
+++ b/ucpp/sample.c
@@ -0,0 +1,107 @@
+/*
+ * Sample code showing how to use ucpp as an integrated lexer.
+ * This file is public domain.
+ */
+
+/*
+ * This is an example of how to use ucpp as a preprocessor and lexer
+ * into another project. The steps are those described in ucpp README
+ * file. To use this code, compile the ucpp source files with
+ * STAND_ALONE not defined, and link them with this code. The resulting
+ * binary will take a C source file as standard input, preprocess it,
+ * and output each non-whitespace token on stdout, with its numerical
+ * value (defined as an enum in cpp.h) and its contents. This code
+ * defines no system include path.
+ *
+ * This code supposes that the ucpp files are compiled with PRAGMA_TOKENIZE
+ * enabled (see the tune.h file).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mem.h"
+#include "cpp.h"
+
+int main(int argc, char *argv[])
+{
+	int i, r;
+	struct lexer_state ls;
+
+	/* step 1 */
+	init_cpp();
+
+	/* step 2 */
+	no_special_macros = 0;
+	emit_defines = emit_assertions = 0;
+
+	/* step 3 -- with assertions */
+	init_tables(1);
+
+	/* step 4 -- no default include path */
+	init_include_path(0);
+
+	/* step 5 -- no need to reset the two emit_* variables set in 2 */
+	emit_dependencies = 0;
+
+	/* step 6 -- we work with stdin, this is not a real filename */
+	set_init_filename("[stdin]", 0);
+
+	/* step 7 -- we make sure that assertions are on, and pragma are
+	   handled */
+	init_lexer_state(&ls);
+	init_lexer_mode(&ls);
+	ls.flags |= HANDLE_ASSERTIONS | HANDLE_PRAGMA | LINE_NUM;
+
+	/* step 8 -- input is from stdin */
+	ls.input = stdin;
+
+	/* step 9 -- we do not have any macro to define, but we add any
+	   argument as an include path */
+	for (i = 1; i < argc; i ++) add_incpath(argv[i]);
+
+	/* step 10 -- we are a lexer and we want CONTEXT tokens */
+	enter_file(&ls, ls.flags);
+
+	/* read tokens until end-of-input is reached -- errors (non-zero
+	   return values different from CPPERR_EOF) are ignored */
+	while ((r = lex(&ls)) < CPPERR_EOF) {
+		if (r) {
+			/* error condition -- no token was retrieved */
+			continue;
+		}
+		/* we print each token: its numerical value, and its
+		   string content; if this is a PRAGMA token, the
+		   string content is in fact a compressed token list,
+		   that we uncompress and print. */
+		if (ls.ctok->type == PRAGMA) {
+			unsigned char *c = (unsigned char *)(ls.ctok->name);
+
+			printf("line %ld: <#pragma>\n", ls.line);
+			for (; *c; c ++) {
+				int t = *c;
+
+				if (STRING_TOKEN(t)) {
+					printf("  <%2d>  ", t);
+					for (c ++; *c != PRAGMA_TOKEN_END;
+						c ++) putchar(*c);
+					putchar('\n');
+				} else {
+					printf("  <%2d>  `%s'\n", t,
+						operators_name[t]);
+				}
+			}
+		} else if (ls.ctok->type == CONTEXT) {
+			printf("new context: file '%s', line %ld\n",
+				ls.ctok->name, ls.ctok->line);
+		} else if (ls.ctok->type == NEWLINE) {
+			printf("[newline]\n");
+		} else {
+			printf("line %ld: <%2d>  `%s'\n", ls.ctok->line,
+				ls.ctok->type,
+				STRING_TOKEN(ls.ctok->type) ? ls.ctok->name
+				: operators_name[ls.ctok->type]);
+		}
+	}
+	return 0;
+}
diff --git a/ucpp/tune.h b/ucpp/tune.h
new file mode 100755
index 0000000..feb6275
--- /dev/null
+++ b/ucpp/tune.h
@@ -0,0 +1,308 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__TUNE__
+#define UCPP__TUNE__
+
+/* ====================================================================== */
+/*
+ * Define LOW_MEM for low memory machines. It seems to improve performance
+ * on larger systems, so this is on by default.
+ */
+#define LOW_MEM
+
+/* ====================================================================== */
+/*
+ * Define AMIGA for systems using "drive letters" at the beginning of
+ * some paths; define MSDOS on systems with drive letters and using
+ * backslashes to seperate directory components. ATARI is same as MSDOS
+ * but does not use %VAR% notation and Turbo C specific code.
+ */
+/* #define AMIGA */
+/* #define MSDOS */
+/* #define ATARI */
+
+/* ====================================================================== */
+/*
+ * Buffering: there are two levels of buffering on input and output streams:
+ * the standard libc buffering (manageable with setbuf() and setvbuf())
+ * and some buffering provided by ucpp itself. The ucpp buffering uses
+ * two buffers, of size respectively INPUT_BUF_MEMG and OUTPUT_BUF_MEMG
+ * (as defined below).
+ * You can disable one or both of these bufferings by defining the macros
+ * NO_LIBC_BUF and NO_UCPP_BUF.
+ *
+ * Performance may vary, depending on the target architecture. On a
+ * Linux/Alpha workstation, use both bufferings (that means, disable none
+ * of them) for maximum performance. On a Minix-86 machine, disabling
+ * ucpp buffering saves some memory and does not seem to impact performance.
+ */
+/* #define NO_LIBC_BUF */
+/* #define NO_UCPP_BUF */
+
+/*
+ * On Unix stations, the system call mmap() might be used on input files.
+ * This option is a subclause of ucpp internal buffering. On one station,
+ * a 10% speed improvement was observe. Do not define this unless the
+ * host architecture has the following characteristics:
+ *  -- Posix compliance
+ *  -- Text files correspond one to one with memory representation
+ * If a file is not seekable or not mmapable, ucpp will revert to the
+ * standard fread() solution.
+ *
+ * This feature is still considered beta quality. On some systems where
+ * files can be bigger than memory address space (mainly, 32-bit systems
+ * with files bigger than 4 GB), this option makes ucpp fail to operate
+ * on those extremely large files.
+ */
+/* #define UCPP_MMAP */
+
+/* To protect the innocent. */
+#if defined(NO_UCPP_BUF) && defined(UCPP_MMAP)
+#undef UCPP_MMAP
+#endif
+
+/* ====================================================================== */
+/*
+ * Define this if you want ucpp to generate tokenized PRAGMA tokens;
+ * otherwise, it will generate raw string contents. This setting is
+ * irrelevant to the stand-alone version of ucpp.
+ */
+/*#define PRAGMA_TOKENIZE*/
+
+/*
+ * Define this to the special character that marks the end of tokens with
+ * a string value inside a tokenized PRAGMA token. The #pragma and _Pragma()
+ * directives which use this character will be a bit more difficult to
+ * decode (but ucpp will not mind). 0 cannot be used. '\n' is fine because
+ * it cannot appear inside a #pragma or _Pragma(), since newlines cannot be
+ * embedded inside tokens, neither directly nor by macro substitution and
+ * stringization. Besides, '\n' is portable.
+ */
+#define PRAGMA_TOKEN_END	((unsigned char)'\n')
+
+/*
+ * Define this if you want ucpp to include encountered #pragma directives
+ * in its output in non-lexer mode; _Pragma() are translated to equivalent
+ * #pragma directives.
+ */
+#define PRAGMA_DUMP
+
+/*
+ * According to may interpretation of the C99 standard, _Pragma() are
+ * evaluated wherever macro expansion could take place. However, Neil Booth,
+ * whose mother language is English (contrary to me) and who is well aware
+ * of the C99 standard (and especially the C preprocessor) told me that
+ * it was unclear whether _Pragma() are evaluated inside directives such
+ * as #if, #include and #line. If you want to disable the evaluation of
+ * _Pragma() inside such directives, define the following macro.
+ */
+/* #define NO_PRAGMA_IN_DIRECTIVE */
+
+/* ====================================================================== */
+/*
+ * Define INMACRO_FLAG to include two flags to the structure lexer_state,
+ * that tell whether tokens come from a macro-replacement, and count those
+ * macro-replacements.
+ */
+/* #define INMACRO_FLAG */
+
+/* ====================================================================== */
+/*
+ * Paths where files are looked for by default, when #include is used.
+ * Typical path is /usr/local/include and /usr/include, in that order.
+ * If you want to set up no path, define the macro to 0.
+ *
+ * For Linux, get gcc includes too, or you will miss things like stddef.h.
+ * The exact path varies much, depending on the distribution.
+ */
+#define STD_INCLUDE_PATH	"/usr/local/include", "/usr/include", \
+	"/usr/lib/gcc-lib/alphaev56-unknown-linux-gnu/2.95.2/include"
+
+/* ====================================================================== */
+/*
+ * For the evaluation of #if expression. If NATIVE_UINTMAX is defined,
+ * the evaluation is done with NATIVE_UINTMAX as unsigned type, and
+ * NATIVE_INTMAX as signed type. If NATIVE_UINTMAX is not defined but
+ * SIMUL_UINTMAX is defined, evaluation is performed with a big integer
+ * type, whom size is twice the size of unsigned long. If neither is
+ * defined, ucpp will use uintmax_t and intmax_t if available, unsigned
+ * long and long otherwise.
+ * See the README file for details.
+ */
+/*
+ * uncomment these two lines if you want evaluation with a "long long" type
+#define NATIVE_UINTMAX	unsigned long long
+#define NATIVE_INTMAX	long long
+ */
+/*
+ * uncomment the following if you want evaluation with an emulated type
+ * built with two "unsigned long".
+#define SIMUL_UINTMAX
+ */
+/*
+ * to force signedness of wide character constants, define WCHAR_SIGNEDNESS
+ * to 0 for unsigned, 1 for signed.
+#define WCHAR_SIGNEDNESS	0
+ */
+
+/* ====================================================================== */
+/*
+ * Standard assertions. They should include one cpu() assertion, one machine()
+ * assertion (identical to cpu()), and one or more system() assertions.
+ *
+ * for Linux/PC:      cpu(i386),  machine(i386),  system(unix), system(linux)
+ * for Linux/Alpha:   cpu(alpha), machine(alpha), system(unix), system(linux)
+ * for Sparc/Solaris: cpu(sparc), machine(sparc), system(unix), system(solaris)
+ *
+ * These are only suggestions. On Solaris, machine() should be defined
+ * for i386 or sparc. For cross-compilation, define assertions related
+ * to the target architecture.
+ *
+ * If you want no standard assertion, define STD_ASSERT to 0.
+ */
+#define STD_ASSERT	"cpu(alpha)", "machine(alpha)", "system(unix)", \
+			"system(linux)"
+
+/* ====================================================================== */
+/*
+ * System predefined macros. Nothing really mandatory, but some programs
+ * might rely on those.
+ * Each string must be either "name" or "name=token-list". If you want
+ * no predefined macro, define STD_MACROS to 0.
+ */
+#define STD_MACROS	"__linux", "__unix", "__alpha", \
+			"__linux__", "__unix__", "__alpha__"
+
+/* ====================================================================== */
+/*
+ * Default flags; HANDLE_ASSERTIONS is required for Solaris system headers.
+ * See cpp.h for the definition of these flags.
+ */
+#define DEFAULT_CPP_FLAGS	(DISCARD_COMMENTS | WARN_STANDARD \
+				| WARN_PRAGMA | FAIL_SHARP | MACRO_VAARG \
+				| CPLUSPLUS_COMMENTS | LINE_NUM | TEXT_OUTPUT \
+				| KEEP_OUTPUT | HANDLE_TRIGRAPHS \
+				| HANDLE_ASSERTIONS)
+#define DEFAULT_LEXER_FLAGS	(DISCARD_COMMENTS | WARN_STANDARD | FAIL_SHARP \
+				| MACRO_VAARG | CPLUSPLUS_COMMENTS | LEXER \
+				| HANDLE_TRIGRAPHS | HANDLE_ASSERTIONS)
+
+/* ====================================================================== */
+/*
+ * Define this to use sigsetjmp()/siglongjmp() instead of setjmp()/longjmp().
+ * This is non-ANSI, but recommended on AIX systems.
+ */
+/* #define POSIX_JMP */
+
+/* ====================================================================== */
+/*
+ * Maximum value (plus one) of a character handled by the lexer; 128 is
+ * alright for ASCII native source code, but 256 is needed for EBCDIC.
+ * 256 is safe in both cases; you will have big problems if you set
+ * this value to INT_MAX or above. On Minix-86 or Msdos (small memory
+ * model), define MAX_CHAR_VAL to 128.
+ *
+ * Set MAX_CHAR_VAL to a power of two to increase lexing speed. Beware
+ * that lexer.c defines a static array of size MSTATE * MAX_CHAR_VAL
+ * values of type int (MSTATE is defined in lexer.c and is about 40).
+ */
+#define MAX_CHAR_VAL	256
+
+/*
+ * If you want some extra character to be considered as whitespace,
+ * define this macro to that space. On ISO-8859-1 machines, 160 is
+ * the code for the unbreakable space.
+ */
+/* #define UNBREAKABLE_SPACE	160 */
+
+/*
+ * If you want whitespace tokens contents to be recorded (making them
+ * tokens with a string content), define this. The macro STRING_TOKEN
+ * will be adjusted accordingly.
+ * Without this option, whitespace tokens are not even returned by the
+ * lex() function. This is irrelevant for the non-lexer mode (almost --
+ * it might slow down a bit ucpp, and with this option, comments will be
+ * kept inside #pragma directives).
+ */
+/* #define SEMPER_FIDELIS */
+
+/* ====================================================================== */
+/*
+ * Some constants used for memory increment granularity. Increasing these
+ * values reduces the number of calls to malloc() but increases memory
+ * consumption.
+ *
+ * Values should be powers of 2.
+ */
+
+/* for cpp.c */
+#define COPY_LINE_LENGTH	80
+#define INPUT_BUF_MEMG		8192
+#define OUTPUT_BUF_MEMG		8192
+#define TOKEN_NAME_MEMG		64	/* must be at least 4 */
+#define TOKEN_LIST_MEMG		32
+#define INCPATH_MEMG		16
+#define GARBAGE_LIST_MEMG	32
+#define LS_STACK_MEMG		4
+#define FNAME_MEMG		32
+
+/* ====================================================================== */
+/*
+ * C90 does not know about the "inline" keyword, but C99 does know,
+ * and some C90 compilers know it as an extension. This part detects
+ * these occurrences.
+ */
+
+#ifndef INLINE
+
+#if __STDC__ && __STDC_VERSION >= 199901L
+/* this is a C99 compiler, keep inline unchanged */
+#elif defined(__GNUC__)
+/* this is GNU gcc; modify inline. The semantics is not identical to C99
+   but the differences are irrelevant as long as inline functions are static */
+#undef inline
+#define inline __inline__
+#elif defined(__DECC) && defined(__linux__)
+/* this is Compaq C under Linux, use __inline__ */
+#undef inline
+#define inline __inline__
+#else
+/* unknown compiler -> deactivate inline */
+#undef inline
+#define inline
+#endif
+
+#else
+/* INLINE has been set, use its value */
+#undef inline
+#define inline INLINE
+#endif
+
+#endif
diff --git a/ucpp/ucppi.h b/ucpp/ucppi.h
new file mode 100755
index 0000000..6ae982d
--- /dev/null
+++ b/ucpp/ucppi.h
@@ -0,0 +1,192 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__UCPPI__
+#define UCPP__UCPPI__
+
+#include "cpp.h"
+#include "tune.h"
+
+/*
+ * A macro represented in a compact form; simple tokens are represented
+ * by one byte, containing their number. Tokens with a string value are
+ * followed by the value (string finished by a 0). Macro arguments are
+ * followed by the argument number (in one byte -- thus implying a hard
+ * limit of 254 arguments (number 255 is for __VA_ARGS__).
+ */
+struct comp_token_fifo {
+	size_t length;
+	size_t rp;
+	unsigned char *t;
+};
+
+/* These declarations are used only internally by ucpp */
+
+/*
+ * S_TOKEN(x)	checks whether x is a token type with an embedded string
+ * ttMWS(x)	checks whether x is macro whitespace (space, comment...)
+ * ttWHI(x)	checks whether x is whitespace (MWS or newline)
+ */
+#define S_TOKEN(x)	STRING_TOKEN(x)
+#define ttMWS(x)	((x) == NONE || (x) == COMMENT || (x) == OPT_NONE)
+#define ttWHI(x)	(ttMWS(x) || (x) == NEWLINE)
+
+/*
+ * Function prototypes
+ */
+/*
+ * from lexer.c
+ */
+#define init_cppm	ucpp_init_cppm
+#define put_char	ucpp_put_char
+#define discard_char	ucpp_discard_char
+#define next_token	ucpp_next_token
+#define grap_char	ucpp_grap_char
+#define space_char	ucpp_space_char
+
+void init_cppm(void);
+void put_char(struct lexer_state *, unsigned char);
+void discard_char(struct lexer_state *);
+int next_token(struct lexer_state *);
+int grap_char(struct lexer_state *);
+int space_char(int);
+
+/*
+ * from assert.c
+ */
+struct assert {
+	char *name;	/* this must be the first field */
+	size_t nbval;
+	struct token_fifo *val;
+};
+
+#define cmp_token_list		ucpp_cmp_token_list
+#define handle_assert		ucpp_handle_assert
+#define handle_unassert		ucpp_handle_unassert
+#define get_assertion		ucpp_get_assertion
+
+int cmp_token_list(struct token_fifo *, struct token_fifo *);
+int handle_assert(struct lexer_state *);
+int handle_unassert(struct lexer_state *);
+struct assert *get_assertion(char *);
+
+/*
+ * from macro.c
+ */
+struct macro {
+	char *name;	/* this must be the first field */
+	int narg;
+	char **arg;
+	int nest;
+	int vaarg;
+#ifdef LOW_MEM
+	struct comp_token_fifo cval;
+#else
+	struct token_fifo val;
+#endif
+};
+
+#define print_token		ucpp_print_token
+#define handle_define		ucpp_handle_define
+#define handle_undef		ucpp_handle_undef
+#define handle_ifdef		ucpp_handle_ifdef
+#define handle_ifndef		ucpp_handle_ifndef
+#define substitute_macro	ucpp_substitute_macro
+#define get_macro		ucpp_get_macro
+#define dsharp_lexer		ucpp_dsharp_lexer
+#define compile_time		ucpp_compile_time
+#define compile_date		ucpp_compile_date
+#define compile_adate		ucpp_compile_adate
+#ifdef PRAGMA_TOKENIZE
+#define tokenize_lexer		ucpp_tokenize_lexer
+#endif
+
+void print_token(struct lexer_state *, struct token *, long);
+int handle_define(struct lexer_state *);
+int handle_undef(struct lexer_state *);
+int handle_ifdef(struct lexer_state *);
+int handle_ifndef(struct lexer_state *);
+int substitute_macro(struct lexer_state *, struct macro *,
+	struct token_fifo *, int, int, long);
+struct macro *get_macro(char *);
+
+extern struct lexer_state dsharp_lexer;
+extern char compile_time[], compile_date[], compile_adate[];
+#ifdef PRAGMA_TOKENIZE
+extern struct lexer_state tokenize_lexer;
+#endif
+
+/*
+ * from eval.c
+ */
+#define strtoconst	ucpp_strtoconst
+#define eval_expr	ucpp_eval_expr
+#define eval_line	ucpp_eval_line
+
+unsigned long strtoconst(char *);
+unsigned long eval_expr(struct token_fifo *, int *, int);
+extern long eval_line;
+
+#define eval_exception	ucpp_eval_exception
+
+#ifdef POSIX_JMP
+#define JMP_BUF	sigjmp_buf
+#define catch(x)	sigsetjmp((x), 0)
+#define throw(x)	siglongjmp((x), 1)
+#else
+#define JMP_BUF	jmp_buf
+#define catch(x)	setjmp((x))
+#define throw(x)	longjmp((x), 1)
+#endif
+extern JMP_BUF eval_exception;
+
+/*
+ * from cpp.c
+ */
+#define token_name		ucpp_token_name
+#define throw_away		ucpp_throw_away
+#define garbage_collect		ucpp_garbage_collect
+#define init_buf_lexer_state	ucpp_init_buf_lexer_state
+#ifdef PRAGMA_TOKENIZE
+#define compress_token_list	ucpp_compress_token_list
+#endif
+
+char *token_name(struct token *);
+void throw_away(struct garbage_fifo *, char *);
+void garbage_collect(struct garbage_fifo *);
+void init_buf_lexer_state(struct lexer_state *, int);
+#ifdef PRAGMA_TOKENIZE
+struct comp_token_fifo compress_token_list(struct token_fifo *);
+#endif
+
+#define ouch		ucpp_ouch
+#define error		ucpp_error
+#define warning		ucpp_warning
+
+#endif
diff --git a/vars.c b/vars.c
new file mode 100644
index 0000000..21a12fe
--- /dev/null
+++ b/vars.c
@@ -0,0 +1,105 @@
+/*  $VER: vbcc (vars.c) $Revision: 1.41 $   */
+#include "vbc.h"
+#ifdef AMIGA
+static const char *__ver="$VER: vbcc 0.9i_pre (xx.yy.2022)\r\n";
+long __stack=65536;
+#endif
+char *s,*ident;
+char number[MAXI],buff[MAXI];
+tunit *first_tunit,*last_tunit;
+struct_declaration *first_sd[MAXN],*last_sd[MAXN],*merk_sdf,*merk_sdl;
+struct_identifier *first_si[MAXN],*last_si[MAXN],*merk_sif,*merk_sil;
+identifier_list *first_ilist[MAXN],*last_ilist[MAXN],*merk_ilistf,*merk_ilistl;
+llist *first_llist,*last_llist;
+int nesting;
+hashtable *hash_ext;
+Var *first_var[MAXN],*last_var[MAXN],*merk_varf,*merk_varl,*first_ext,*last_ext;
+Var *block_vla[MAXN];
+llist *vladeflabels[MAXN],*vlajmplabels[MAXN];
+vlaadjust_list *vlaadjusts[MAXN];
+rpair rp;
+FILE *out,*ic1,*ic2,*ppout,*cmdfile;
+int c99=1;
+int force_statics,prefer_statics;
+int range_opt;
+int merge_strings;
+int sec_per_obj;
+int mask_opt;
+int opencl;
+int disallow_statics;
+int header_cnt;
+int wpo,wpo_key;
+FILE *input_wpo;
+int nocode,dontdelete;
+int const_expr,for_decl;
+int registerpri=200,currentpri,looppri=10;
+int return_value,break_label,switch_typ,switch_count,switch_act;
+int pointer_call;
+int softfloat;
+int ecpp;
+type *return_typ;
+Var *return_var;
+zmax local_offset[MAXN];
+int c_flags[MAXCF]={
+    VALFLAG,STRINGFLAG,0,0,
+    VALFLAG,0,0,0,
+    VALFLAG,FUNCFLAG,FUNCFLAG,VALFLAG,
+    VALFLAG,0,0,0,
+    0,0,0,0,
+    0,0,0,0,0,
+    VALFLAG,0,0,0,0,
+    0,VALFLAG,0,0,0,STRINGFLAG,0,
+    VALFLAG,VALFLAG,0,VALFLAG,0,
+    FUNCFLAG,FUNCFLAG,FUNCFLAG,0,
+    0,0,0,0,
+    0,0,0,VALFLAG,
+    0,
+    VALFLAG,VALFLAG,VALFLAG,VALFLAG,
+    STRINGFLAG,0,0,0,0,0,
+    0,0,0,0
+};
+char *c_flags_name[MAXCF]={
+    "O","o","ic1","ic2",
+    "debug","noasm","quiet","ansi",
+    "maxerrors","dontwarn","warn","maxoptpasses",
+    "inline-size","+","cpp-comments","no-trigraphs",
+    "no-inline-peephole","final","E","dontkeep-initialized-data",
+    "strip-path","fp-associative","iso","no-alias-opt","no-multiple-ccs",
+    "unroll-size","double-push","speed","size","unroll-all",
+    "stack-check","inline-depth","g","c99","wpo","cmd","noitra",
+    "misra","coloring","dmalloc","disable","soft-float",
+    "misrawarn","misradontwarn","reserve-reg","ecpp",
+    "short-push","unsigned-char","opencl","no-include-stack",
+    "deps","deps-for-libs","no-cpp-warn","hash-size",
+    "warnings-as-errors",
+    "clist-copy-stack","clist-copy-static","clist-copy-pointer","inline-memcpy",
+    "depobj","c89","force-statics","prefer-statics","range-opt","merge-strings",
+    "sec-per-obj","no-eff-ics","early-eff-ics","mask-opt"
+};
+union ppi c_flags_val[MAXCF];
+char *inname;
+char **target_macros;
+Var *regsbuf[MAXR+1];
+int regbnesting[MAXR+1];
+const_list *first_clist,*last_clist;
+int afterlabel;
+terr_out err_out[]={
+#include "errors.h"
+"",0
+};
+int err_num=sizeof(err_out)/sizeof(err_out[0])-1;
+
+tmisra_err_out misra_err_out[]={
+#include "misra_errors.h"
+0,0,"",0
+};
+
+#ifdef HAVE_ECPP
+struct_declaration *current_class=0;
+type *current_func=0;
+ecpp_dtor_list *ecpp_dlist[MAXN];
+#endif
+
+char *cur_func="shouldn't happen!";
+Var *cur_funcv;
+char *copyright="vbcc V0.9i pre (c) in 1995-2022 by Volker Barthelmann";
diff --git a/vbc.h b/vbc.h
new file mode 100644
index 0000000..6d170ac
--- /dev/null
+++ b/vbc.h
@@ -0,0 +1,273 @@
+/*  $VER: vbcc (vbc.h) $Revision: 1.23 $    */
+
+#include "supp.h"
+
+#define eval_constn(a) eval_const(&a->val,a->ntyp->flags)
+
+typedef struct identifier_list{
+    char *identifier;
+    int length;
+    struct identifier_list *next;
+} identifier_list;
+typedef struct struct_identifier{
+/*    int flags;*/
+  char *identifier;
+  struct struct_declaration *sd;
+  struct struct_identifier *next;
+} struct_identifier;
+
+#ifndef NODES
+#error wrong node
+typedef struct node{
+    int flags,lvalue,sidefx;
+    type *ntyp;
+    struct node *left;
+    struct node *right;
+    struct argument_list *alist;
+    char *identifier;
+    union atyps val;
+    struct obj o;
+} node;
+
+typedef node *np;
+
+#define NODES sizeof(node)
+#endif
+
+typedef struct argument_list{
+  np  arg;
+  struct argument_list *next;
+  struct IC *pushic;
+} argument_list;
+
+
+#define MAXI 512 /* maximale Laenge von Identifiers in Bytes    */
+#define MAXN 128 /* maximale Verschachtelung von Bloecken */
+
+extern struct tunit *first_tunit,*last_tunit;
+extern type *arith_typ(type*,type *);
+extern void insert_constn(np);
+extern int int_erw(int);
+extern type *andcomp(np,np);
+extern void simple_alg_opt(np);
+extern int type_expression(np,type *),
+  compatible_types(type *,type *,int),
+  compare_sd(struct struct_declaration *,struct struct_declaration *);
+#if HAVE_AOS4
+extern int aos4_attr(type *,char *);
+#endif
+extern np identifier_expression(void),constant_expression(void),string_expression(void),
+   postfix_expression(void),unary_expression(void),cast_expression(void),
+   multiplicative_expression(void),additive_expression(void),
+   shift_expression(void),relational_expression(void),equality_expression(void),
+   and_expression(void),exclusive_or_expression(void),
+   inclusive_or_expression(void),logical_and_expression(void),
+   logical_or_expression(void),conditional_expression(void),
+   assignment_expression(void),expression(void),primary_expression(void);
+extern struct argument_list *argument_list_expression(void);
+extern struct const_list *cl_from_string(char *start, char *end);
+
+extern np new_node(void);
+
+/* puh  */
+extern int is_keyword(char *);
+extern void pre(FILE *,np),pra(FILE *,struct argument_list *);
+extern void free_expression(np),free_alist(struct argument_list *);
+extern void cpbez(char *m,int ckw),cpnum(char *m),killsp(void);
+extern void copy_token(/*no prototype because cpp.h not always included*/);
+extern void push_token(/*no prototype because cpp.h not always included*/);
+extern void next_token(void);
+extern struct struct_declaration *add_sd(struct struct_declaration *,int);
+extern void add_sl(struct struct_declaration *,struct struct_list (*)[]);
+extern void free_sd(struct struct_declaration *);
+extern void prl(FILE *,struct struct_declaration *);
+extern char *add_identifier(char *,int);
+extern type *declarator(type *),*direct_declarator(type *),
+           *pointer(type *),*declaration_specifiers(void);
+extern int declaration(int),type_uncomplete(type *);
+extern struct const_list *initialization(type *,int,int,int,struct struct_declaration *,struct const_list *);
+extern void init_local_compound(struct Var *);
+extern zmax init_dyn_sz,init_const_sz;
+extern int init_dyn_cnt,init_const_cnt;
+extern struct struct_declaration *find_struct(char *,int);
+extern void add_struct_identifier(char *,struct struct_declaration *);
+extern void free_si(struct struct_identifier *);
+extern char *ident;
+extern char number[MAXI],buff[MAXI];
+extern struct struct_declaration *first_sd[MAXN],*last_sd[MAXN],*merk_sdf,*merk_sdl;
+extern struct struct_identifier *first_si[MAXN],*last_si[MAXN],*merk_sif,*merk_sil;
+extern struct identifier_list *first_ilist[MAXN],*last_ilist[MAXN],*merk_ilistf,*merk_ilistl;
+extern void free_ilist(struct identifier_list *);
+extern int nesting;
+extern hashtable *hash_ext;
+extern struct Var *first_var[MAXN],*last_var[MAXN],*merk_varf,*merk_varl,*first_ext,*last_ext;
+extern struct Var *block_vla[MAXN];
+extern struct llist *vladeflabels[MAXN],*vlajmplabels[MAXN];
+extern struct vlaadjust_list *vlaadjusts[MAXN];
+extern void freevl(void);
+extern void clearvl(void);
+extern void free_var(struct Var *);
+extern void var_declaration(void);
+extern int storage_class_specifiers(void);
+extern void enter_block(void),leave_block(void);
+extern struct Var *find_var(char *,int);
+extern struct Var *find_ext_var(char *);
+extern struct Var *add_var(char *,type *,int,struct const_list *);
+extern void fi_from_attr(struct Var *);
+extern void needs(char *s);
+
+
+extern int usz;
+
+extern int c99;
+extern int opencl;
+extern int merge_strings;
+extern int mask_opt;
+extern int disallow_statics;
+extern int header_cnt;
+extern int softfloat;
+#define MAGIC_WPO 123
+extern int wpo,wpo_key;
+extern FILE *input_wpo;
+
+extern void gen_IC(np,int,int),convert(np,int),gen_label(int);
+extern void gen_test(struct obj *,int,int,int);
+extern void savescratch(int,struct IC *,int,struct obj *);
+typedef struct regargs_list{
+  struct regargs_list *next;
+  struct argument_list *al;
+  int reg;
+  struct Var *v;
+  int rsaved;
+} regargs_list;
+#ifdef HAVE_REGPARMS
+extern zmax push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **,struct reg_handle *,struct obj *,type *,int,type *);
+#else
+extern zmax push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **);
+#endif
+extern int allocreg(int,int);
+extern void free_reg(int),alloc_hardreg(int);
+
+extern FILE *out,*ic1,*ic2,*ppout,*cmdfile;
+
+extern void statement(void),labeled_statement(void),if_statement(void);
+extern void switch_statement(void),while_statement(void),for_statement(void);
+extern void do_statement(void),goto_statement(void),continue_statement(void);
+extern void break_statement(void),return_statement(void);
+extern void expression_statement(void),compound_statement(void);
+extern void translation_unit(void);
+extern int main(int, char *[]);
+extern int nocode,dontdelete,registerpri,looppri,currentpri;
+extern int no_cast_free;
+
+extern np makepointer(np);
+
+typedef struct vlaadjust_list {
+  struct IC *branch,*first;
+  struct vlaadjust_list *next;
+} vlaadjust_list;
+
+extern int switch_typ,switch_count,switch_act;
+typedef struct llist{
+    char *identifier;
+    int label,flags,switch_count;
+    struct llist *next;
+    union atyps val;
+} llist;
+#define LABELDEFINED 1
+#define LABELUSED 2
+#define LABELDEFAULT 4
+#define LSIZE sizeof(struct llist)
+extern struct llist *first_llist,*last_llist;
+extern struct llist *find_label(char *),*add_label(char *);
+extern void free_llist(struct llist *);
+
+extern int endok,return_label,return_value,break_label;
+extern int const_expr,for_decl;
+extern struct Var *return_var;
+extern type *return_typ;
+extern zmax local_offset[MAXN];
+
+extern void scratch_var(struct obj *,int,type *);
+extern void get_scratch(struct obj *,int,int,type *);
+extern void gen_cond(struct obj *,int,int,int);
+
+#define MAXCF 70
+extern int c_flags[MAXCF];
+extern char *c_flags_name[MAXCF];
+extern union ppi c_flags_val[MAXCF];
+
+extern FILE *open_out(char *,char *);
+
+extern char *inname;
+
+extern void gen_vars(struct Var *);
+
+/*  Format der Tabelle fuer Fehlermeldungen */
+typedef struct err_out{
+    char *text;
+    int  flags;
+} terr_out;
+
+
+/*  Flags fuer err_out.flags    */
+#define ERROR       1
+#define WARNING     2
+#define ANSIV       4
+#define INTERNAL    8
+#define FATAL      16
+#define MESSAGE    32
+#define DONTWARN   64
+#define PREPROC   128
+#define NOLINE    256
+#define INFUNC    512
+#define INIC     1024
+#define NORAUS   2048
+
+extern struct err_out err_out[];
+extern int err_num;
+
+typedef struct misra_err_out{
+		int chapter;
+		int rule;
+		char *text;
+		int flags;
+} tmisra_err_out;
+
+extern struct misra_err_out misra_err_out[];
+
+#define MISRA								1
+#define	MISRA_PREPROC				2
+#define MISRA_2004					4
+#define MISRA_1998					8
+
+#ifdef HAVE_ECPP
+typedef struct ecpp_dtor_list {
+  struct Var *var;
+  struct ecpp_dtor_list *next;
+} ecpp_dtor_list;
+extern struct struct_declaration *current_class;
+extern type *current_func;
+extern struct ecpp_dtor_list *ecpp_dlist[MAXN];
+struct Var *ecpp_find_ext_var(char *identifier);
+struct Var *ecpp_find_var(char *identifier);
+struct struct_declaration *ecpp_find_scope(char* nested_name,char** identifier);
+struct struct_list *ecpp_find_member(char* identifier,struct struct_declaration *scope,struct struct_declaration** ret_scope,int search_flag);
+void ecpp_auto_call_dtors();
+int ecpp_is_friend(struct struct_declaration *class);
+#endif
+
+extern int afterlabel;
+
+extern int errors;
+
+extern int float_used;
+extern char *cur_func;
+extern Var *cur_funcv;
+extern int line;
+extern void free_clist(struct const_list *);
+extern struct const_list *first_clist,*last_clist;
+extern struct Var *regsbuf[MAXR+1];
+extern int regbnesting[MAXR+1];
+
+
diff --git a/vbcc_cpp.h b/vbcc_cpp.h
new file mode 100755
index 0000000..1e14b0f
--- /dev/null
+++ b/vbcc_cpp.h
@@ -0,0 +1,47 @@
+/*  $VER: vbcc (vbcc_cpp.h) $Revision: 1.2 $     */
+
+
+/* fix some name clashes between vbcc and ucpp and include cpp.h */
+/* has to be include prior to other vbcc includes                */
+
+
+#define STRING T_STRING
+#define CHAR T_CHAR
+#define CAST T_CAST
+#define AND T_AND
+#define OR T_OR
+#define COLON T_COLON
+#define LOR T_LOR
+#define LAND T_LAND
+#define MINUS T_MINUS
+
+#define NO_UCPP_ERROR_FUNCTIONS 1
+#include "ucpp/cpp.h"
+
+typedef struct token token;
+typedef struct lexer_state lexer_state;
+typedef struct stack_context stack_context;
+
+extern token *ctok;
+extern lexer_state ls;
+
+#undef STRING
+#undef CHAR
+#undef CAST
+#undef AND
+#undef OR
+#undef COLON
+#undef LOR
+#undef LAND
+#undef MINUS
+
+#define next_token vbcc_next_token
+#undef error
+
+#undef S_TOKEN
+#define S_TOKEN(x) ((x) >= NUMBER && (x) <= T_CHAR) 
+ 
+#define ttMWS(x)        ((x) == NONE || (x) == COMMENT || (x) == OPT_NONE)
+#define ttWHI(x)        (ttMWS(x) || (x) == NEWLINE)
+
+char *ucpp_token_name();
diff --git a/vbpp.h b/vbpp.h
new file mode 100755
index 0000000..aa70f07
--- /dev/null
+++ b/vbpp.h
@@ -0,0 +1,89 @@
+#ifndef _VBPP_H
+#define _VBPP_H 1
+
+/* vbpp.h
+ * last change: 17.08.1995 Thorsten Schaaps
+ */
+
+/* strnode-types */
+#define NORMAL      0          /* anything: brackets,+,-,/,*, etc.. */
+#define PP_IDENT    1          /* possible identifier               */
+#define ARGUMENT    2          /* argument: see number              */
+#define PP_STR      3          /* strings                           */
+#define NUMBER      4          /* numbers (123,0x00,0L,..)          */
+#define SPACE       5          /* spaces, tabs, etc.                */
+#define SPECIAL     6          /* flags=1->#,flags=2->##            */
+
+/* flags for type==SPECIAL */
+#define NONE        0
+#define TOSTRING    1          /* #define t(c) #c                   */
+#define KILLSPACES  2          /* #define t(a,b) a##b               */
+
+struct strnode{
+  char           *str;         /* the string =8) ah, you guessed that. */
+  int             len;         /* the length of the string             */
+  int             flags;       /* flags: see above                     */
+  int             type;        /* type:  see above                     */
+  int             number;      /* only valid if type==ARGUMENT         */
+  struct strnode *prev,*next;  /* pointers to previous and next node or NULL */
+};
+
+/* Macro-Node-Flags */
+#define FUNCTION  1     /* for macros changing from line to line, e.g. */
+                        /*          __LINE__, __FILE__, __TIME__ etc.. */
+#define PARAMETER 2     /* Macro has arguments                         */
+#define NODELETE  4     /* Macro cannot be UNDEFined, e.g. __TIME__,   */
+                        /*          __DATE__, __STDC__                 */
+#define NOREDEF   8     /* Macro cannot be reDEFINED, (s. above, but   */
+                        /*          not __STDC__)                      */
+
+/* Function-Numbers for FUNCTION-Macros */
+#define FUNCLINE  1     /* __LINE__ */
+#define FUNCFILE  2     /* __FILE__ */
+#define FUNCDATE  3     /* __DATE__ */
+#define FUNCTIME  4     /* __TIME__ */
+       /* __STDC__ is a normal macro, but cannot be deleted */
+
+struct mnode{
+  char           *name;       /* name, e.g. SQR                         */
+  char           *args;       /* arguments, e.g. (x)                    */
+  char           *token;      /* definition as string, e.g. ((x)*(x))   */
+                              /* BE CAREFULL: may be NULL in the future */
+  struct strnode *tokenlist;  /* definition as list                     */
+  int             flags;      /* flags, see above                       */
+  int             numargs;    /* number of arguments                    */
+  int             funcnum;    /* number of function (see above)         */
+  struct mnode   *prev,*next; /* pointers to previos and next node or NULL */
+};
+
+/* Return-Codes for ExpandList/ExpandArgMakro/CloneArg-Functions */
+#define OK            0
+#define OUT_OF_MEM   -1
+#define NUM_OF_ARGS  -2
+#define ARG_EXPECTED -3
+
+void            AddMakroNode(struct mnode **, struct mnode *);
+void            InsertMakroNode(struct mnode **, struct mnode *, struct mnode *);
+void            RemMakroNode(struct mnode **, struct mnode *);
+struct mnode   *FindMakroNode(struct mnode *, char *, int);
+void            DelMakroNode(struct mnode **, struct mnode *);
+void            DelMakroList(struct mnode **);
+
+void            AddStrNode(struct strnode **, struct strnode *, char *);
+void            RemStrNode(struct strnode **, struct strnode *);
+/* struct strnode *FindStrNode(struct strnode *, char *, int); */
+void            DelStrNode(struct strnode **, struct strnode *);
+void            DelStrList(struct strnode **);
+struct strnode *CloneStrList(struct strnode *, struct strnode *);
+struct strnode *DoMakroFunction(struct mnode *);
+
+struct strnode *Str2List(char *);
+int             List2Str(struct strnode *, char *, int);
+
+int             ExpandList(struct strnode **);
+
+struct mnode   *ParseIdentifier(char *);
+int             PreParse(void);
+
+#endif
+
diff --git a/vcpr/vcpr.c b/vcpr/vcpr.c
new file mode 100644
index 0000000..8fa0bff
--- /dev/null
+++ b/vcpr/vcpr.c
@@ -0,0 +1,441 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "vcpr.h"
+
+line *first_line,*last_line;
+
+int debug=0;
+
+
+
+int labcnt,maxlab;
+labinfo *labinfos;
+
+const char vs_copyright[]="vcpr code compressor V0.1 (c) 2020 by Volker Barthelmann";
+
+
+
+void *mymalloc(size_t sz)
+{
+  void *p=malloc(sz);
+  if(!p){
+    fprintf(stderr,"Out of memory!\n");
+    exit(EXIT_FAILURE);
+  }
+  return p;
+}
+
+match *new_match(void)
+{
+  match *new;
+  new=mymalloc(sizeof(*new));
+  new->next=0;
+  new->start=0;
+  new->max=0;
+  return new;
+}
+
+void extend_labinfos(int n)
+{
+  if(n>maxlab)
+    maxlab=n;
+  /* TODO */
+}
+
+int new_label(void)
+{
+  maxlab++;
+  extend_labinfos(maxlab);
+  return maxlab;
+}
+
+line *new_line(void)
+{
+  line *new;
+  new=mymalloc(sizeof(*new));
+  new->next=new->prev=0;
+  new->code=0;
+  new->flags=0;
+  new->size=0;
+  new->l1=new->l2=0;
+  return new;
+}
+
+void add_line(line *new)
+{
+  if(last_line){
+    last_line->next=new;
+    new->prev=last_line;
+    last_line=new;
+  }else{
+    first_line=last_line=new;
+  }
+}
+
+void insert_line(line *after, line *new)
+{
+  if(!after){
+    new->next=first_line;
+    first_line=new;
+  }else{
+    new->next=after->next;
+    after->next=new;
+  }
+  new->prev=after;
+  if(new->next)
+    new->next->prev=new;
+  else
+    last_line=new;
+}
+
+void free_line(line *p)
+{
+  if(p->code) free(p->code);
+  free(p);
+}
+
+void remove_line(line *p)
+{
+  if(p->prev) p->prev->next=p->next; else first_line=p->next;
+  if(p->next) p->next->prev=p->prev; else last_line=p->prev;
+}
+
+
+
+
+
+
+void read_lines(FILE *f)
+{
+  char buf[MAXLEN],*p;
+  line *new;
+  int idx=0;
+
+  while(1){
+    p=fgets(buf,MAXLEN,f);
+    if(feof(f))
+      return;
+    new=new_line();
+    parse_line(buf,new);
+    new->code=mymalloc(strlen(buf)+1);
+    strcpy(new->code,buf);
+    new->idx=++idx;
+    add_line(new);
+    if(new->flags&LABUSE){
+      extend_labinfos(new->l1);
+      extend_labinfos(new->l2);
+      labinfos[new->l1].usecnt++;
+      labinfos[new->l2].usecnt++;
+    }
+    if(new->flags&LABDEF)
+      extend_labinfos(new->l1);
+    /* skip rest of long line, TODO */
+    while(p==&buf[MAXLEN-1])
+      p=fgets(buf,MAXLEN,f);
+  }
+}
+
+void print_line(line *p)
+{
+  printf("[idx=%d flags=%d sz=%d l1=%d l2=%d]: %s",p->idx,p->flags,p->size,p->l1,p->l2,p->code);
+}
+
+int slab,dlab;
+
+int match_line(line *a, line *b)
+{
+  if((a->flags&(BARRIER|LBARRIER))||(b->flags&(BARRIER|LBARRIER)))
+    return 0;
+
+  /* we currently handle only one label */
+  if(a->l2!=b->l2)
+    return 0;
+
+  if(a->l1&&!b->l1)
+    return 0;
+  if(b->l1&&!a->l1)
+    return 0;
+
+  if(a->l1&&a->l1==slab)
+    if(b->l1!=dlab)
+      return 0;
+
+  if(!strcmp(a->code, b->code)&&!(a->flags&BRANCH))
+    return 1;
+
+  if(slab&&a->l1!=slab&&a->l1!=b->l1)
+    return 0;
+
+  if(a->l1&&b->l1){
+    char *pa=a->code;
+    char *pb=b->code;
+    char al[32],bl[32];
+    int la,lb;
+    sprintf(al,"l%d",a->l1);
+    sprintf(bl,"l%d",b->l1);
+    la=strlen(al);
+    lb=strlen(bl);
+    while(*pa&&*pb){
+      if(!strncmp(pa,al,la)){
+	if(!strncmp(pb,bl,lb)){
+	  pa+=la;
+	  pb+=lb;
+	}else
+	  return 0;
+      }else{
+	if(*pa!=*pb)
+	  return 0;
+	pa++;
+	pb++;
+      }
+    }
+    if(*pa||*pb)
+      return 0;
+    if(!slab){
+      slab=a->l1;
+      dlab=b->l1;
+    }else{
+      if(a->l1!=slab||b->l1!=dlab)
+	return 0;
+    }
+    return 1;
+  }
+
+  return 0;
+}
+
+match *check_matches(line *s,line *p, int min)
+{
+  int sz=0,n=0;
+  match *new;
+  line *first;
+
+  slab=dlab=0;
+
+  if(!match_line(s, p))
+    return 0;
+
+  first=p;
+
+  new=new_match();
+  new->start=p;
+
+  do{
+    sz+=p->size;
+    new->size[n]=sz;
+    n++;
+    new->max=n;
+    p=p->next;
+    s=s->next;
+  }while(n<MAXMLEN&&p&&s&&match_line(s ,p)&&s!=first);
+
+  if(sz<min){
+    free(new);
+    return 0;
+  }
+
+  if(slab){
+    int lstart=0,luse=0,ldef=0;
+    if(debug) printf("checking labvalid\n");
+    for(n=0,p=new->start;n<new->max;n++,p=p->next){
+      if(p->l1==dlab){
+	lstart=1;
+	if(p->flags&LABDEF)
+	  ldef=1;
+	if(p->flags&LABUSE)
+	  luse++;
+      }
+      if(lstart&&(!ldef||luse<labinfos[dlab].usecnt))
+	new->size[n]=0;
+    }
+  }
+
+  return new;
+}   
+
+void free_matches(match *p)
+{
+  match *n;
+  while(p){
+    n=p->next;
+    free(p);
+    p=n;
+  }
+}
+
+void print_matches(match *p)
+{
+  int i;
+  line *l;
+  if(p->next)
+    print_matches(p->next);
+  printf("match:\n");
+  for(i=0,l=p->start;i<p->max;i++){
+    printf("sv=%d ",p->size[i]);
+    print_line(l);
+    l=l->next;
+  }
+}
+  
+
+int main(int argc,char *argv[])
+{
+  int i,quiet=0,changed,pass=0;
+  FILE *in,*out; char *inname=0,*outname=0;
+  line *p;
+
+  for(i=1;i<argc;i++){
+    if(*argv[i]!='-'){
+      if(!inname){
+        inname=argv[i];
+      }else{
+        if(outname){
+          printf("Only one input file allowed\n");
+	  exit(EXIT_FAILURE);
+        }else{
+          outname=argv[i];
+        }
+      }
+    }else{
+      if(!strcmp("-quiet",argv[i])) {quiet=1;continue;}
+#ifndef DEBUG
+      if(!strncmp("-debug=",argv[i],7)){debug=atoi(argv[i]+7);continue;}
+#endif
+      printf("Unknown option \"%s\"\n",argv[i]);
+      exit(EXIT_FAILURE);
+    }
+  }
+  if(!quiet){
+#ifdef SPECIAL_COPYRIGHT
+    printf("%s\n",SPECIAL_COPYRIGHT);
+#else
+    printf("%s\n%s\n",vs_copyright,tg_copyright);
+#endif
+  }
+  if(!inname){printf("No input file\n");exit(EXIT_FAILURE);}
+  if(!outname){printf("No output file\n");exit(EXIT_FAILURE);}
+  in=fopen(inname,"r");
+  if(!in){printf("Could not open input file \"%s\"\n",inname);exit(EXIT_FAILURE);}
+  out=fopen(outname,"w");
+  if(!out){printf("Could not open output file \"%s\"\n",outname);exit(EXIT_FAILURE);}
+
+  labinfos=mymalloc(sizeof(labinfo)*LABNUM);
+  labcnt=LABNUM;
+
+  for(i=0;i<labcnt;i++)
+    labinfos[i].usecnt=0;
+
+  read_lines(in);
+
+  if(debug)
+    for(p=first_line;p;p=p->next)
+      print_line(p);
+
+  if(debug)
+    for(i=1;i<labcnt;i++)
+      if(labinfos[i].usecnt)
+	printf("lab %d used %d times\n",i,labinfos[i].usecnt);
+
+  do{
+    pass++;
+    changed=0;
+    if(debug) printf("pass %d\n",pass);
+    for(p=first_line;p;p=p->next){
+      line *n;
+      match *m,*mlist=0;int max=0,tmp;
+
+      if(sscanf(p->code,";vcprmin=%d",&tmp)==1)
+	minsave=tmp;
+      if(sscanf(p->code,"#vcprmin=%d",&tmp)==1)
+	minsave=tmp;
+      
+      for(n=p->next;n;n=n->next){
+	m=check_matches(p,n,minsave);
+	if(m){
+	  m->next=mlist;
+	  mlist=m;
+	  if(m->max>max) max=m->max;
+	  /* TODO: is this necessary? */
+	  for(i=0;i<m->max;i++)
+	    n=n->next;
+	}
+      }
+      if(mlist){
+	int maxsav=0,maxn=0,csav,cnt;
+	
+	if(debug){
+	  printf("mlist: \n");
+	  print_line(p);
+	  print_matches(mlist);
+	}
+	for(i=1;i<=max;i++){
+	  csav=0;cnt=0;
+	  for(m=mlist;m;m=m->next){
+	    if(m->max>=i){
+	      cnt++;
+	      csav+=m->size[i-1]-minsave;
+	    }
+	  }
+	  if(debug) printf("%d times %d: total %d\n",cnt,i,csav);
+	  if(csav>maxsav){
+	    maxsav=csav;
+	    maxn=i;
+	  }
+	}
+	if(debug) printf("best saving: %d: total %d\n",maxn,maxsav);
+	
+	n=p->prev;
+	if(n&&maxsav>0){
+	  add_header(last_line);
+	  if(last_line->next==last_line) abort();
+	  if(debug) printf("copying header:\n");
+	  for(i=0;i<maxn;i++){
+	    p=n->next;
+	    if(debug) print_line(p);
+	    p->flags|=LBARRIER;
+	    remove_line(p);
+	    insert_line(last_line,p);
+	  }
+
+	  changed=1;
+	  add_jsr(n);
+	  
+	  add_ret(last_line);
+	  
+	  labinfos[n->next->l1].usecnt++;
+	  if(debug) printf("update usecnt lab %d to %d\n",n->next->l1,labinfos[n->next->l1].usecnt);
+	  
+	  for(m=mlist;m;m=m->next){
+	    if(m->max>=maxn){
+	      if(debug) printf("remove copy:\n");
+	      p=m->start->prev;
+	      for(i=0;i<maxn;i++){
+		line *t=p->next;
+		if(debug) print_line(t);
+		remove_line(t);
+		free_line(t);
+	      }
+	      add_jsr(p);
+	      labinfos[p->next->l1].usecnt++;
+	      if(debug) printf("update usecnt lab %d to %d\n",p->next->l1,labinfos[p->next->l1].usecnt);
+	    }
+	  }
+	  p=n;
+	}
+	free_matches(mlist);
+      }
+    }
+    if(changed){
+      for(p=first_line;p;p=p->next)
+	p->flags&=~LBARRIER;
+    }
+  }while(changed);
+
+  for(p=first_line;p;p=p->next)
+    fprintf(out,"%s",p->code);
+
+  exit(EXIT_SUCCESS);
+}
diff --git a/vcpr/vcpr.h b/vcpr/vcpr.h
new file mode 100644
index 0000000..d2b64e7
--- /dev/null
+++ b/vcpr/vcpr.h
@@ -0,0 +1,50 @@
+#define LABDEF 1
+#define LABUSE 2
+#define BARRIER 4
+#define LBARRIER 8
+#define BRANCH 16 /* only move if target also moved */
+
+typedef struct line {
+  struct line *next,*prev;
+  char *code;
+  int flags;
+  int size;
+  int idx;
+  int l1,l2;
+} line;
+
+#define MAXMLEN 64
+
+typedef struct match {
+  struct match *next;
+  line *start;
+  int max;
+  int size[MAXMLEN];
+} match;
+
+typedef struct {
+  int usecnt;
+} labinfo;
+
+#define LABNUM 10000
+
+#define MAXLEN 1024
+
+
+/* functions available to backend */
+void *mymalloc(size_t sz);
+int new_label(void);
+void extend_labinfos(int n);
+line *new_line(void);
+void insert_line(line *after, line *new);
+void remove_line(line *p);
+void free_line(line *p);
+
+/* functions provided by the backend */
+extern int minsave;
+extern const char tg_copyright[];
+
+void parse_line(char *s,line *p);
+void add_header(line *after);
+void add_ret(line *after);
+void add_jsr(line *after);
diff --git a/vprof/vprof.c b/vprof/vprof.c
new file mode 100755
index 0000000..4601092
--- /dev/null
+++ b/vprof/vprof.c
@@ -0,0 +1,166 @@
+/*
+ * vprof
+ *
+ * vbcc profiler. Displays the contents of "mon.out" files.
+ * (C)1998,2010 by Frank Wille <frank@phoenix.owl.de>
+ *
+ * vprof is freeware and part of the portable and retargetable ANSI C
+ * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
+ * vprof may be freely redistributed as long as no modifications are
+ * made and nothing is charged for it. Non-commercial usage is allowed
+ * without any restrictions.
+ * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
+ * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define VERSION 0
+#define REVISION 2
+#define PLEVEL 0
+#define DEFAULTNAME "mon.out"
+
+struct profdata {
+  char *funcname;
+  unsigned long ncalls;
+  unsigned long tottime;
+  unsigned long loctime;
+};
+
+
+static void show(struct profdata *pdata,int n)
+/* write profdata records to stdout */
+{
+  struct profdata *p;
+  unsigned long runtime;
+  int i;
+
+  for (i=0,p=pdata,runtime=0; i<n; i++,p++)
+    runtime += p->loctime;
+
+  printf("  %%     total   local                local      total\n"
+         " time  seconds seconds     calls    ms/call    ms/call  name\n");
+  for (i=0,p=pdata; i<n; i++,p++) {
+    printf("%5.2f %7.2f %7.2f %9lu %10.3f %10.3f  %s\n",
+           ((double)p->loctime/(double)runtime)*100.0,
+           (double)p->tottime/1000000.0,
+           (double)p->loctime/1000000.0,
+           p->ncalls,
+           ((double)p->loctime/(double)p->ncalls)/1000.0,
+           ((double)p->tottime/(double)p->ncalls)/1000.0,
+           p->funcname);
+  }
+}
+
+
+static int cmp_total(const void *pd1,const void *pd2)
+{
+  return ((int)(((struct profdata *)pd2)->loctime -
+          ((struct profdata *)pd1)->loctime));
+}
+
+
+static void show_local(struct profdata *pd,int n)
+/* show profiling data, sorted according to the local time */
+/* spent in each function */
+{
+  qsort(pd,n,sizeof(struct profdata),cmp_total);
+  show(pd,n);
+}
+
+
+static char *skipname(char *p)
+/* skip name and alignment bytes and return pointer to profile data */
+{
+  int n = strlen(p)+1;
+
+  p += n;
+  if (n &= 3)
+    p += 4-n;
+  return (p);
+}
+
+
+int main(int argc,char *argv[])
+{
+  char *mname;
+  FILE *fp;
+  long size,len;
+  char *buf,*p;
+  int i,nrecs = 0;
+  struct profdata *pdata,*pd;
+
+  if (argc >= 2) {
+    if (*argv[1]=='-' || *argv[1]=='?') {
+      printf("%s V%d.%d%c (c)1998,2010 by Frank Wille\n"
+             "Usage:\n  %s [mon.out]\n",argv[0],
+             VERSION,REVISION,PLEVEL?('a'+PLEVEL-1):' ',argv[0]);
+      exit(1);
+    }
+    else
+      mname = argv[1];
+  }
+  else
+    mname = DEFAULTNAME;
+
+  if (fp = fopen(mname,"r")) {
+    /* determine file size */
+    fseek(fp,0,SEEK_END);
+    size = ftell(fp);
+    fseek(fp,0,SEEK_SET);
+    if (size < 0) {
+      fclose(fp);
+      fprintf(stderr,"%s: Seek error on %s!\n",argv[0],mname);
+      exit(EXIT_FAILURE);
+    }
+
+    /* allocate buffer and read file */
+    if (!(buf = malloc(size))) {
+      fclose(fp);
+      fprintf(stderr,"%s: Not enough memory!\n",argv[0]);
+      exit(EXIT_FAILURE);
+    }
+    if (fread(buf,1,size,fp) != size) {
+      fclose(fp);
+      fprintf(stderr,"%s: %s had a read error!\n",argv[0],mname);
+      exit(EXIT_FAILURE);
+    }
+    fclose(fp);
+
+    /* count number of entries in mon.out and allocate profdata array */
+    p = buf;
+    while (p < buf+size) {
+      nrecs++;
+      p = skipname(p) + 3*sizeof(unsigned long);
+    }
+    if (p!=buf+size || nrecs==0) {
+      fprintf(stderr,"%s: %s: Corrupted file format.\n",argv[0],mname);
+      exit(EXIT_FAILURE);
+    }
+    if (!(pdata = malloc(nrecs * sizeof(struct profdata)))) {
+      fprintf(stderr,"%s: Not enough memory!\n",argv[0]);
+      exit(EXIT_FAILURE);
+    }
+
+    /* fill profdata array */
+    for (i=0,p=buf,pd=pdata; i<nrecs; i++,pd++) {
+      pd->funcname = p;
+      p = skipname(p);
+      pd->ncalls = *(unsigned long *)p;
+      pd->tottime = *(unsigned long *)(p+sizeof(unsigned long));
+      pd->loctime = *(unsigned long *)(p+2*sizeof(unsigned long));
+      p += 3*sizeof(unsigned long);
+    }
+
+    /* display */
+    show_local(pdata,nrecs);
+  }
+  else {
+    fprintf(stderr,"%s: Can't open %s.\n",argv[0],mname);
+    exit(EXIT_FAILURE);
+  }
+
+  return 0;
+}
diff --git a/vsc/vsc.c b/vsc/vsc.c
new file mode 100755
index 0000000..9fc9a25
--- /dev/null
+++ b/vsc/vsc.c
@@ -0,0 +1,239 @@
+/* vsc - portable instruction scheduler for vbcc.   */
+/* (c) 1997-99 by Volker Barthelmann.               */
+
+#include "vsc.h"
+
+char vs_copyright[]="vsc scheduler V0.1 (c) 1997-99 by Volker Barthelmann";
+
+#define MAX_INS 128
+#define LINELENGTH 1024
+
+#ifndef DEBUG
+int DEBUG;
+#endif
+
+struct sinfo silist[MAX_INS];
+int si_count;
+int done;
+
+int bvcmp(unsigned char *dest,unsigned char *src,size_t len)
+/*  vergleicht zwei Bitvektoren    */
+{
+    for(;len>0;len--)
+        if(*dest++!=*src++) return(0);
+    return(1);
+}
+void bvunite(unsigned char *dest,unsigned char *src,size_t len)
+/*  berechnet Vereinigung zweier Bitvektoren    */
+{
+    for(;len>0;len--)
+        *dest++|=*src++;
+}
+void bvintersect(unsigned char *dest,unsigned char *src,size_t len)
+/*  berechnet Durchschnitt zweier Bitvektoren   */
+{
+    for(;len>0;len--)
+        *dest++&=*src++;
+}
+void bvdiff(unsigned char *dest,unsigned char *src,size_t len)
+/*  berechnet 'Differenz' zweier Bitvektoren    */
+{
+    for(;len>0;len--)
+        *dest++&=~(*src++);
+}
+
+void raus(void)
+{
+  sched_cleanup();
+  if(DEBUG&1) printf("raus\n");
+  if(done)
+    exit(EXIT_SUCCESS);
+  else
+    exit(EXIT_FAILURE);
+}
+void *mymalloc(size_t sz)
+{
+  void *p=malloc(sz);
+  if(!p){
+    puts("Out of memory!");
+    raus();
+  }
+  return p;
+}
+void print_sinfo(void)
+{
+  struct sinfo *p;int i,j;
+  if(DEBUG&2)
+    printf("print_sinfo\n");
+  else
+    return;
+  for(j=0;j<si_count;j++){
+    p=&silist[j];
+    printf("inst: %s",p->txt);
+    printf("flags=%u, label=%u latency=%u\n",p->flags,p->label,p->latency);
+    printf("available pipelines: ");
+    for(i=0;i<PIPES;i++)
+      if(BTST(p->pipes,i))
+        printf("%d ",i);
+    printf("\nuses registers (%d=mem): ",MEM);
+    for(i=0;i<=MEM;i++)
+      if(BTST(p->uses,i))
+        printf("%d ",i);
+    printf("\nmodifies registers (%d=MEM): ",MEM);
+    for(i=0;i<=MEM;i++)
+      if(BTST(p->modifies,i))
+        printf("%d ",i);
+    printf("\n\n");
+  }
+}
+void free_sinfo(void)
+{
+  int j;
+  for(j=0;j<si_count;j++)
+    free(silist[j].txt);
+}
+void output_scheduled(FILE *f)
+{
+  int pipes[PIPES],i,j,k,l,remaining;
+  int latency[MEM+1]={0},cycle=0;
+  unsigned char used[REGS_SIZE],modified[REGS_SIZE],tmp[REGS_SIZE],empty[REGS_SIZE]={0};
+  remaining=si_count;
+  if(DEBUG&2) print_sinfo();
+  while(remaining){
+    cycle++;
+    if(DEBUG&4){
+      printf("cycle %d\n",cycle);
+      for(i=0;i<=MEM;i++)
+        if(latency[i]>0) printf("latency[%d]=%d\n",i,latency[i]);
+    }
+    /* Mark all instructions which are ready. */
+    memset(modified,0,REGS_SIZE);
+    memset(used,0,REGS_SIZE);
+    for(i=0;i<si_count;i++){
+      if(silist[i].flags&OUT) continue;
+      memcpy(tmp,silist[i].uses,REGS_SIZE);
+      bvunite(tmp,silist[i].modifies,REGS_SIZE);
+      bvintersect(tmp,modified,REGS_SIZE);
+      if(bvcmp(tmp,empty,REGS_SIZE)){
+        /* uses and modifies nothing that has to be modified before */
+        memcpy(tmp,used,REGS_SIZE);
+        bvintersect(tmp,silist[i].modifies,REGS_SIZE);
+        if(bvcmp(tmp,empty,REGS_SIZE)){
+          /* modifies nothing that has to be used before */
+          for(k=0,j=0;j<=MEM;j++){
+            if(BTST(silist[i].uses,j)&&latency[j]>0) k=1;
+          }
+          if(!k) silist[i].flags|=READY;
+        }
+      }
+      bvunite(modified,silist[i].modifies,REGS_SIZE);
+      bvunite(used,silist[i].uses,REGS_SIZE);
+    }
+
+    /* Fill pipeline slots with ready instructions. */
+    for(i=0;i<PIPES;i++) pipes[i]=-1;
+    for(i=0;i<si_count;i++){
+      if(silist[i].flags&OUT) continue;
+      if(!(silist[i].flags&READY)) continue;
+      if(DEBUG&4) printf("inst ready: %s",silist[i].txt);
+      k=0;
+      /* Is there a free slot? */
+      for(j=0;!k&&j<PIPES;j++){
+        if(pipes[j]<0&&BTST(silist[i].pipes,j)){
+          pipes[j]=i;
+          k=1;
+        }
+      }
+      /* Replace a scheduled instruction with smaller latency. */
+      for(j=0;!k&&j<PIPES;j++){
+        if(BTST(silist[i].pipes,j)&&silist[i].latency>silist[pipes[j]].latency){
+          pipes[j]=i;
+          k=1;
+        }
+      }
+    }
+    if(DEBUG&4) printf("instructions for cycle %d:\n",cycle);
+    for(i=0;i<PIPES;i++){
+      if(pipes[i]>=0){
+        if(DEBUG&4) printf("%3d: %s",i,silist[pipes[i]].txt);
+        fprintf(f,"%s",silist[pipes[i]].txt);
+        silist[pipes[i]].flags|=OUT;
+        remaining--;
+        for(j=0;j<=MEM;j++){
+          if(BTST(silist[pipes[i]].modifies,j)) latency[j]=silist[pipes[i]].latency;
+        }
+      }
+    }
+    for(i=0;i<=MEM;i++)
+      if(latency[i]>0) latency[i]--;
+  }
+}
+int main(int argc,char *argv[])
+{
+  char s[LINELENGTH];int i,quiet=0;
+  FILE *in,*out; char *inname=0,*outname=0;
+  for(i=1;i<argc;i++){
+    if(*argv[i]!='-'){
+      if(!inname){
+        inname=argv[i];
+      }else{
+        if(outname){
+          printf("Only one input file allowed\n");
+          raus();
+        }else{
+          outname=argv[i];
+        }
+      }
+    }else{
+      if(!strcmp("-quiet",argv[i])) {quiet=1;continue;}
+#ifndef DEBUG
+      if(!strncmp("-debug=",argv[i],7)){DEBUG=atoi(argv[i]+7);continue;}
+#endif
+      printf("Unknown option \"%s\"\n",argv[i]);
+      raus();
+    }
+  }
+  if(!sched_init()){printf("sched_init failed\n");raus();}
+  if(!quiet){
+#ifdef SPECIAL_COPYRIGHT
+    printf("%s\n",SPECIAL_COPYRIGHT);
+#else
+    printf("%s\n%s\n",vs_copyright,tg_copyright);
+#endif
+  }
+  if(!inname){printf("No input file\n");raus();}
+  if(!outname){printf("No output file\n");raus();}
+  in=fopen(inname,"r");
+  if(!in){printf("Could not open input file \"%s\"\n",inname);raus();}
+  out=fopen(outname,"w");
+  if(!out){printf("Could not open output file \"%s\"\n",outname);raus();}
+  while(fgets(s,LINELENGTH-1,in)){
+    memset(&silist[si_count],0,sizeof(silist[0]));
+    silist[si_count].txt=mymalloc(strlen(s)+1);
+    strcpy(silist[si_count].txt,s);
+    if(!sched_info(&silist[si_count])){
+      printf("Do not understand instruction:\n%s\n",silist[si_count].txt);
+      raus();
+    }
+    if(silist[si_count].flags&(BARRIER|LABEL|COND_BRANCH|UNCOND_BRANCH)){
+      if(DEBUG&1) printf("Barrier: %s",silist[si_count].txt);
+      output_scheduled(out);
+      free_sinfo();
+      fprintf(out,silist[si_count].txt);
+      si_count=0;
+    }else{
+      if(++si_count>=MAX_INS){
+        if(DEBUG&1) printf("MAX_INS reached: %s",silist[si_count].txt);
+        output_scheduled(out);
+        free_sinfo();
+        si_count=0;
+      }
+    }
+  }
+  output_scheduled(out);
+  free_sinfo();
+  done=1;
+  raus();
+}
+
+
diff --git a/vsc/vsc.h b/vsc/vsc.h
new file mode 100755
index 0000000..468d592
--- /dev/null
+++ b/vsc/vsc.h
@@ -0,0 +1,121 @@
+/*  vsc portable scheduler (c) 1997-99 by Volker Barthelmann */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#define BSET(array,bit) (array)[(bit)/CHAR_BIT]|=1<<((bit)%CHAR_BIT)
+#define BCLR(array,bit) (array)[(bit)/CHAR_BIT]&=~(1<<((bit)%CHAR_BIT))
+#define BTST(array,bit) ((array)[(bit)/CHAR_BIT]&(1<<((bit)%CHAR_BIT)))
+
+/* An instruction with LABEL set is preceded with a numbered label. */
+/* The number is in <label>.                                        */
+#define LABEL 1
+
+/* An instrution with COND_BRANCH set may be followed by the next */
+/* instruction or by the instruction with the label in <label>.   */
+#define COND_BRANCH 2
+
+/* An instruction with UNCOND_BRANCH set is followed by the */
+/* instruction with the label in <label>.                   */
+#define UNCOND_BRANCH 4
+
+/* The side-effects of an instruction with BARRIER set cannot entirely */
+/* be specified by a struct sinfo (e.g. function-calls, pseudo-ops or  */
+/* other complicated things). vsc will not move any code across this   */
+/* instruction.                                                        */
+#define BARRIER 8
+
+/* An instruction with neither COND_BRANCH, UNCOND_BRANCH nor BARRIER  */
+/* set _must_ _not_ change control-flow.                               */
+
+/* Used by vsched.c. */
+#define OUT 16
+#define READY 32
+
+/* schedule.h has to #define REGS (the maximum number of registers */
+/* (numbered from 0 to REGS-1) and the maximum number of pipelines */
+/* PIPES (numbered from 0 to PIPES-1). If multiple CPUs with       */
+/* different numbers of pipelines or registers are supported the   */
+/* largest number must be specified. The CPU-differences must be   */
+/* represented by the information provided by sched_info().        */
+#include "schedule.h"
+
+/* MEM is a pseudo-register used to indicate that memory is        */
+/* accessed.                                                       */
+#define MEM REGS
+
+#define PIPES_SIZE ((PIPES+CHAR_BIT-1)/CHAR_BIT*CHAR_BIT)
+#define REGS_SIZE ((MEM+1+CHAR_BIT-1)/CHAR_BIT*CHAR_BIT)
+
+/* The struct to hold scheduling-information on an instruction. */
+struct sinfo {
+  /* The instruction in assembly-language. */
+  char *txt;
+
+  /* A combination of the flags mentioned above. */
+  unsigned int flags;
+
+  /* A numbered label used with LABEL, COND_BRANCH and UNCOND_BRANCH. */
+  unsigned int label;
+
+  /* Number of cycles until all side-effects of the operation are */
+  /* completed. */
+  unsigned int latency;
+
+  /* Bit-vector which contains 1s for every pipeline which can execute */
+  /* this instruction. */
+  unsigned char pipes[PIPES_SIZE];
+
+  /* Bit-vector which contains 1s for every register that is used by */
+  /* this instruction. Use pseudo-register MEM if it reads memory.   */
+  unsigned char uses[REGS_SIZE];
+
+  /* Bit-vector which contains 1s for every register that is modified  */
+  /* by this instruction. Use pseudo-register MEM if it writes memory. */
+  unsigned char modifies[REGS_SIZE];
+
+  /* An ID which identifies the memory-object which is read. 0 means    */
+  /* no further information available. Two accesses with different IDs  */
+  /* are guaranteed not to access the same memory.                      */
+  unsigned long memread_id;
+
+  /* An ID which identifies the memory-object which is written. 0 means */
+  /* no further information available. Two accesses with different IDs  */
+  /* are guaranteed not to access the same memory.                      */
+  unsigned long memwrite_id;
+
+  /* If this flag is set to 1 then the write to the object with the     */
+  /* ID specified by memwrite_id completely overwrites the object.      */
+  unsigned int memwrite_completely;
+};
+
+
+/* Target-specific data which must be provided by schedule.c. */
+
+/* Copyright notice which is printed if -quiet is not specified. */
+extern char tg_copyright[];
+
+
+/* Target-specific functions which must be provided by schedule.c */
+
+/* This function allows some initializations to be done. If       */
+/* zero is returned vsc assumes an error has happened and aborts. */
+extern int sched_init(void);
+
+/* This function allows some cleanup before vsc exits. */
+extern void sched_cleanup(void);
+
+/* This is the main target-specific function. It will be called with  */
+/* a pointer to a struct sinfo that is set to binary zeroes except    */
+/* for the member <txt> which points to the assembly representation   */
+/* of the instruction.                                                */
+/* sched_info() has to fill in all the other members with information */
+/* that correctly represents the instruction.                         */
+/* If the BARRIER-flag is set all other informations are basically    */
+/* irrelevant.                                                        */
+extern int sched_info(struct sinfo *);
+
+
+