diff --git a/.clang-format b/.clang-format
index d5e0c3a16..7dced3479 100644
--- a/.clang-format
+++ b/.clang-format
@@ -7,5 +7,6 @@ IndentCaseLabels: 'true'
 PointerAlignment: Left
 TabWidth: '4'
 UseTab: ForIndentation
+SortIncludes: false
 
 ...
diff --git a/.travis.yml b/.travis.yml
index c6e2f5913..f06e5aca3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,12 @@
 matrix:
     include:
         - os: linux
-        - os: osx
 
 addons:
     apt:
         packages:
         - ed
-        - openbios-ppc
+        - qemu-user
 
 git:
     depth: 10
diff --git a/Makefile b/Makefile
index 635650bc4..59b4e1a57 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,7 @@ PLATDEP = $(INSDIR)/lib/ack
 
 .NOTPARALLEL:
 
-MAKECMDGOALS ?= +ack
+MAKECMDGOALS ?= +ack +tests
 BUILD_FILES = $(shell find * -name '*.lua')
 
 ifneq ($(shell which ninja),)
@@ -88,6 +88,7 @@ $(BUILDDIR)/build.$(BUILDSYSTEM): first/ackbuilder.lua Makefile $(BUILD_FILES) $
 	@$(LUA) first/ackbuilder.lua \
 		first/build.lua build.lua \
 		--$(BUILDSYSTEM) \
+		DEFAULT_PLATFORM=$(DEFAULT_PLATFORM) \
 		OBJDIR=$(OBJDIR) \
 		BINDIR=$(BINDIR) \
 		LIBDIR=$(LIBDIR) \
@@ -95,6 +96,7 @@ $(BUILDDIR)/build.$(BUILDSYSTEM): first/ackbuilder.lua Makefile $(BUILD_FILES) $
 		INSDIR=$(INSDIR) \
 		PLATIND=$(PLATIND) \
 		PLATDEP=$(PLATDEP) \
+		PREFIX=$(PREFIX) \
 		AR=$(AR) \
 		CC=$(CC) \
 		> $(BUILDDIR)/build.$(BUILDSYSTEM)
diff --git a/README b/README
index 701581f17..d3273fc0b 100644
--- a/README
+++ b/README
@@ -2,7 +2,7 @@
                      ===================================
 
                   © 1987-2005 Vrije Universiteit, Amsterdam
-                                2016-08-02
+                                2017-01-07
 
 
 INTRODUCTION
@@ -19,22 +19,25 @@ probably broken. However, what's there should be sufficient to get things
 done and to evaluate how the full 6.1 release should work. 
 
 
+
 SUPPORT
 =======
 
 Languages:
 
-ANSI C, Pascal, Modula 2, Basic. K&R is supported via the ANSI C compiler.
+ANSI C, B, Pascal, Modula 2, Basic. K&R is supported via the ANSI C compiler.
 
 Platforms:
 
 pc86          produces bootable floppy disk images for 8086 PCs
 linux386      produces ELF executables for PC Linux systems
 linux68k      produces ELF executables for m68020 Linux systems
+linuxppc      produces ELF executables for PowerPC Linux systems
 cpm           produces i80 CP/M .COM files
 rpi           produces Raspberry Pi GPU binaries
 
 
+
 INSTALLATION
 ============
 
@@ -55,6 +58,11 @@ Requirements:
 - (optionally) ninja; if you've got this, this will be autodetected and give
   you faster builds.
 
+- (optionally) the qemu suite: if you have this installed, the build system
+  will detect it automatically and run the test suites for the supported
+  architectures. Get both the qemu-system-* platform emulators and the qemu-*
+  userland emulators (only works on Linux).
+
 - about 40MB free in /tmp (or some other temporary directory).
 
 - about 6MB in the target directory.
@@ -89,6 +97,7 @@ Instructions:
 The ACK should now be ready to use.
 
 
+
 USAGE
 =====
 
@@ -111,7 +120,8 @@ Some useful options include:
 ack figures out which language to use from the file extension:
 
   .c               C (ANSI or K&R)
-  .b               Basic
+  .b               the PDP-11 dialect of B
+  .bas             Basic
   .mod             Modula-2
   .ocm             Occam 1
   .p               Pascal
@@ -150,11 +160,17 @@ There are some things you should be aware of.
 - The ACK uses its own .o format. You won't be able to mix the ACK's object
   files and another compiler's.
 
+- When compiling together multiple B source files, you need to do some extra
+  work to initialise them properly otherwise your program will crash on
+  startup; see the ack(1) and abmodules(1) man pages.
+
 - The distribution contains *everything*, including the weird, ancient,
   archaic stuff that doesn't work any more and never will, such as the int EM
   interpreter and the assembler-linkers. Only some of it builds. Look for
   build.lua files.
 
+
+
 DISCLAIMER
 ==========
 
@@ -177,6 +193,6 @@ You can find the mailing list on the project's web site:
 	
 Please enjoy.
 
-David Given (dtrg on Sourceforge)
+David Given (davidgiven on Github)
 dg@cowlark.com
-2016-08-02
+2016-11-26
diff --git a/build.lua b/build.lua
index cc550cb9e..f7b0ca1ea 100644
--- a/build.lua
+++ b/build.lua
@@ -9,12 +9,17 @@ vars.plats = {
 	"linux386",
 	"linux68k",
 	"linuxppc",
+	"osx386",
+	"osxppc",
 	"qemuppc",
 	"pc86",
 	"rpi",
 }
 vars.plats_with_tests = {
+	"linux386",
+	"linuxppc",
 	"qemuppc",
+	"pc86",
 }
 
 local plat_packages = {}
@@ -33,6 +38,7 @@ installable {
 		"lang/cem/cemcom.ansi+pkg",
 		"lang/m2/comp+pkg",
 		"lang/pc/comp+pkg",
+		"lang/b/compiler+pkg",
 		"util/ack+pkg",
 		"util/amisc+pkg",
 		"util/arch+pkg",
@@ -43,8 +49,18 @@ installable {
 		"examples+pkg",
 		plat_packages
 	},
-	deps = {
-		test_packages
-	}
 }
 
+normalrule {
+	name = "tests",
+	ins = {
+		"first/testsummary.sh",
+		test_packages
+	},
+	outleaves = {
+		"stamp"
+	},
+	commands = {
+		"%{ins}"
+	}
+}
diff --git a/examples/build.lua b/examples/build.lua
index 631752976..fced8e299 100644
--- a/examples/build.lua
+++ b/examples/build.lua
@@ -6,6 +6,7 @@ local conly = {
 
 local sourcefiles = filenamesof(
 	"./hilo.b",
+	"./hilo.bas",
 	"./hilo.c",
 	"./hilo.mod",
 	"./hilo.p",
diff --git a/examples/hilo.b b/examples/hilo.b
index bdde01eab..818d1fb12 100644
--- a/examples/hilo.b
+++ b/examples/hilo.b
@@ -1,39 +1,108 @@
-1 ' $Source$
-2 ' $State$
-3 ' $Revision$
+#
 
-10 print "Hi there! I'm written in Basic. Before we start, what is your name?"
-20 input "> ", PlayerName$
-30 print
-40 print "Hello, "; PlayerName$; "!"
+buffer[6];
+PlayerName[6];
 
-100 gosub 1000
-110 print
-120 print "Would you like another go?"
-130 input "> ", s$
-140 s$ = left$(s$, 1)
-150 if s$ = "n" or s$ = "N" then goto 200
-160 print
-170 print "Excellent! ";
-180 goto 100
-200 print
-210 print "Thanks for playing --- goodbye!"
-220 end
+/* Taken intact from the B reference manual. */
+strcopy(sl ,s2)
+{
+	auto i;
 
-1000 print "See if you can guess my number."
-1010 Number% = rnd(1) mod 100
-1020 Attempts% = 1
+	i = 0;
+	while (lchar(sl, i, char(s2, i)) != '*e')
+		i++;
+}
 
-1030 print
-1040 input "> ", guess%
-1050 if guess% < Number% then print: print "Try a bit higher."
-1060 if guess% > Number% then print: print "Try a bit lower."
-1070 if guess% = Number% then goto 1100
-1080 Attempts% = Attempts% + 1
-1090 goto 1030
-1100 print
-1110 print "You got it right in only"; Attempts%;
-1120 if Attempts% = 1 then print "go"; else print "goes";
-1130 print "!"
-1140 return
+reads()
+{
+	extrn buffer;
+
+	putstr("> ");
+	flush();
+	getstr(buffer);
+}
+
+atoi(s)
+{
+	auto value, sign, i, c;
+
+	i = 0;
+	if (char(s, i) == '-')
+	{
+		sign = -1;
+		i++;
+	}
+	else
+		sign = 1;
+
+	value = 0;
+	while ((c = char(s, i++)) != '*e')
+		value = value*10 + (c - '0');
+
+	return(value * sign);
+}
+
+rand()
+{
+	/* Genuinely random; retrieved from random.org */
+	return(57);
+}
+
+game()
+{
+	extrn buffer;
+	auto Number, Attempts;
+	auto guess;
+
+	printf("See if you can guess my number.*n");
+
+	Number = rand() % 100;
+	Attempts = 1;
+	
+	while (1)
+	{
+		reads();
+		guess = atoi(buffer);
+		
+		if (guess == Number)
+		{
+			printf("*nYou got it right in only %d %s!*n", Attempts,
+				(Attempts == 1) ? "go" : "goes");
+			return;
+		}
+		
+		if (guess < Number)
+			printf("*nTry a bit higher.*n");
+		if (guess > Number)
+			printf("*nTry a bit lower.*n");
+		Attempts++;
+	}
+}
+
+main()
+{
+	extrn buffer, PlayerName;
+
+	printf("*nHi there! I'm written in B. Before we start, what is your name?*n");
+	reads();
+	strcopy(PlayerName, buffer);
+	printf("*nHello, %s! ", PlayerName);
+	
+	while (1)
+	{
+		game();
+		printf("*nWould you like another go?*n");
+		reads();
+		
+		if ((char(buffer, 0) == 'n') | (char(buffer, 0) == 'N'))
+		{
+			printf("*nThanks for playing --- goodbye!*n");
+			break;
+		}
+		
+		printf("*nExcellent! ");
+	}
+	
+	return(0);
+}
 
diff --git a/examples/hilo.bas b/examples/hilo.bas
new file mode 100644
index 000000000..bdde01eab
--- /dev/null
+++ b/examples/hilo.bas
@@ -0,0 +1,39 @@
+1 ' $Source$
+2 ' $State$
+3 ' $Revision$
+
+10 print "Hi there! I'm written in Basic. Before we start, what is your name?"
+20 input "> ", PlayerName$
+30 print
+40 print "Hello, "; PlayerName$; "!"
+
+100 gosub 1000
+110 print
+120 print "Would you like another go?"
+130 input "> ", s$
+140 s$ = left$(s$, 1)
+150 if s$ = "n" or s$ = "N" then goto 200
+160 print
+170 print "Excellent! ";
+180 goto 100
+200 print
+210 print "Thanks for playing --- goodbye!"
+220 end
+
+1000 print "See if you can guess my number."
+1010 Number% = rnd(1) mod 100
+1020 Attempts% = 1
+
+1030 print
+1040 input "> ", guess%
+1050 if guess% < Number% then print: print "Try a bit higher."
+1060 if guess% > Number% then print: print "Try a bit lower."
+1070 if guess% = Number% then goto 1100
+1080 Attempts% = Attempts% + 1
+1090 goto 1030
+1100 print
+1110 print "You got it right in only"; Attempts%;
+1120 if Attempts% = 1 then print "go"; else print "goes";
+1130 print "!"
+1140 return
+
diff --git a/examples/paranoia.c b/examples/paranoia.c
index f7020f71e..8a25800d9 100644
--- a/examples/paranoia.c
+++ b/examples/paranoia.c
@@ -15,6 +15,7 @@
 
    This is a public domain adventure and may not be sold for profit */
 
+#include <stdlib.h>
 #include <stdio.h>
 
 #define MOXIE	13
@@ -32,7 +33,9 @@ int plato_clone=3;
 int blast_door=0;
 int killer_count=0;
 
-char get_char()
+void character(void);
+
+char get_char(void)
 {
 	char c;
 	fflush(stdout);
@@ -41,7 +44,7 @@ char get_char()
 	return c;
 }
 
-more()
+void more(void)
 {
 	printf("---------- More ----------");
 #ifdef DEBUG
@@ -55,8 +58,7 @@ more()
 	};
 }
 
-new_clone(resume)
-int resume;
+int new_clone(int resume)
 {
 	printf("\nClone %d just died.\n",clone);
 	if (++clone>6)
@@ -75,15 +77,14 @@ int resume;
 	}
 }
 
-dice_roll(number,faces)
-int number, faces;
+int dice_roll(int number, int faces)
 {
 	int i,total=0;
 	for(i=number;i>0;i--)	total+= rand()%faces+1;
 	return total;
 }
 
-instructions()
+void instructions(void)
 {
 	printf("\n\n\n\nWelcome to Paranoia!\n\n");
 	printf("HOW TO PLAY:\n\n");
@@ -104,7 +105,7 @@ instructions()
 	printf("  If not, you can try again later.\n");
 }
 
-character()
+void character(void)
 {
 	printf("===============================================================================\n");
 	printf("The Character : Philo-R-DMD %d\n", clone);
@@ -130,9 +131,7 @@ character()
 	printf("===============================================================================\n");
 }
 
-choose(a,aptr,b,bptr)
-int a,b;
-char *aptr, *bptr;
+int choose(int a, char* aptr, int b, char* bptr)
 {
 	printf("\nSelect \'a\' or \'b\' :\n");
 	printf(" a - %s.\n b - %s.\n", aptr, bptr);
@@ -140,7 +139,7 @@ char *aptr, *bptr;
 	else	 		return b;
 }
 
-page1()
+int page1(void)
 {
 	printf("  You wake up face down on the red and pink checked E-Z-Kleen linoleum floor.\n");
 	printf("  You recognise the pattern, it\'s the type preferred in the internal security\nbriefing cells.  When you finally look around you, you see that you are alone\n");
@@ -148,7 +147,7 @@ page1()
 	return 57;
 }
 
-page2()
+int page2(void)
 {
 	printf("\"Greetings,\" says the kindly Internal Security self incrimination expert who\n");
 	printf("meets you at the door, \"How are we doing today?\"  He offers you a doughnut\n");
@@ -166,7 +165,7 @@ page2()
 	else 			 return new_clone(32);
 }
 
-page3()
+int page3(void)
 {
 	printf("You walk to the nearest Computer terminal and request more information about\n");
 	printf("Christmas.  The Computer says, \"That is an A-1 ULTRAVIOLET ONLY IMMEDIATE\n");
@@ -174,7 +173,7 @@ page3()
 	return choose(4,"You give your correct clearance",5,"You lie and claim Ultraviolet clearance");
 }
 
-page4()
+int page4(void)
 {
 	printf("\"That is classified information, Troubleshooter, thank you for your inquiry.\n");
 	printf(" Please report to an Internal Security self incrimination station as soon as\n");
@@ -182,7 +181,7 @@ page4()
 	return 9;
 }
 
-page5()
+int page5(void)
 {
 	printf("The computer says, \"Troubleshooter, you are not wearing the correct colour\n");
 	printf("uniform.  You must put on an Ultraviolet uniform immediately.  I have seen to\n");
@@ -193,7 +192,7 @@ page5()
 	return choose(6, "You open the package and put on the uniform", 7, "You finally come to your senses and run for it");
 }
 
-page6()
+int page6(void)
 {
 	printf("The uniform definitely makes you look snappy and pert.  It really looks\n");
 	printf("impressive, and even has the new lopsided lapel fashion that you admire so\n");
@@ -205,7 +204,7 @@ page6()
 	return 8;
 }
 
-page7()
+int page7(void)
 {
 	printf("The corridor lights dim and are replaced by red battle lamps as the Security\n");
 	printf("Breach alarms howl all around you.  You run headlong down the corridor and\n");
@@ -232,7 +231,7 @@ page7()
 	return 8;
 }
 
-page8()
+int page8(void)
 {
 	printf("\"Now, about your question, citizen.  Christmas was an old world marketing ploy\n");
 	printf("to induce lower clearance citizens to purchase vast quantities of goods, thus\n");
@@ -249,7 +248,7 @@ page8()
 	return 10;
 }
 
-page9()
+int page9(void)
 {
 	int choice;
 	printf("As you walk toward the tubecar that will take you to GDH7-beta, you pass one\n");
@@ -262,7 +261,7 @@ page9()
 	return choice;
 }
 
-page10()
+int page10(void)
 {
 	int choice;
 	printf("You stroll briskly down the corridor, up a ladder, across an unrailed catwalk,\n");
@@ -290,7 +289,7 @@ page10()
 	}
 }
 
-page11()
+int page11(void)
 {
 	printf("The printing on the folder says \"Experimental Self Briefing.\"\n");
 	printf("You open it and begin to read the following:\n");
@@ -321,7 +320,7 @@ page11()
 	return choose(3,"You wish to ask The Computer for more information about Christmas",10,"You have decided to go directly to Goods Distribution Hall 7-beta");
 }
 
-page12()
+int page12(void)
 {
 	printf("You walk up to the door and push the button labelled \"push to exit.\"\n");
 	printf("Within seconds a surly looking guard shoves his face into the small plexiglass\n");
@@ -333,7 +332,7 @@ page12()
 	return choose(11,"You sit down at the table and read the Orange packet",57,"You stare around the room some more");
 }
 
-page13()
+int page13(void)
 {
 	printf("You step into the shiny plasteel tubecar, wondering why the shape has always\n");
 	printf("reminded you of bullets.  The car shoots forward the instant your feet touch\n");
@@ -346,7 +345,7 @@ page13()
 	return 14;
 }
 
-page14()
+int page14(void)
 {
 	printf("You manage to pull yourself out of the tubecar and look around.  Before you is\n");
 	printf("one of the most confusing things you have ever seen, a hallway that is\n");
@@ -360,7 +359,7 @@ page14()
 	return 22;
 }
 
-page15()
+int page15(void)
 {
 	printf("You are set upon by a runty robot with a queer looking face and two pointy\n");
 	printf("rubber ears poking from beneath a tattered cap.  \"Hey mister,\" it says,\n");
@@ -384,7 +383,7 @@ page15()
 	}
 }
 
-page16()
+int page16(void)
 {
 	printf("The doll is a good buy for fifty credits; it will make a fine Christmas present\n");
 	printf("for one of your friends.  After the sale the robot rolls away.  You can use\n");
@@ -395,7 +394,7 @@ page16()
 	return 22;
 }
 
-page17()
+int page17(void)
 {
 	int i, robot_hp=15;
 	printf("You whip out your laser and shoot the robot, but not before it squeezes the\n");
@@ -432,7 +431,7 @@ page17()
 	return 22;
 }
 
-page18()
+int page18(void)
 {
 	printf("You walk to the centre of the hall, ogling like an infrared fresh from the\n");
 	printf("clone vats.  Towering before you is the most unearthly thing you have ever\n");
@@ -448,7 +447,7 @@ page18()
 	else				return 20;
 }
 
-page19()
+int page19(void)
 {
 	printf("Quickly you regain your balance, whirl and fire your laser into the Ultraviolet\n");
 	printf("citizen behind you.  For a moment your heart leaps to your throat, then you\n");
@@ -461,7 +460,7 @@ page19()
 	return choose(34,"You search the body, keeping an eye open for Internal Security",22,"You run away like the cowardly dog you are");
 }
 
-page20()
+int page20(void)
 {
 	printf("Oh no! you can\'t keep your balance.  You\'re falling, falling head first into\n");
 	printf("the Christmas beast\'s gaping maw.  It\'s a valiant struggle; you think you are\n");
@@ -473,7 +472,7 @@ page20()
 	return 22;
 }
 
-page21()
+int page21(void)
 {
 	printf("You have been wasting the leading citizens of Alpha Complex at a prodigious\n");
 	printf("rate.  This has not gone unnoticed by the Internal Security squad at GDH7-beta.\n");
@@ -482,7 +481,7 @@ page21()
 	return new_clone(45);
 }
 
-page22()
+int page22(void)
 {
 	printf("You are searching Goods Distribution Hall 7-beta.\n");
 	switch(dice_roll(1,4))
@@ -494,7 +493,7 @@ page22()
 	}
 }
 
-page23()
+int page23(void)
 {
 	printf("You go to the nearest computer terminal and declare yourself a mutant.\n");
 	printf("\"A mutant, he\'s a mutant,\" yells a previously unnoticed infrared who had\n");
@@ -503,7 +502,7 @@ page23()
 	return choose(28,"You tell them that it was really only a bad joke",24,"You want to fight it out, one against twelve");
 }
 
-page24()
+int page24(void)
 {
 	printf("Golly, I never expected someone to pick this.  I haven\'t even designed\n");
 	printf("the 12 citizens who are going to make a sponge out of you.  Tell you what,\n");
@@ -511,7 +510,7 @@ page24()
 	return choose(28,"You change your mind and say it was only a bad joke",25,"You REALLY want to shoot it out");
 }
 
-page25()
+int page25(void)
 {
 	printf("Boy, you really can\'t take a hint!\n");
 	printf("They\'re closing in.  Their trigger fingers are twitching, they\'re about to\n");
@@ -519,7 +518,7 @@ page25()
 	return choose(28,"You tell them it was all just a bad joke",26,"You are going to shoot");
 }
 
-page26()
+int page26(void)
 {
 	printf("You can read the cold, sober hatred in their eyes (They really didn\'t think\n");
 	printf("it was funny), as they tighten the circle around you.  One of them shoves a\n");
@@ -529,19 +528,19 @@ page26()
 	return new_clone(32);
 }
 
-page27()
+int page27(void)
 {
 	/* doesn't exist.  Can't happen with computer version.
 	   designed to catch dice cheats */
 }
 
-page28()
+int page28(void)
 {
 	printf("They don\'t think it\'s funny.\n");
 	return 26;
 }
 
-page29()
+int page29(void)
 {
 	printf("\"Psst, hey citizen, come here.  Pssfft,\" you hear.  When you peer around\n");
 	printf("you can see someone\'s dim outline in the shadows.  \"I got some information\n");
@@ -559,7 +558,7 @@ page29()
 	}
 }
 
-page30()
+int page30(void)
 {
 	printf("You step into the shadows and offer the man a thirty credit bill.  \"Just drop\n");
 	printf("it on the floor,\" he says.  \"So you\'re looking for the Master Retailer, pssfft?\n");
@@ -586,7 +585,7 @@ page30()
 	}
 }
 
-page31()
+int page31(void)
 {
 	printf("Like any good troubleshooter you make the least expensive decision and threaten\n");
 	printf("him for information.  With lightning like reflexes you whip out your laser and\n");
@@ -599,7 +598,7 @@ page31()
 	return choose(30,"You pay the 30 credits",22,"You pssfft go away stupid");
 }
 
-page32()
+int page32(void)
 {
 	printf("Finally it\'s your big chance to prove that you\'re as good a troubleshooter\n");
 	printf("as your previous clone.  You walk briskly to mission briefing and pick up your\n");
@@ -609,7 +608,7 @@ page32()
 	return 22;
 }
 
-page33()
+int page33(void)
 {
 	blast_door=1;
 	printf("You release the megabolts on the blast door, then strain against it with your\n");
@@ -622,7 +621,7 @@ page33()
 	else			return 36;
 }
 
-page34()
+int page34(void)
 {
 	printf("You have found a sealed envelope on the body.  You open it and read:\n");
 	printf("\"WARNING: Ultraviolet Clearance ONLY.  DO NOT READ.\n");
@@ -650,7 +649,7 @@ page34()
 	return choose(46,"You rush off to the nearest computer terminal to expose the commies",22,"You wander off to look for more evidence");
 }
 
-page35()
+int page35(void)
 {
 	printf("\"Oh master,\" you hear through the gun barrel, \"where have you been? It is\n");
 	printf("time for the great Christmas gifting ceremony.  You had better hurry and get\n");
@@ -669,7 +668,7 @@ page35()
 	return new_clone(32);
 }
 
-page36()
+int page36(void)
 {
 	printf("\"Congratulations, troubleshooter, you have successfully found the lair of the\n");
 	printf("Master Retailer and completed the Troubleshooter Training Course test mission,\"\n");
@@ -692,7 +691,7 @@ page36()
 	}
 }
 
-page37()
+int page37(void)
 {
 	printf("\"Come with me please, Troubleshooter,\" says the Green clearance technician\n");
 	printf("after he has dislodged your head from the cannon.  \"You have been participating\n");
@@ -708,7 +707,7 @@ page37()
 	return 38;
 }
 
-page38()
+int page38(void)
 {
 	printf("\"I am Plato-B-PHI%d, head of mutant propaganda here at the training course.\n",plato_clone);
 	printf("If you have any questions about mutants please come to me.  Today I will be\n");
@@ -725,7 +724,7 @@ page38()
 	return choose(39,"You volunteer for the test",40,"You duck behind a chair and hope the instructor doesn\'t notice you");
 }
 
-page39()
+int page39(void)
 {
 	printf("You bravely volunteer to test the mutant detection gun.  You stand up and walk\n");
 	printf("down the steps to the podium, passing a very relieved Troubleshooter along the\n");
@@ -743,7 +742,7 @@ page39()
 	return 41;
 }
 
-page40()
+int page40(void)
 {
 	printf("You breathe a sigh of relief as Plato-B-PHI picks on the other Troubleshooter.\n");
 	printf("\"You down here in the front,\" says the instructor pointing at the other\n");
@@ -775,7 +774,7 @@ page40()
 	}
 }
 
-page41()
+int page41(void)
 {
 	printf("You stumble down the hallway of the Troubleshooter Training Course looking for\n");
 	printf("your next class.  Up ahead you see one of the instructors waving to you.  When\n");
@@ -789,7 +788,7 @@ page41()
 	return choose(42,"You respond with the proper Illuminati code phrase, \"Ewige Blumenkraft\"",43,"You ignore this secret society contact");
 }
 
-page42()
+int page42(void)
 {
 	printf("\"Aha, so you are a member of the elitist Illuminati secret society,\" he says\n");
 	printf("loudly, \"that is most interesting.\"  He turns to the large class already\n");
@@ -799,7 +798,7 @@ page42()
 	return choose(51,"You run for it",52,"You wait for the guard");
 }
 
-page43()
+int page43(void)
 {
 	printf("You sit through a long lecture on how to recognise and infiltrate secret\n");
 	printf("societies, with an emphasis on mimicking secret handshakes.  The basic theory,\n");
@@ -815,7 +814,7 @@ page43()
 	return choose(44,"You go looking for a computer terminal",55,"You go to the graduation ceremony immediately");
 }
 
-page44()
+int page44(void)
 {
 	printf("You walk down to a semi-secluded part of the training course complex and\n");
 	printf("activate a computer terminal.  \"AT YOUR SERVICE\" reads the computer screen.\n");
@@ -833,7 +832,7 @@ page44()
 	}
 }
 
-page45()
+int page45(void)
 {
 	printf("\"Hrank Hrank,\" snorts the alarm in your living quarters.  Something is up.\n");
 	printf("You look at the monitor above the bathroom mirror and see the message you have\n");
@@ -847,7 +846,7 @@ page45()
 	return 10;
 }
 
-page46()
+int page46(void)
 {
 	printf("\"Why do you ask about the communists, Troubleshooter?  It is not in the\n");
 	printf("interest of your continued survival to be asking about such topics,\" says\n");
@@ -855,7 +854,7 @@ page46()
 	return choose(53,"You insist on talking about the communists",54,"You change the subject");
 }
 
-page47()
+int page47(void)
 {
 	printf("The Computer orders the entire Vulture squadron to terminate the Troubleshooter\n");
 	printf("Training Course.  Unfortunately you too are terminated for possessing\n");
@@ -867,7 +866,7 @@ page47()
 	return 0;
 }
 
-page48()
+int page48(void)
 {
 	printf("The tubecar shoots forward as you enter, slamming you back into a pile of\n");
 	printf("garbage.  The front end rotates upward and you, the garbage and the garbage\n");
@@ -877,14 +876,14 @@ page48()
 	return new_clone(45);
 }
 
-page49()
+int page49(void)
 {
 	printf("The instructor drags your inert body into a specimen detainment cage.\n");
 	printf("\"He\'ll make a good subject for tomorrow\'s mutant dissection class,\" you hear.\n");
 	return new_clone(32);
 }
 
-page50()
+int page50(void)
 {
 	printf("You put down the other Troubleshooter, and then wisely decide to drill a few\n");
 	printf("holes in the instructor as well; the only good witness is a dead witness.\n");
@@ -893,27 +892,27 @@ page50()
 	return 41;
 }
 
-page51()
+int page51(void)
 {
 	printf("You run for it, but you don\'t run far.  Three hundred strange and exotic\n");
 	printf("weapons turn you into a freeze dried cloud of soot.\n");
 	return new_clone(32);
 }
 
-page52()
+int page52(void)
 {
 	printf("You wisely wait until the instructor returns with a Blue Internal Security\n");
 	printf("guard.  The guard leads you to an Internal Security self incrimination station.\n");
 	return 2;
 }
 
-page53()
+int page53(void)
 {
 	printf("You tell The Computer about:\n");
 	return choose(47,"The commies who have infiltrated the Troubleshooter Training Course\n     and the impending People\'s Revolution",54,"Something less dangerous");
 }
 
-page54()
+int page54(void)
 {
 	printf("\"Do not try to change the subject, Troubleshooter,\" says The Computer.\n");
 	printf("\"It is a serious crime to ask about the communists.  You will be terminated\n");
@@ -927,7 +926,7 @@ page54()
 	else		   return new_clone(32);
 }
 
-page55()
+int page55(void)
 {
 	printf("You and 300 other excited graduates are marched  from the lecture hall and into\n");
 	printf("a large auditorium for the graduation exercise.  The auditorium is\n");
@@ -955,7 +954,7 @@ page55()
 	return 0;
 }
 
-page56()
+int page56(void)
 {
 	printf("That familiar strange feeling of deja\'vu envelops you again.  It is hard to\n");
 	printf("say, but whatever is on the other side of the door does not seem to be intended\n");
@@ -963,15 +962,14 @@ page56()
 	return choose(33,"You open the door and step through",22,"You go looking for more information");
 }
 
-page57()
+int page57(void)
 {
 	printf("In the centre of the room is a table and a single chair.  There is an Orange\n");
 	printf("folder on the table top, but you can\'t make out the lettering on it.\n");
 	return choose(11,"You sit down and read the folder",12,"You leave the room");
 }
 
-next_page(this_page)
-int this_page;
+int next_page(int this_page)
 {
 	printf("\n");
 	switch (this_page)
@@ -1038,10 +1036,11 @@ int this_page;
 	}
 }
 
-main()
+int main(int argc, const char* argv[])
 {
 	/* srand(time(0)); */
 	instructions();	more();
 	character();	more();
 	while((page=next_page(page))!=0)	more();
+	return 0;
 }
diff --git a/first/testsummary.sh b/first/testsummary.sh
new file mode 100755
index 000000000..9ab5daa2f
--- /dev/null
+++ b/first/testsummary.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+echo ""
+
+succeeding="$(find "$@" -size 0)"
+notsucceeding="$(find "$@" ! -size 0)"
+if [ "$notsucceeding" != "" ]; then
+	skipped="$(grep -l @@SKIPPED $notsucceeding)"
+	timedout="$(grep -l @@TIMEDOUT $notsucceeding)"
+	failed="$(grep -l @@FAIL $notsucceeding)"
+else
+	skipped=
+	timedout=
+	failed=
+fi
+
+for a in $failed $timedout; do
+    echo "**** $a"
+    cat $a
+    echo ""
+done
+
+echo "$(echo "$succeeding" | wc -w) tests passed"
+echo "$(echo "$notsucceeding" | wc -w) tests failed to pass"
+echo "$(echo "$skipped" | wc -w) were skipped (see build log for details)"
+echo "$(echo "$timedout" | wc -w) timed out"
+echo "$(echo "$failed" | wc -w) failed"
+echo ""
+
+if [ "$failed" != "" ]; then
+	echo "Failing test logs:"
+	for t in $failed; do
+		echo $t
+	done
+	exit 1
+fi
+if [ "$failed" != "" -o "$timedout" != "" ]; then
+	echo "Test status: SAD FACE (tests are failing)"
+	exit 1
+fi
+if [ "$succeeding" = "" ]; then
+	echo "Test status: PUZZLED FACE (all tests were skipped)"
+	exit 0
+fi
+if [ "$skipped" != "" ]; then
+	echo "Test status: MILDLY PLEASED FACE (some tests were skipped, but the rest pass)"
+	exit 0
+fi
+echo "Test status: HAPPY FACE (all tests are passing)"
+exit 0
+
diff --git a/h/out.h b/h/out.h
index 45289f313..6aeffc446 100644
--- a/h/out.h
+++ b/h/out.h
@@ -65,9 +65,9 @@ struct outname {
 #define RELO1	   1			/* 1 byte */
 #define RELO2	   2			/* 2 bytes */
 #define RELO4	   3			/* 4 bytes */
-#define RELOPPC    4            /* PowerPC 26-bit address */
-/* relo 5 is unused */
-#define RELOVC4    6            /* VideoCore IV address in 32-bit instruction */
+#define RELOPPC    4			/* PowerPC 26-bit address */
+#define RELOLIS    5			/* PowerPC lis */
+#define RELOVC4    6	/* VideoCore IV address in 32-bit instruction */
 
 #define RELPC	0x2000			/* pc relative */
 #define RELBR	0x4000			/* High order byte lowest address. */
diff --git a/lang/b/LICENSE b/lang/b/LICENSE
new file mode 100644
index 000000000..db5ca3b4b
--- /dev/null
+++ b/lang/b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2016 aap
+
+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.
+
diff --git a/lang/b/README.md b/lang/b/README.md
new file mode 100644
index 000000000..d2ab5faf4
--- /dev/null
+++ b/lang/b/README.md
@@ -0,0 +1,53 @@
+A B Compiler
+============
+
+abc is a compiler for the [B Programming Language](http://en.wikipedia.org/wiki/B_(programming_language)) that targets x86\_32 processors. It is currently tested under Linux but should work (or at least be easily ported) to other UNIX-like systems. The code is based on [an early C compiler (last1120c)](http://www.cs.bell-labs.com/who/dmr/primevalC.html) by Dennis Ritchie.
+
+Documentation
+-------------
+
+* [The Programming Language B](http://9p.io/cm/cs/who/dmr/bintro.html)
+
+* [B Reference by Ken Thompson](http://9p.io/cm/cs/who/dmr/kbman.html) describes a presumably earlier variant of B, which is slightly different from the one described above. The compiler cannot understand it, but I plan to implement a compatibility mode (the differences are minor).
+
+Implementation
+--------------
+
+Since B was first implemented for machines with word addressing, some hacking was required to make it work on the byte addressed x86. Addresses filled in by the linker are always byte addresses, so pointers to these addresses are collectively stored at the end of the .data section and are then converted to word addresses at runtime, before main() is called.
+
+The generated assembly is *very* inefficient, not even constant expressions are reduced at compile time. Also I/O is currently not buffered.
+
+How to use
+----------
+
+The installation requires a little configuration:
+'abc' is a frontend for the actual compiler which feels somewhat like gcc (it also handles assembling and linking). Before you can use it, set it's BDIR variable to the directory of the B compiler.
+In the Makefile, change the directory of the 'install' rule to wherever you want your 'abc' file to reside.
+Then type
+
+	make install libs
+
+which compiles the compiler 'b', installs the 'abc' frontend and compiles the B runtime and library (brt.o and lib.o).
+
+To compile and link a B program, simply type
+
+	abc -o outfile file1.b [file2.b ...]
+
+If you want to compile and assemble only:
+
+	abc -c file1.b [file2.b ...]
+
+or generate only the assembly:
+
+	abc -S file1.b [file2.b ...]
+
+Examples of B programs are in the 'examples' directory, they are mostly from Brian Kernighan's tutorial.
+
+Bugs
+----
+
+Since command line parameters aren't passed word-aligned, B can't handle them easily. brt.s copies the strings to another location and aligns them, the space is not dynamically allocated however and only 256 bytes are available by default.
+
+The library is incomplete but has some of the most important functions.
+
+I have only tested the compiler on an x86\_64 gentoo system.
diff --git a/lang/b/compiler/b.h b/lang/b/compiler/b.h
new file mode 100644
index 000000000..f5a11fd2a
--- /dev/null
+++ b/lang/b/compiler/b.h
@@ -0,0 +1,176 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <em.h>
+#include "astring.h"
+
+#define	NCPS	8	/* chars per symbol */
+#define	HSHSIZ	400	/* hash table size */
+#define	SWSIZ	230	/* switch table size */
+#define	CMSIZ	40	/* symbol stack size */
+#define	SSIZE	20	/* operator and precedence stack size */
+#define	OSSIZ	300*8	/* space for expression tree */
+
+#define	EOS	04	/* end of string marker */
+
+/*
+ * Holds a B symbol.
+ * class is one of the storage classes below.
+ * offset is used depending on class.
+ */
+struct	hshtab {
+	int	class;
+	int	offset;
+	int 	dim;
+	struct	hshtab *next;
+	char	name[NCPS+1];
+};
+
+struct	tnode {
+	int	op;
+	int 	value;
+	struct tnode *tr1;
+	struct tnode *tr2;
+};
+
+struct	swtab {
+	int	swlab;
+	int	swval;
+};
+
+extern int wordsize;
+extern const char* modulename;
+int paramsize;
+struct	hshtab hshtab[HSHSIZ];
+int	hshused;
+int	eof;
+int	peekc;
+char	ctab[128];
+struct	hshtab *bsym;
+struct	hshtab *paraml, *parame;
+int	cval;
+int	isn;
+char	symbuf[NCPS+1];
+FILE	*sbufp;
+int	stack;
+struct	tnode **cp;
+int	*space;
+int	ospace[OSSIZ];
+int	retlab;
+int	nerror;
+struct	swtab swtab[SWSIZ];
+struct	swtab *swp;
+int	deflab;
+extern int	contlab;
+extern int	brklab;
+
+extern int opdope[];
+extern int line;
+extern int peeksym, peeksym2;
+
+void error(char *s, ...);
+void printtoken(int tok, FILE *out);
+struct tnode * block(int op, int value, struct tnode *tr1, struct tnode *tr2);
+void rcexpr(struct tnode *tr);
+void cbranch(struct tnode *t, int lab);
+void jump(int lab);
+void fnlabel(int l);
+void tonativeaddr(void);
+void fromnativeaddr(void);
+char* manglename(char* name, char prefix);
+
+#define	EOFC	0
+#define	SEMI	1
+#define	LBRACE	2
+#define	RBRACE	3
+#define	LBRACK	4
+#define	RBRACK	5
+#define	LPARN	6
+#define	RPARN	7
+#define	COLON	8
+#define	COMMA	9
+#define HASH	10
+
+#define	MCALL	15
+#define	CALL	16
+#define	DECBEF	17
+#define	INCBEF	18
+#define	DECAFT	19
+#define	INCAFT	20
+#define	EXCLA	21
+#define	NEG	22
+#define	AMPER	23
+#define	STAR	24
+#define	QUEST	25
+#define	NOT     26
+
+#define	PLUS	30
+#define	MINUS	31
+#define	MOD	32
+#define	TIMES	33
+#define	DIVIDE	34
+#define	OR	35
+#define	AND	36
+#define	LSHIFT	37
+#define	RSHIFT	38
+#define	EQUAL	39
+#define	NEQUAL	40
+#define	LESSEQ	41
+#define	LESS	42
+#define	GREATEQ	43
+#define	GREAT	44
+#define EOR     45
+
+#define	ASSIGN	49
+#define	ASPLUS	50
+#define	ASMINUS	51
+#define	ASMOD	52
+#define	ASTIMES	53
+#define	ASDIV	54
+#define	ASOR	55
+#define	ASAND	56
+#define	ASLSH	57
+#define	ASRSH	58
+#define	ASEQUAL	59
+#define	ASNEQL	60
+#define	ASLEQ	61
+#define	ASLESS	62
+#define	ASGTQ	63
+#define	ASGREAT	64
+#define ASEOR   65
+
+#define	CON	70
+#define	STRING	71
+#define	NAME	72
+#define	KEYW	73
+
+#define	SQUOTE	121
+#define	DQUOTE	122
+#define	NEWLN	123
+#define	SPACE	124
+#define	LETTER	125
+#define	DIGIT	126
+#define	UNKN	127
+
+#define	SEOF	200
+
+/* storage classes */
+#define AUTO	1
+#define EXTERN	2
+#define INTERN	3
+#define ARG	4
+#define KEYWF	5
+
+/* keywords */
+#define	CASE	3
+#define	IF	4
+#define	ELSE	5
+#define	WHILE	6
+#define	SWITCH	7
+#define	GOTO	8
+#define	RETURN	9
+#define	DEFAULT	10
+#define	BREAK	11
+
diff --git a/lang/b/compiler/b0.c b/lang/b/compiler/b0.c
new file mode 100644
index 000000000..7ae35239b
--- /dev/null
+++ b/lang/b/compiler/b0.c
@@ -0,0 +1,1383 @@
+#include "b.h"
+
+void extdef(void);
+struct hshtab * lookup(void);
+void blkhed(void);
+void blkend(void);
+void statement(int d);
+struct tnode * tree(void);
+void errflush(int o);
+
+int	line = 1;
+int	peeksym = -1, peeksym2 = -1;;
+int	contlab = -1;
+int	brklab = -1;
+
+int wordsize = 4;
+const char* modulename = "bmodule_main";
+int bsymb_part;
+int code_part;
+int string_part;
+
+void
+init(char *s, int val)
+{
+	char *sp;
+	struct hshtab *np;
+
+	sp = symbuf;
+	while (sp < symbuf+NCPS+1)
+		if ((*sp++ = *s++) == '\0')
+			s--;
+	np = lookup();
+	np->class = KEYWF;
+	np->offset = val;
+}
+
+int
+main(int argc, char *argv[])
+{
+
+	for (;;) {
+		int opt = getopt(argc, argv, "-w:B:i:o:");
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+			case 'w':
+				wordsize = atoi(optarg);
+				break;
+
+			case 'B':
+				modulename = aprintf("bmodule_%s", optarg);
+				break;
+
+			case 'i':
+				if (freopen(optarg, "r", stdin) == NULL) {
+					error("Can't find %s", optarg);
+					exit(1);
+				}
+				break;
+
+			case 'o':
+				if (freopen(optarg, "w", stdout) == NULL) {
+					error("Can't create %s", optarg);
+					exit(1);
+				}
+				break;
+
+			derfault:
+				error("Usage: em_b [-w wordsize] [-B modulename] [-i inputfile] [-o outputfile]");
+				exit(1);
+		}
+	}
+
+	init("auto", AUTO);
+	init("extrn", EXTERN);
+	init("case", CASE);
+	init("if", IF);
+	init("else", ELSE);
+	init("while", WHILE);
+	init("switch", SWITCH);
+	init("goto", GOTO);
+	init("return", RETURN);
+	init("default", DEFAULT);
+	init("break", BREAK);
+
+	C_init(wordsize, wordsize);
+	C_open(NULL);
+	C_magic();
+	C_ms_emx(wordsize, wordsize);
+	bsymb_part = 0;
+	string_part = 0;
+	code_part = C_getid();
+	C_beginpart(code_part);
+	while (!eof) {
+		extdef();
+		blkend();
+	}
+	C_endpart(code_part);
+	C_insertpart(code_part);
+
+	if (string_part)
+		C_insertpart(string_part);
+
+	C_exa_dnam((char*) modulename);
+	C_df_dnam((char*) modulename);
+	if (bsymb_part)
+		C_insertpart(bsymb_part);
+	C_rom_cst(0);
+
+	C_close();
+
+	return nerror != 0;
+}
+
+/*
+ * Lexer
+ */
+
+int
+spnextchar(void)
+{
+	int c;
+
+	if ((c = peekc) == 0)
+		c = getchar();
+	if (c == '\t')
+		c = ' ';
+	else if (c == '\n') {
+		c = ' ';
+		line++;
+	}
+	peekc = c;
+	return c;
+}
+
+int
+nextchar(void)
+{
+	while (spnextchar() == ' ')
+		peekc = 0;
+	return peekc;
+}
+
+int
+subseq(int c, int a, int b)
+{
+	if (spnextchar() != c)
+		return a;
+	peekc = 0;
+	return b;
+}
+
+/* Only decimal and octal bases, could extend */
+int
+getnum(void)
+{
+	int base;
+	int c;
+
+	base = 10;
+	cval = 0;
+	if ((c=spnextchar()) == '0')
+		base = 8;
+	for (; ctab[c] == DIGIT; c = getchar())
+		cval = cval*base + c-'0';
+	peekc = c;
+	return CON;
+}
+
+int
+mapch(char c)
+{
+	int a;
+
+	if ((a=getchar()) == c)
+		return -1;
+	switch (a) {
+
+	case '\n':
+	case '\0':
+		error("Nonterminated string");
+		peekc = a;
+		return -1;
+
+	case '*':
+		switch (a=getchar()) {
+
+		case 't':
+			return('\t');
+
+		case 'n':
+			return('\n');
+
+		case '0':
+			return('\0');
+
+		case '(':
+			return('{');
+
+		case ')':
+			return('}');
+
+		case 'e':
+			return(EOS);
+
+		case '\n':
+			line++;
+			return('\n');
+		}
+	}
+	return a;
+}
+
+int
+getcc(void)
+{
+	char *cp;
+	int c, cc;
+
+	cval = 0;
+	cc = 0;
+	cp = (char*) &cval;
+	while ((c = mapch('\'')) >= 0)
+		if (cc++ < wordsize)
+			*cp++ = c;
+	if (cc > wordsize)
+		error("Long character constant");
+	return CON;
+}
+
+int
+getstr(void)
+{
+	int c;
+	int i;
+	char b;
+	int partid;
+
+	partid = C_getid();
+	C_beginpart(partid);
+	if (string_part)
+		C_insertpart(string_part);
+
+	cval = isn++;
+	C_df_dlb(cval);
+	for (i = 1; (c = mapch('"')) >= 0; i++) {
+		b = c;
+		C_con_scon(&b, 1);
+	}
+
+	b = 04;
+	C_con_scon(&b, 1);
+
+	b = 0;
+	while ((i++%4) != 0)
+		C_con_scon(&b, 1);
+
+	C_endpart(partid);
+	string_part = partid;
+
+	return STRING;
+}
+
+struct hshtab *
+lookup(void)
+{
+	int i;
+	char *sp, *np;
+	struct hshtab *rp;
+
+	i = 0;
+	sp = symbuf;
+	while (sp < symbuf+NCPS)
+		i += *sp++&0177;
+	rp = &hshtab[i%HSHSIZ];
+	while (*(np = rp->name)) {
+		for (sp=symbuf; sp < symbuf+NCPS;)
+			if (*np++ != *sp++)
+				goto no;
+		return rp;
+	no:
+		if (++rp >= &hshtab[HSHSIZ])
+			rp = hshtab;
+	}
+	if (++hshused > HSHSIZ) {
+		error("Symbol table overflow");
+		exit(1);
+	}
+	rp->class = 0;
+	rp->offset = 0;
+	rp->dim = 0;
+	sp = symbuf;
+	for (np = rp->name; sp < symbuf+NCPS+1;)
+		*np++ = *sp++;
+	return rp;
+}
+
+/*
+ * Symbol peeking with one peeksym doesn't work if an ASSIGN is only peeked,
+ * since it itself peeks a symbol, which is then overwritten.
+ */
+
+/* Note: does not push bsyms !! */
+int
+pushsym(int sym)
+{
+	if (peeksym < 0)
+		peeksym = sym;
+	else if (peeksym2 < 0) {
+		peeksym2 = peeksym;
+		peeksym = sym;
+	} else
+		error("Cannot push more than two symbols\n");
+	return sym;
+}
+
+int
+symbol(void)
+{
+	int c;
+	char *sp;
+
+	if (peeksym >= 0) {
+		c = peeksym;
+		peeksym = peeksym2;
+		peeksym2 = -1;
+		return c;
+	}
+	if (peekc) {
+		c = peekc;
+		peekc = 0;
+	} else
+		if (eof)
+			return EOFC;
+		else
+			c = getchar();
+	if (c==EOF) {
+		eof++;
+		return(EOFC);
+	}
+
+loop:
+	switch (ctab[c]) {
+
+	case NEWLN:
+		line++;
+		/* fall through */
+	case SPACE:
+		c = getchar();
+		goto loop;
+
+	case HASH:
+		/* # is invalid in B; but we handle it out of convenience so that we can read
+		 * in input files that have been run through the C preprocessor. Ideally we
+		 * should only recognise it when it's the first character in a line, but as
+		 * it's not used anywhere else we can get away with recognising it anywhere.
+		 */
+
+		while ((c = getchar()) == ' ')
+			;
+
+		peekc = c;
+		getnum();
+		line = cval;
+
+		while ((c = getchar()) != '\n')
+			;
+
+		goto loop;
+
+	case PLUS:
+		return subseq(c,PLUS,INCBEF);
+
+	case MINUS:
+		return subseq(c,MINUS,DECBEF);
+
+	case LESS:
+		if (subseq(c,0,1))
+			return LSHIFT;
+		return subseq('=', LESS, LESSEQ);
+
+	case GREAT:
+		if (subseq(c,0,1))
+			return RSHIFT;
+		return subseq('=', GREAT, GREATEQ);
+
+	case ASSIGN:
+		if (subseq(' ',0,1))
+			return ASSIGN;
+		/* avoid peeking a name, which could overwrite
+		 * an already set bsym. */
+		if (ctab[peekc = spnextchar()] == LETTER)
+			return ASSIGN;
+		c = symbol();
+		if (PLUS <= c && c <= EOR)
+			return c + ASPLUS-PLUS;
+		if (c == ASSIGN)
+			return EQUAL;
+		pushsym(c);
+		return ASSIGN;
+
+	case EXCLA:
+		return subseq('=',EXCLA,NEQUAL);
+
+	case DIVIDE:
+		if (subseq('*',1,0))
+			return DIVIDE;
+		while ((c = spnextchar()) != EOFC) {
+			peekc = 0;
+			if (c == '*') {
+				if (spnextchar() == '/') {
+					peekc = 0;
+					c = getchar();
+					goto loop;
+				}
+			}
+		}
+		eof++;
+		error("Nonterminated comment");
+		return EOFC;
+
+	case DIGIT:
+		peekc = c;
+		return getnum();
+
+	case SQUOTE:
+		return(getcc());
+
+	case DQUOTE:
+		return(getstr());
+
+	case LETTER:
+		sp = symbuf;
+		while (ctab[c] == LETTER || ctab[c] == DIGIT) {
+			if (sp < symbuf+NCPS)
+				*sp++ = c;
+			c = getchar();
+		}
+		while (sp < symbuf+NCPS+1)
+			*sp++ = '\0';
+		peekc = c;
+		bsym = lookup();
+		if (bsym->class == KEYWF) {
+			cval = bsym->offset;
+			return KEYW;
+		}
+		return NAME;
+
+	case UNKN:
+		error("Unknown character");
+		c = getchar();
+		goto loop;
+	}
+	return (ctab[c]);
+}
+
+/*
+ * Declarations and Definitions
+ */
+
+/* Declares a list of names to be of storage class "kw". */
+void
+declare(int kw)
+{
+	int o;
+
+	while ((o = symbol()) == NAME) {
+		if (bsym->class)
+			error("%s redeclared", bsym->name);
+		bsym->class = kw;
+		while ((o = symbol()) == LBRACK) {
+			if ((o = symbol()) == CON) {
+				if (bsym->dim)
+					error("Bad vector");
+				bsym->dim = cval + 1;
+				o = symbol();
+			}
+			if (o != RBRACK)
+				goto syntax;
+		}
+		if (kw == ARG) {
+			bsym->next = NULL;
+			if (!paraml)
+				paraml = bsym;
+			else
+				parame->next = bsym;
+			parame = bsym;
+		}
+		if (o != COMMA)
+			break;
+	}
+	if ((o == SEMI && kw != ARG) || (o == RPARN && kw == ARG))
+		return;
+syntax:
+	error("Declaration syntax");
+	errflush(o);
+}
+
+void
+declist(void)
+{
+	int o;
+
+	while ((o = symbol()) == KEYW && (cval == AUTO || cval == EXTERN))
+		declare(cval);
+	pushsym(o);
+}
+
+void
+function(void)
+{
+	declare(ARG);
+	statement(1);
+	C_ret(0);
+	C_end(paramsize);
+}
+
+void
+global(char *s)
+{
+	C_exa_dnam(manglename(s, 'b'));
+}
+
+void
+bsymb(char *s)
+{
+	int newpart = C_getid();
+	C_beginpart(newpart);
+	if (bsymb_part != 0)
+		C_insertpart(bsymb_part);
+	C_rom_dlb(isn, 0);
+	C_endpart(newpart);
+
+	bsymb_part = newpart;
+	C_df_dlb(isn++);
+}
+
+void
+extdef(void)
+{
+	int o, dim, i;
+	char *bs;
+	char *ms;
+	int neg;
+
+	if ((o = symbol()) == EOFC || o == SEMI)
+		return;
+	if (o != NAME)
+		goto syntax;
+	bs = bsym->name;
+	i = dim = 0;
+	neg = 0;
+	switch(o = symbol()) {
+
+	case SEMI:
+		global(bs);
+		C_df_dnam(manglename(bs, 'b'));
+		C_bss_cst(wordsize, 0, 1);
+		goto done;
+
+	/* init */
+	case CON:
+	case STRING:
+	case MINUS:
+		global(bs);
+		if (o == STRING)
+			bsymb(bs);
+		else if (o == MINUS) {
+			o = symbol();
+			if (o != CON)
+				goto syntax;
+			cval = -cval;
+		}
+		C_df_dnam(manglename(bs, 'b'));
+		pushsym(o);
+		goto init;
+
+	/* vector */
+	case LBRACK:
+		if ((o=symbol()) == CON) {
+			dim = cval + 1;
+			o=symbol();
+		}
+		if (o != RBRACK)
+			goto syntax;
+		global(bs);
+		if ((o=symbol()) == SEMI) {
+			bsymb(bs);
+			C_df_dnam(manglename(bs, 'b'));
+			C_con_dlb(isn, 0);
+			C_df_dlb(isn++);
+			C_bss_cst(wordsize*dim, 0, 1); 
+			goto done;
+		}
+		bsymb(bs);
+		C_df_dnam(manglename(bs, 'b'));
+		C_con_dlb(isn, 0);
+		C_df_dlb(isn++);
+		pushsym(o);
+
+	init:
+		do {
+			if ((o=symbol()) != CON && o != STRING && o != NAME)
+				goto syntax;
+			if (o == NAME) {
+				bsymb(NULL);
+				C_con_dnam(manglename(bsym->name, 'b'), 0);
+			} else {
+				if (o == STRING) {
+					bsymb(NULL);
+					C_con_dlb(cval, 0);
+				} else
+					C_con_cst(cval);
+			}
+			i++;
+		} while ((o=symbol()) == COMMA);
+		dim = (i > dim) ? i : dim;
+		if (i == 0)
+			C_bss_cst((dim-i)*wordsize, 0, 1);
+		else {
+			while (dim -i) {
+				C_con_cst(0);
+				i++;
+			}
+		}
+		if (o == SEMI)
+			goto done;
+		goto syntax;
+
+	/* function */
+	case LPARN:
+		global(bs);
+		ms = manglename(bs, 'b');
+		bsymb(ms);
+		C_df_dnam(ms);
+		ms = manglename(bs, 'i');
+		C_con_pnam(ms);
+		C_inp(ms);
+		C_pro_narg(ms);
+		function();
+	done:
+		return;
+
+	case EOFC:
+		return;
+	}
+syntax:
+	error("External definition syntax");
+	printtoken(o, stderr);
+	errflush(o);
+	statement(0);
+}
+
+void
+blkhed(void)
+{
+	int al, pl;
+	struct hshtab *bs;
+
+	declist();
+	stack = al = -wordsize;
+	pl = 0; /* EM parameters start at offset 0. */
+	while (paraml) {
+		paraml = (bs = paraml)->next;
+		bs->offset = pl;
+		pl += wordsize;
+	}
+	for (bs = hshtab; bs < &hshtab[HSHSIZ]; bs++)
+		if (bs->name[0]) {
+			if (bs->class == AUTO) {
+				bs->offset = al;
+				if (bs->dim) {
+					al -= bs->dim*wordsize;
+					C_lal(al);
+					al -= wordsize;
+					fromnativeaddr();
+					C_stl(al);
+					bs->offset = al;
+				}
+				al -= wordsize;
+			} else if (bs->class == ARG)
+				bs->class = AUTO;
+		}
+	paramsize = -al - wordsize;
+}
+
+void
+blkend(void)
+{
+	struct hshtab *np;
+
+	for (np = hshtab; np < &hshtab[HSHSIZ]; np++)
+		if (np->class != KEYWF) {
+			np->name[0] = '\0';
+			hshused--;
+		}
+}
+
+/*
+ * Statements and Expressions
+ */
+
+struct tnode *
+pexpr(void)
+{
+	struct tnode *t;
+	int o;
+
+	if ((o = symbol()) != LPARN)
+		goto syntax;
+	t = tree();
+	if ((o = symbol()) != RPARN)
+		goto syntax;
+	return t;
+syntax:
+	error("Statement syntax");
+	errflush(o);
+	return NULL;
+}
+
+void
+fnlabel(int l)
+{
+	C_ilb(l);
+}
+
+/* Jump to "lab", if the expression "t" evaluated to 0. */
+void
+cbranch(struct tnode *t, int lab)
+{
+	rcexpr(t);
+	C_zeq(lab);
+}
+
+void
+jump(int lab)
+{
+	C_bra(lab);
+}
+
+void
+pswitch(void)
+{
+	struct swtab *sswp;
+	int dl, swlab;
+
+	if (swp == NULL)
+		swp = swtab;
+	sswp = swp;
+	swlab = isn++;
+	C_lae_dlb(swlab, 0);
+	C_csb(wordsize);
+
+	dl = deflab;
+	deflab = 0;
+	statement(0);
+	if (!deflab)
+		deflab = brklab;
+
+	C_df_dlb(swlab);
+	C_rom_ilb(deflab);
+	C_rom_cst(swp - sswp);
+
+	while (swp > sswp && swp > swtab) {
+		--swp;
+		C_rom_cst(swp->swval);
+		C_rom_ilb(swp->swlab);
+	}
+
+	C_df_ilb(brklab);
+
+	deflab = dl;
+	swp = sswp;
+}
+
+void
+statement(int d)
+{
+	int o, o1, o2;
+
+stmt:
+	if ((o = symbol()) == LBRACE) {
+		if (d)
+			blkhed();
+		while (!eof) {
+			if ((o = symbol()) == RBRACE)
+				goto bend;
+			pushsym(o);
+			statement(0);
+		}
+		error("Missing '}'");
+	bend:
+		return;
+	} else {
+		pushsym(o);
+		if (d)
+			blkhed();
+	}
+
+	switch (o = symbol()) {
+
+	case EOFC:
+		error("Unexpected EOF");
+
+	case SEMI:
+	case RBRACE:
+		return;
+
+	case KEYW:
+		switch (cval) {
+		case GOTO:
+			if ((o = symbol()) != NAME)
+				goto syntax;
+			if (bsym->offset == 0)
+				bsym->offset = isn++;
+			jump(bsym->offset);
+			goto semi;
+
+		case RETURN:
+			if (pushsym(symbol()) == LPARN) {
+				rcexpr(pexpr());
+				C_ret(wordsize);
+			} else {
+				C_ret(0);
+			}
+			goto semi;
+
+		case IF:
+			cbranch(pexpr(), o1=isn++);
+			statement(0);
+			if ((o = symbol()) == KEYW && cval == ELSE) {
+				jump(o2 = isn++);
+				fnlabel(o1);
+				statement(0);
+				fnlabel(o2);
+				return;
+			}
+			pushsym(o);
+			fnlabel(o1);
+			return;
+
+		case WHILE:
+			o1 = contlab;
+			o2 = brklab;
+			fnlabel(contlab = isn++);
+			cbranch(pexpr(), brklab=isn++);
+			statement(0);
+			jump(contlab);
+			fnlabel(brklab);
+			contlab = o1;
+			brklab = o2;
+			return;
+
+		case BREAK:
+			if (brklab < 0)
+				error("Nothing to break from");
+			jump(brklab);
+			goto semi;
+
+		/* Not part of B, but very easy to implement */
+/*
+		case CONTINUE:
+			if (contlab < 0)
+				error("Nothing to continue");
+			jump(contlab);
+			goto semi;
+*/
+
+		case SWITCH:
+			o1 = brklab;
+			brklab = isn++;
+			rcexpr(pexpr());
+/*			rcexpr(tree()); */
+			pswitch();
+			brklab = o1;
+			return;
+
+		case CASE:
+			if ((o = symbol()) != CON)
+				goto syntax;
+			if ((o = symbol()) != COLON)
+				goto syntax;
+			if (swp == NULL) {
+				error("Case not in switch");
+				goto stmt;
+			}
+			if (swp >= swtab+SWSIZ)
+				error("Switch table overflow");
+			else {
+				swp->swlab = isn;
+				(swp++)->swval = cval;
+				fnlabel(isn++);
+			}
+			goto stmt;
+
+		case DEFAULT:
+			if (swp == NULL)
+				error("Default not in switch");
+			if ((o = symbol()) != COLON)
+				goto syntax;
+			deflab = isn++;
+			fnlabel(deflab);
+			goto stmt;
+		}
+
+		error("Unknown keyword");
+		goto syntax;
+
+	case NAME:
+		if (peekc == ':') {
+			peekc = 0;
+			if (bsym->class) {
+				error("Redefinition");
+				goto stmt;
+			}
+			bsym->class = INTERN;
+			if (bsym->offset == 0)
+				bsym->offset = isn++;
+			fnlabel(bsym->offset);
+			goto stmt;
+		}
+	}
+	pushsym(o);
+	rcexpr(tree());
+	C_asp(wordsize);
+	goto semi;
+
+semi:
+	if ((o = symbol()) != SEMI)
+		goto syntax;
+	return;
+
+syntax:
+	error("Statement syntax");
+	errflush(o);
+	goto stmt;
+}
+
+struct tnode *
+block(int op, int value, struct tnode *tr1, struct tnode *tr2)
+{
+	struct tnode t;
+	int n;
+	int *p, *ap;
+
+	p = space;
+	t.op = op;
+	t.value = value;
+	t.tr1 = tr1;
+	t.tr2 = tr2;
+	ap = (int*) &t;
+	n = (sizeof(struct tnode)+sizeof(int)-1) & ~sizeof(int);
+	if (space+n >= &ospace[OSSIZ]) {
+		error("Expression overflow 1");
+		exit(1);
+	}
+	while (n--)
+		*space++ = *ap++;
+	return (struct tnode *) p;
+}
+
+void
+chklval(struct tnode *p)
+{
+	if (p->op != NAME && p->op != STAR)
+		error("Lvalue required");
+}
+
+void
+build(int op)
+{
+	struct tnode *p1, *p2;
+	int dope;
+
+	/* a[i] -> *(a+i) */
+	if (op == LBRACK) {
+		build(PLUS);
+		op = STAR;
+	}
+	dope = opdope[op];
+	if (dope&01)
+		p2 = *--cp;
+	p1 = *--cp;
+	switch (op) {
+	case QUEST:
+		if (p2->op != COLON)
+			error("Illegal conditional");
+		break;
+
+	case AMPER:
+		if (p1->op == STAR) {
+			*cp++ = p1->tr1;
+			return;
+		}
+		if (p1->op == NAME) {
+			*cp++ = block(op,0,p1,NULL);
+			return;
+		}
+		error("Illegal lvalue");
+	}
+	if (dope&02)
+		chklval(p1);
+	if (dope&01)
+		*cp++ = block(op,0,p1,p2);
+	else
+		*cp++ = block(op,0,p1,NULL);
+}
+
+struct tnode *
+tree(void)
+{
+	struct tnode *cmst[CMSIZ];
+	int opst[SSIZE], prst[SSIZE];
+	int *op, *pp;
+	int andflg;
+	int o, os;
+	int p, ps;
+
+	space = ospace;
+	op = opst;
+	pp = prst;
+	cp = cmst;
+	*op = SEOF;
+	*pp = 06;
+	andflg = 0;
+
+advanc:
+	switch (o=symbol()) {
+	case NAME:
+		if (pushsym(symbol()) == LPARN) {	/* function */
+			if (bsym->class == 0)
+				bsym->class = EXTERN;
+		} else if (bsym->class == 0) {
+			error("%s undefined", bsym->name);
+			bsym->class = EXTERN;
+		}
+		*cp++ = block(NAME,0,(struct tnode *)bsym,NULL);
+		goto tand;
+
+	case STRING:
+		*cp++ = block(STRING,cval,NULL,NULL);
+		goto tand;
+
+	case CON:
+	caseCON:
+		*cp++ = block(CON,cval,NULL,NULL);
+		goto tand;
+
+tand:
+		if (cp >= &cmst[CMSIZ]) {
+			error("Expression overflow 2");
+			exit(1);
+		}
+		if (andflg)
+			goto syntax;
+		andflg = 1;
+		goto advanc;
+
+	case DECBEF:
+	case INCBEF:
+		if (andflg)
+			o += 2;
+		goto oponst;
+
+	case EXCLA:
+	case NOT:
+		if (andflg)
+			goto syntax;
+		goto oponst;
+
+	case MINUS:
+		if (!andflg) {
+			if (pushsym(symbol()) == CON) {
+				symbol();
+				cval = -cval;
+				goto caseCON;
+			}
+			o = NEG;
+		}
+		andflg = 0;
+		goto oponst;
+
+	case AND:
+	case TIMES:
+		if (andflg)
+			andflg = 0;
+		else
+			if (o == AND)
+				o = AMPER;
+			else
+				o = STAR;
+		goto oponst;
+
+	case LPARN:
+		if (andflg) {
+			o = symbol();
+			if (o == RPARN)
+				o = MCALL;
+			else {
+				pushsym(o);
+				o = CALL;
+				andflg = 0;
+			}
+		}
+		goto oponst;
+
+	case RPARN:
+	case RBRACK:
+		if (!andflg)
+			goto syntax;
+		goto oponst;
+	}
+
+	if (!andflg)
+		goto syntax;
+	andflg = 0;
+
+oponst:
+	p = (opdope[o]>>9) & 077;
+opon1:
+	ps = *pp;
+	if (p > ps || (p == ps && (opdope[o]&0200))) {	/* right-assoc */
+		switch (o) {
+		case LPARN:
+		case LBRACK:
+		case CALL:
+			p = 04;
+		}
+		if (op >= &opst[SSIZE]) {
+			error("Expression overflow 3");
+			exit(1);
+		}
+		*++op = o;
+		*++pp = p;
+		goto advanc;
+	}
+	--pp;
+	switch (os = *op--) {
+	case SEOF:
+		pushsym(o);
+		return(*--cp);
+
+	case CALL:
+		if (o != RPARN)
+			goto syntax;
+		build(os);
+		goto advanc;
+
+	case MCALL:
+		*cp++ = NULL;
+		os = CALL;
+		goto fbuild;
+
+	case LPARN:
+		if (o != RPARN)
+			goto syntax;
+		goto advanc;
+
+	case LBRACK:
+		if (o != RBRACK)
+			goto syntax;
+		build(LBRACK);
+		goto advanc;
+
+	}
+fbuild:
+	build(os);
+	goto opon1;
+syntax:
+	error("Expression syntax");
+	errflush(o);
+	return NULL;
+}
+
+void
+error(char *s, ...)
+{
+	va_list args;
+
+	va_start(args, s);
+	nerror++;
+	fprintf(stderr, "%d: ", line);
+	vfprintf(stderr, s, args);
+	putc('\n', stderr);
+	va_end(args);
+}
+
+void
+errflush(int o)
+{
+	while (o > RBRACE)	/* ; { } */
+		o = symbol();
+	pushsym(o);
+}
+
+/*
+ *	000001	binary
+ *	000002	need lvalue
+ *	000004	relational
+ *	000010	assignment
+ *	000100	commutative
+ *	000200	right-assoc
+ *	0XX000	precedence
+ */
+int opdope[] = {
+	000000,	/* EOFC */
+	000000,	/* ; */
+	000000,	/* { */
+	000000,	/* } */
+	036000,	/* [ */
+	002000,	/* ] */
+	036000,	/* ( */
+	002000,	/* ) */
+	014201,	/* : */
+	007001,	/* , */
+	000000,	/* 10 */
+	000000,	/* 11 */
+	000000,	/* 12 */
+	000000,	/* 13 */
+	000000,	/* 14 */
+	036001,	/* mcall */
+	036001,	/* call */
+	034202,	/* ++a */
+	034202,	/* a++ */
+	034202,	/* --a */
+	034202,	/* a-- */
+	034200,	/* !un */
+	034200,	/* -un */
+	034200,	/* &un */
+	034200,	/* *un */
+	014201,	/* ? */
+	034200, /* ~un */
+	000000,	/* 27 */
+	000000,	/* 28 */
+	000000,	/* 29 */
+	030101,	/* + */
+	030001,	/* - */
+	032001,	/* % */
+	032101,	/* * */
+	032001,	/* / */
+	016101,	/* | */
+	020101,	/* & */
+	026001,	/* << */
+	026001,	/* >> */
+	022105,	/* == */
+	022105,	/* != */
+	024005,	/* <= */
+	024005,	/* < */
+	024005,	/* >= */
+	024005,	/* > */
+	017005,	/* ^ */
+	000000,	/* 46 */
+	000000,	/* 47 */
+	000000,	/* 48 */
+	012013,	/* = */
+	012213,	/* =+ */
+	012213,	/* =- */
+	012213,	/* =% */
+	012213,	/* =* */
+	012213,	/* =/ */
+	012213,	/* =| */
+	012213,	/* =& */
+	012213,	/* =<< */
+	012213,	/* =>> */
+	012213,	/* === */
+	012213,	/* =!= */
+	012213,	/* =<= */
+	012213,	/* =< */
+	012213,	/* =>= */
+	012213,	/* => */
+	012213,	/* =^ */
+	000000, /* 66 */
+	000000, /* 67 */
+	000000, /* 68 */
+	000000, /* 69 */
+	000000,	/* CON */
+	000000,	/* STRING */
+	000000	/* NAME */
+};
+
+char ctab[128] = {
+	EOFC,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,
+	LETTER,	SPACE,	NEWLN,	SPACE,	SPACE,	UNKN,	UNKN,	UNKN,
+	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,
+	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,
+	SPACE,	EXCLA,	DQUOTE,	HASH,	UNKN,	MOD,	AND,	SQUOTE,
+	LPARN,	RPARN,	TIMES,	PLUS,	COMMA,	MINUS,	UNKN,	DIVIDE,
+	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,
+	DIGIT,	DIGIT,	COLON,	SEMI,	LESS,	ASSIGN,	GREAT,	QUEST,
+	UNKN,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
+	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
+	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
+	LETTER,	LETTER,	LETTER,	LBRACK,	UNKN,	RBRACK,	EOR,	LETTER,
+	UNKN,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
+	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
+	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
+	LETTER,	LETTER,	LETTER,	LBRACE,	OR,	RBRACE,	NOT,	UNKN
+};
+
+/* debug function */
+void printtoken(int tok, FILE *out)
+{
+	static char *strtab[128];
+	strtab[0] = "EOFC";
+	strtab[1] = "SEMI";
+	strtab[2] = "LBRACE";
+	strtab[3] = "RBRACE";
+	strtab[4] = "LBRACK";
+	strtab[5] = "RBRACK";
+	strtab[6] = "LPARN";
+	strtab[7] = "RPARN";
+	strtab[8] = "COLON";
+	strtab[9] = "COMMA";
+	strtab[10] = "HASH";
+
+	strtab[15] = "MCALL";
+	strtab[16] = "CALL";
+	strtab[17] = "DECBEF";
+	strtab[18] = "INCBEF";
+	strtab[19] = "DECAFT";
+	strtab[20] = "INCAFT";
+	strtab[21] = "EXCLA";
+	strtab[22] = "NEG";
+	strtab[23] = "AMPER";
+	strtab[24] = "STAR";
+	strtab[25] = "QUEST";
+	strtab[26] = "NOT";
+
+	strtab[30] = "PLUS";
+	strtab[31] = "MINUS";
+	strtab[32] = "MOD";
+	strtab[33] = "TIMES";
+	strtab[34] = "DIVIDE";
+	strtab[35] = "OR";
+	strtab[36] = "AND";
+	strtab[37] = "LSHIFT";
+	strtab[38] = "RSHIFT";
+	strtab[39] = "EQUAL";
+	strtab[40] = "NEQUAL";
+	strtab[41] = "LESSEQ";
+	strtab[42] = "LESS";
+	strtab[43] = "GREATEQ";
+	strtab[44] = "GREAT";
+	strtab[45] = "EOR";
+
+	strtab[49] = "ASSIGN";
+	strtab[50] = "ASPLUS";
+	strtab[51] = "ASMINUS";
+	strtab[52] = "ASMOD";
+	strtab[53] = "ASTIMES";
+	strtab[54] = "ASDIV";
+	strtab[55] = "ASOR";
+	strtab[56] = "ASAND";
+	strtab[57] = "ASLSH";
+	strtab[58] = "ASRSH";
+	strtab[59] = "ASEQUAL";
+	strtab[60] = "ASNEQL";
+	strtab[61] = "ASLEQ";
+	strtab[62] = "ASLESS";
+	strtab[63] = "ASGTQ";
+	strtab[64] = "ASGREAT";
+	strtab[65] = "ASEOR";
+
+	strtab[70] = "CON";
+	strtab[71] = "STRING";
+	strtab[72] = "NAME";
+	strtab[73] = "KEYW";
+
+	strtab[127] = "UNKN";
+
+	if (tok == CON || tok == STRING) {
+		fprintf(out, "%s(%d) ", strtab[tok], cval);
+		return;
+	}
+	if (tok == NAME) {
+		fprintf(out, "%s(%s) ", strtab[tok], symbuf);
+		return;
+	}
+		
+	fprintf(out, "%s ", strtab[tok]);
+}
+
diff --git a/lang/b/compiler/b1.c b/lang/b/compiler/b1.c
new file mode 100644
index 000000000..ca5ae5593
--- /dev/null
+++ b/lang/b/compiler/b1.c
@@ -0,0 +1,403 @@
+#include "b.h"
+
+/*
+ * Code generation (EM)
+ */
+
+static int
+shiftsize(void)
+{
+	switch (wordsize) {
+		case 1: return 0;
+		case 2: return 1;
+		case 4: return 2;
+		case 8: return 3;
+		default:
+			error("unsupported word size");
+			exit(1);
+	}
+}
+
+void
+tonativeaddr(void)
+{
+	C_loc(shiftsize());
+	C_slu(wordsize);
+}
+
+void
+fromnativeaddr(void)
+{
+	C_loc(shiftsize());
+	C_sru(wordsize);
+}
+
+char*
+manglename(char* name, char prefix)
+{
+	static char buffer[NCPS+3];
+	buffer[0] = prefix;
+	buffer[1] = '_';
+	strcpy(buffer+2, name);
+	return buffer;
+}
+
+void
+binary(struct tnode *tr)
+{
+	rcexpr(tr->tr1);
+	rcexpr(tr->tr2);
+}
+
+int
+pushargs(struct tnode *tr)
+{
+	int stk;
+
+	if (tr == NULL)
+		return 0;
+	if (tr->op == COMMA) {
+		rcexpr(tr->tr2);
+		stk = pushargs(tr->tr1);
+		return stk+wordsize;
+	}
+	rcexpr(tr);
+	return wordsize;
+}
+
+void
+lvalexp(struct tnode *tr)
+{
+	struct hshtab *bs;
+	char memloc[64];
+
+	switch (tr->op) {
+
+	case DECBEF:
+	case INCBEF:
+	case DECAFT:
+	case INCAFT:
+		if (tr->tr1->op == STAR) {
+			rcexpr(tr->tr1->tr1);
+			tonativeaddr();
+
+			if ((tr->op == DECBEF) || (tr->op == INCBEF)) {
+				C_dup(wordsize); /* ( addr addr -- ) */
+				C_loi(wordsize); /* ( addr val -- ) */
+				if (tr->op == DECBEF)
+					C_dec(); /* ( addr newval -- ) */
+				else
+					C_inc(); /* ( addr newval -- ) */
+				C_exg(wordsize); /* ( newval addr -- ) */
+				C_dup(wordsize*2); /* ( newval addr newval addr -- ) */
+				C_sti(wordsize); /* ( newval addr -- ) */
+				C_asp(wordsize); /* ( newval -- ) */
+			} else {
+				C_dup(wordsize); /* ( addr addr -- ) */
+				C_loi(wordsize); /* ( addr val -- ) */
+				C_dup(wordsize*2); /* ( addr val addr val -- ) */
+				if (tr->op == DECAFT)
+					C_dec(); /* ( addr val addr newval -- ) */
+				else
+					C_inc(); /* ( addr val addr newval -- ) */
+				C_exg(wordsize); /* ( addr val newval addr -- ) */
+				C_sti(wordsize); /* ( addr val -- ) */
+				C_exg(wordsize); /* ( val addr -- ) */
+				C_asp(wordsize); /* ( val -- ) */
+			}
+		} else {	/* NAME, checked in "build" */
+			bs = (struct hshtab *) tr->tr1->tr1;
+			if (bs->class == EXTERN) {
+				switch (tr->op) {
+					case INCBEF:
+						C_ine_dnam(manglename(bs->name, 'b'), 0);
+						C_loe_dnam(manglename(bs->name, 'b'), 0);
+						break;
+
+					case DECBEF:
+						C_dee_dnam(manglename(bs->name, 'b'), 0);
+						C_loe_dnam(manglename(bs->name, 'b'), 0);
+						break;
+
+					case INCAFT:
+						C_loe_dnam(manglename(bs->name, 'b'), 0);
+						C_ine_dnam(manglename(bs->name, 'b'), 0);
+						break;
+
+					case DECAFT:
+						C_loe_dnam(manglename(bs->name, 'b'), 0);
+						C_dee_dnam(manglename(bs->name, 'b'), 0);
+						break;
+				}
+			} else if (bs->class == AUTO) {
+				switch (tr->op) {
+					case INCBEF:
+						C_inl(bs->offset);
+						C_lol(bs->offset);
+						break;
+
+					case DECBEF:
+						C_del(bs->offset);
+						C_lol(bs->offset);
+						break;
+
+					case INCAFT:
+						C_lol(bs->offset);
+						C_inl(bs->offset);
+						break;
+
+					case DECAFT:
+						C_lol(bs->offset);
+						C_del(bs->offset);
+						break;
+				}
+			} else
+				goto classerror;
+		}
+		return;
+
+	case ASSIGN:
+		rcexpr(tr->tr2);
+		C_dup(wordsize);
+		if (tr->tr1->op == STAR) {
+			rcexpr(tr->tr1->tr1);
+			tonativeaddr();
+			C_sti(wordsize);
+		} else {	/* NAME */
+			bs = (struct hshtab *) tr->tr1->tr1;
+			if (bs->class == EXTERN) {
+				C_ste_dnam(manglename(bs->name, 'b'), 0);
+			} else if (bs->class == AUTO) {
+				C_stl(bs->offset);
+			} else
+				goto classerror;
+		}
+		return;
+
+	case ASPLUS:
+	case ASMINUS:
+	case ASMOD:
+	case ASTIMES:
+	case ASDIV:
+	case ASOR:
+	case ASAND:
+	case ASLSH:
+	case ASRSH:
+	case ASEQUAL:
+	case ASNEQL:
+	case ASLEQ:
+	case ASLESS:
+	case ASGTQ:
+	case ASGREAT:
+	case ASEOR:
+		tr->op -= ASPLUS-PLUS;
+		rcexpr(block(ASSIGN,0,tr->tr1,tr));
+		return;
+	}
+
+classerror:
+	error("Storage class");
+}
+
+void
+rcexpr(struct tnode *tr)
+{
+	int o1, o2;
+	int stk;
+	struct hshtab *bs;
+
+	if (tr == NULL)
+		return;
+
+	if (opdope[tr->op]&02) {
+		lvalexp(tr);
+		return;
+	}
+
+	switch (tr->op) {
+
+	case CON:
+		C_loc(tr->value);
+		return;
+
+	case STRING:
+		C_lae_dlb(tr->value, 0);
+		fromnativeaddr();
+		return;
+
+	case NAME:	/* only rvalue */
+		bs = (struct hshtab *) tr->tr1;
+		if (bs->class == EXTERN)
+			C_loe_dnam(manglename(bs->name, 'b'), 0);
+		else if (bs->class == AUTO)
+			C_lol(bs->offset);
+		else
+			goto classerror;
+		return;
+
+	case CALL:
+		stk = pushargs(tr->tr2);
+		rcexpr(tr->tr1);
+		tonativeaddr();
+		C_cai();
+		if (stk)
+			C_asp(stk);
+		C_lfr(wordsize);
+		return;
+
+	case AMPER:
+		bs = (struct hshtab *) tr->tr1->tr1;
+		if (bs->class == EXTERN) {
+			C_lae_dnam(manglename(bs->name, 'b'), 0);
+		} else if (bs->class == AUTO) {
+			C_lal(bs->offset);
+		} else
+			goto classerror;
+		fromnativeaddr();
+		return;
+
+	case STAR:	/* only rvalue */
+		rcexpr(tr->tr1);
+		tonativeaddr();
+		C_loi(wordsize);
+		return;
+
+	case PLUS:
+		binary(tr);
+		C_adi(wordsize);
+		return;
+
+	case MINUS:
+		binary(tr);
+		C_sbi(wordsize);
+		return;
+
+	case TIMES:
+		binary(tr);
+		C_mli(wordsize);
+		return;
+
+	case DIVIDE:
+		binary(tr);
+		C_dvi(wordsize);
+		return;
+
+	case MOD:
+		binary(tr);
+		C_rmi(wordsize);
+		return;
+
+	case AND:
+		binary(tr);
+		C_and(wordsize);
+		return;
+
+	case OR:
+		binary(tr);
+		C_ior(wordsize);
+		return;
+
+	case EOR:
+		binary(tr);
+		C_xor(wordsize);
+		return;
+
+	case LSHIFT:
+		binary(tr);
+		C_sli(wordsize);
+		return;
+
+	case RSHIFT:
+		binary(tr);
+		C_sri(wordsize);
+		return;
+
+	case EQUAL:
+	case NEQUAL:
+	case LESS:
+	case LESSEQ:
+	case GREAT:
+	case GREATEQ:
+		binary(tr);
+		C_cmi(wordsize);
+		switch (tr->op) {
+		case EQUAL:
+			C_teq();
+			break;
+		case NEQUAL:
+			C_tne();
+			break;
+		case LESS:
+			C_tlt();
+			break;
+		case LESSEQ:
+			C_tle();
+			break;
+		case GREAT:
+			C_tgt();
+			break;
+		case GREATEQ:
+			C_tge();
+			break;
+		}
+		return;
+
+	case EXCLA:
+		rcexpr(tr->tr1);
+		C_teq();
+		return;
+
+	case NEG:
+		rcexpr(tr->tr1);
+		C_ngi(wordsize);
+		return;
+
+	case NOT:
+		rcexpr(tr->tr1);
+		C_com(wordsize);
+		return;
+
+	case QUEST:
+		cbranch(tr->tr1, o1=isn++);
+		rcexpr(tr->tr2->tr1);
+		jump(o2 = isn++);
+		fnlabel(o1);
+		rcexpr(tr->tr2->tr2);
+		fnlabel(o2);
+		return;
+
+	default:
+		error("Can't print tree (op: %d)", tr->op);
+	}
+
+classerror:
+	error("Storage class");
+}
+
+/* Prints the tree in RPN, for debugging */
+/*
+void
+rcexpr(struct tnode *tr)
+{
+	struct hshtab *bs;
+
+	if (tr == NULL)
+		printf("(NULL) ");
+	else if (tr->op == CON)
+		printf("%d ", tr->value);
+	else if (tr->op == STRING)
+		printf("s(L%d) ", tr->value);
+	else if (tr->op == NAME) {
+		bs = (struct hshtab *)tr->tr1;
+		if (bs->class == AUTO)
+			printf("%s(%d) ", bs->name, bs->offset);
+		else
+			printf("%s ", bs->name);
+	} else {
+		rcexpr(tr->tr1);
+		if (opdope[tr->op]&01)
+			rcexpr(tr->tr2);
+		printtoken(tr->op, stdout);
+	}
+}
+*/
diff --git a/lang/b/compiler/build.lua b/lang/b/compiler/build.lua
new file mode 100644
index 000000000..c647f6036
--- /dev/null
+++ b/lang/b/compiler/build.lua
@@ -0,0 +1,28 @@
+
+cprogram {
+	name = "em_b",
+	srcs = {
+		"./*.c",
+	},
+	deps = {
+		"./*.h",
+		"modules+headers",
+		"modules/src/alloc+lib",
+		"modules/src/data+lib",
+		"modules/src/em_code+lib_k",
+		"modules/src/em_data+lib",
+		"modules/src/em_mes+lib",
+		"modules/src/print+lib",
+		"modules/src/string+lib",
+		"modules/src/system+lib",
+	}
+}
+
+installable {
+	name = "pkg",
+	map = {
+		["$(PLATDEP)/em_b"] = "+em_b",
+		["$(INSDIR)/share/man/man6/em_b.6"] = "./em_b.6"
+	}
+}
+
diff --git a/lang/b/compiler/em_b.6 b/lang/b/compiler/em_b.6
new file mode 100644
index 000000000..f7030f214
--- /dev/null
+++ b/lang/b/compiler/em_b.6
@@ -0,0 +1,53 @@
+.TH EM_B 6 2017-01-18
+.ad
+.SH NAME
+em_b \- ACK B compiler
+.SH SYNOPSIS
+.B ~em/lib/ack/em_b
+.RI [ options ]
+.SH DESCRIPTION
+.I em_b
+is a port of the ABC B compiler to the ACK.
+Interested parties will be
+interested in the upstream distribution here:
+.nf
+.sp
+https://github.com/aap/abc
+.fi
+.PP
+However, the version here has been heavily modified \(em bug reports should be
+filed with the ACK, not with the upstream compiler.
+.PP
+Since B was designed for machines with word addressing, some hacking is
+required to make it work on modern, byte addressed machines.
+The generated
+code expects B variables to contain word addresses, and then generates
+code to transform these into native addresses before use (which,
+unfortunately, impacts performance).
+However, the ACK's linker doesn't know
+how to emit word addresses into the program's data sections, and so a
+separate fixup stage has to happen at runtime, just before \fBmain()\fP,
+to convert the byte addresses into word addresses.
+.PP
+The end result is that using multiple source files with B is somewhat
+unwieldy, requiring each module to be explicitly named and then an extra
+stage to generate the fixup code.
+See the \fBack\fP(1) and \fBabmodules\fP(1) for details.
+.SH OPTIONS
+.I em_b
+accepts the following flags:
+.IP \-w\ \fIsize\fP
+Sets the word size, used for scaling addresses.
+Usually either 2 or 4.
+.IP \-B\ \fIname\fP
+Sets the name of the module currently being compiled (used to generate the
+fixup table symbol name).
+Defaults to \fImain\fP if not specified.
+.IP \-i\ \fIfilename\fP
+The source B file.
+.IP \-o\ \fIfilename\fP
+The output compact EM bytecode file.
+.SH SEE ALSO
+\fIack\fR(1), \fIabmodules\fR(1)
+.SH REMARKS
+It is very unlikely the \fIem_b\fP will ever be useful for anything.
diff --git a/lang/b/distr/Makefile b/lang/b/distr/Makefile
new file mode 100644
index 000000000..283848647
--- /dev/null
+++ b/lang/b/distr/Makefile
@@ -0,0 +1,15 @@
+CFLAGS=-Wall -Wextra
+b: b0.o b1.o
+	cc b0.o b1.o -o b
+b0.o: b0.c b.h
+b1.o: b1.c b.h
+
+libs:
+	./abc -c brt.s lib.b
+
+install: b abc
+	cp abc $(HOME)/bin
+
+%.o: %.s
+	as --32 $^ -o $@
+
diff --git a/lang/b/distr/abc b/lang/b/distr/abc
new file mode 100755
index 000000000..21cdda485
--- /dev/null
+++ b/lang/b/distr/abc
@@ -0,0 +1,95 @@
+#!/bin/sh
+BDIR="$HOME/abc"
+objs="$BDIR/brt.o $BDIR/lib.o"
+BC="$BDIR/b"
+
+# compile in.b [out.s]
+compile() {
+	if [ "${1##*.}" != "b" ]; then
+		echo "Error: can only compile b files" >&2
+		exit 1
+	fi
+	cout=$2
+	[ "$cout" != "" ] || cout=${1%b}s
+	tmp1=`mktemp`; tmp2=`mktemp`
+	$BC $1 $tmp2 $tmp1
+	retval=$?
+	cat $tmp1 $tmp2 > $cout
+	rm $tmp1 $tmp2
+	[ $retval -eq 0 ] || rm $cout && return $retval
+	echo $cout
+	return $retval
+}
+
+# assemble in.{sb} [out.o]
+assemble() {
+	atmp=""
+	ain=$1
+	aout=$2;
+	if [ "${1##*.}" = "b" ]; then
+		[ "$aout" != "" ] || aout=${ain%b}o
+		ain=`mktemp --suffix=.s`
+		compile $1 $ain >/dev/null || return 1
+		atmp="foo"
+	elif [ "${1##*.}" = "s" ]; then
+		[ "$aout" != "" ] || aout=${ain%s}o
+	else
+		echo "Error: can only compile b and s files" >&2
+		exit 1
+	fi
+	as --32 -g $ain -o $aout
+	[ "$atmp" != "" ] && rm $ain
+	echo $aout
+}
+
+out=""
+action="link"
+while getopts "o:Sc" o
+do	case "$o" in
+	o)	out="$OPTARG";;
+	S)	action=compile;;
+	c)	action=assemble;;
+	esac
+done
+shift $(($OPTIND - 1))
+
+# ignore -o option if more than one file given and not linking objs
+if [ $# -gt 1 ]; then
+	if [ "$action" != "link" ]; then
+		out=""
+	fi
+fi
+
+[ $# -ne 1 ] && havelist=yes
+tmpobjs=""
+for i in $@; do
+	if [ "$action" != "link" ]; then
+		[ "$havelist" = "yes" ] && echo $i:
+		$action $i $out >/dev/null
+		[ $? -eq 0 ] || break=1
+	else
+		if [ "${i##*.}" = "o" ]; then
+			objs="$objs $i"
+		else
+			[ "$havelist" = "yes" ] && echo $i:
+			ltmp=`mktemp --suffix=.o`
+			tmpobjs="$tmpobjs $ltmp"
+			assemble $i $ltmp >/dev/null
+			[ $? -eq 0 ] || break=1
+		fi
+	fi
+done
+if [ $break ]; then
+	[ "$tmpobjs" = "" ] || rm $tmpobjs
+	echo "Error" >&2
+	exit 1
+fi
+if [ "$action" = "link" ]; then
+	if [ "$out" = "" ]; then
+		out="-o a.out"
+	else
+		out="-o $out"
+	fi
+	ld -m elf_i386 -T $BDIR/link.ld $out $objs $tmpobjs
+	rm $tmpobjs
+fi
diff --git a/lang/b/distr/brt.s b/lang/b/distr/brt.s
new file mode 100644
index 000000000..18f4fb351
--- /dev/null
+++ b/lang/b/distr/brt.s
@@ -0,0 +1,151 @@
+	.globl _argv
+	.data
+	.align 4
+	.comm	argstr,256,4
+_argv:	.long	0
+
+	.text
+	.globl start
+start:
+	# clear bss (could be done better)
+	# is it actually necessary?
+	mov	$__bss,%eax
+1:
+	movb	$0,(%eax)
+	inc	%eax
+	cmp	$__ebss,%eax
+	jbe	1b
+
+	# copy command line args (can't use them directly, not aligned)
+	mov	%esp,%eax
+	shr	$2,%eax
+	mov	%eax,_argv
+	mov	(%esp),%ecx	# number of arguments
+	mov	$argstr,%edi
+1:
+	mov	(%esp,%ecx,4),%esi
+	mov	%edi,%eax
+	shr	$2,%eax
+	mov	%eax,(%esp,%ecx,4)
+	call	cpystr
+	loop	1b
+
+	call	bsymbs
+	mov	_main,%eax
+	shl	$2,%eax
+	call	*%eax
+	mov	%eax,%ebx
+	mov	$1,%eax
+	int	$0x80
+
+# copy string from esi to edi and convert '\0' to B's '*e', align edi
+cpystr:
+	mov	(%esi),%al
+	test	%al,%al
+	jz	1f
+	mov	%al,(%edi)
+	inc	%edi
+	inc	%esi
+	jmp	cpystr
+1:
+	movb	$04,(%edi)
+	inc	%edi
+	add	$3,%edi
+	and	$~3,%edi
+	ret
+
+# shift addresses filled in by the linker 2 bits to the right
+# so B only ever sees word addresses
+bsymbs:
+	mov	$__bsymb,%eax
+1:
+	cmp	$__ebsymb,%eax
+	jge	1f
+	mov	(%eax),%ebx
+	mov	(%ebx),%ecx
+	shr	$2,%ecx
+	mov	%ecx,(%ebx)
+	add	$4,%eax
+	jmp	1b
+1:
+	ret
+
+	.globl retrn
+retrn:
+	mov	%ebp,%esp
+	pop	%ebp
+	ret
+
+# handle switch table:
+# eax has the value, ebx the address of the switch table
+	.globl bswitch
+bswitch:
+	xor	%ecx,%ecx
+1:
+	mov	(%ebx,%ecx,8),%edx
+	mov	4(%ebx,%ecx,8),%edi
+	test	%edi,%edi
+	jz	1f		# default (last in table)
+	cmp	%eax,%edx
+	je	2f
+	inc	%ecx
+	jmp	1b
+1:
+	jmp	*%edx
+2:
+	jmp	*%edi
+
+#
+# Library functions in assembly
+#
+	.globl _exit
+	.data
+	.align 4
+	.section .bsymb; .long _exit; .data
+_exit:	.long	1f
+	.text
+	.align 4
+1:	mov	$1,%eax
+	mov	$0,%ebx
+	int	$0x80
+
+	.globl _write
+	.data
+	.align 4
+	.section .bsymb; .long _write; .data
+_write:	.long	1f
+	.text
+	.align 4
+1:	mov	4(%esp),%ebx
+	mov	8(%esp),%ecx
+	shl	$2,%ecx
+	mov	12(%esp),%edx
+	mov	$4,%eax
+	int	$0x80
+	ret
+
+	.globl _read
+	.data
+	.align 4
+	.section .bsymb; .long _read; .data
+_read:	.long	1f
+	.text
+	.align 4
+1:	mov	4(%esp),%ebx
+	mov	8(%esp),%ecx
+	shl	$2,%ecx
+	mov	12(%esp),%edx
+	mov	$3,%eax
+	int	$0x80
+	ret
+
+	.globl	_inv
+	.data
+	.align 4
+	.section .bsymb; .long _inv; .data
+_inv:	.long	1f
+	.text
+	.align 4
+1:	mov	4(%esp),%eax
+	not	%eax
+	ret
diff --git a/lang/b/distr/examples/1_var.b b/lang/b/distr/examples/1_var.b
new file mode 100644
index 000000000..aa315442f
--- /dev/null
+++ b/lang/b/distr/examples/1_var.b
@@ -0,0 +1,7 @@
+main() {
+	auto a, b, c, sum;
+
+	a = 1; b = 2; c = 3;
+	sum = a+b+c;
+	putnumb(sum);
+}
diff --git a/lang/b/distr/examples/2_ext.b b/lang/b/distr/examples/2_ext.b
new file mode 100644
index 000000000..a8deac665
--- /dev/null
+++ b/lang/b/distr/examples/2_ext.b
@@ -0,0 +1,9 @@
+main() {
+	extrn a, b, c;
+	putchar(a); putchar(b); putchar(c); putchar('!*n');
+}
+
+a 'hell';
+b 'o, w';
+c 'orld';
+
diff --git a/lang/b/distr/examples/3_fun.b b/lang/b/distr/examples/3_fun.b
new file mode 100644
index 000000000..16d740964
--- /dev/null
+++ b/lang/b/distr/examples/3_fun.b
@@ -0,0 +1,13 @@
+main() {
+	extrn a, b, c, d;
+	put2char(a,b);
+	put2char(c,d);
+}
+
+put2char(x,y) {
+putchar(x);
+putchar(y);
+}
+
+a 'hell'; b 'o, w'; c 'orld'; d '!*n';
+
diff --git a/lang/b/distr/examples/4_goto.b b/lang/b/distr/examples/4_goto.b
new file mode 100644
index 000000000..2d5256afc
--- /dev/null
+++ b/lang/b/distr/examples/4_goto.b
@@ -0,0 +1,7 @@
+main() {
+	auto c;
+read:
+	c= getchar();
+	putchar(c);
+	if(c != '*n')	goto read;
+}
diff --git a/lang/b/distr/examples/5_while.b b/lang/b/distr/examples/5_while.b
new file mode 100644
index 000000000..13baa0cac
--- /dev/null
+++ b/lang/b/distr/examples/5_while.b
@@ -0,0 +1,10 @@
+main() {
+	auto c;
+	while (1) {
+		while ( (c=getchar()) != ' ')
+			if (putchar(c) == '*n') exit();
+		putchar( '*n' );
+		while ( (c=getchar()) == ' ');	/* skip blanks */
+		if (putchar(c)=='*n') exit();
+		}
+}
diff --git a/lang/b/distr/examples/printargs.b b/lang/b/distr/examples/printargs.b
new file mode 100644
index 000000000..444932054
--- /dev/null
+++ b/lang/b/distr/examples/printargs.b
@@ -0,0 +1,10 @@
+main() {
+	extrn argv;
+	auto i;
+
+	i = 1;
+	printf("%d args:*n", argv[0]);
+	while (i <= argv[0])
+		printf("%s*n", argv[i++]);
+	return(0);
+}
diff --git a/lang/b/distr/lib.b b/lang/b/distr/lib.b
new file mode 100644
index 000000000..9e274eb92
--- /dev/null
+++ b/lang/b/distr/lib.b
@@ -0,0 +1,111 @@
+char(s, n)
+	return((s[n/4]>>8*(n%4))&0377); /* s[n/4] */
+
+lchar(s, n, char) {
+	auto i;
+	i = 8*(n%4);
+	char = (char&0377)<<i;
+	i = inv(0377<<i);
+	s[(n/4)*4] = s[n/4]&i | char;
+}
+
+putchar(char) {
+	auto c, i;
+
+	c = char;
+	i = 4;
+	while ((c&0377) != '*e' & (c&0377) != '*0' & i != 0) {
+		i--;
+		c =>> 8;
+	}
+	write(1, &char, 4-i);
+	return(char);
+}
+
+getchar() {
+	auto char;
+
+	char = 0;
+	read(1, &char, 1);
+	return(char);
+}
+
+printn(n,b) {
+	extrn putchar;
+	auto a;
+
+	if (a = n/b)
+		printn(a, b);
+	putchar(char("0123456789ABCDEF", n%b));
+}
+
+putnumb(n) {
+	printn(n,10);
+	putchar('*n');
+}
+
+putstr(s) {
+	auto c, i;
+
+	i = 0;
+	while ((c = char(s,i++)) != '*e')
+		putchar(c);
+}
+
+getstr(s) {
+	auto c, i;
+
+	while ((c = getchar()) != '*n')
+		lchar(s,i++,c);
+	lchar(s,i,'*e');
+	return(s);
+}
+
+printf(fmt, x1,x2,x3,x4,x5,x6,x7,x8,x9) {
+	extrn printn, char, putchar;
+	auto adx, x, c, i, j;
+
+	i = 0;
+	adx = &x1;
+loop:
+	while((c=char(fmt,i++)) != '%') {
+		if(c == '*e')
+			return;
+		putchar(c);
+	}
+	x = *adx++;
+	switch (c = char(fmt,i++)) {
+
+	case 'd':
+	case 'o':
+		if(x < 0) {
+			x = -x;
+			putchar('-');
+		}
+		printn(x, c=='o'?8:10);
+		goto loop;
+
+	case 'x':
+		if(x < 0) {
+			x = -x;
+			putchar('-');
+		}
+		printn(x, 16);
+		goto loop;
+
+	case 'c':
+		putchar(x);
+		goto loop;
+
+	case 's':
+		j = 0;
+		while((c=char(x,j++)) != '*e')
+			putchar(c);
+		goto loop;
+	}
+	putchar('%');
+	i--;
+	adx--;
+	goto loop;
+}
+
diff --git a/lang/b/distr/link.ld b/lang/b/distr/link.ld
new file mode 100644
index 000000000..fd0fb71ce
--- /dev/null
+++ b/lang/b/distr/link.ld
@@ -0,0 +1,21 @@
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH(i386)
+
+ENTRY(start)
+
+SECTIONS
+{
+	. = 0x400000;
+	.text : { *(.text) }
+	. = 0x8000000;
+	.data : {
+		*(.data)
+		__bsymb = .;
+		*(.bsymb)
+		__ebsymb = .;
+	}
+	. = ALIGN(16);
+	__bss = .;
+	.bss : { *(.bss) }
+	__ebss = .;
+}
diff --git a/lang/b/lib/b.h b/lang/b/lib/b.h
new file mode 100644
index 000000000..1125452cd
--- /dev/null
+++ b/lang/b/lib/b.h
@@ -0,0 +1,28 @@
+#ifndef B_H
+#define B_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#if EM_PSIZE == 2
+#define SHIFT 1
+#elif EM_PSIZE == 4
+#define SHIFT 2
+#elif EM_PSIZE == 8
+#define SHIFT 3
+#else
+#error Unsupported EM_PSIZE
+#endif
+
+extern FILE* input_unit;
+extern FILE* output_unit;
+
+#define END 4
+
+extern uintptr_t* bmodule_main[];
+
+extern void patch_addresses(uintptr_t** p);
+
+extern void binit(void);
+
+#endif
diff --git a/lang/b/lib/build.lua b/lang/b/lib/build.lua
new file mode 100644
index 000000000..62ae88966
--- /dev/null
+++ b/lang/b/lib/build.lua
@@ -0,0 +1,27 @@
+include("plat/build.lua")
+
+for _, plat in ipairs(vars.plats) do
+    acklibrary {
+        name = "lib_"..plat,
+        srcs = {
+			"./*.c",
+			"./*.e",
+        },
+		hdrs = {}, -- must be empty
+		deps = {
+			"./*.h",
+			"h+emheaders",
+			"lang/cem/libcc.ansi/headers+pkg",
+			"plat/"..plat.."/include+pkg",
+		},
+        vars = { plat = plat }
+    }
+
+	installable {
+		name = "pkg_"..plat,
+		map = {
+			["$(PLATIND)/"..plat.."/libb.a"] = "+lib_"..plat,
+		}
+	}
+end
+
diff --git a/lang/b/lib/init.c b/lang/b/lib/init.c
new file mode 100644
index 000000000..b7ad01f08
--- /dev/null
+++ b/lang/b/lib/init.c
@@ -0,0 +1,10 @@
+#include "b.h"
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+
+void binit(void)
+{
+    patch_addresses(bmodule_main);
+}
+
diff --git a/lang/b/lib/main.c b/lang/b/lib/main.c
new file mode 100644
index 000000000..b583a4309
--- /dev/null
+++ b/lang/b/lib/main.c
@@ -0,0 +1,186 @@
+#include "b.h"
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+
+extern intptr_t i_main(intptr_t argc, const char* argv[]);
+
+FILE* input_unit;
+FILE* output_unit;
+
+static intptr_t i_char(intptr_t s, intptr_t n)
+{
+    const char* p = (const char*)(s<<SHIFT);
+    return p[n];
+}
+
+static void i_lchar(intptr_t s, intptr_t n, intptr_t c)
+{
+    char* p = (char*)(s<<SHIFT);
+    p[n] = c;
+}
+
+static intptr_t i_getchar(void)
+{
+    return fgetc(input_unit);
+}
+
+static intptr_t i_putchar(intptr_t c)
+{
+    fputc(c, output_unit);
+    return c;
+}
+
+static intptr_t i_putstr(intptr_t s)
+{
+	char* p = (char*)(s<<SHIFT);
+	char c;
+
+	while ((c = *p++) != END)
+		fputc(c, output_unit);
+
+	return s;
+}
+
+static intptr_t i_getstr(intptr_t s)
+{
+	char* p = (char*)(s<<SHIFT);
+
+	for (;;)
+	{
+		int c = fgetc(input_unit);
+		if ((c == -1) || (c == '\n'))
+			break;
+		*p++ = c;
+	}
+
+	*p++ = END;
+	return s;
+}
+	
+static void i_flush(void)
+{
+	fflush(output_unit);
+}
+
+static int tochar(int n)
+{
+	if (n <= 9)
+		return n + '0';
+	return n - 10 + 'a';
+}
+
+static void putnum(intptr_t value, int base)
+{
+	int i;
+	char s[32];
+
+	if (value < 0)
+	{
+		fputc('-', output_unit);
+		value = -value;
+	}
+
+	i = 0;
+	do
+		s[i++] = tochar(value % base);
+	while ((value /= base) > 0);
+
+	do
+		fputc(s[--i], output_unit);
+	while (i > 0);
+}
+
+static void i_printf(intptr_t s, ...)
+{
+	char* p = (char*)(s<<SHIFT);
+	char c;
+
+	va_list ap;
+	va_start(ap, s);
+
+	while ((c = *p++) != END)
+	{
+		switch (c)
+		{
+			case '%':
+			{
+				intptr_t ss = va_arg(ap, intptr_t);
+
+				switch ((c = *p++))
+				{
+					case 's':
+						i_putstr(ss);
+						break;
+
+					case 'd':
+						putnum(ss, 10);
+						break;
+
+					case 'o':
+						putnum(ss, 8);
+						break;
+
+					case 'x':
+						putnum(ss, 16);
+						break;
+
+					case 'c':
+						fputc(ss, output_unit);
+						break;
+
+					default:
+						fputc('?', output_unit);
+						break;
+				}
+				break;
+			}
+				
+			default:
+				fputc(c, output_unit);
+				break;
+		}
+	}
+
+	va_end(ap);
+}
+
+uintptr_t b_char = (uintptr_t)i_char;
+uintptr_t b_lchar = (uintptr_t)i_lchar;
+uintptr_t b_getchar = (uintptr_t)i_getchar;
+uintptr_t b_putchar = (uintptr_t)i_putchar;
+uintptr_t b_putstr = (uintptr_t)i_putstr;
+uintptr_t b_getstr = (uintptr_t)i_getstr;
+uintptr_t b_flush = (uintptr_t)i_flush;
+uintptr_t b_printf = (uintptr_t)i_printf;
+
+static uintptr_t* bmodule_stdlib[] =
+{
+    &b_char,
+    &b_lchar,
+    &b_getchar,
+    &b_putchar,
+	&b_putstr,
+	&b_getstr,
+	&b_flush,
+	&b_printf,
+    0
+};
+
+void patch_addresses(uintptr_t** p)
+{
+    while (*p)
+    {
+        uintptr_t* q = *p++;
+        *q >>= SHIFT;
+    }
+}
+
+int main(int argc, const char* argv[])
+{
+    patch_addresses(bmodule_stdlib);
+	binit();
+    input_unit = stdin;
+    output_unit = stdout;
+    return i_main(argc, NULL);
+}
diff --git a/lang/basic/lib/build.lua b/lang/basic/lib/build.lua
index 71710a542..cff3b57ca 100644
--- a/lang/basic/lib/build.lua
+++ b/lang/basic/lib/build.lua
@@ -10,8 +10,8 @@ for _, plat in ipairs(vars.plats) do
 		hdrs = {}, -- must be empty
 		deps = {
 			"h+emheaders",
-			"lang/cem/libcc.ansi/headers+headers",
-			"plat/"..plat.."/include+headers",
+			"lang/cem/libcc.ansi/headers+pkg",
+			"plat/"..plat.."/include+pkg",
 		},
         vars = { plat = plat }
     }
diff --git a/lang/basic/src/basic.lex b/lang/basic/src/basic.lex
index 4eb9e1659..3ee185e3f 100644
--- a/lang/basic/src/basic.lex
+++ b/lang/basic/src/basic.lex
@@ -522,7 +522,7 @@ scanstring()
 		yylval.integer= genemlabel();
 		C_rom_dlb((label)i,(arith)0);
 		C_rom_icon("9999",(arith)BEMINTSIZE);
-		C_rom_icon(itoa(length),(arith)BEMINTSIZE);
+		C_rom_icon(myitoa(length),(arith)BEMINTSIZE);
 	}
 #ifdef YYDEBUG
 	if (yydebug) print("STRVALUE found\n");
diff --git a/lang/basic/src/bem.h b/lang/basic/src/bem.h
index eb1435802..a92cff0b8 100644
--- a/lang/basic/src/bem.h
+++ b/lang/basic/src/bem.h
@@ -72,5 +72,5 @@ extern int 	dataused;
 extern Linerecord *currline;
 
 
-extern char *itoa();
+extern char *myitoa();
 extern char *salloc();
diff --git a/lang/basic/src/gencode.c b/lang/basic/src/gencode.c
index 8fb611dc0..710de169d 100644
--- a/lang/basic/src/gencode.c
+++ b/lang/basic/src/gencode.c
@@ -670,7 +670,7 @@ gendata()
 	C_df_dnam("datfdes");
 	C_rom_dnam("datfname",(arith)0);
 	C_rom_cst((arith)1);
-	C_rom_cst((arith)(itoa(strlen(datfname))));
+	C_rom_cst((arith)(myitoa(strlen(datfname))));
 	C_df_dnam("dattdes");
 	C_rom_dnam("dattyp",(arith)0);
 	C_rom_cst((arith)1);
diff --git a/lang/basic/src/util.c b/lang/basic/src/util.c
index ff98cf82b..a85339bc5 100644
--- a/lang/basic/src/util.c
+++ b/lang/basic/src/util.c
@@ -69,7 +69,7 @@ illegalcmd()
 
 
 
-char *itoa(i)
+char *myitoa(i)
 int i;
 {
 	static char buf[30];
diff --git a/lang/basic/test/bull.b b/lang/basic/test/bull.bas
similarity index 100%
rename from lang/basic/test/bull.b
rename to lang/basic/test/bull.bas
diff --git a/lang/basic/test/buzzword.b b/lang/basic/test/buzzword.bas
similarity index 100%
rename from lang/basic/test/buzzword.b
rename to lang/basic/test/buzzword.bas
diff --git a/lang/basic/test/checker.b b/lang/basic/test/checker.bas
similarity index 100%
rename from lang/basic/test/checker.b
rename to lang/basic/test/checker.bas
diff --git a/lang/basic/test/creator.b b/lang/basic/test/creator.bas
similarity index 100%
rename from lang/basic/test/creator.b
rename to lang/basic/test/creator.bas
diff --git a/lang/basic/test/grafiek.b b/lang/basic/test/grafiek.bas
similarity index 100%
rename from lang/basic/test/grafiek.b
rename to lang/basic/test/grafiek.bas
diff --git a/lang/basic/test/gunner.b b/lang/basic/test/gunner.bas
similarity index 100%
rename from lang/basic/test/gunner.b
rename to lang/basic/test/gunner.bas
diff --git a/lang/basic/test/learn.b b/lang/basic/test/learn.bas
similarity index 100%
rename from lang/basic/test/learn.b
rename to lang/basic/test/learn.bas
diff --git a/lang/basic/test/opg1.b b/lang/basic/test/opg1.bas
similarity index 100%
rename from lang/basic/test/opg1.b
rename to lang/basic/test/opg1.bas
diff --git a/lang/basic/test/opg2.b b/lang/basic/test/opg2.bas
similarity index 100%
rename from lang/basic/test/opg2.b
rename to lang/basic/test/opg2.bas
diff --git a/lang/basic/test/opg3.b b/lang/basic/test/opg3.bas
similarity index 100%
rename from lang/basic/test/opg3.b
rename to lang/basic/test/opg3.bas
diff --git a/lang/basic/test/opg4.b b/lang/basic/test/opg4.bas
similarity index 100%
rename from lang/basic/test/opg4.b
rename to lang/basic/test/opg4.bas
diff --git a/lang/basic/test/opg5.b b/lang/basic/test/opg5.bas
similarity index 100%
rename from lang/basic/test/opg5.b
rename to lang/basic/test/opg5.bas
diff --git a/lang/basic/test/opg6.b b/lang/basic/test/opg6.bas
similarity index 100%
rename from lang/basic/test/opg6.b
rename to lang/basic/test/opg6.bas
diff --git a/lang/basic/test/som4.b b/lang/basic/test/som4.bas
similarity index 100%
rename from lang/basic/test/som4.b
rename to lang/basic/test/som4.bas
diff --git a/lang/basic/test/test01.b b/lang/basic/test/test01.bas
similarity index 100%
rename from lang/basic/test/test01.b
rename to lang/basic/test/test01.bas
diff --git a/lang/basic/test/test02.b b/lang/basic/test/test02.bas
similarity index 100%
rename from lang/basic/test/test02.b
rename to lang/basic/test/test02.bas
diff --git a/lang/basic/test/test03.b b/lang/basic/test/test03.bas
similarity index 100%
rename from lang/basic/test/test03.b
rename to lang/basic/test/test03.bas
diff --git a/lang/basic/test/test04.b b/lang/basic/test/test04.bas
similarity index 100%
rename from lang/basic/test/test04.b
rename to lang/basic/test/test04.bas
diff --git a/lang/basic/test/test05.b b/lang/basic/test/test05.bas
similarity index 100%
rename from lang/basic/test/test05.b
rename to lang/basic/test/test05.bas
diff --git a/lang/basic/test/test06.b b/lang/basic/test/test06.bas
similarity index 100%
rename from lang/basic/test/test06.b
rename to lang/basic/test/test06.bas
diff --git a/lang/basic/test/test07.b b/lang/basic/test/test07.bas
similarity index 100%
rename from lang/basic/test/test07.b
rename to lang/basic/test/test07.bas
diff --git a/lang/basic/test/test08.b b/lang/basic/test/test08.bas
similarity index 100%
rename from lang/basic/test/test08.b
rename to lang/basic/test/test08.bas
diff --git a/lang/basic/test/test09.b b/lang/basic/test/test09.bas
similarity index 100%
rename from lang/basic/test/test09.b
rename to lang/basic/test/test09.bas
diff --git a/lang/basic/test/test10.b b/lang/basic/test/test10.bas
similarity index 100%
rename from lang/basic/test/test10.b
rename to lang/basic/test/test10.bas
diff --git a/lang/basic/test/test11.b b/lang/basic/test/test11.bas
similarity index 100%
rename from lang/basic/test/test11.b
rename to lang/basic/test/test11.bas
diff --git a/lang/basic/test/test12.b b/lang/basic/test/test12.bas
similarity index 100%
rename from lang/basic/test/test12.b
rename to lang/basic/test/test12.bas
diff --git a/lang/basic/test/test13.b b/lang/basic/test/test13.bas
similarity index 100%
rename from lang/basic/test/test13.b
rename to lang/basic/test/test13.bas
diff --git a/lang/basic/test/test14.b b/lang/basic/test/test14.bas
similarity index 100%
rename from lang/basic/test/test14.b
rename to lang/basic/test/test14.bas
diff --git a/lang/basic/test/test15.b b/lang/basic/test/test15.bas
similarity index 100%
rename from lang/basic/test/test15.b
rename to lang/basic/test/test15.bas
diff --git a/lang/basic/test/test16.b b/lang/basic/test/test16.bas
similarity index 100%
rename from lang/basic/test/test16.b
rename to lang/basic/test/test16.bas
diff --git a/lang/basic/test/test17.b b/lang/basic/test/test17.bas
similarity index 100%
rename from lang/basic/test/test17.b
rename to lang/basic/test/test17.bas
diff --git a/lang/basic/test/test18.b b/lang/basic/test/test18.bas
similarity index 100%
rename from lang/basic/test/test18.b
rename to lang/basic/test/test18.bas
diff --git a/lang/basic/test/test19.b b/lang/basic/test/test19.bas
similarity index 100%
rename from lang/basic/test/test19.b
rename to lang/basic/test/test19.bas
diff --git a/lang/basic/test/test20.b b/lang/basic/test/test20.bas
similarity index 100%
rename from lang/basic/test/test20.b
rename to lang/basic/test/test20.bas
diff --git a/lang/basic/test/test21.b b/lang/basic/test/test21.bas
similarity index 100%
rename from lang/basic/test/test21.b
rename to lang/basic/test/test21.bas
diff --git a/lang/basic/test/test22.b b/lang/basic/test/test22.bas
similarity index 100%
rename from lang/basic/test/test22.b
rename to lang/basic/test/test22.bas
diff --git a/lang/basic/test/test23.b b/lang/basic/test/test23.bas
similarity index 100%
rename from lang/basic/test/test23.b
rename to lang/basic/test/test23.bas
diff --git a/lang/basic/test/test24.b b/lang/basic/test/test24.bas
similarity index 100%
rename from lang/basic/test/test24.b
rename to lang/basic/test/test24.bas
diff --git a/lang/basic/test/test25.b b/lang/basic/test/test25.bas
similarity index 100%
rename from lang/basic/test/test25.b
rename to lang/basic/test/test25.bas
diff --git a/lang/basic/test/test26.b b/lang/basic/test/test26.bas
similarity index 100%
rename from lang/basic/test/test26.b
rename to lang/basic/test/test26.bas
diff --git a/lang/basic/test/test27.b b/lang/basic/test/test27.bas
similarity index 100%
rename from lang/basic/test/test27.b
rename to lang/basic/test/test27.bas
diff --git a/lang/basic/test/test28.b b/lang/basic/test/test28.bas
similarity index 100%
rename from lang/basic/test/test28.b
rename to lang/basic/test/test28.bas
diff --git a/lang/basic/test/test29.b b/lang/basic/test/test29.bas
similarity index 100%
rename from lang/basic/test/test29.b
rename to lang/basic/test/test29.bas
diff --git a/lang/basic/test/test30.b b/lang/basic/test/test30.bas
similarity index 100%
rename from lang/basic/test/test30.b
rename to lang/basic/test/test30.bas
diff --git a/lang/basic/test/test31.b b/lang/basic/test/test31.bas
similarity index 100%
rename from lang/basic/test/test31.b
rename to lang/basic/test/test31.bas
diff --git a/lang/basic/test/test32.b b/lang/basic/test/test32.bas
similarity index 100%
rename from lang/basic/test/test32.b
rename to lang/basic/test/test32.bas
diff --git a/lang/basic/test/test33.b b/lang/basic/test/test33.bas
similarity index 100%
rename from lang/basic/test/test33.b
rename to lang/basic/test/test33.bas
diff --git a/lang/basic/test/test34.b b/lang/basic/test/test34.bas
similarity index 100%
rename from lang/basic/test/test34.b
rename to lang/basic/test/test34.bas
diff --git a/lang/basic/test/test35.b b/lang/basic/test/test35.bas
similarity index 100%
rename from lang/basic/test/test35.b
rename to lang/basic/test/test35.bas
diff --git a/lang/cem/libcc.ansi/build.lua b/lang/cem/libcc.ansi/build.lua
index 601a50de4..20591f803 100644
--- a/lang/cem/libcc.ansi/build.lua
+++ b/lang/cem/libcc.ansi/build.lua
@@ -51,8 +51,8 @@ for _, plat in ipairs(vars.plats) do
 		},
 		hdrs = {}, -- must be empty
 		deps = {
-			"lang/cem/libcc.ansi/headers+headers",
-			"plat/"..plat.."/include+headers",
+			"lang/cem/libcc.ansi/headers+pkg",
+			"plat/"..plat.."/include+pkg",
 			"./malloc/malloc.h",
 			"./math/localmath.h",
 			"./stdio/loc_incl.h",
diff --git a/lang/m2/comp/build.lua b/lang/m2/comp/build.lua
index 95c4a30d7..4e12d24f7 100644
--- a/lang/m2/comp/build.lua
+++ b/lang/m2/comp/build.lua
@@ -113,6 +113,7 @@ cprogram {
 		"h+emheaders",
 		"modules+headers",
 		"modules/src/alloc+lib",
+		"modules/src/data+lib",
 		"modules/src/em_code+lib_k",
 		"modules/src/em_data+lib",
 		"modules/src/em_mes+lib",
diff --git a/lang/m2/comp/defmodule.c b/lang/m2/comp/defmodule.c
index f26168a28..0ecb1dd2a 100644
--- a/lang/m2/comp/defmodule.c
+++ b/lang/m2/comp/defmodule.c
@@ -9,48 +9,50 @@
 
 /* $Id$ */
 
+#include "debug.h"
 #include "parameters.h"
-#include	"debug.h"
 
+#include <alloc.h>
+#include <assert.h>
+#include <em_arith.h>
+#include <em_label.h>
 #include <stdlib.h>
-#include	<assert.h>
-#include	<em_arith.h>
-#include	<em_label.h>
-#include	<alloc.h>
+#include <astring.h>
 
-#include	"idf.h"
-#include	"input.h"
-#include	"scope.h"
-#include	"LLlex.h"
-#include	"def.h"
-#include	"Lpars.h"
-#include	"f_info.h"
-#include	"main.h"
-#include	"node.h"
-#include	"type.h"
-#include	"misc.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "def.h"
+#include "f_info.h"
+#include "idf.h"
+#include "input.h"
+#include "main.h"
+#include "misc.h"
+#include "node.h"
+#include "scope.h"
+#include "type.h"
 
 #ifdef DEBUG
-long	sys_filesize();
+long sys_filesize();
 #endif
 
-t_idf *DefId;
+t_idf* DefId;
 
-char *
-getwdir(fn)
-	register char *fn;
+char*
+    getwdir(fn) register char* fn;
 {
-	register char *p;
-	char *strrchr();
+	register char* p;
+	char* strrchr();
 
-	while ((p = strrchr(fn,'/')) && *(p + 1) == '\0') {
+	while ((p = strrchr(fn, '/')) && *(p + 1) == '\0')
+	{
 		/* remove trailing /'s */
 		*p = '\0';
 	}
 
-	if (p) {
+	if (p)
+	{
 		*p = '\0';
-		fn = Salloc(fn, (unsigned) (p - &fn[0] + 1));
+		fn = Salloc(fn, (unsigned)(p - &fn[0] + 1));
 		*p = '/';
 		return fn;
 	}
@@ -58,20 +60,15 @@ getwdir(fn)
 }
 
 STATIC
-GetFile(name)
-	char *name;
+GetFile(name) char* name;
 {
 	/*	Try to find a file with basename "name" and extension ".def",
 		in the directories mentioned in "DEFPATH".
 	*/
-	char buf[15];
-	char *strncpy(), *strcat();
-
-	strncpy(buf, name, 10);
-	buf[10] = '\0';			/* maximum length */
-	strcat(buf, ".def");
+	char* buf = aprintf("%s.def", name);
 	DEFPATH[0] = WorkingDir;
-	if (! InsertFile(buf, DEFPATH, &(FileName))) {
+	if (!InsertFile(buf, DEFPATH, &(FileName)))
+	{
 		error("could not find a DEFINITION MODULE for \"%s\"", name);
 		return 0;
 	}
@@ -81,25 +78,25 @@ GetFile(name)
 	return 1;
 }
 
-t_def *
-GetDefinitionModule(id, incr)
-	register t_idf *id;
+t_def*
+    GetDefinitionModule(id, incr) register t_idf* id;
 {
 	/*	Return a pointer to the "def" structure of the definition
 		module indicated by "id".
 		We may have to read the definition module itself.
 		Also increment level by "incr".
 	*/
-	register t_def *df;
+	register t_def* df;
 	static int level;
-	t_scopelist *vis;
-	char *fn = FileName;
+	t_scopelist* vis;
+	char* fn = FileName;
 	int ln = LineNumber;
-	t_scope *newsc;
+	t_scope* newsc;
 
 	level += incr;
 	df = lookup(id, GlobalScope, D_IMPORTED, 0);
-	if (!df) {
+	if (!df)
+	{
 		/* Read definition module. Make an exception for SYSTEM.
 		*/
 		extern int ForeignFlag;
@@ -110,53 +107,62 @@ GetDefinitionModule(id, incr)
 		newsc = CurrentScope;
 		vis = CurrVis;
 		newsc->sc_defmodule = incr;
-		if (!strcmp(id->id_text, "SYSTEM")) {
+		if (!strcmp(id->id_text, "SYSTEM"))
+		{
 			do_SYSTEM();
 			df = lookup(id, GlobalScope, D_IMPORTED, 0);
 		}
-		else {
-			if (!is_anon_idf(id) && GetFile(id->id_text)) {
+		else
+		{
+			if (!is_anon_idf(id) && GetFile(id->id_text))
+			{
 
-				char *f = FileName;
+				char* f = FileName;
 				DefModule();
 				df = lookup(id, GlobalScope, D_IMPORTED, 0);
-				if (level == 1 &&
-				    (df && !(df->df_flags & D_FOREIGN))) {
+				if (level == 1 && (df && !(df->df_flags & D_FOREIGN)))
+				{
 					/* The module is directly imported by
 					   the currently defined module, and
 					   is not foreign, so we have to
 					   remember its name because we have 
 					   to call its initialization routine
 					*/
-					static t_node *nd_end;
-					register t_node *n;
-					extern t_node *Modules;
+					static t_node* nd_end;
+					register t_node* n;
+					extern t_node* Modules;
 
 					n = dot2leaf(Def);
 					n->nd_def = newsc->sc_definedby;
-					if (nd_end) nd_end->nd_NEXT = n;
-					else Modules = n;
+					if (nd_end)
+						nd_end->nd_NEXT = n;
+					else
+						Modules = n;
 					nd_end = n;
 				}
 				free(f);
 			}
-			else {
+			else
+			{
 				df = lookup(id, GlobalScope, D_IMPORTED, 0);
 				newsc->sc_name = id->id_text;
 			}
 		}
 		close_scope(SC_CHKFORW);
-		if (! df) {
+		if (!df)
+		{
 			df = MkDef(id, GlobalScope, D_ERROR);
 			df->mod_vis = vis;
 			newsc->sc_definedby = df;
 		}
 	}
-	else if (df->df_flags & D_BUSY) {
+	else if (df->df_flags & D_BUSY)
+	{
 		error("definition module \"%s\" depends on itself",
-			id->id_text);
+		    id->id_text);
 	}
-	else if (df == Defined && level == 1) {
+	else if (df == Defined && level == 1)
+	{
 		error("cannot import from current module \"%s\"", id->id_text);
 		df->df_kind = D_ERROR;
 	}
diff --git a/lang/m2/comp/em_m2.6 b/lang/m2/comp/em_m2.6
index a122a4a30..dfe41a3df 100644
--- a/lang/m2/comp/em_m2.6
+++ b/lang/m2/comp/em_m2.6
@@ -1,10 +1,10 @@
-.TH EM_M2 6 "$Revision$"
+.TH EM_M2 6 2017-01-18
 .ad
 .SH NAME
 em_m2 \- ACK Modula\-2 compiler
 .SH SYNOPSIS
 .B ~em/lib.bin/em_m2
-.RI [ option ] 
+.RI [ option ]
 .I source
 .I destination
 .SH DESCRIPTION
@@ -15,9 +15,9 @@ into EM code.
 The input is taken from
 .IR source ,
 while the
-EM code is written on 
+EM code is written on
 .IR destination .
-.br
+.PP
 .I Option
 is a, possibly empty, sequence of the following combinations:
 .IP \fB\-I\fIdirname\fR
@@ -65,7 +65,8 @@ make all procedure names global, so that \fIadb\fR(1) understands them.
 .IP \fB\-g\fR
 produce a DBX-style symbol table.
 .IP \fB\-l\fR
-enable local extensions. Currently, there are two local extensions:
+enable local extensions.
+Currently, there are two local extensions:
 procedure constants, and the type LONGCARD.
 .IP \fB\-s\fR
 make INTEGER ranges symmetric, t.i., MIN(INTEGER) = - MAX(INTEGER).
@@ -77,11 +78,11 @@ disable all range checks.
 enable extra array bound checks, for machines that do not implement the
 EM ones.
 .IP \fB-U\fR
-allow for underscores within identifiers. Identifiers may not start with
+allow for underscores within identifiers.
+Identifiers may not start with
 an underscore, even if this flag is given.
 .IP \fB-3\fR
 only accept Modula-2 programs that strictly conform to [1].
-.LP
 .SH SEE ALSO
 \fIack\fR(1), \fImodula-2\fR(1)
 .IP [1]
diff --git a/lang/m2/comp/modula-2.1 b/lang/m2/comp/modula-2.1
index 206d33bb7..ee9bc94bd 100644
--- a/lang/m2/comp/modula-2.1
+++ b/lang/m2/comp/modula-2.1
@@ -19,11 +19,6 @@ Implementation modules and program modules must reside in files having a
 .PP
 The name of the file in which a definition module is stored must be the same as
 the module-name, apart from the extension.
-Also, in most Unix systems filenames are only 14 characters long.
-So, given an IMPORT declaration for a module called "LongModulName",
-the compiler will try to open a file called "LongModulN.def".
-The requirement does not hold for implementation or program modules,
-but is certainly recommended.
 .SH CALLING THE COMPILER
 The easiest way to do this is to let the \fIack\fR(1) program do it.
 So, to compile a program module "prog.mod", just call
diff --git a/lang/m2/comp/walk.c b/lang/m2/comp/walk.c
index 93cc3308b..b36dbc8f0 100644
--- a/lang/m2/comp/walk.c
+++ b/lang/m2/comp/walk.c
@@ -13,71 +13,72 @@
 	code for these parts.
 */
 
-#include   <stdlib.h>
-#include   <string.h>
+#include <stdlib.h>
+#include <string.h>
 #include "parameters.h"
-#include	"debug.h"
+#include "debug.h"
 
-#include	<em_arith.h>
-#include	<em_label.h>
-#include	<em_reg.h>
-#include	<em_code.h>
-#include	<m2_traps.h>
-#include	<assert.h>
-#include	<alloc.h>
-#include	<stb.h>
+#include <em_arith.h>
+#include <em_label.h>
+#include <em_reg.h>
+#include <em_code.h>
+#include <m2_traps.h>
+#include <assert.h>
+#include <alloc.h>
+#include <stb.h>
 
-#include	"LLlex.h"
-#include	"def.h"
-#include	"type.h"
-#include	"scope.h"
-#include	"main.h"
-#include	"node.h"
-#include	"Lpars.h"
-#include	"desig.h"
-#include	"f_info.h"
-#include	"idf.h"
-#include	"chk_expr.h"
-#include	"walk.h"
-#include	"misc.h"
-#include	"warning.h"
+#include "LLlex.h"
+#include "def.h"
+#include "type.h"
+#include "scope.h"
+#include "main.h"
+#include "node.h"
+#include "Lpars.h"
+#include "desig.h"
+#include "f_info.h"
+#include "idf.h"
+#include "chk_expr.h"
+#include "walk.h"
+#include "misc.h"
+#include "warning.h"
 
-extern arith		NewPtr();
-extern arith		NewInt();
-extern arith		TmpSpace();
+extern arith NewPtr();
+extern arith NewInt();
+extern arith TmpSpace();
 
-extern int		proclevel;
-extern int		gdb_flag;
+extern int proclevel;
+extern int gdb_flag;
 
-label			text_label;
-label			data_label = 1;
-struct withdesig	*WithDesigs;
-t_node			*Modules;
+label text_label;
+label data_label = 1;
+struct withdesig* WithDesigs;
+t_node* Modules;
 
-static t_type		*func_type;
-static t_node		*priority;
-static int		oldlineno;
+static t_type* func_type;
+static t_node* priority;
+static int oldlineno;
 
-static int		RegisterMessage();
-static int		WalkDef();
+static int RegisterMessage();
+static int WalkDef();
 #ifdef DBSYMTAB
-static int		stabdef();
+static int stabdef();
 #endif
-static int		MkCalls();
-static void	UseWarnings();
+static int MkCalls();
+static void UseWarnings();
 
-#define	NO_EXIT_LABEL	((label) 0)
-#define RETURN_LABEL	((label) 1)
+#define NO_EXIT_LABEL ((label)0)
+#define RETURN_LABEL ((label)1)
 
-#define REACH_FLAG	1
-#define EXIT_FLAG	2
+#define REACH_FLAG 1
+#define EXIT_FLAG 2
 
 void DoAssign();
 
 int
-LblWalkNode(lbl, nd, exit, reach)
-	label lbl, exit;
-	t_node *nd;
+    LblWalkNode(lbl, nd, exit, reach)
+        label lbl,
+    exit;
+t_node* nd;
 {
 	/*	Generate code for node "nd", after generating instruction
 		label "lbl". "exit" is the exit label for the closest
@@ -96,10 +97,11 @@ DoPriority()
 	/*	For the time being (???), handle priorities by calls to
 		the runtime system
 	*/
-	if (priority) {
+	if (priority)
+	{
 		tmpprio = NewInt();
 		C_loc(priority->nd_INT);
-		CAL("stackprio", (int) word_size);
+		CAL("stackprio", (int)word_size);
 		C_lfr(word_size);
 		C_stl(tmpprio);
 	}
@@ -108,15 +110,16 @@ DoPriority()
 STATIC
 EndPriority()
 {
-	if (priority) {
+	if (priority)
+	{
 		C_lol(tmpprio);
-		CAL("unstackprio", (int) word_size);
+		CAL("unstackprio", (int)word_size);
 		FreeInt(tmpprio);
 	}
 }
 
 def_ilb(l)
-	label l;
+    label l;
 {
 	/*	Instruction label definition. Forget about line number.
 	*/
@@ -124,27 +127,29 @@ def_ilb(l)
 	oldlineno = 0;
 }
 
-DoLineno(nd)
-	register t_node *nd;
+DoLineno(nd) register t_node* nd;
 {
 	/*	Generate line number information, if necessary.
 	*/
-	if ((! options['L']
+	if ((!options['L']
 #ifdef DBSYMTAB
-	     || options['g']
+	        || options['g']
 #endif /* DBSYMTAB */
-	    ) &&
-	    nd->nd_lineno &&
-	    nd->nd_lineno != oldlineno) {
+	        )
+	    && nd->nd_lineno && nd->nd_lineno != oldlineno)
+	{
 		oldlineno = nd->nd_lineno;
-		if (! options['L']) C_lin((arith) nd->nd_lineno);
+		if (!options['L'])
+			C_lin((arith)nd->nd_lineno);
 #ifdef DBSYMTAB
-		if ( options['g']) {
-			static int	ms_lineno;
+		if (options['g'])
+		{
+			static int ms_lineno;
 
-			if (ms_lineno != nd->nd_lineno) {
+			if (ms_lineno != nd->nd_lineno)
+			{
 				ms_lineno = nd->nd_lineno;
-				C_ms_std((char *) 0, N_SLINE, ms_lineno);
+				C_ms_std((char*)0, N_SLINE, ms_lineno);
 			}
 		}
 #endif /* DBSYMTAB */
@@ -158,30 +163,31 @@ DoFilename(needed)
 		procedure entry, and after generating a call to
 		another procedure.
 	*/
-	static label	filename_label = 0;
+	static label filename_label = 0;
 
-	oldlineno = 0;	/* always invalidate remembered line number */
-	if (needed && ! options['L']) {
+	oldlineno = 0; /* always invalidate remembered line number */
+	if (needed && !options['L'])
+	{
 
-		if (! filename_label) {
+		if (!filename_label)
+		{
 			filename_label = 1;
-			C_df_dlb((label) 1);
-			C_rom_scon(FileName, (arith) (strlen(FileName) + 1));
+			C_df_dlb((label)1);
+			C_rom_scon(FileName, (arith)(strlen(FileName) + 1));
 		}
 
-		C_fil_dlb((label) 1, (arith) 0);
+		C_fil_dlb((label)1, (arith)0);
 	}
 }
 
-WalkModule(module)
-	register t_def *module;
+WalkModule(module) register t_def* module;
 {
 	/*	Walk through a module, and all its local definitions.
 		Also generate code for its body.
 		This code is collected in an initialization routine.
 	*/
-	register t_scope *sc;
-	t_scopelist *savevis = CurrVis;
+	register t_scope* sc;
+	t_scopelist* savevis = CurrVis;
 
 	CurrVis = module->mod_vis;
 	priority = module->mod_priority;
@@ -195,52 +201,58 @@ WalkModule(module)
 	   First call initialization routines for modules defined within
 	   this module.
 	*/
-	sc->sc_off = 0;		/* no locals (yet) */
-	text_label = 1;		/* label at end of initialization routine */
-	TmpOpen(sc);		/* Initialize for temporaries */
+	sc->sc_off = 0; /* no locals (yet) */
+	text_label = 1; /* label at end of initialization routine */
+	TmpOpen(sc); /* Initialize for temporaries */
 	C_pro_narg(sc->sc_name);
 #ifdef DBSYMTAB
-	if (options['g']) {
+	if (options['g'])
+	{
 		stb_string(module, D_MODULE);
 		WalkDefList(sc->sc_def, stabdef);
-		if (state == PROGRAM && module == Defined) {
+		if (state == PROGRAM && module == Defined)
+		{
 			C_ms_stb_cst(module->df_idf->id_text,
-				     N_MAIN,
-				     0,
-				     (arith) 0);
+			    N_MAIN,
+			    0,
+			    (arith)0);
 		}
 		stb_string(module, D_END);
 	}
 #endif
 	DoPriority();
-	if (module == Defined) {
+	if (module == Defined)
+	{
 		/* Body of implementation or program module.
 		   Call initialization routines of imported modules.
 		   Also prevent recursive calls of this one.
 		*/
-		register t_node *nd = Modules;
+		register t_node* nd = Modules;
 
-		if (state == IMPLEMENTATION) {
+		if (state == IMPLEMENTATION)
+		{
 			/* We don't actually prevent recursive calls,
 			   but do nothing if called recursively
 			*/
 			C_df_dlb(++data_label);
-			C_con_cst((arith) 0);
+			C_con_cst((arith)0);
 			/* if this one is set to non-zero, the initialization
 			   was already done.
 			*/
-			C_loe_dlb(data_label, (arith) 0);
+			C_loe_dlb(data_label, (arith)0);
 			C_zne(RETURN_LABEL);
-			C_ine_dlb(data_label, (arith) 0);
+			C_ine_dlb(data_label, (arith)0);
 		}
-		else if (! options['R']) {
+		else if (!options['R'])
+		{
 			/* put funny value in BSS, in an attempt to detect
 			   uninitialized variables
 			*/
 			C_cal("killbss");
 		}
 
-		for (; nd; nd = nd->nd_NEXT) {
+		for (; nd; nd = nd->nd_NEXT)
+		{
 			C_cal(nd->nd_def->mod_vis->sc_scope->sc_name);
 		}
 		DoFilename(1);
@@ -248,18 +260,20 @@ WalkModule(module)
 	WalkDefList(sc->sc_def, MkCalls);
 	proclevel++;
 #ifdef DBSYMTAB
-	if (options['g']) {
-		C_ms_std((char *) 0, N_LBRAC, gdb_flag ? 0 : proclevel);
+	if (options['g'])
+	{
+		C_ms_std((char*)0, N_LBRAC, gdb_flag ? 0 : proclevel);
 	}
 #endif /* DBSYMTAB */
 	WalkNode(module->mod_body, NO_EXIT_LABEL, REACH_FLAG);
 	DO_DEBUG(options['X'], PrNode(module->mod_body, 0));
 	def_ilb(RETURN_LABEL);
 	EndPriority();
-	C_ret((arith) 0);
+	C_ret((arith)0);
 #ifdef DBSYMTAB
-	if (options['g']) {
-		C_ms_std((char *) 0, N_RBRAC, gdb_flag ? 0 : proclevel);
+	if (options['g'])
+	{
+		C_ms_std((char*)0, N_RBRAC, gdb_flag ? 0 : proclevel);
 	}
 #endif /* DBSYMTAB */
 	C_end(-sc->sc_off);
@@ -270,19 +284,18 @@ WalkModule(module)
 	WalkDefList(sc->sc_def, UseWarnings);
 }
 
-WalkProcedure(procedure)
-	register t_def *procedure;
+WalkProcedure(procedure) register t_def* procedure;
 {
 	/*	Walk through the definition of a procedure and all its
 		local definitions, checking and generating code.
 	*/
-	t_scopelist *savevis = CurrVis;
-	register t_type *tp;
-	register t_param *param;
-	register t_scope *procscope = procedure->prc_vis->sc_scope;
-	label too_big = 0;		/* returnsize larger than returnarea */
-	arith StackAdjustment = 0;	/* space for conformant arrays */
-	arith retsav = 0;		/* temporary space for return value */
+	t_scopelist* savevis = CurrVis;
+	register t_type* tp;
+	register t_param* param;
+	register t_scope* procscope = procedure->prc_vis->sc_scope;
+	label too_big = 0; /* returnsize larger than returnarea */
+	arith StackAdjustment = 0; /* space for conformant arrays */
+	arith retsav = 0; /* temporary space for return value */
 	arith func_res_size = 0;
 #ifdef USE_INSERT
 	int partno = C_getid();
@@ -301,9 +314,11 @@ WalkProcedure(procedure)
 
 	func_type = tp = RemoveEqual(ResultType(procedure->df_type));
 
-	if (tp) {
+	if (tp)
+	{
 		func_res_size = WA(tp->tp_size);
-		if (TooBigForReturnArea(tp)) {
+		if (TooBigForReturnArea(tp))
+		{
 #ifdef BIG_RESULT_ON_STACK
 			/* The result type of this procedure is too big.
 			   The caller will have reserved space on its stack,
@@ -330,22 +345,23 @@ WalkProcedure(procedure)
 	*/
 	TmpOpen(procscope);
 #ifdef USE_INSERT
-	C_insertpart(partno2);	/* procedure header */
+	C_insertpart(partno2); /* procedure header */
 #else
 	C_pro_narg(procedure->prc_name);
 #ifdef DBSYMTAB
-	if (options['g']) {
+	if (options['g'])
+	{
 		stb_string(procedure, D_PROCEDURE);
 		WalkDefList(procscope->sc_def, stabdef);
 		stb_string(procedure, D_PEND);
-		C_ms_std((char *) 0, N_LBRAC, gdb_flag ? 0 : proclevel);
+		C_ms_std((char*)0, N_LBRAC, gdb_flag ? 0 : proclevel);
 	}
 #endif /* DBSYMTAB */
 	C_ms_par(procedure->df_type->prc_nbpar
 #ifdef BIG_RESULT_ON_STACK
-		+ (too_big ? func_res_size : 0)
+	    + (too_big ? func_res_size : 0)
 #endif
-		);
+	        );
 #endif
 	/* generate code for filename only when the procedure can be
 	   exported, either directly or by taking the address.
@@ -355,27 +371,31 @@ WalkProcedure(procedure)
 	DoFilename(procscope->sc_level == 1);
 	DoPriority();
 
-	text_label = 1;		/* label at end of procedure */
+	text_label = 1; /* label at end of procedure */
 
 	/* Check if we must save the stack pointer */
 	for (param = ParamList(procedure->df_type);
 	     param;
-	     param = param->par_next) {
-		if (! IsVarParam(param)) {
+	     param = param->par_next)
+	{
+		if (!IsVarParam(param))
+		{
 			tp = TypeOfParam(param);
 
-			if ( IsConformantArray(tp)) {
+			if (IsConformantArray(tp))
+			{
 				/* First time we get here
 				*/
-				if (func_type && !too_big) {
+				if (func_type && !too_big)
+				{
 					/* Some local space, only
 					   needed if the value itself
 					   is returned
 					*/
-					retsav= TmpSpace(func_res_size, 1);
+					retsav = TmpSpace(func_res_size, 1);
 				}
 				StackAdjustment = NewPtr();
-				C_lor((arith) 1);
+				C_lor((arith)1);
 				STL(StackAdjustment, pointer_size);
 			}
 		}
@@ -390,12 +410,14 @@ WalkProcedure(procedure)
 	def_ilb(cd_body);
 #endif
 
-	if ((WalkNode(procedure->prc_body, NO_EXIT_LABEL, REACH_FLAG) & REACH_FLAG)) {
-		if (func_res_size) {
+	if ((WalkNode(procedure->prc_body, NO_EXIT_LABEL, REACH_FLAG) & REACH_FLAG))
+	{
+		if (func_res_size)
+		{
 			node_warning(procscope->sc_end,
-				     W_ORDINARY,
-				     "function procedure \"%s\" does not always return a value",
-				     procedure->df_idf->id_text);
+			    W_ORDINARY,
+			    "function procedure \"%s\" does not always return a value",
+			    procedure->df_idf->id_text);
 			c_loc(M2_NORESULT);
 			C_trp();
 			C_asp(-func_res_size);
@@ -422,13 +444,16 @@ WalkProcedure(procedure)
 	*/
 	for (param = ParamList(procedure->df_type);
 	     param;
-	     param = param->par_next) {
-		if (! IsVarParam(param)) {
+	     param = param->par_next)
+	{
+		if (!IsVarParam(param))
+		{
 			tp = TypeOfParam(param);
 
-			if (! IsConformantArray(tp)) {
-				if (tp->tp_size < word_size &&
-				    (int) word_size % (int) tp->tp_size == 0) {
+			if (!IsConformantArray(tp))
+			{
+				if (tp->tp_size < word_size && (int)word_size % (int)tp->tp_size == 0)
+				{
 					C_lol(param->par_def->var_off);
 					STL(param->par_def->var_off,
 					    tp->tp_size);
@@ -450,11 +475,11 @@ WalkProcedure(procedure)
 			CAL("new_stackptr", (int)pointer_size);
 			C_lfr(pointer_size);
 			C_ass(pointer_size);
-					/* adjusted stack pointer */
+			/* adjusted stack pointer */
 			LOL(param->par_def->var_off, pointer_size);
-					/* push source address */
+			/* push source address */
 			CAL("copy_array", (int)pointer_size);
-					/* copy */
+			/* copy */
 		}
 	}
 #ifdef USE_INSERT
@@ -463,9 +488,10 @@ WalkProcedure(procedure)
 	c_bra(cd_body);
 #endif
 	DO_DEBUG(options['X'], PrNode(procedure->prc_body, 0));
-	def_ilb(RETURN_LABEL);	/* label at end */
-	if (too_big) {
-		/* Fill the data area reserved for the function result
+	def_ilb(RETURN_LABEL); /* label at end */
+	if (too_big)
+	{
+/* Fill the data area reserved for the function result
 		   with the result
 		*/
 #ifdef BIG_RESULT_ON_STACK
@@ -474,11 +500,12 @@ WalkProcedure(procedure)
 		c_lae_dlb(too_big);
 #endif /* BIG_RESULT_ON_STACK */
 		C_sti(func_res_size);
-		if (StackAdjustment) {
+		if (StackAdjustment)
+		{
 			/* Remove copies of conformant arrays
 			*/
 			LOL(StackAdjustment, pointer_size);
-			C_str((arith) 1);
+			C_str((arith)1);
 		}
 #ifdef BIG_RESULT_ON_STACK
 		func_res_size = 0;
@@ -487,17 +514,20 @@ WalkProcedure(procedure)
 		func_res_size = pointer_size;
 #endif /* BIG_RESULT_ON_STACK */
 	}
-	else if (StackAdjustment) {
+	else if (StackAdjustment)
+	{
 		/* First save the function result in a safe place.
 		   Then remove copies of conformant arrays,
 		   and put function result back on the stack
 		*/
-		if (func_type) {
+		if (func_type)
+		{
 			STL(retsav, func_res_size);
 		}
 		LOL(StackAdjustment, pointer_size);
-		C_str((arith) 1);
-		if (func_type) {
+		C_str((arith)1);
+		if (func_type)
+		{
 			LOL(retsav, func_res_size);
 		}
 	}
@@ -507,32 +537,36 @@ WalkProcedure(procedure)
 	C_beginpart(partno2);
 	C_pro(procedure->prc_name, -procscope->sc_off);
 #ifdef DBSYMTAB
-	if (options['g']) {
+	if (options['g'])
+	{
 		stb_string(procedure, D_PROCEDURE);
 		WalkDefList(procscope->sc_def, stabdef);
 		stb_string(procedure, D_PEND);
-		C_ms_std((char *) 0, N_LBRAC, gdb_flag ? 0 : proclevel);
+		C_ms_std((char*)0, N_LBRAC, gdb_flag ? 0 : proclevel);
 	}
 #endif /* DBSYMTAB */
 	C_ms_par(procedure->df_type->prc_nbpar
 #ifdef BIG_RESULT_ON_STACK
-		+ (too_big ? func_res_size : 0)
+	    + (too_big ? func_res_size : 0)
 #endif
-		);
+	        );
 #endif
-	if (! options['n']) WalkDefList(procscope->sc_def, RegisterMessage);
+	if (!options['n'])
+		WalkDefList(procscope->sc_def, RegisterMessage);
 #ifdef USE_INSERT
 	C_endpart(partno2);
 #endif
 #ifdef DBSYMTAB
-	if (options['g']) {
-		C_ms_std((char *) 0, N_RBRAC, gdb_flag ? 0 : proclevel);
+	if (options['g'])
+	{
+		C_ms_std((char*)0, N_RBRAC, gdb_flag ? 0 : proclevel);
 	}
 #endif /* DBSYMTAB */
 	C_end(-procscope->sc_off);
-	if (! fit(procscope->sc_off, (int) word_size)) {
+	if (!fit(procscope->sc_off, (int)word_size))
+	{
 		node_error(procedure->prc_body,
-			   "maximum local byte count exceeded");
+		    "maximum local byte count exceeded");
 	}
 	TmpClose();
 	CurrVis = savevis;
@@ -540,50 +574,48 @@ WalkProcedure(procedure)
 	WalkDefList(procscope->sc_def, UseWarnings);
 }
 
-static
-WalkDef(df)
-	register t_def *df;
+static WalkDef(df) register t_def* df;
 {
 	/*	Walk through a list of definitions
 	*/
 
-	switch(df->df_kind) {
-	case D_MODULE:
-		WalkModule(df);
-		break;
-	case D_PROCEDURE:
-		WalkProcedure(df);
-		break;
-	case D_VARIABLE:
-		if (!proclevel  && !(df->df_flags & D_ADDRGIVEN)) {
-			C_df_dnam(df->var_name);
-			C_bss_cst(
-				WA(df->df_type->tp_size),
-				(arith) 0, 0);
-		}
-		break;
-	default:
-		/* nothing */
-		;
+	switch (df->df_kind)
+	{
+		case D_MODULE:
+			WalkModule(df);
+			break;
+		case D_PROCEDURE:
+			WalkProcedure(df);
+			break;
+		case D_VARIABLE:
+			if (!proclevel && !(df->df_flags & D_ADDRGIVEN))
+			{
+				C_df_dnam(df->var_name);
+				C_bss_cst(
+				    WA(df->df_type->tp_size),
+				    (arith)0, 0);
+			}
+			break;
+		default:
+		    /* nothing */
+		    ;
 	}
 }
 
-static
-MkCalls(df)
-	register t_def *df;
+static MkCalls(df) register t_def* df;
 {
 	/*	Generate calls to initialization routines of modules
 	*/
 
-	if (df->df_kind == D_MODULE) {
-		C_lxl((arith) 0);
+	if (df->df_kind == D_MODULE)
+	{
+		C_lxl((arith)0);
 		CAL(df->mod_vis->sc_scope->sc_name, (int)pointer_size);
 	}
 }
 
-WalkLink(nd, exit_label, end_reached)
-	register t_node *nd;
-	label exit_label;
+WalkLink(nd, exit_label, end_reached) register t_node* nd;
+label exit_label;
 {
 	/*	Walk node "nd", which is a link.
 		"exit_label" is set to a label number when inside a LOOP.
@@ -591,7 +623,8 @@ WalkLink(nd, exit_label, end_reached)
 		and whether an EXIT statement was seen (EXIT_FLAG).
 	*/
 
-	while (nd && nd->nd_class == Link) {	 /* statement list */
+	while (nd && nd->nd_class == Link)
+	{ /* statement list */
 		end_reached = WalkNode(nd->nd_LEFT, exit_label, end_reached);
 		nd = nd->nd_RIGHT;
 	}
@@ -600,85 +633,94 @@ WalkLink(nd, exit_label, end_reached)
 }
 
 STATIC
-ForLoopVarExpr(nd)
-	register t_node *nd;
+ForLoopVarExpr(nd) register t_node* nd;
 {
-	register t_type *tp = nd->nd_type;
+	register t_type* tp = nd->nd_type;
 
 	CodePExpr(nd);
 	CodeCoercion(tp, BaseType(tp));
 }
 
 int
-WalkStat(nd, exit_label, end_reached)
-	register t_node *nd;
-	label exit_label;
+    WalkStat(nd, exit_label, end_reached) register t_node* nd;
+label exit_label;
 {
 	/*	Walk through a statement, generating code for it.
 	*/
-	register t_node *left = nd->nd_LEFT;
-	register t_node *right = nd->nd_RIGHT;
+	register t_node* left = nd->nd_LEFT;
+	register t_node* right = nd->nd_RIGHT;
 
 	assert(nd->nd_class == Stat);
 
-	if (nd->nd_symb == ';') return 1;
+	if (nd->nd_symb == ';')
+		return 1;
 
-	if (! end_reached & REACH_FLAG) {
+	if (!end_reached & REACH_FLAG)
+	{
 		node_warning(nd, W_ORDINARY, "statement not reached");
 	}
-	if (nd->nd_symb != WHILE ||
-	    nd->nd_lineno != left->nd_lineno) {
+	if (nd->nd_symb != WHILE || nd->nd_lineno != left->nd_lineno)
+	{
 		/* Avoid double linenumber generation in while statements */
 		DoLineno(nd);
 	}
 	options['R'] = (nd->nd_flags & ROPTION);
 	options['A'] = (nd->nd_flags & AOPTION);
-	switch(nd->nd_symb) {
-	case '(': {
-		t_node *nd1 = nd;
-		if (ChkCall(&nd1)) {
-			assert(nd == nd1);
-			if (nd->nd_type != 0) {
-				node_error(nd, "procedure call expected instead of function call");
-				break;
+	switch (nd->nd_symb)
+	{
+		case '(':
+		{
+			t_node* nd1 = nd;
+			if (ChkCall(&nd1))
+			{
+				assert(nd == nd1);
+				if (nd->nd_type != 0)
+				{
+					node_error(nd, "only proper procedures can be called from top-level "
+						"statement; this is a function procedure");
+					break;
+				}
+				CodeCall(nd);
 			}
-			CodeCall(nd);
-		}
 		}
 		break;
 
-	case BECOMES:
-		DoAssign(nd);
-		break;
+		case BECOMES:
+			DoAssign(nd);
+			break;
 
-	case IF:
-		{	label l1 = ++text_label, l3 = ++text_label;
+		case IF:
+		{
+			label l1 = ++text_label, l3 = ++text_label;
 			int end_r;
 
 			ExpectBool(&(nd->nd_LEFT), l3, l1);
 			assert(right->nd_symb == THEN);
 			end_r = LblWalkNode(l3, right->nd_LEFT, exit_label, end_reached);
 
-			if (right->nd_RIGHT) {	/* ELSE part */
+			if (right->nd_RIGHT)
+			{ /* ELSE part */
 				label l2 = ++text_label;
 
 				c_bra(l2);
 				end_reached = end_r | LblWalkNode(l1, right->nd_RIGHT, exit_label, end_reached);
 				l1 = l2;
 			}
-			else	end_reached |= end_r;
+			else
+				end_reached |= end_r;
 			def_ilb(l1);
 			break;
 		}
 
-	case CASE:
-		end_reached = CaseCode(nd, exit_label, end_reached);
-		break;
+		case CASE:
+			end_reached = CaseCode(nd, exit_label, end_reached);
+			break;
 
-	case WHILE:
-		{	label	loop = ++text_label,
-				exit = ++text_label,
-				dummy = ++text_label;
+		case WHILE:
+		{
+			label loop = ++text_label,
+			      exit = ++text_label,
+			      dummy = ++text_label;
 
 			c_bra(dummy);
 			end_reached |= LblWalkNode(loop, right, exit_label, end_reached);
@@ -688,8 +730,9 @@ WalkStat(nd, exit_label, end_reached)
 			break;
 		}
 
-	case REPEAT:
-		{	label loop = ++text_label, exit = ++text_label;
+		case REPEAT:
+		{
+			label loop = ++text_label, exit = ++text_label;
 
 			end_reached = LblWalkNode(loop, left, exit_label, end_reached);
 			ExpectBool(&(nd->nd_RIGHT), exit, loop);
@@ -697,19 +740,22 @@ WalkStat(nd, exit_label, end_reached)
 			break;
 		}
 
-	case LOOP:
-		{	label loop = ++text_label, exit = ++text_label;
+		case LOOP:
+		{
+			label loop = ++text_label, exit = ++text_label;
 
-			if (LblWalkNode(loop, right, exit, end_reached) & EXIT_FLAG) {
+			if (LblWalkNode(loop, right, exit, end_reached) & EXIT_FLAG)
+			{
 				end_reached &= REACH_FLAG;
 			}
-			else	end_reached = 0;
+			else
+				end_reached = 0;
 			c_bra(loop);
 			def_ilb(exit);
 			break;
 		}
 
-	case FOR:
+		case FOR:
 		{
 			arith tmp = NewInt();
 			arith tmp2 = NewInt();
@@ -718,17 +764,19 @@ WalkStat(nd, exit_label, end_reached)
 			label l2 = ++text_label;
 			int uns = 0;
 			arith stepsize;
-			t_type *bstp;
-			t_node *loopid;
+			t_type* bstp;
+			t_node* loopid;
 
 			good_forvar = DoForInit(left);
 			loopid = left->nd_LEFT;
-			if ((stepsize = right->nd_LEFT->nd_INT) == 0) {
+			if ((stepsize = right->nd_LEFT->nd_INT) == 0)
+			{
 				node_warning(right->nd_LEFT,
-					     W_ORDINARY,
-					     "zero stepsize in FOR loop");
+				    W_ORDINARY,
+				    "zero stepsize in FOR loop");
 			}
-			if (good_forvar) {
+			if (good_forvar)
+			{
 				bstp = BaseType(loopid->nd_type);
 				uns = bstp->tp_fund != T_INTEGER;
 				CodePExpr(left->nd_RIGHT->nd_RIGHT);
@@ -737,37 +785,46 @@ WalkStat(nd, exit_label, end_reached)
 				C_dup(int_size);
 				C_stl(tmp2);
 				C_lol(tmp);
-				if (uns) C_cmu(int_size);
-				else C_cmi(int_size);
-				if (stepsize >= 0) C_zgt(l2);
-				else C_zlt(l2);
+				if (uns)
+					C_cmu(int_size);
+				else
+					C_cmi(int_size);
+				if (stepsize >= 0)
+					C_zgt(l2);
+				else
+					C_zlt(l2);
 				C_lol(tmp2);
 				RangeCheck(loopid->nd_type,
-					   left->nd_RIGHT->nd_LEFT->nd_type);
+				    left->nd_RIGHT->nd_LEFT->nd_type);
 				CodeDStore(loopid);
-				if (stepsize >= 0) {
+				if (stepsize >= 0)
+				{
 					C_lol(tmp);
 					ForLoopVarExpr(loopid);
 				}
-				else {
+				else
+				{
 					stepsize = -stepsize;
 					ForLoopVarExpr(loopid);
 					C_lol(tmp);
 				}
 				C_sbu(int_size);
-				if (stepsize) {
+				if (stepsize)
+				{
 					C_loc(stepsize);
 					C_dvu(int_size);
 				}
 				C_stl(tmp);
 				loopid->nd_def->df_flags |= D_FORLOOP;
 				def_ilb(l1);
-				if (! options['R']) {
+				if (!options['R'])
+				{
 					ForLoopVarExpr(loopid);
 					C_stl(tmp2);
 				}
 				end_reached |= WalkNode(right->nd_RIGHT, exit_label, end_reached);
-				if (! options['R']) {
+				if (!options['R'])
+				{
 					label x = ++text_label;
 					C_lol(tmp2);
 					ForLoopVarExpr(loopid);
@@ -778,7 +835,8 @@ WalkStat(nd, exit_label, end_reached)
 				}
 				loopid->nd_def->df_flags &= ~D_FORLOOP;
 				FreeInt(tmp2);
-				if (stepsize) {
+				if (stepsize)
+				{
 					C_lol(tmp);
 					C_zeq(l2);
 					C_lol(tmp);
@@ -792,7 +850,8 @@ WalkStat(nd, exit_label, end_reached)
 					CodeDStore(loopid);
 				}
 			}
-			else {
+			else
+			{
 				end_reached |= WalkNode(right->nd_RIGHT, exit_label, end_reached);
 				loopid->nd_def->df_flags &= ~D_FORLOOP;
 			}
@@ -802,15 +861,17 @@ WalkStat(nd, exit_label, end_reached)
 		}
 		break;
 
-	case WITH:
+		case WITH:
 		{
 			t_scopelist link;
 			struct withdesig wds;
 			t_desig ds;
 
-			if (! WalkDesignator(&(nd->nd_LEFT), &ds, D_USED)) break;
+			if (!WalkDesignator(&(nd->nd_LEFT), &ds, D_USED))
+				break;
 			left = nd->nd_LEFT;
-			if (left->nd_type->tp_fund != T_RECORD) {
+			if (left->nd_type->tp_fund != T_RECORD)
+			{
 				node_error(left, "record variable expected");
 				break;
 			}
@@ -836,44 +897,50 @@ WalkStat(nd, exit_label, end_reached)
 			CurrVis = link.sc_next;
 			WithDesigs = wds.w_next;
 			FreePtr(ds.dsg_offset);
-			ChkDesig(&(nd->nd_LEFT), wds.w_flags & (D_USED|D_DEFINED));
+			ChkDesig(&(nd->nd_LEFT), wds.w_flags & (D_USED | D_DEFINED));
 			break;
 		}
 
-	case EXIT:
-		assert(exit_label != 0);
+		case EXIT:
+			assert(exit_label != 0);
 
-		if (end_reached & REACH_FLAG) end_reached = EXIT_FLAG;
-		c_bra(exit_label);
-		break;
+			if (end_reached & REACH_FLAG)
+				end_reached = EXIT_FLAG;
+			c_bra(exit_label);
+			break;
 
-	case RETURN:
-		end_reached &= ~REACH_FLAG;
-		if (right) {
-			if (! ChkExpression(&(nd->nd_RIGHT))) break;
-			/* The type of the return-expression must be
+		case RETURN:
+			end_reached &= ~REACH_FLAG;
+			if (right)
+			{
+				if (!ChkExpression(&(nd->nd_RIGHT)))
+					break;
+				/* The type of the return-expression must be
 			   assignment compatible with the result type of the
 			   function procedure (See Rep. 9.11).
 			*/
-			if (!ChkAssCompat(&(nd->nd_RIGHT), func_type, "RETURN")) {
-				break;
+				if (!ChkAssCompat(&(nd->nd_RIGHT), func_type, "RETURN"))
+				{
+					break;
+				}
+				right = nd->nd_RIGHT;
+				if (right->nd_type->tp_fund == T_STRING)
+				{
+					CodePString(right, func_type);
+				}
+				else
+					CodePExpr(right);
 			}
-			right = nd->nd_RIGHT;
-			if (right->nd_type->tp_fund == T_STRING) {
-				CodePString(right, func_type);
-			}
-			else	CodePExpr(right);
-		}
-		c_bra(RETURN_LABEL);
-		break;
+			c_bra(RETURN_LABEL);
+			break;
 
-	default:
-		crash("(WalkStat)");
+		default:
+			crash("(WalkStat)");
 	}
 	return end_reached;
 }
 
-extern int	NodeCrash();
+extern int NodeCrash();
 
 int (*WalkTable[])() = {
 	NodeCrash,
@@ -893,9 +960,8 @@ int (*WalkTable[])() = {
 
 extern t_desig null_desig;
 
-ExpectBool(pnd, true_label, false_label)
-	register t_node **pnd;
-	label true_label, false_label;
+ExpectBool(pnd, true_label, false_label) register t_node** pnd;
+label true_label, false_label;
 {
 	/*	"pnd" must indicate a boolean expression. Check this and
 		generate code to evaluate the expression.
@@ -903,25 +969,27 @@ ExpectBool(pnd, true_label, false_label)
 	t_desig ds;
 
 	ds = null_desig;
-	if (ChkExpression(pnd)) {
-		if ((*pnd)->nd_type != bool_type &&
-		    (*pnd)->nd_type != error_type) {
+	if (ChkExpression(pnd))
+	{
+		if ((*pnd)->nd_type != bool_type && (*pnd)->nd_type != error_type)
+		{
 			node_error(*pnd, "boolean expression expected");
 		}
 
-		CodeExpr(*pnd, &ds,  true_label, false_label);
+		CodeExpr(*pnd, &ds, true_label, false_label);
 	}
 }
 
 int
-WalkDesignator(pnd, ds, flags)
-	t_node **pnd;
-	t_desig *ds;
+    WalkDesignator(pnd, ds, flags)
+        t_node** pnd;
+t_desig* ds;
 {
 	/*	Check designator and generate code for it
 	*/
 
-	if (! ChkVariable(pnd, flags)) return 0;
+	if (!ChkVariable(pnd, flags))
+		return 0;
 
 	*ds = null_desig;
 	CodeDesig(*pnd, ds);
@@ -929,47 +997,54 @@ WalkDesignator(pnd, ds, flags)
 }
 
 DoForInit(nd)
-	t_node *nd;
+    t_node* nd;
 {
-	register t_node *right = nd->nd_RIGHT;
-	register t_def *df;
-	t_type *base_tp;
+	register t_node* right = nd->nd_RIGHT;
+	register t_def* df;
+	t_type* base_tp;
 	t_type *tpl, *tpr;
 	int r;
 
-	r = ChkVariable(&(nd->nd_LEFT), D_USED|D_DEFINED);
+	r = ChkVariable(&(nd->nd_LEFT), D_USED | D_DEFINED);
 	r &= ChkExpression(&(right->nd_LEFT));
 	r &= ChkExpression(&(right->nd_RIGHT));
-	if (!r) return 0;
+	if (!r)
+		return 0;
 
 	df = nd->nd_LEFT->nd_def;
-	if (df->df_kind == D_FIELD) {
+	if (df->df_kind == D_FIELD)
+	{
 		node_error(nd,
-			   "FOR-loop variable may not be a field of a record");
+		    "FOR-loop variable may not be a field of a record");
 		return 1;
 	}
 
-	if (!df->var_name && df->var_off >= 0) {
+	if (!df->var_name && df->var_off >= 0)
+	{
 		node_error(nd, "FOR-loop variable may not be a parameter");
 		return 1;
 	}
 
-	if (df->df_scope != CurrentScope) {
-		register t_scopelist *sc = CurrVis;
+	if (df->df_scope != CurrentScope)
+	{
+		register t_scopelist* sc = CurrVis;
 
-		for (;;) {
-			if (!sc) {
+		for (;;)
+		{
+			if (!sc)
+			{
 				node_error(nd,
-				      "FOR-loop variable may not be imported");
+				    "FOR-loop variable may not be imported");
 				return 1;
 			}
-			if (sc->sc_scope == df->df_scope) break;
+			if (sc->sc_scope == df->df_scope)
+				break;
 			sc = nextvisible(sc);
 		}
 	}
 
-	if (df->df_type->tp_size > word_size ||
-	    !(df->df_type->tp_fund & T_DISCRETE)) {
+	if (df->df_type->tp_size > word_size || !(df->df_type->tp_fund & T_DISCRETE))
+	{
 		node_error(nd, "illegal type of FOR loop variable");
 		return 1;
 	}
@@ -978,19 +1053,21 @@ DoForInit(nd)
 	tpl = right->nd_LEFT->nd_type;
 	tpr = right->nd_RIGHT->nd_type;
 #ifndef STRICT_3RD_ED
-	if (! options['3']) {
-	  if (!ChkAssCompat(&(right->nd_LEFT), base_tp, "FOR statement") ||
-	      !ChkAssCompat(&(right->nd_RIGHT), base_tp, "FOR statement")) {
-		return 1;
-	  }
-	  if (!TstCompat(df->df_type, tpl) ||
-	      !TstCompat(df->df_type, tpr)) {
-node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement");
-	  }
-	} else
+	if (!options['3'])
+	{
+		if (!ChkAssCompat(&(right->nd_LEFT), base_tp, "FOR statement") || !ChkAssCompat(&(right->nd_RIGHT), base_tp, "FOR statement"))
+		{
+			return 1;
+		}
+		if (!TstCompat(df->df_type, tpl) || !TstCompat(df->df_type, tpr))
+		{
+			node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement");
+		}
+	}
+	else
 #endif
-	if (!ChkCompat(&(right->nd_LEFT), base_tp, "FOR statement") ||
-	    !ChkCompat(&(right->nd_RIGHT), base_tp, "FOR statement")) {
+	    if (!ChkCompat(&(right->nd_LEFT), base_tp, "FOR statement") || !ChkCompat(&(right->nd_RIGHT), base_tp, "FOR statement"))
+	{
 		return 1;
 	}
 
@@ -998,8 +1075,7 @@ node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement");
 }
 
 void
-DoAssign(nd)
-	register t_node *nd;
+    DoAssign(nd) register t_node* nd;
 {
 	/* May we do it in this order (expression first) ???
 	   The reference manual sais nothing about it, but the book does:
@@ -1007,148 +1083,151 @@ DoAssign(nd)
 	   DAMN THE BOOK!
 	*/
 	t_desig dsr;
-	register t_type *tp;
+	register t_type* tp;
 
-	if (! (ChkExpression(&(nd->nd_RIGHT)) &
-	       ChkVariable(&(nd->nd_LEFT), D_DEFINED))) return;
+	if (!(ChkExpression(&(nd->nd_RIGHT)) & ChkVariable(&(nd->nd_LEFT), D_DEFINED)))
+		return;
 	tp = nd->nd_LEFT->nd_type;
 
-	if (! ChkAssCompat(&(nd->nd_RIGHT), tp, "assignment")) {
+	if (!ChkAssCompat(&(nd->nd_RIGHT), tp, "assignment"))
+	{
 		return;
 	}
 	dsr = null_desig;
 
-#define StackNeededFor(ds)	((ds).dsg_kind == DSG_PLOADED \
-				  || (ds).dsg_kind == DSG_INDEXED)
+#define StackNeededFor(ds) ((ds).dsg_kind == DSG_PLOADED \
+    || (ds).dsg_kind == DSG_INDEXED)
 	CodeExpr(nd->nd_RIGHT, &dsr, NO_LABEL, NO_LABEL);
 	tp = nd->nd_RIGHT->nd_type;
-	if (complex(tp)) {
-		if (StackNeededFor(dsr)) CodeAddress(&dsr);
+	if (complex(tp))
+	{
+		if (StackNeededFor(dsr))
+			CodeAddress(&dsr);
 	}
-	else {
+	else
+	{
 		CodeValue(&dsr, tp);
 	}
 	CodeMove(&dsr, nd->nd_LEFT, tp);
 }
 
-static
-RegisterMessage(df)
-	register t_def *df;
+static RegisterMessage(df) register t_def* df;
 {
-	register t_type *tp;
+	register t_type* tp;
 
-	if (df->df_kind == D_VARIABLE) {
-		if ( !(df->df_flags & D_NOREG)) {
+	if (df->df_kind == D_VARIABLE)
+	{
+		if (!(df->df_flags & D_NOREG))
+		{
 			/* Examine type and size
 			*/
 			tp = BaseType(df->df_type);
-			if ((df->df_flags & D_VARPAR) ||
-			    (tp->tp_fund&(T_POINTER|T_HIDDEN|T_EQUAL))) {
+			if ((df->df_flags & D_VARPAR) || (tp->tp_fund & (T_POINTER | T_HIDDEN | T_EQUAL)))
+			{
 				C_ms_reg(df->var_off,
-					 pointer_size,
-					 reg_pointer,
-					 0);
+				    pointer_size,
+				    reg_pointer,
+				    0);
 			}
-			else if (tp->tp_fund & T_NUMERIC) {
+			else if (tp->tp_fund & T_NUMERIC)
+			{
 				C_ms_reg(df->var_off,
-					 tp->tp_size,
-					 tp->tp_fund == T_REAL ?
-					    reg_float : reg_any,
-					 0);
+				    tp->tp_size,
+				    tp->tp_fund == T_REAL ? reg_float : reg_any,
+				    0);
 			}
 		}
 	}
 }
 
 static void
-df_warning(nd, df, warning)
-	t_node	*nd;
-	t_def	*df;
-	char	*warning;
+    df_warning(nd, df, warning)
+        t_node* nd;
+t_def* df;
+char* warning;
 {
-	if (! (df->df_kind & (D_VARIABLE|D_PROCEDURE|D_TYPE|D_CONST|D_PROCHEAD))) {
+	if (!(df->df_kind & (D_VARIABLE | D_PROCEDURE | D_TYPE | D_CONST | D_PROCHEAD)))
+	{
 		return;
 	}
-	if (warning) {
+	if (warning)
+	{
 		node_warning(nd,
-			     W_ORDINARY,
-			     "%s \"%s\" %s",
-			     (df->df_flags & D_VALPAR) ? "value parameter" :
-			      (df->df_flags & D_VARPAR) ? "variable parameter" :
-			       (df->df_kind == D_VARIABLE) ? "variable" :
-				(df->df_kind == D_TYPE) ? "type" :
-				 (df->df_kind == D_CONST) ? "constant" :
-				  "procedure",
-			     df->df_idf->id_text, warning);
+		    W_ORDINARY,
+		    "%s \"%s\" %s",
+		    (df->df_flags & D_VALPAR) ? "value parameter" : (df->df_flags & D_VARPAR) ? "variable parameter" : (df->df_kind == D_VARIABLE) ? "variable" : (df->df_kind == D_TYPE) ? "type" : (df->df_kind == D_CONST) ? "constant" : "procedure",
+		    df->df_idf->id_text, warning);
 	}
 }
 
 static void
-UseWarnings(df)
-	register t_def *df;
+    UseWarnings(df) register t_def* df;
 {
-	t_node	*nd = df->df_scope->sc_end;
+	t_node* nd = df->df_scope->sc_end;
 
-	if (is_anon_idf(df->df_idf) ||
-	    !(df->df_kind&(D_IMPORTED|D_VARIABLE|D_PROCEDURE|D_CONST|D_TYPE)) ||
-	    (df->df_flags&(D_EXPORTED|D_QEXPORTED))) {
+	if (is_anon_idf(df->df_idf) || !(df->df_kind & (D_IMPORTED | D_VARIABLE | D_PROCEDURE | D_CONST | D_TYPE)) || (df->df_flags & (D_EXPORTED | D_QEXPORTED)))
+	{
 		return;
 	}
 
-	if (df->df_kind & D_IMPORTED) {
-		register t_def *df1 = df->imp_def;
+	if (df->df_kind & D_IMPORTED)
+	{
+		register t_def* df1 = df->imp_def;
 
-		df1->df_flags |= df->df_flags & (D_USED|D_DEFINED);
-		if (df->df_kind == D_INUSE) return;
-		if ( !(df->df_flags & D_IMP_BY_EXP)) {
-			if (df->df_flags & (D_USED | D_DEFINED)) {
+		df1->df_flags |= df->df_flags & (D_USED | D_DEFINED);
+		if (df->df_kind == D_INUSE)
+			return;
+		if (!(df->df_flags & D_IMP_BY_EXP))
+		{
+			if (df->df_flags & (D_USED | D_DEFINED))
+			{
 				return;
 			}
 			df_warning(nd,
-				   df1,
-				   df1->df_kind == D_VARIABLE ?
-					"imported but not used/assigned" :
-					"imported but not used");
+			    df1,
+			    df1->df_kind == D_VARIABLE ? "imported but not used/assigned" : "imported but not used");
 			return;
 		}
 		df = df1;
 		nd = df->df_scope->sc_end;
 	}
-	switch(df->df_flags & (D_USED|D_DEFINED|D_VALPAR|D_VARPAR)) {
-	case 0:
-	case D_VARPAR:
-		df_warning(nd, df,"never used/assigned");
-		break;
-	case D_USED:
-		df_warning(nd, df,"never assigned");
-		break;
-	case D_VALPAR:
-	case D_DEFINED:
-	case D_DEFINED|D_VALPAR:
-		df_warning(nd, df,"never used");
-		break;
+	switch (df->df_flags & (D_USED | D_DEFINED | D_VALPAR | D_VARPAR))
+	{
+		case 0:
+		case D_VARPAR:
+			df_warning(nd, df, "never used/assigned");
+			break;
+		case D_USED:
+			df_warning(nd, df, "never assigned");
+			break;
+		case D_VALPAR:
+		case D_DEFINED:
+		case D_DEFINED | D_VALPAR:
+			df_warning(nd, df, "never used");
+			break;
 	}
 }
 
-WalkDefList(df, proc)
-	register t_def *df;
-	int (*proc)();
+WalkDefList(df, proc) register t_def* df;
+int (*proc)();
 {
-	for (; df; df = df->df_nextinscope) {
+	for (; df; df = df->df_nextinscope)
+	{
 		(*proc)(df);
 	}
 }
 
 #ifdef DBSYMTAB
 static int
-stabdef(df)
-	t_def	*df;
+    stabdef(df)
+        t_def* df;
 {
-	switch(df->df_kind) {
-	case D_CONST:
-	case D_VARIABLE:
-		stb_string(df, df->df_kind);
-		break;
+	switch (df->df_kind)
+	{
+		case D_CONST:
+		case D_VARIABLE:
+			stb_string(df, df->df_kind);
+			break;
 	}
 }
 #endif
diff --git a/lang/m2/libm2/Conversion.def b/lang/m2/libm2/Conversions.def
similarity index 100%
rename from lang/m2/libm2/Conversion.def
rename to lang/m2/libm2/Conversions.def
diff --git a/lang/m2/libm2/Conversion.mod b/lang/m2/libm2/Conversions.mod
similarity index 100%
rename from lang/m2/libm2/Conversion.mod
rename to lang/m2/libm2/Conversions.mod
diff --git a/lang/m2/libm2/RealConver.def b/lang/m2/libm2/RealConversions.def
similarity index 100%
rename from lang/m2/libm2/RealConver.def
rename to lang/m2/libm2/RealConversions.def
diff --git a/lang/m2/libm2/RealConver.mod b/lang/m2/libm2/RealConversions.mod
similarity index 100%
rename from lang/m2/libm2/RealConver.mod
rename to lang/m2/libm2/RealConversions.mod
diff --git a/lang/m2/libm2/build.lua b/lang/m2/libm2/build.lua
index d0861b966..a1a9e5c0a 100644
--- a/lang/m2/libm2/build.lua
+++ b/lang/m2/libm2/build.lua
@@ -29,8 +29,8 @@ for _, plat in ipairs(vars.plats) do
         },
 		hdrs = {}, -- must be empty
 		deps = {
-			"lang/cem/libcc.ansi/headers+headers",
-			"plat/"..plat.."/include+headers",
+			"lang/cem/libcc.ansi/headers+pkg",
+			"plat/"..plat.."/include+pkg",
 			"h+emheaders",
 		},
         vars = { plat = plat }
diff --git a/lang/occam/comp/em.c b/lang/occam/comp/em.c
index ecd779824..605817371 100644
--- a/lang/occam/comp/em.c
+++ b/lang/occam/comp/em.c
@@ -355,7 +355,7 @@ void zgt(lab) int lab;		{	C_zgt((label) lab); }
 void zlt(lab) int lab;		{	C_zlt((label) lab); }
 void zne(lab) int lab;		{	C_zne((label) lab); }
 
-char *itoa(i) long i;
+char *myitoa(i) long i;
 {
 	static char a[sizeof(long)*3];
 	sprint(a, "%ld", i);
@@ -364,7 +364,7 @@ char *itoa(i) long i;
 
 void rom(size, c) int size; long c;
 {
-	C_rom_icon(itoa(c), (arith) size);
+	C_rom_icon(myitoa(c), (arith) size);
 }
 
 void lin()
diff --git a/lang/pc/comp/LLlex.c b/lang/pc/comp/LLlex.c
index 7bd857a2b..4de2c0d8b 100644
--- a/lang/pc/comp/LLlex.c
+++ b/lang/pc/comp/LLlex.c
@@ -164,14 +164,10 @@ register int delim;
 				Malloc((unsigned) sizeof(struct string));
 	register char *p;
 	register int len = ISTRSIZE;
-	
+
 	str->s_str = p = Malloc((unsigned int) ISTRSIZE);
 	for( ; ; )	{
 		LoadChar(ch);
-		if( ch & 0200 ) {
-			fatal("non-ascii '\\%03o' read", ch & 0377);
-			/*NOTREACHED*/
-		}
 		if( class(ch) == STNL )	{
 			lexerror("newline in string");
 			LineNumber++;
@@ -310,11 +306,6 @@ again:
 		LoadChar(ch);
 		if( !options['C'] )		/* -C : cases are different */
 			TO_LOWER(ch);
-
-		if( (ch & 0200) && ch != EOI ) {
-			fatal("non-ascii '\\%03o' read", ch & 0377);
-			/*NOTREACHED*/
-		}
 	}
 
 	switch( class(ch) )	{
@@ -420,7 +411,7 @@ again:
 		/* dtrg: removed to allow Pascal programs to access system routines
 		 * (necessary to make them do anything useful). What's this for,
 		 * anyway? */
-		 
+
 #if 0
 		if( buf[0] == '_' ) lexerror("underscore starts identifier");
 #endif
@@ -492,7 +483,7 @@ again:
 				PushBack();
 				goto end;
 			}
-				
+
 		}
 		if( ch == 'e' || ch == 'E' )	{
 			char *tp = np;		/* save position in string */
diff --git a/lang/pc/comp/em_pc.6 b/lang/pc/comp/em_pc.6
index f544e0536..7ba0de3eb 100644
--- a/lang/pc/comp/em_pc.6
+++ b/lang/pc/comp/em_pc.6
@@ -1,4 +1,4 @@
-.TH EM_PC 6 "$Revision$"
+.TH EM_PC 6 2017-01-18
 .ad
 .SH NAME
 em_pc \- Pascal compiler
@@ -45,9 +45,9 @@ and the \fIn\fR parameter for the alignment of that type.
 Absence of \fIm\fR or \fIn\fR causes a default value to be retained.
 .IP \fB\-w\fR
 suppress warning messages.
-.IP
 .IP \fB\-R\fR
-disable range checks. Additionally, the run-time tests to see if
+disable range checks.
+Additionally, the run-time tests to see if
 a function is assigned, are skipped.
 .IP \fB\-A\fR
 enable extra array bound checks, for machines that do not implement the
@@ -55,26 +55,28 @@ EM ones.
 .IP \fB\-C\fR
 the lower case and upper case letters are treated differently.
 .IP "\fB\-u\fR, \fB\-U\fR"
-allow underscores in identifiers. It is not allowed to start an identifier
+allow underscores in identifiers.
+It is not allowed to start an identifier
 with an underscore.
 .IP \fB\-a\fR
 don't generate code for assertions.
 .IP \fB\-c\fR
-allow C-like strings. This option is mainly intended for usage with
-C-functions. This option will cause the type 'string' to be known.
+allow C-like strings.
+This option is mainly intended for usage with C-functions.
+This option will cause the type 'string' to be known.
 .IP \fB\-d\fR
 allow the type 'long'.
 .IP \fB\-i\fR\fIn\fR
 set the size of integer sets to \fIn\fR. When not used, a default value is
 retained.
 .IP \fB\-s\fR
-allow only standard Pascal. This disables the \fB\-c\fR, \fB\-d\fR, \fB\-u\fR,
-\fB\-U\fR and \fB\-C\fR
-options. Furthermore, assertions are not recognized at all (instead of just
+allow only standard Pascal.
+This disables the \fB\-c\fR, \fB\-d\fR, \fB\-u\fR,
+\fB\-U\fR and \fB\-C\fR options.
+Furthermore, assertions are not recognized at all (instead of just
 being skipped).
 .IP \fB\-t\fR
 trace calls and exits of procedures and functions.
-.PP
 .SH FILES
 .IR ~em/lib/em_pc :
 binary of the Pascal compiler.
diff --git a/lang/pc/comp/type.c b/lang/pc/comp/type.c
index faca8fee5..d13419cf4 100644
--- a/lang/pc/comp/type.c
+++ b/lang/pc/comp/type.c
@@ -94,8 +94,8 @@ InitTypes()
 	/* character type
 	*/
 	char_type = standard_type(T_CHAR, 1, (arith) 1);
-	char_type->enm_ncst = 128;	/* only 7 bits ASCII characters */
-	
+	char_type->enm_ncst = 256; /* all bytes */
+
 	/* boolean type
 	*/
 	bool_type = standard_type(T_ENUMERATION, 1, (arith) 1);
diff --git a/lang/pc/libpc/build.lua b/lang/pc/libpc/build.lua
index 7845991e5..215f0c745 100644
--- a/lang/pc/libpc/build.lua
+++ b/lang/pc/libpc/build.lua
@@ -17,8 +17,8 @@ for _, plat in ipairs(vars.plats) do
         },
 		hdrs = {}, -- must be empty
 		deps = {
-			"lang/cem/libcc.ansi/headers+headers",
-			"plat/"..plat.."/include+headers",
+			"lang/cem/libcc.ansi/headers+pkg",
+			"plat/"..plat.."/include+pkg",
 			"h+emheaders",
 		},
         vars = { plat = plat }
diff --git a/lib/6500/descr b/lib/6500/descr
index 70c5445b4..32885519b 100644
--- a/lib/6500/descr
+++ b/lib/6500/descr
@@ -29,19 +29,19 @@ name asld
 	mapflag -i  IFILE={EM}/{RT}i
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {IFILE?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon2 {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/6800/descr b/lib/6800/descr
index 59bcabf56..7bf0b53c4 100644
--- a/lib/6800/descr
+++ b/lib/6800/descr
@@ -25,19 +25,19 @@ name led
 	program {EM}/lib.bin/em_led
 	mapflag -l* LNAME={EM}/{LIB}*
 	args (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/6805/descr b/lib/6805/descr
index c4b0077a3..3081cd2d7 100644
--- a/lib/6805/descr
+++ b/lib/6805/descr
@@ -25,19 +25,19 @@ name led
 	program {EM}/lib.bin/em_led
 	mapflag -l* LNAME={EM}/{LIB}*
 	args (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/6809/descr b/lib/6809/descr
index b42be9d4a..1d9848569 100644
--- a/lib/6809/descr
+++ b/lib/6809/descr
@@ -26,19 +26,19 @@ name led
 	program {EM}/lib.bin/em_led
 	mapflag -l* LNAME={EM}/{LIB}*
 	args -b0:0x800 (.e:{HEAD}={ALIGN} {EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/arm/descr b/lib/arm/descr
index 4f12cc1da..cd49778a0 100644
--- a/lib/arm/descr
+++ b/lib/arm/descr
@@ -37,7 +37,7 @@ name asld
 	mapflag -l* LNAME={EM}/{LIB}*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -45,14 +45,14 @@ name asld
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.f.e:{TAIL}={EM}/{LIB}mon) \
-		(.mod.ocm.b.c.p.f.e:{TAIL}={EM}/{LIB}fp) \
+		(.mod.ocm.bas.c.p.f.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.f.e:{TAIL}={EM}/{LIB}fp) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon2 {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/descr/cpm b/lib/descr/cpm
index 9575b3222..e414ed68f 100644
--- a/lib/descr/cpm
+++ b/lib/descr/cpm
@@ -22,7 +22,7 @@ name asld
 	mapflag -s* SIZE_F=-s*
 	args {ASS_F?} ({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
 		(.b.c.p:{TAIL}={EM}/{LIB}mon)
 	linker
diff --git a/lib/descr/fe b/lib/descr/fe
index e88663a6d..b7a07cdc4 100644
--- a/lib/descr/fe
+++ b/lib/descr/fe
@@ -153,20 +153,20 @@ name ocm
 	prep cond
 	callname ocm
 end
-name abc
-	from .b
+name basic
+	from .bas
 	to .k
 	program {EM}/lib/ack/em_bem
-	mapflag -h ABC_F={ABC_F?} -h
-	mapflag -w ABC_F={ABC_F?} -w
-	mapflag -L ABC_F={ABC_F?} -L
-	mapflag -E ABC_F={ABC_F?} -E
-#	mapflag -d ABC_F={ABC_F?} -d
-	args -Vw{w}p{p}f{d} {ABC_F?} < > {SOURCE}
+	mapflag -h BASIC_F={BASIC_F?} -h
+	mapflag -w BASIC_F={BASIC_F?} -w
+	mapflag -L BASIC_F={BASIC_F?} -L
+	mapflag -E BASIC_F={BASIC_F?} -E
+#	mapflag -d BASIC_F={BASIC_F?} -d
+	args -Vw{w}p{p}f{d} {BASIC_F?} < > {SOURCE}
 	prep cond
-	rts .b
-	need .b
-	callname abc
+	rts .bas
+	need .bas
+	callname basic
 end
 var A68INIT={EM}/lib/ack/em_a68s_init
 name a68s
@@ -180,6 +180,17 @@ name a68s
         need .8
         callname a68s
 end
+name b
+        from .b
+        to .k
+        program {EM}/lib/ack/em_b
+		mapflag -B* ABC_F={ABC_F?} -B*
+        args -i < -o > -w {p} {ABC_F?}
+        prep cond
+        rts .b
+        need .b
+        callname abc
+end
 name encode
 	from .e
 	to .k
diff --git a/lib/em22/descr b/lib/em22/descr
index ca39d5a94..551222b05 100644
--- a/lib/em22/descr
+++ b/lib/em22/descr
@@ -25,17 +25,17 @@ name asld
 	mapflag -s* SIZE_FLAG=-s*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {SIZE_FLAG} \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		(.b.c.ocm.mod.p.e:{TAIL}={EM}/{LIB}mon) \
 		({RTS}{ANSI?}:.cansi={EM}/lib/em22/end_em)
diff --git a/lib/em24/descr b/lib/em24/descr
index aa04837d7..b3eeb0fb9 100644
--- a/lib/em24/descr
+++ b/lib/em24/descr
@@ -25,17 +25,17 @@ name asld
 	mapflag -s* SIZE_FLAG=-s*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {SIZE_FLAG} \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		(.p.b.mod.ocm.c.e:{TAIL}={EM}/{LIB}mon) \
 		({RTS}{ANSI?}:.cansi={EM}/lib/em24/end_em)
diff --git a/lib/em44/descr b/lib/em44/descr
index 0b4439ced..79531e21b 100644
--- a/lib/em44/descr
+++ b/lib/em44/descr
@@ -25,7 +25,7 @@ name asld
 	mapflag -s* SIZE_FLAG=-s*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {SIZE_FLAG} \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -33,11 +33,11 @@ name asld
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		(.p.b.ocm.mod.c.f.e:{TAIL}={EM}/{LIB}mon) \
 		({RTS}{ANSI?}:.cansi={EM}/lib/em44/end_em)
diff --git a/lib/i286/descr b/lib/i286/descr
index 31b74f2b8..9d505d3ca 100644
--- a/lib/i286/descr
+++ b/lib/i286/descr
@@ -28,7 +28,7 @@ name asld
 	args {IFILE?} (.e:{HEAD}={EM}/{RT}em) \
 		({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
 		(.b.c.p.e:{TAIL}={EM}/{LIB}alo) (.b.c.p:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em)
diff --git a/lib/i386/descr b/lib/i386/descr
index a6ef6b3d8..c8a26cbf5 100644
--- a/lib/i386/descr
+++ b/lib/i386/descr
@@ -41,7 +41,7 @@ name led
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	mapflag -g LIBDB={EM}/{LIB}db
 	args {ALIGN} {SEPID?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
@@ -49,11 +49,11 @@ name led
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f {EM}/{LIB}ac) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{FLOATS?} \
 		{LIBDB?} \
diff --git a/lib/i80/descr b/lib/i80/descr
index 9964d031a..293352338 100644
--- a/lib/i80/descr
+++ b/lib/i80/descr
@@ -36,19 +36,19 @@ name led
 	mapflag -l* LNAME={EM}/{LIB}*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args -b0:0x1000 {ALIGN} {SEPID?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon2 {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/i86/descr b/lib/i86/descr
index 7fcb90e0d..1d402fba5 100644
--- a/lib/i86/descr
+++ b/lib/i86/descr
@@ -38,17 +38,17 @@ name led
 	mapflag -fp FLOATS={EM}/{ILIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} {SEPID?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{FLOATS?} \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/m68020/descr b/lib/m68020/descr
index 2e3e7fbc5..73b147869 100644
--- a/lib/m68020/descr
+++ b/lib/m68020/descr
@@ -49,7 +49,7 @@ name led
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	mapflag -g LIBDB={EM}/{LIB}db
 	args {ALIGN} (.e:{HEAD}= {EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -57,11 +57,11 @@ name led
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		{LIBDB?} \
diff --git a/lib/m68k2/descr b/lib/m68k2/descr
index 61dcbdb08..581debf09 100644
--- a/lib/m68k2/descr
+++ b/lib/m68k2/descr
@@ -51,17 +51,17 @@ name led
 	mapflag -fp LIBFP={EM}/{LIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args -b0:0x20000 {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/m68k4/descr b/lib/m68k4/descr
index bc2fa4992..ca628d5c6 100644
--- a/lib/m68k4/descr
+++ b/lib/m68k4/descr
@@ -51,7 +51,7 @@ name led
 	mapflag -fp LIBFP={EM}/{LIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args -b0:0x20000 {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -59,11 +59,11 @@ name led
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/mantra/descr b/lib/mantra/descr
index 2183e9555..8ca806316 100644
--- a/lib/mantra/descr
+++ b/lib/mantra/descr
@@ -52,7 +52,7 @@ name led
 	mapflag -fp LIBFP={EM}/{MLIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args -b0:0x80000 {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
@@ -60,11 +60,11 @@ name led
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{MLIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/minix/descr b/lib/minix/descr
index 45b22a525..66e48c8a9 100644
--- a/lib/minix/descr
+++ b/lib/minix/descr
@@ -42,14 +42,14 @@ name led
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} {SEPID?} \
 		(.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) -o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{MLIB}em {EM}/{LIB}mon {EM}/lib/i86/end_em)
diff --git a/lib/minixST/descr b/lib/minixST/descr
index cd3f7b838..e9326714d 100644
--- a/lib/minixST/descr
+++ b/lib/minixST/descr
@@ -41,17 +41,17 @@ name led
 	mapflag -fp LIBFP={EM}/{NLIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} {SEPID?} -c (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{LIB}mon {EM}/{MLIB}em {EM}/lib/m68k2/end_em)
diff --git a/lib/ns/descr b/lib/ns/descr
index 1fe1b8f82..7b21ddc19 100644
--- a/lib/ns/descr
+++ b/lib/ns/descr
@@ -36,7 +36,7 @@ name led
 	mapflag -l* LNAME={EM}/{LIB}*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -44,11 +44,11 @@ name led
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		(.e:{TAIL}={EM}/{LIB}mon {EM}/{LIB}mon2 {EM}/{LIB}em {EM}/lib/{M}/end_em)
 	linker
diff --git a/lib/pdp/descr b/lib/pdp/descr
index 46d403b54..7b4bf0f0d 100644
--- a/lib/pdp/descr
+++ b/lib/pdp/descr
@@ -47,17 +47,17 @@ name led
 	mapflag -nr ALIGN=-a0:1 -a1:1 -a2:0x2000 -a3:1
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} {SEPID?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
 	linker
diff --git a/lib/pmds/descr b/lib/pmds/descr
index c5f76c60d..96342504c 100644
--- a/lib/pmds/descr
+++ b/lib/pmds/descr
@@ -53,17 +53,17 @@ name led
 	mapflag -fp LIBFP={EM}/{MLIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args  {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{MLIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/pmds4/descr b/lib/pmds4/descr
index 0802f1cc1..8ae806f24 100644
--- a/lib/pmds4/descr
+++ b/lib/pmds4/descr
@@ -53,7 +53,7 @@ name led
 	mapflag -fp LIBFP={EM}/{MLIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args  {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -61,11 +61,11 @@ name led
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{MLIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/s2650/descr b/lib/s2650/descr
index 11028bd59..a9fdc0076 100644
--- a/lib/s2650/descr
+++ b/lib/s2650/descr
@@ -25,19 +25,19 @@ name led
 	program {EM}/lib.bin/em_led
 	mapflag -l* LNAME={EM}/{LIB}*
 	args (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/sparc/descr b/lib/sparc/descr
index 10d129b47..1730f009e 100644
--- a/lib/sparc/descr
+++ b/lib/sparc/descr
@@ -48,7 +48,7 @@ name led
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args -Bstatic -dc -e begtext \
 		(.e:{HEAD}= {EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -59,11 +59,11 @@ name led
 		(.8:{TAIL}={EM}/{LIB}a68s) \
 		(.p:{TAIL}={EM}/{LIB}pc) \
 		(.cp.8:{TAIL}={EM}/{LIB}cpc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBDB?} \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/sparc_solaris/descr b/lib/sparc_solaris/descr
index 43faa72ab..137768b9d 100644
--- a/lib/sparc_solaris/descr
+++ b/lib/sparc_solaris/descr
@@ -48,7 +48,7 @@ name led
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args \
 		(.e:{HEAD}= {EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -59,11 +59,11 @@ name led
 		(.8:{TAIL}={EM}/{LIB}a68s) \
 		(.p:{TAIL}={EM}/{LIB}pc) \
 		(.cp.8:{TAIL}={EM}/{LIB}cpc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBDB?} \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon -lc {EM}/lib/{M}/end_em)
diff --git a/lib/sun2/descr b/lib/sun2/descr
index 84507ffdb..b4a20bdf0 100644
--- a/lib/sun2/descr
+++ b/lib/sun2/descr
@@ -55,7 +55,7 @@ name led
 	mapflag -fp LIBFP={EM}/{MLIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args  {ALIGN} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.f={EM}/{RT}ac) \
@@ -63,11 +63,11 @@ name led
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		(.e:{TAIL}={EM}/{MLIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/sun3/descr b/lib/sun3/descr
index a1d3a33d0..4cf88dd52 100644
--- a/lib/sun3/descr
+++ b/lib/sun3/descr
@@ -56,7 +56,7 @@ name led
 	mapflag -g LIBDB={EM}/{MLIB}db
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} (.e:{HEAD}= {EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
@@ -67,11 +67,11 @@ name led
 		(.8:{TAIL}={EM}/{LIB}a68s) \
 		(.p:{TAIL}={EM}/{LIB}pc) \
 		(.cp.8:{TAIL}={EM}/{LIB}cpc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBFP?} \
 		{LIBDB?} \
diff --git a/lib/vax4/descr b/lib/vax4/descr
index d17a937e4..ef2c96e58 100644
--- a/lib/vax4/descr
+++ b/lib/vax4/descr
@@ -51,7 +51,7 @@ name led
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	mapflag -g LIBDB={EM}/{LIB}db
 	args {ALIGN} (.e:{HEAD}= {EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
@@ -60,11 +60,11 @@ name led
 		-o > < \
 		(.8:{TAIL}={EM}/{LIB}a68s) \
 		(.p.8:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.f:{TAIL}={EM}/{LIB}f77 {EM}/{LIB}ac) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{LIBDB?} \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
diff --git a/lib/xenix3/descr b/lib/xenix3/descr
index 2d3f85d0d..9fefc2a9e 100644
--- a/lib/xenix3/descr
+++ b/lib/xenix3/descr
@@ -40,17 +40,17 @@ name led
 	mapflag -fp FLOATS={EM}/{ILIB}fp
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {ALIGN} {SEPID?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		{FLOATS?} \
 		(.e:{TAIL}={EM}/{ILIB}em {EM}/{LIB}mon {EM}/lib/i86/end_em)
diff --git a/lib/z80/descr b/lib/z80/descr
index cd1fd4850..152b5d7df 100644
--- a/lib/z80/descr
+++ b/lib/z80/descr
@@ -35,19 +35,19 @@ name led
 	mapflag -l* LNAME={EM}/{LIB}*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args -b0:0x1000 (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon2 {EM}/lib/{M}/end_em)
 	linker
 end
diff --git a/lib/z8000/descr b/lib/z8000/descr
index 61085f014..1ac1780e5 100644
--- a/lib/z8000/descr
+++ b/lib/z8000/descr
@@ -29,19 +29,19 @@ name asld
 	mapflag -i  IFILE={EM}/{RT}i
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {IFILE?} (.e:{HEAD}={EM}/{RT}em) \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.p={EM}/{RT}pc) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
-		(.mod.ocm.b.c.p.e:{TAIL}={EM}/{LIB}mon) \
+		(.mod.ocm.bas.c.p.e:{TAIL}={EM}/{LIB}mon) \
 		(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon2 {EM}/lib/z8000/end_em)
 	linker
 end
diff --git a/mach/i386/ncg/mach.h b/mach/i386/ncg/mach.h
index e58f4f423..f3075a37f 100644
--- a/mach/i386/ncg/mach.h
+++ b/mach/i386/ncg/mach.h
@@ -11,6 +11,7 @@
 
 #define newilb(x)       fprintf(codefile,"%s:\n",x)
 #define newdlb(x)       fprintf(codefile,"%s:\n",x)
+#define newplb(x)       fprintf(codefile,".align 4\n%s:\n", x)
 #define dlbdlb(x,y)     fprintf(codefile,"%s = %s\n",x,y)
 #define newlbss(l,x)    fprintf(codefile,".comm %s,%ld\n",l,x);
 
diff --git a/mach/i80/as/mach0.c b/mach/i80/as/mach0.c
index 2249df643..e5a7e88ec 100644
--- a/mach/i80/as/mach0.c
+++ b/mach/i80/as/mach0.c
@@ -9,3 +9,5 @@
  */
 #define	LISTING
 #define RELOCATION
+#define THREE_PASS
+
diff --git a/mach/i86/ncg/mach.h b/mach/i86/ncg/mach.h
index 8f9f65938..ab5a0d156 100644
--- a/mach/i86/ncg/mach.h
+++ b/mach/i86/ncg/mach.h
@@ -11,6 +11,7 @@
 
 #define newilb(x)       fprintf(codefile,"%s:\n",x)
 #define newdlb(x)       fprintf(codefile,"%s:\n",x)
+#define newplb(x)       fprintf(codefile,".align 2\n%s:\n", x)
 #define dlbdlb(x,y)     fprintf(codefile,"%s = %s\n",x,y)
 #define newlbss(l,x)    fprintf(codefile,".comm %s,%u\n",l,x);
 
diff --git a/mach/powerpc/as/mach0.c b/mach/powerpc/as/mach0.c
index 325c08910..1c2051753 100644
--- a/mach/powerpc/as/mach0.c
+++ b/mach/powerpc/as/mach0.c
@@ -11,15 +11,13 @@
 #define DEBUG 0
 
 #undef valu_t
-#define valu_t long
+#define valu_t int32_t
 
 #undef ADDR_T
-#define ADDR_T long
+#define ADDR_T uint32_t
 
 #undef word_t
-#define word_t long
-
-typedef uint32_t quad;
+#define word_t uint32_t
 
 #undef ALIGNWORD
 #define ALIGNWORD	4
@@ -31,3 +29,9 @@ typedef uint32_t quad;
 #define VALWIDTH	8
 
 #define FIXUPFLAGS (RELBR | RELWR)
+
+/* 6-bit mb (mask begin) or me (mask end) field */
+#define MB6(v) (((v) & 0x1F)<<6 | ((v) & 0x20)>>0)
+
+/* 6-bit sh (shift) field */
+#define SH6(v) (((v) & 0x1F)<<11 | ((v) & 0x20)>>4)
diff --git a/mach/powerpc/as/mach1.c b/mach/powerpc/as/mach1.c
index 998cd8d9c..50f799684 100644
--- a/mach/powerpc/as/mach1.c
+++ b/mach/powerpc/as/mach1.c
@@ -3,3 +3,10 @@
  * $State$
  */
 
+/*
+ * Do not #include anything here.  Do it in mach/proto/as/comm0.h
+ */
+
+void no_hl(void);
+word_t eval_hl(struct expr_t* expr, int token);
+void emit_hl(word_t in);
diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c
index 96d6690df..4065334e6 100644
--- a/mach/powerpc/as/mach2.c
+++ b/mach/powerpc/as/mach2.c
@@ -8,20 +8,35 @@
 %token <y_word> FPR
 %token <y_word> CR
 %token <y_word> C
+%token <y_word> OP_HI OP_HA OP_LO
 
 %token <y_word> OP
+%token <y_word> OP_BDA
+%token <y_word> OP_BDL
 %token <y_word> OP_BF
 %token <y_word> OP_BF_BFA
 %token <y_word> OP_BF_FRA_FRB
 %token <y_word> OP_BF_L_RA_RB
 %token <y_word> OP_BF_L_RA_SI
 %token <y_word> OP_BF_L_RA_UI
+%token <y_word> OP_BF_RA_RB
+%token <y_word> OP_BF_RA_SI
+%token <y_word> OP_BF_RA_UI
 %token <y_word> OP_BF_U_C
+%token <y_word> OP_BH
+%token <y_word> OP_BI_BDA
+%token <y_word> OP_BI_BDL
+%token <y_word> OP_BI_BH
+%token <y_word> OP_BICR_BDA
+%token <y_word> OP_BICR_BDL
+%token <y_word> OP_BICR_BH
 %token <y_word> OP_BO_BI_BDA
 %token <y_word> OP_BO_BI_BDL
 %token <y_word> OP_BO_BI_BH
 %token <y_word> OP_BT_C
+%token <y_word> OP_BT_BA_BA
 %token <y_word> OP_BT_BA_BB
+%token <y_word> OP_BT_BT_BT
 %token <y_word> OP_FLM_FRB_C
 %token <y_word> OP_FRS_RA_D
 %token <y_word> OP_FRS_RA_RB
@@ -32,34 +47,28 @@
 %token <y_word> OP_FRT_FRB_C
 %token <y_word> OP_FRT_RA_D
 %token <y_word> OP_FRT_RA_RB
-%token <y_word> OP_L
 %token <y_word> OP_LEV
 %token <y_word> OP_LIA
 %token <y_word> OP_LIL
-%token <y_word> OP_L_RB
-%token <y_word> OP_RA_RB
-%token <y_word> OP_RB
-%token <y_word> OP_RS
+%token <y_word> OP_LI32
+%token <y_word> OP_RA_RS_C
+%token <y_word> OP_RA_RS_RB_C
+%token <y_word> OP_RA_RS_RB_MB5_ME5_C
+%token <y_word> OP_RA_RS_RB_MB6_C
+%token <y_word> OP_RA_RS_SH5_C
+%token <y_word> OP_RA_RS_SH5_MB5_ME5_C
+%token <y_word> OP_RA_RS_SH6_C
+%token <y_word> OP_RA_RS_SH6_MB6_C
+%token <y_word> OP_RA_RS_UI
+%token <y_word> OP_RA_RS_UI_CC
 %token <y_word> OP_RS_FXM
-%token <y_word> OP_RS_L
 %token <y_word> OP_RS_RA
-%token <y_word> OP_RS_RA_C
 %token <y_word> OP_RS_RA_D
 %token <y_word> OP_RS_RA_DS
 %token <y_word> OP_RS_RA_NB
 %token <y_word> OP_RS_RA_RB
 %token <y_word> OP_RS_RA_RB_C
 %token <y_word> OP_RS_RA_RA_C
-%token <y_word> OP_RS_RA_RB_MB5_ME5_C
-%token <y_word> OP_RS_RA_RB_MB6_C
-%token <y_word> OP_RS_RA_RB_ME6_C
-%token <y_word> OP_RS_RA_SH_MB5_ME5_C
-%token <y_word> OP_RS_RA_SH_MB6_SH_C
-%token <y_word> OP_RS_RA_SH_ME6_SH_C
-%token <y_word> OP_RS_RA_SH5_C
-%token <y_word> OP_RS_RA_SH6_C
-%token <y_word> OP_RS_RA_UI
-%token <y_word> OP_RS_RA_UI_CC
 %token <y_word> OP_RS_RB
 %token <y_word> OP_RS_SPR
 %token <y_word> OP_RS_SR
@@ -73,19 +82,26 @@
 %token <y_word> OP_RT_RA_RB_C
 %token <y_word> OP_RT_RA_SI
 %token <y_word> OP_RT_RA_SI_addic
+%token <y_word> OP_RT_RA_SI_subi
+%token <y_word> OP_RT_RA_SI_subic
 %token <y_word> OP_RT_RB
+%token <y_word> OP_RT_RB_RA_C
+%token <y_word> OP_RT_SI
 %token <y_word> OP_RT_SPR
 %token <y_word> OP_RT_SR
 %token <y_word> OP_RT_TBR
 %token <y_word> OP_TH_RA_RB
 %token <y_word> OP_TO_RA_RB
 %token <y_word> OP_TO_RA_SI
-
-%token <y_word> OP_LA
-%token <y_word> OP_LI32
+%token <y_word> OP_TOX_RA_RB
+%token <y_word> OP_TOX_RA_SI
+%token <y_word> OP_clrlsldi OP_clrldi OP_clrrdi OP_extldi OP_extrdi
+%token <y_word> OP_insrdi OP_rotrdi OP_sldi OP_srdi
+%token <y_word> OP_clrlslwi OP_clrlwi OP_clrrwi OP_extlwi OP_extrwi
+%token <y_word> OP_inslwi OP_insrwi OP_rotlwi OP_rotrwi OP_slwi OP_srwi
 
 /* Other token types */
 
 %type <y_word> c
-%type <y_word> e16 u8 u7 u6 u5 u4 u2 u1
-%type <y_word> nb ds bda bdl lia lil
+%type <y_word> e16 negate16 u8 u7 u6 u5 u4 u2 u1
+%type <y_word> opt_bh cr_opt nb ds bda bdl lia lil spr_num
diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c
index 0f0bfdae7..91b088a6a 100644
--- a/mach/powerpc/as/mach3.c
+++ b/mach/powerpc/as/mach3.c
@@ -99,9 +99,9 @@
 /* Special instructions */
 
 0,     OP_LI32,               0,                                       "li32",
-0,     OP_LA,                 0,                                       "la",
-0,     OP_LA,                 0,                                       "li",
-0,     OP_RS_RA_RA_C,         31<<26 | 444<<1,                         "mr",
+0,     OP_HI,                 0,                                       "hi16",
+0,     OP_HA,                0,                                        "ha16",
+0,     OP_LO,                 0,                                       "lo16",
 
 /* Branch processor instructions (page 20) */
 
@@ -123,11 +123,173 @@
 0,     OP_BT_BA_BB,           19<<26 | 193<<1,                         "crxor",
 0,     OP_BT_BA_BB,           19<<26 | 225<<1,                         "crnand",
 0,     OP_BT_BA_BB,           19<<26 | 33<<1,                          "crnor",
-0,     OP_BT_BA_BB,           19<<26 | 289<<1,                         "crneqv",
+0,     OP_BT_BA_BB,           19<<26 | 289<<1,                         "creqv",
 0,     OP_BT_BA_BB,           19<<26 | 129<<1,                         "crandc",
 0,     OP_BT_BA_BB,           19<<26 | 417<<1,                         "crorc",
 0,     OP_BF_BFA,             19<<26 | 0<<1,                           "mcrf",
 
+/* extended mnemonics for bc, bcctr, bclr */
+0,     OP_BH,       19<<26 | 20<<21 | 528<<1 | 0<<0,            "bctr",
+0,     OP_BH,       19<<26 | 20<<21 | 528<<1 | 1<<0,            "bctrl",
+0,     OP_BDL,      16<<26 | 16<<21 | 0<<1 | 0<<0,              "bdnz",
+0,     OP_BDA,      16<<26 | 16<<21 | 1<<1 | 0<<0,              "bdnza",
+0,     OP_BH,       19<<26 | 16<<21 | 16<<1 | 0<<0,             "bdnzlr",
+0,     OP_BDL,      16<<26 | 16<<21 | 0<<1 | 1<<0,              "bdnzl",
+0,     OP_BDA,      16<<26 | 16<<21 | 1<<1 | 1<<0,              "bdnzla",
+0,     OP_BH,       19<<26 | 16<<21 | 16<<1 | 1<<0,             "bdnzlrl",
+0,     OP_BI_BDL,   16<<26 | 0<<21 | 0<<1 | 0<<0,               "bdnzf",
+0,     OP_BI_BDA,   16<<26 | 0<<21 | 1<<1 | 0<<0,               "bdnzfa",
+0,     OP_BI_BH,    19<<26 | 0<<21 | 16<<1 | 0<<0,              "bdnzflr",
+0,     OP_BI_BDL,   16<<26 | 0<<21 | 0<<1 | 1<<0,               "bdnzfl",
+0,     OP_BI_BDA,   16<<26 | 0<<21 | 1<<1 | 1<<0,               "bdnzfla",
+0,     OP_BI_BH,    19<<26 | 0<<21 | 16<<1 | 1<<0,              "bdnzflrl",
+0,     OP_BI_BDL,   16<<26 | 8<<21 | 0<<1 | 0<<0,               "bdnzt",
+0,     OP_BI_BDA,   16<<26 | 8<<21 | 1<<1 | 0<<0,               "bdnzta",
+0,     OP_BI_BH,    19<<26 | 8<<21 | 16<<1 | 0<<0,              "bdnztlr",
+0,     OP_BI_BDL,   16<<26 | 8<<21 | 0<<1 | 1<<0,               "bdnztl",
+0,     OP_BI_BDA,   16<<26 | 8<<21 | 1<<1 | 1<<0,               "bdnztla",
+0,     OP_BI_BH,    19<<26 | 8<<21 | 16<<1 | 1<<0,              "bdnztlrl",
+0,     OP_BDL,      16<<26 | 18<<21 | 0<<1 | 0<<0,              "bdz",
+0,     OP_BDA,      16<<26 | 18<<21 | 1<<1 | 0<<0,              "bdza",
+0,     OP_BH,       19<<26 | 18<<21 | 16<<1 | 0<<0,             "bdzlr",
+0,     OP_BDL,      16<<26 | 18<<21 | 0<<1 | 1<<0,              "bdzl",
+0,     OP_BDA,      16<<26 | 18<<21 | 1<<1 | 1<<0,              "bdzla",
+0,     OP_BH,       19<<26 | 18<<21 | 16<<1 | 1<<0,             "bdzlrl",
+0,     OP_BI_BDL,   16<<26 | 2<<21 | 0<<1 | 0<<0,               "bdzf",
+0,     OP_BI_BDA,   16<<26 | 2<<21 | 1<<1 | 0<<0,               "bdzfa",
+0,     OP_BI_BH,    19<<26 | 2<<21 | 16<<1 | 0<<0,              "bdzflr",
+0,     OP_BI_BDL,   16<<26 | 2<<21 | 0<<1 | 1<<0,               "bdzfl",
+0,     OP_BI_BDA,   16<<26 | 2<<21 | 1<<1 | 1<<0,               "bdzfla",
+0,     OP_BI_BH,    19<<26 | 2<<21 | 16<<1 | 1<<0,              "bdzflrl",
+0,     OP_BI_BDL,   16<<26 | 10<<21 | 0<<1 | 0<<0,              "bdzt",
+0,     OP_BI_BDA,   16<<26 | 10<<21 | 1<<1 | 0<<0,              "bdzta",
+0,     OP_BI_BH,    19<<26 | 10<<21 | 16<<1 | 0<<0,             "bdztlr",
+0,     OP_BI_BDL,   16<<26 | 10<<21 | 0<<1 | 1<<0,              "bdztl",
+0,     OP_BI_BDA,   16<<26 | 10<<21 | 1<<1 | 1<<0,              "bdztla",
+0,     OP_BI_BH,    19<<26 | 10<<21 | 16<<1 | 1<<0,             "bdztlrl",
+0,     OP_BI_BDL,   16<<26 | 4<<21 | 0<<1 | 0<<0,               "bf",
+0,     OP_BI_BDA,   16<<26 | 4<<21 | 1<<1 | 0<<0,               "bfa",
+0,     OP_BI_BH,    19<<26 | 4<<21 | 528<<1 | 0<<0,             "bfctr",
+0,     OP_BI_BH,    19<<26 | 4<<21 | 528<<1 | 1<<0,             "bfctrl",
+0,     OP_BI_BDL,   16<<26 | 4<<21 | 0<<1 | 1<<0,               "bfl",
+0,     OP_BI_BDA,   16<<26 | 4<<21 | 0<<1 | 1<<0,               "bfla",
+0,     OP_BI_BH,    19<<26 | 4<<21 | 16<<1 | 0<<0,              "bflr",
+0,     OP_BI_BH,    19<<26 | 4<<21 | 16<<1 | 1<<0,              "bflrl",
+0,     OP_BH,       19<<26 | 20<<21 | 16<<1 | 0<<0,             "blr",
+0,     OP_BH,       19<<26 | 20<<21 | 16<<1 | 1<<0,             "blrl",
+0,     OP_BI_BDL,   16<<26 | 12<<21 | 0<<1 | 0<<0,              "bt",
+0,     OP_BI_BDA,   16<<26 | 12<<21 | 1<<1 | 0<<0,              "bta",
+0,     OP_BI_BH,    19<<26 | 12<<21 | 528<<1 | 0<<0,            "btctr",
+0,     OP_BI_BH,    19<<26 | 12<<21 | 528<<1 | 1<<0,            "btctrl",
+0,     OP_BI_BDL,   16<<26 | 12<<21 | 0<<1 | 1<<0,              "btl",
+0,     OP_BI_BDA,   16<<26 | 12<<21 | 0<<1 | 1<<0,              "btla",
+0,     OP_BI_BH,    19<<26 | 12<<21 | 16<<1 | 0<<0,             "btlr",
+0,     OP_BI_BH,    19<<26 | 12<<21 | 16<<1 | 1<<0,             "btlrl",
+
+/* extended m with condition in BI */
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 2<<16 | 0<<1 | 0<<0,     "beq",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 2<<16 | 1<<1 | 0<<0,     "beqa",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 2<<16 | 528<<1 | 0<<0,   "beqctr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 2<<16 | 528<<1 | 1<<0,   "beqctrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 2<<16 | 0<<1 | 1<<0,     "beql",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 2<<16 | 1<<1 | 1<<0,     "beqla",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 2<<16 | 16<<1 | 0<<0,    "beqlr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 2<<16 | 16<<1 | 1<<0,    "beqlrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 0<<16 | 0<<1 | 0<<0,      "bge",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 0<<16 | 1<<1 | 0<<0,      "bgea",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 528<<1 | 0<<0,    "bgectr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 528<<1 | 1<<0,    "bgectrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 0<<16 | 0<<1 | 1<<0,      "bgel",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 0<<16 | 1<<1 | 1<<0,      "bgela",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 16<<1 | 0<<0,     "bgelr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 16<<1 | 1<<0,     "bgelrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 1<<16 | 0<<1 | 0<<0,     "bgt",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 1<<16 | 1<<1 | 0<<0,     "bgta",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 1<<16 | 528<<1 | 0<<0,   "bgtctr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 1<<16 | 528<<1 | 1<<0,   "bgtctrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 1<<16 | 0<<1 | 1<<0,     "bgtl",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 1<<16 | 1<<1 | 1<<0,     "bgtla",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 1<<16 | 16<<1 | 0<<0,    "bgtlr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 1<<16 | 16<<1 | 1<<0,    "bgtlrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 1<<16 | 0<<1 | 0<<0,      "ble",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 1<<16 | 1<<1 | 0<<0,      "blea",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 528<<1 | 0<<0,    "blectr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 528<<1 | 1<<0,    "blectrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 1<<16 | 0<<1 | 1<<0,      "blel",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 1<<16 | 1<<1 | 1<<0,      "blela",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 16<<1 | 0<<0,     "blelr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 16<<1 | 1<<0,     "blelrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 0<<16 | 0<<1 | 0<<0,     "blt",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 0<<16 | 1<<1 | 0<<0,     "blta",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 0<<16 | 528<<1 | 0<<0,   "bltctr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 0<<16 | 528<<1 | 1<<0,   "bltctrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 0<<16 | 0<<1 | 1<<0,     "bltl",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 0<<16 | 1<<1 | 1<<0,     "bltla",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 0<<16 | 16<<1 | 0<<0,    "bltlr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 0<<16 | 16<<1 | 1<<0,    "bltlrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 2<<16 | 0<<1 | 0<<0,      "bne",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 2<<16 | 1<<1 | 0<<0,      "bnea",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 2<<16 | 528<<1 | 0<<0,    "bnectr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 2<<16 | 528<<1 | 1<<0,    "bnectrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 2<<16 | 0<<1 | 1<<0,      "bnel",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 2<<16 | 1<<1 | 1<<0,      "bnela",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 2<<16 | 16<<1 | 0<<0,     "bnelr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 2<<16 | 16<<1 | 1<<0,     "bnelrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 1<<16 | 0<<1 | 0<<0,      "bng",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 1<<16 | 1<<1 | 0<<0,      "bnga",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 528<<1 | 0<<0,    "bngctr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 528<<1 | 1<<0,    "bngctrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 1<<16 | 0<<1 | 1<<0,      "bngl",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 1<<16 | 1<<1 | 1<<0,      "bngla",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 16<<1 | 0<<0,     "bnglr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 1<<16 | 16<<1 | 1<<0,     "bnglrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 0<<16 | 0<<1 | 0<<0,      "bnl",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 0<<16 | 1<<1 | 0<<0,      "bnla",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 528<<1 | 0<<0,    "bnlctr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 528<<1 | 1<<0,    "bnlctrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 0<<16 | 0<<1 | 1<<0,      "bnll",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 0<<16 | 1<<1 | 1<<0,      "bnlla",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 16<<1 | 0<<0,     "bnllr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 0<<16 | 16<<1 | 1<<0,     "bnllrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 3<<16 | 0<<1 | 0<<0,      "bns",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 3<<16 | 1<<1 | 0<<0,      "bnsa",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 528<<1 | 0<<0,    "bnsctr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 528<<1 | 1<<0,    "bnsctrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 3<<16 | 0<<1 | 1<<0,      "bnsl",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 3<<16 | 1<<1 | 1<<0,      "bnsla",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 16<<1 | 0<<0,     "bnslr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 16<<1 | 1<<0,     "bnslrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 3<<16 | 0<<1 | 0<<0,      "bnu",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 3<<16 | 1<<1 | 0<<0,      "bnua",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 528<<1 | 0<<0,    "bnuctr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 528<<1 | 1<<0,    "bnuctrl",
+0,     OP_BICR_BDL,  16<<26 | 4<<21 | 3<<16 | 0<<1 | 1<<0,      "bnul",
+0,     OP_BICR_BDA,  16<<26 | 4<<21 | 3<<16 | 1<<1 | 1<<0,      "bnula",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 16<<1 | 0<<0,     "bnulr",
+0,     OP_BICR_BH,   19<<26 | 4<<21 | 3<<16 | 16<<1 | 1<<0,     "bnulrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 3<<16 | 0<<1 | 0<<0,     "bso",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 3<<16 | 1<<1 | 0<<0,     "bsoa",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 528<<1 | 0<<0,   "bsoctr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 528<<1 | 1<<0,   "bsoctrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 3<<16 | 0<<1 | 1<<0,     "bsol",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 3<<16 | 1<<1 | 1<<0,     "bsola",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 16<<1 | 0<<0,    "bsolr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 16<<1 | 1<<0,    "bsolrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 3<<16 | 0<<1 | 0<<0,     "bun",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 3<<16 | 1<<1 | 0<<0,     "buna",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 528<<1 | 0<<0,   "bunctr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 528<<1 | 1<<0,   "bunctrl",
+0,     OP_BICR_BDL,  16<<26 | 12<<21 | 3<<16 | 0<<1 | 1<<0,     "bunl",
+0,     OP_BICR_BDA,  16<<26 | 12<<21 | 3<<16 | 1<<1 | 1<<0,     "bunla",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 16<<1 | 0<<0,    "bunlr",
+0,     OP_BICR_BH,   19<<26 | 12<<21 | 3<<16 | 16<<1 | 1<<0,    "bunlrl",
+
+/* extended m for cr logic */
+0,     OP_BT_BT_BT,  19<<26 | 289<<1,                           "crset",
+0,     OP_BT_BT_BT,  19<<26 | 193<<1,                           "crclr",
+0,     OP_BT_BA_BA,  19<<26 | 449<<1,                           "crmove",
+0,     OP_BT_BA_BA,  19<<26 | 33<<1,                            "crnot",
+
 /* Fixed point instructions (page 29) */
 
 0,     OP_RT_RA_D,            34<<26,                                  "lbz",
@@ -196,6 +358,10 @@
 0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 40<<1,                  "subfo",
 0,     OP_RT_RA_SI_addic,     12<<26,                                  "addic", /* special case C */
 0,     OP_RT_RA_SI,           8<<26,                                   "subfic",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 10<<1,                  "addc",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 10<<1,                  "addco",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 8<<1,                   "subfc",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 8<<1,                   "subfco",
 0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 138<<1,                 "adde",
 0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 138<<1,                 "addeo",
 0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 136<<1,                 "subfe",
@@ -211,6 +377,20 @@
 0,     OP_RT_RA_C,            31<<26 | 0<<10 | 104<<1,                 "neg",
 0,     OP_RT_RA_C,            31<<26 | 1<<10 | 104<<1,                 "nego",
 
+/* extended m for addition */
+0,     OP_RT_RA_D,            14<<26,                       "la",
+0,     OP_RT_SI,              14<<26 | 0<<16,               "li",
+0,     OP_RT_SI,              15<<26 | 0<<16,               "lis",
+
+/* extended m for subtraction */
+0,     OP_RT_RB_RA_C,         31<<26 | 0<<10 | 40<<1,       "sub",
+0,     OP_RT_RB_RA_C,         31<<26 | 1<<10 | 40<<1,       "subo",
+0,     OP_RT_RB_RA_C,         31<<26 | 0<<10 | 8<<1,        "subc",
+0,     OP_RT_RB_RA_C,         31<<26 | 0<<10 | 8<<1,        "subco",
+0,     OP_RT_RA_SI_subi,      14<<26,                       "subi",
+0,     OP_RT_RA_SI_subi,      15<<26,                       "subis",
+0,     OP_RT_RA_SI_subic,     12<<26,                       "subic",
+
 /* page 54 */
 0,     OP_RT_RA_SI,           7<<26,                                   "mulli",
 0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 233<<1,                 "mulld",
@@ -238,53 +418,159 @@
 0,     OP_BF_L_RA_UI,         10<<26,                                  "cmpli",
 0,     OP_BF_L_RA_RB,         31<<26 | 32<<1,                          "cmpl",
 
+/* extended m for comparison */
+0,     OP_BF_RA_SI,           11<<26 | 1<<21,               "cmpdi",
+0,     OP_BF_RA_RB,           31<<26 | 1<<21 | 0<<1,        "cmpd",
+0,     OP_BF_RA_UI,           10<<26 | 1<<21,               "cmpldi",
+0,     OP_BF_RA_RB,           31<<26 | 1<<21 | 32<<1,       "cmpld",
+0,     OP_BF_RA_SI,           11<<26 | 0<<21,               "cmpwi",
+0,     OP_BF_RA_RB,           31<<26 | 0<<21 | 0<<1,        "cmpw",
+0,     OP_BF_RA_UI,           10<<26 | 0<<21,               "cmplwi",
+0,     OP_BF_RA_RB,           31<<26 | 0<<21 | 32<<1,       "cmplw",
+
 /* page 60 */
 0,     OP_TO_RA_SI,           2<<26,                                   "tdi",
 0,     OP_TO_RA_SI,           3<<26,                                   "twi",
 0,     OP_TO_RA_RB,           31<<26 | 68<<1,                          "td",
 0,     OP_TO_RA_RB,           31<<26 | 4<<1,                           "tw",
 
+/* extended m for traps */
+0,     OP_TOX_RA_RB,          31<<26 | 4<<21 | 68<<1,       "tdeq",
+0,     OP_TOX_RA_SI,          2<<26 | 4<<21,                "tdeqi",
+0,     OP_TOX_RA_RB,          31<<26 | 12<<21 | 68<<1,      "tdge",
+0,     OP_TOX_RA_SI,          2<<26 | 12<<21,               "tdgei",
+0,     OP_TOX_RA_RB,          31<<26 | 8<<21 | 68<<1,       "tdgt",
+0,     OP_TOX_RA_SI,          2<<26 | 8<<21,                "tdgti",
+0,     OP_TOX_RA_RB,          31<<26 | 20<<21 | 68<<1,      "tdle",
+0,     OP_TOX_RA_SI,          2<<26 | 20<<21,               "tdlei",
+0,     OP_TOX_RA_RB,          31<<26 | 5<<21 | 68<<1,       "tdlge",
+0,     OP_TOX_RA_SI,          2<<26 | 5<<21,                "tdlgei",
+0,     OP_TOX_RA_RB,          31<<26 | 1<<21 | 68<<1,       "tdlgt",
+0,     OP_TOX_RA_SI,          2<<26 | 1<<21,                "tdlgti",
+0,     OP_TOX_RA_RB,          31<<26 | 6<<21 | 68<<1,       "tdlle",
+0,     OP_TOX_RA_SI,          2<<26 | 6<<21,                "tdllei",
+0,     OP_TOX_RA_RB,          31<<26 | 2<<21 | 68<<1,       "tdllt",
+0,     OP_TOX_RA_SI,          2<<26 | 2<<21,                "tdllti",
+0,     OP_TOX_RA_RB,          31<<26 | 6<<21 | 68<<1,       "tdlng",
+0,     OP_TOX_RA_SI,          2<<26 | 6<<21,                "tdlngi",
+0,     OP_TOX_RA_RB,          31<<26 | 5<<21 | 68<<1,       "tdlnl",
+0,     OP_TOX_RA_SI,          2<<26 | 5<<21,                "tdlnli",
+0,     OP_TOX_RA_RB,          31<<26 | 16<<21 | 68<<1,      "tdlt",
+0,     OP_TOX_RA_SI,          2<<26 | 16<<21,               "tdlti",
+0,     OP_TOX_RA_RB,          31<<26 | 24<<21 | 68<<1,      "tdne",
+0,     OP_TOX_RA_SI,          2<<26 | 24<<21,               "tdnei",
+0,     OP_TOX_RA_RB,          31<<26 | 20<<21 | 68<<1,      "tdng",
+0,     OP_TOX_RA_SI,          2<<26 | 20<<21,               "tdngi",
+0,     OP_TOX_RA_RB,          31<<26 | 12<<21 | 68<<1,      "tdnl",
+0,     OP_TOX_RA_SI,          2<<26 | 12<<21,               "tdnli",
+0,     OP_TOX_RA_RB,          31<<26 | 31<<21 | 68<<1,      "tdu",
+0,     OP_TOX_RA_SI,          2<<26 | 31<<21,               "tdui",
+0,     OP,                    31<<26 | 31<<21 | 4<<1,       "trap",
+0,     OP_TOX_RA_RB,          31<<26 | 4<<21 | 4<<1,        "tweq",
+0,     OP_TOX_RA_SI,          3<<26 | 4<<21,                "tweqi",
+0,     OP_TOX_RA_RB,          31<<26 | 12<<21 | 4<<1,       "twge",
+0,     OP_TOX_RA_SI,          3<<26 | 12<<21,               "twgei",
+0,     OP_TOX_RA_RB,          31<<26 | 8<<21 | 4<<1,        "twgt",
+0,     OP_TOX_RA_SI,          3<<26 | 8<<21,                "twgti",
+0,     OP_TOX_RA_RB,          31<<26 | 20<<21 | 4<<1,       "twle",
+0,     OP_TOX_RA_SI,          3<<26 | 20<<21,               "twlei",
+0,     OP_TOX_RA_RB,          31<<26 | 5<<21 | 4<<1,        "twlge",
+0,     OP_TOX_RA_SI,          3<<26 | 5<<21,                "twlgei",
+0,     OP_TOX_RA_RB,          31<<26 | 1<<21 | 4<<1,        "twlgt",
+0,     OP_TOX_RA_SI,          3<<26 | 1<<21,                "twlgti",
+0,     OP_TOX_RA_RB,          31<<26 | 6<<21 | 4<<1,        "twlle",
+0,     OP_TOX_RA_SI,          3<<26 | 6<<21,                "twllei",
+0,     OP_TOX_RA_RB,          31<<26 | 2<<21 | 4<<1,        "twllt",
+0,     OP_TOX_RA_SI,          3<<26 | 2<<21,                "twllti",
+0,     OP_TOX_RA_RB,          31<<26 | 6<<21 | 4<<1,        "twlng",
+0,     OP_TOX_RA_SI,          3<<26 | 6<<21,                "twlngi",
+0,     OP_TOX_RA_RB,          31<<26 | 5<<21 | 4<<1,        "twlnl",
+0,     OP_TOX_RA_SI,          3<<26 | 5<<21,                "twlnli",
+0,     OP_TOX_RA_RB,          31<<26 | 16<<21 | 4<<1,       "twlt",
+0,     OP_TOX_RA_SI,          3<<26 | 16<<21,               "twlti",
+0,     OP_TOX_RA_RB,          31<<26 | 24<<21 | 4<<1,       "twne",
+0,     OP_TOX_RA_SI,          3<<26 | 24<<21,               "twnei",
+0,     OP_TOX_RA_RB,          31<<26 | 20<<21 | 4<<1,       "twng",
+0,     OP_TOX_RA_SI,          3<<26 | 20<<21,               "twngi",
+0,     OP_TOX_RA_RB,          31<<26 | 12<<21 | 4<<1,       "twnl",
+0,     OP_TOX_RA_SI,          3<<26 | 12<<21,               "twnli",
+0,     OP_TOX_RA_RB,          31<<26 | 31<<21 | 4<<1,       "twu",
+0,     OP_TOX_RA_SI,          3<<26 | 31<<21,               "twui",
+
 /* page 62 */
-0,     OP_RS_RA_UI_CC,        28<<26,                                  "andi", /* C compulsory */
-0,     OP_RS_RA_UI_CC,        29<<26,                                  "andis", /* C compulsory */
-0,     OP_RS_RA_UI,           24<<26,                                  "ori",
-0,     OP_RS_RA_UI,           25<<26,                                  "oris",
-0,     OP_RS_RA_UI,           26<<26,                                  "xori",
-0,     OP_RS_RA_UI,           27<<26,                                  "xoris",
-0,     OP_RS_RA_RB_C,         31<<26 | 28<<1,                          "and",
-0,     OP_RS_RA_RB_C,         31<<26 | 444<<1,                         "or",
-0,     OP_RS_RA_RB_C,         31<<26 | 316<<1,                         "xor",
-0,     OP_RS_RA_RB_C,         31<<26 | 476<<1,                         "nand",
-0,     OP_RS_RA_RB_C,         31<<26 | 124<<1,                         "nor",
-0,     OP_RS_RA_RB_C,         31<<26 | 284<<1,                         "eqv",
-0,     OP_RS_RA_RB_C,         31<<26 | 60<<1,                          "andc",
-0,     OP_RS_RA_RB_C,         31<<26 | 412<<1,                         "orc",
-0,     OP_RS_RA_C,            31<<26 | 954<<1,                         "extsb",
-0,     OP_RS_RA_C,            31<<26 | 922<<1,                         "extsh",
-0,     OP_RS_RA_C,            31<<26 | 986<<1,                         "extsw",
-0,     OP_RS_RA_C,            31<<26 | 58<<1,                          "cntlzd",
-0,     OP_RS_RA_C,            31<<26 | 26<<1,                          "cntlzw",
+0,     OP_RA_RS_UI_CC,        28<<26,                                  "andi", /* C compulsory */
+0,     OP_RA_RS_UI_CC,        29<<26,                                  "andis", /* C compulsory */
+0,     OP_RA_RS_UI,           24<<26,                                  "ori",
+0,     OP_RA_RS_UI,           25<<26,                                  "oris",
+0,     OP_RA_RS_UI,           26<<26,                                  "xori",
+0,     OP_RA_RS_UI,           27<<26,                                  "xoris",
+0,     OP_RA_RS_RB_C,         31<<26 | 28<<1,                          "and",
+0,     OP_RA_RS_RB_C,         31<<26 | 444<<1,                         "or",
+0,     OP_RA_RS_RB_C,         31<<26 | 316<<1,                         "xor",
+0,     OP_RA_RS_RB_C,         31<<26 | 476<<1,                         "nand",
+0,     OP_RA_RS_RB_C,         31<<26 | 124<<1,                         "nor",
+0,     OP_RA_RS_RB_C,         31<<26 | 284<<1,                         "eqv",
+0,     OP_RA_RS_RB_C,         31<<26 | 60<<1,                          "andc",
+0,     OP_RA_RS_RB_C,         31<<26 | 412<<1,                         "orc",
+0,     OP_RA_RS_C,            31<<26 | 954<<1,                         "extsb",
+0,     OP_RA_RS_C,            31<<26 | 922<<1,                         "extsh",
+0,     OP_RA_RS_C,            31<<26 | 986<<1,                         "extsw",
+0,     OP_RA_RS_C,            31<<26 | 58<<1,                          "cntlzd",
+0,     OP_RA_RS_C,            31<<26 | 26<<1,                          "cntlzw",
+
+/* extended m using logic */
+0,     OP_RS_RA_RA_C,         31<<26 | 444<<1,              "mr",
+0,     OP,                    24<<26,                       "nop",
+0,     OP_RS_RA_RA_C,         31<<26 | 124<<1,              "not",
+0,     OP,                    26<<26,                       "xnop",
 
 /* page 69 */
-0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 0<<2,                           "rldicl",
-0,     OP_RS_RA_SH_ME6_SH_C,  30<<26 | 1<<2,                           "rldicr",
-0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 2<<2,                           "rldic",
-0,     OP_RS_RA_SH_MB5_ME5_C, 21<<26,                                  "rlwinm",
-0,     OP_RS_RA_RB_MB6_C,     30<<26 | 8<<1,                           "rldcl", 
-0,     OP_RS_RA_RB_ME6_C,     30<<26 | 9<<1,                           "rldcr",
-0,     OP_RS_RA_RB_MB5_ME5_C, 23<<26,                                  "rlwnm",
-0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 3<<2,                           "rldimi",
-0,     OP_RS_RA_SH_MB5_ME5_C, 20<<26,                                  "rlwimi",
+0,     OP_RA_RS_SH6_MB6_C,     30<<26 | 0<<2,               "rldicl",
+0,     OP_RA_RS_SH6_MB6_C,     30<<26 | 1<<2,               "rldicr",
+0,     OP_RA_RS_SH6_MB6_C,     30<<26 | 2<<2,               "rldic",
+0,     OP_RA_RS_SH5_MB5_ME5_C, 21<<26,                      "rlwinm",
+0,     OP_RA_RS_RB_MB6_C,      30<<26 | 8<<1,               "rldcl",
+0,     OP_RA_RS_RB_MB6_C,      30<<26 | 9<<1,               "rldcr",
+0,     OP_RA_RS_RB_MB5_ME5_C,  23<<26,                      "rlwnm",
+0,     OP_RA_RS_SH6_MB6_C,     30<<26 | 3<<2,               "rldimi",
+0,     OP_RA_RS_SH5_MB5_ME5_C, 20<<26,                      "rlwimi",
+
+/* extended m for doubleword rotation */
+0,     OP_clrlsldi,           30<<26 | 2<<2,                "clrlsldi",
+0,     OP_clrldi,             30<<26 | 0<<2,                "clrldi",
+0,     OP_clrrdi,             30<<26 | 1<<2,                "clrrdi",
+0,     OP_extldi,             30<<26 | 0<<2,                "extldi",
+0,     OP_extrdi,             30<<26 | 1<<2,                "extrdi",
+0,     OP_insrdi,             30<<26 | 3<<2,                "insrdi",
+0,     OP_RA_RS_RB_C,         30<<26 | MB6(0) | 8<<1,       "rotld",
+0,     OP_RA_RS_SH6_C,        30<<26 | MB6(0) | 0<<2,       "rotldi",
+0,     OP_rotrdi,             30<<26 | 0<<2,                "rotrdi",
+0,     OP_sldi,               30<<26 | 1<<2,                "sldi",
+0,     OP_srdi,               30<<26 | 0<<2,                "srdi",
+
+/* extended m for word rotation */
+0,     OP_clrlslwi,           21<<26,                       "clrlslwi",
+0,     OP_clrlwi,             21<<26,                       "clrlwi",
+0,     OP_clrrwi,             21<<26,                       "clrrwi",
+0,     OP_extlwi,             21<<26,                       "extlwi",
+0,     OP_extrwi,             21<<26,                       "extrwi",
+0,     OP_inslwi,             20<<26,                       "inslwi",
+0,     OP_insrwi,             20<<26,                       "insrwi",
+0,     OP_RA_RS_RB_C,         23<<26 | 0<<6 | 31<<1,        "rotlw",
+0,     OP_RA_RS_SH5_C,        21<<26 | 0<<6 | 31<<1,        "rotlwi",
+0,     OP_rotrwi,             21<<26,                       "rotrwi",
+0,     OP_slwi,               21<<26,                       "slwi",
+0,     OP_srwi,               21<<26,                       "srwi",
 
 /* page 74 */
-0,     OP_RS_RA_RB_C,         31<<26 | 27<<1,                          "sld",
-0,     OP_RS_RA_RB_C,         31<<26 | 24<<1,                          "slw",
-0,     OP_RS_RA_RB_C,         31<<26 | 539<<1,                         "srd",
-0,     OP_RS_RA_RB_C,         31<<26 | 536<<1,                         "srw",
-0,     OP_RS_RA_SH6_C,        31<<26 | 413<<2,                         "sradi",
-0,     OP_RS_RA_SH5_C,        31<<26 | 824<<1,                         "srawi",
-0,     OP_RS_RA_RB_C,         31<<26 | 794<<1,                         "srad",
-0,     OP_RS_RA_RB_C,         31<<26 | 792<<1,                         "sraw",
+0,     OP_RA_RS_RB_C,         31<<26 | 27<<1,               "sld",
+0,     OP_RA_RS_RB_C,         31<<26 | 24<<1,               "slw",
+0,     OP_RA_RS_RB_C,         31<<26 | 539<<1,              "srd",
+0,     OP_RA_RS_RB_C,         31<<26 | 536<<1,              "srw",
+0,     OP_RA_RS_SH6_C,        31<<26 | 413<<2,              "sradi",
+0,     OP_RA_RS_SH5_C,        31<<26 | 824<<1,              "srawi",
+0,     OP_RA_RS_RB_C,         31<<26 | 794<<1,              "srad",
+0,     OP_RA_RS_RB_C,         31<<26 | 792<<1,              "sraw",
 
 /* page 78 */
 0,     OP_RS_SPR,             31<<26 | 467<<1,                         "mtspr",
@@ -292,6 +578,14 @@
 0,     OP_RS_FXM,             31<<26 | 0<<21 | 144<<1,                 "mtcrf",
 0,     OP_RT,                 31<<26 | 0<<21 | 19<<1,                  "mfcr",
 
+/* extended m for special purpose registers */
+0,     OP_RT,       31<<26 | 9<<16 | 0<<11 | 339<<1,        "mfctr",
+0,     OP_RT,       31<<26 | 8<<16 | 0<<11 | 339<<1,        "mflr",
+0,     OP_RT,       31<<26 | 1<<16 | 0<<11 | 339<<1,        "mfxer",
+0,     OP_RT,       31<<26 | 9<<16 | 0<<11 | 467<<1,        "mtctr",
+0,     OP_RT,       31<<26 | 8<<16 | 0<<11 | 467<<1,        "mtlr",
+0,     OP_RT,       31<<26 | 1<<16 | 0<<11 | 467<<1,        "mtxer",
+
 /* Floating point instructions (page 83) */
 
 0,     OP_FRT_RA_D,           48<<26,                                  "lfs",
diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c
index 3f79ca86c..8a0cca9de 100644
--- a/mach/powerpc/as/mach4.c
+++ b/mach/powerpc/as/mach4.c
@@ -4,69 +4,212 @@
  */
 
 operation
-	: OP_BF_BFA            CR ',' CR                  { emit4($1 | ($2<<23) | ($4<<18)); }
+	: OP                                              { emit4($1); }
+	| OP_BDA               bda                        { emit4($1 | $2); }
+	| OP_BDL               bdl                        { emit4($1 | $2); }
+	| OP_BF_BFA            CR ',' CR                  { emit4($1 | ($2<<23) | ($4<<18)); }
 	| OP_BF_FRA_FRB        CR ',' FPR ',' FPR         { emit4($1 | ($2<<23) | ($4<<16) | ($6<<11)); }
 	| OP_BF_L_RA_RB        CR ',' u1 ',' GPR ',' GPR  { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | ($8<<11)); }
-	| OP_BF_L_RA_SI        CR ',' u1 ',' GPR ',' e16  { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
-	| OP_BF_L_RA_UI        CR ',' u1 ',' GPR ',' e16  { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+	| OP_BF_L_RA_SI        CR ',' u1 ',' GPR ',' e16  { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+	| OP_BF_L_RA_UI        CR ',' u1 ',' GPR ',' e16  { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+	| OP_BF_RA_RB          cr_opt GPR ',' GPR         { emit4($1 | ($2<<23) | ($3<<16) | ($5<<11)); }
+	| OP_BF_RA_SI          cr_opt GPR ',' e16         { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
+	| OP_BF_RA_UI          cr_opt GPR ',' e16         { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
 	| OP_BF_U_C            c CR ',' u4                { emit4($1 | $2 | ($3<<23) | ($5<<12)); }
+	| OP_BH                                           { emit4($1); }
+	| OP_BH                u2                         { emit4($1 | ($2<<11)); }
+	| OP_BI_BDA            u5 ',' bda                 { emit4($1 | ($2<<16) | $4); }
+	| OP_BI_BDL            u5 ',' bdl                 { emit4($1 | ($2<<16) | $4); }
+	| OP_BI_BH             u5 opt_bh                  { emit4($1 | ($2<<16) | $3); }
+	| OP_BICR_BDA          cr_opt bda                 { emit4($1 | ($2<<18) | $3); }
+	| OP_BICR_BDL          cr_opt bdl                 { emit4($1 | ($2<<18) | $3); }
+	| OP_BICR_BH                                      { emit4($1); }
+	| OP_BICR_BH           CR opt_bh                  { emit4($1 | ($2<<18) | $3); }
 	| OP_BO_BI_BDA         u5 ',' u5 ',' bda          { emit4($1 | ($2<<21) | ($4<<16) | $6); }
 	| OP_BO_BI_BDL         u5 ',' u5 ',' bdl          { emit4($1 | ($2<<21) | ($4<<16) | $6); }
-	| OP_BO_BI_BH          u5 ',' u5 ',' u2           { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_BO_BI_BH          u5 ',' u5 opt_bh           { emit4($1 | ($2<<21) | ($4<<16) | $5); }
+	| OP_BT_BA_BA          u5 ',' u5                  { emit4($1 | ($2<<21) | ($4<<16) | ($4<<11)); }
 	| OP_BT_BA_BB          u5 ',' u5 ',' u5           { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_BT_BT_BT          u5                         { emit4($1 | ($2<<21) | ($2<<16) | ($2<<11)); }
 	| OP_BT_C              c u5                       { emit4($1 | $2 | ($3<<21)); }
 	| OP_FLM_FRB_C         c u8 ',' FPR               { emit4($1 | $2 | ($3<<17) | ($5<<11)); }
-	| OP_FRS_RA_D          FPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_FRS_RA_D          FPR ',' e16 '(' GPR ')'    { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
 	| OP_FRS_RA_RB         FPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
 	| OP_FRT_FRA_FRB_C     c FPR ',' FPR ',' FPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
-	| OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } 
+	| OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); }
 	| OP_FRT_FRA_FRC_C     c FPR ',' FPR ',' FPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); }
-	| OP_FRT_FRB_C         c FPR ',' FPR              { emit4($1 | $2 | ($3<<21) | ($5<<11)); } 
-	| OP_FRT_RA_D          FPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_FRT_FRB_C         c FPR ',' FPR              { emit4($1 | $2 | ($3<<21) | ($5<<11)); }
+	| OP_FRT_RA_D          FPR ',' e16 '(' GPR ')'    { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
 	| OP_FRT_RA_RB         FPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
 	| OP_FRT_C             c FPR                      { emit4($1 | $2 | ($3<<21)); }
+	| OP_RA_RS_C           c GPR ',' GPR              { emit4($1 | $2 | ($5<<21) | ($3<<16)); }
+	| OP_RA_RS_RB_C        c GPR ',' GPR ',' GPR
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
+	| OP_RA_RS_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) |
+		($9<<6) | ($11<<1)); }
+	| OP_RA_RS_RB_MB6_C    c GPR ',' GPR ',' GPR ',' u6
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | MB6($9)); }
+	| OP_RA_RS_SH5_C       c GPR ',' GPR ',' u5
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
+	| OP_RA_RS_SH5_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		($7<<11) | ($9<<6) | ($11<<1)); }
+	| OP_RA_RS_SH6_C       c GPR ',' GPR ',' u6
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7)); }
+	| OP_RA_RS_SH6_MB6_C   c GPR ',' GPR ',' u6 ',' u6
+	{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6($9)); }
+	| OP_RA_RS_UI          GPR ',' GPR ',' e16        { emit_hl($1 | ($4<<21) | ($2<<16) | $6); }
+	| OP_RA_RS_UI_CC       C GPR ',' GPR ',' e16      { emit_hl($1 | ($5<<21) | ($3<<16) | $7); }
 	| OP_RT                GPR                        { emit4($1 | ($2<<21)); }
 	| OP_RT_RA_C           c GPR ',' GPR              { emit4($1 | $2 | ($3<<21) | ($5<<16)); }
-	| OP_RT_RA_D           GPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
-	| OP_RT_RA_DS          GPR ',' ds '(' GPR ')'     { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RT_RA_D           GPR ',' e16 '(' GPR ')'    { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RT_RA_DS          GPR ',' ds '(' GPR ')'     { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
 	| OP_RT_RA_NB          GPR ',' GPR ',' nb         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
 	| OP_RT_RA_RB          GPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
-    | OP_RT_RA_RB_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
-	| OP_RT_RA_SI          GPR ',' GPR ',' e16        { emit4($1 | ($2<<21) | ($4<<16) | $6); }
-	| OP_RT_RA_SI_addic    c GPR ',' GPR ',' e16      { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
-	| OP_RT_SPR            GPR ',' SPR                { emit4($1 | ($2<<21) | ($4<<11)); }
+	| OP_RT_RA_RB_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
+	| OP_RT_RA_SI          GPR ',' GPR ',' e16        { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_RT_RA_SI_addic    c GPR ',' GPR ',' e16      { emit_hl($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
+	| OP_RT_RA_SI_subi     GPR ',' GPR ',' negate16   { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_RT_RA_SI_subic    c GPR ',' GPR ',' negate16 { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
+	| OP_RT_RB_RA_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($3<<21) | ($7<<16) | ($5<<11)); }
+	| OP_RT_SI             GPR ',' e16                { emit_hl($1 | ($2<<21) | $4); }
+	| OP_RT_SPR            GPR ',' spr_num            { emit4($1 | ($2<<21) | ($4<<11)); }
 	| OP_RS_FXM            u7 ',' GPR                 { emit4($1 | ($4<<21) | ($2<<12)); }
-	| OP_RS_RA_C           c GPR ',' GPR              { emit4($1 | $2 | ($5<<21) | ($3<<16)); }
-	| OP_RS_RA_D           GPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
-	| OP_RS_RA_DS          GPR ',' ds '(' GPR ')'     { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RS_RA_D           GPR ',' e16 '(' GPR ')'    { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RS_RA_DS          GPR ',' ds '(' GPR ')'     { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
 	| OP_RS_RA_NB          GPR ',' GPR ',' nb         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
-	| OP_RS_RA_UI          GPR ',' GPR ',' e16        { emit4($1 | ($4<<21) | ($2<<16) | $6); } 
-	| OP_RS_RA_UI_CC       C GPR ',' GPR ',' e16      { emit4($1 | ($5<<21) | ($3<<16) | $7); } 
 	| OP_RS_RA_RB          GPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
 	| OP_RS_RA_RB_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
 	| OP_RS_RA_RA_C        c GPR ',' GPR              { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); }
-	| OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }  
-	| OP_RS_RA_RB_MB6_C    c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
-	| OP_RS_RA_RB_ME6_C    c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
-	| OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }  
-	| OP_RS_RA_SH_MB6_SH_C  c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
-	| OP_RS_RA_SH_ME6_SH_C  c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
-	| OP_RS_RA_SH5_C       c GPR ',' GPR ',' u5       { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
-	| OP_RS_RA_SH6_C       c GPR ',' GPR ',' u6       { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | (($7&0x20)>>4)); }
-	| OP_RS_SPR            SPR ',' GPR                { emit4($1 | ($4<<21) | ($2<<11)); }
+	| OP_RS_SPR            spr_num ',' GPR            { emit4($1 | ($4<<21) | ($2<<11)); }
 	| OP_TO_RA_RB          u5 ',' GPR ',' GPR         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
-	| OP_TO_RA_SI          u5 ',' GPR ',' e16         { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_TO_RA_SI          u5 ',' GPR ',' e16         { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_TOX_RA_RB         GPR ',' GPR                { emit4($1 | ($2<<16) | ($4<<11)); }
+	| OP_TOX_RA_SI         GPR ',' e16                { emit_hl($1 | ($2<<16) | $4); }
+	| OP_LEV                                          { emit4($1); }
 	| OP_LEV               u7                         { emit4($1 | ($2<<5)); }
 	| OP_LIA               lia                        { emit4($1 | $2); }
 	| OP_LIL               lil                        { emit4($1 | $2); }
 	| OP_LI32              li32                       /* emitted in subrule */
+	| OP_clrlsldi          c GPR ',' GPR ',' u6 ',' u6
+	{
+		word_t mb = ($7 - $9) & 0x3f;
+		fit($9 <= $7);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($9) | MB6(mb));
+	}
+	| OP_clrldi            c GPR ',' GPR ',' u6
+	{
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(0) | MB6($7));
+	}
+	| OP_clrrdi            c GPR ',' GPR ',' u6
+	{
+		word_t me = 63 - $7;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(0) | MB6(me));
+	}
+	| OP_extldi            c GPR ',' GPR ',' u6 ',' u6
+	{
+		word_t me = ($7 - 1) & 0x3f;
+		fit($7 > 0);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($9) | MB6(me));
+	}
+	| OP_extrdi            c GPR ',' GPR ',' u6 ',' u6
+	{
+		word_t sh = ($9 + $7) & 0x3f;
+		word_t mb = (64 - $7) & 0x3f;
+		fit($7 > 0);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6(mb));
+	}
+	| OP_rotrdi            c GPR ',' GPR ',' u6
+	{
+		word_t sh = (64 - $7) & 0x3f;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6(0));
+	}
+	| OP_sldi              c GPR ',' GPR ',' u6
+	{
+		word_t me = 63 - $7;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6(me));
+	}
+	| OP_srdi              c GPR ',' GPR ',' u6
+	{
+		word_t sh = (64 - $7) & 0x3f;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6($7));
+	}
+	| OP_clrlslwi          c GPR ',' GPR ',' u5 ',' u5
+	{
+		word_t mb = ($7 - $9) & 0x1f;
+		word_t me = 31 - $9;
+		fit($9 <= $7);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      ($9<<11) | (mb<<6) | (me<<1));
+	}
+	| OP_clrlwi            c GPR ',' GPR ',' u5
+	{
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (0<<11) | ($7<<6) | (31<<1));
+	}
+	| OP_clrrwi            c GPR ',' GPR ',' u5
+	{
+		word_t me = 31 - $7;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (0<<11) | (0<<6) | (me<<1));
+	}
+	| OP_extlwi            c GPR ',' GPR ',' u5 ',' u5
+	{
+		word_t me = ($7 - 1) & 0x1f;
+		fit($7 > 0);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      ($9<<11) | (0<<6) | (me<<1));
+	}
+	| OP_extrwi            c GPR ',' GPR ',' u5 ',' u5
+	{
+		word_t sh = ($9 + $7) & 0x1f;
+		word_t mb = (32 - $7) & 0x1f;
+		fit($7 > 0);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (sh<<11) | (mb<<6) | (31<<1));
+	}
+	| OP_inslwi            c GPR ',' GPR ',' u5 ',' u5
+	{
+		word_t sh = (32 - $9) & 0x1f;
+		word_t me = ($9 + $7 - 1) & 0x1f;
+		fit($7 > 0);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (sh<<11) | ($9<<6) | (me<<1));
+	}
+	| OP_insrwi            c GPR ',' GPR ',' u5 ',' u5
+	{
+		word_t sh = (32 - $9 - $7) & 0x1f;
+		word_t me = ($9 + $7 - 1) & 0x1f;
+		fit($7 > 0);
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (sh<<11) | ($9<<6) | (me<<1));
+	}
+	| OP_rotrwi      c GPR ',' GPR ',' u5
+	{
+		word_t sh = (32 - $7) & 0x1f;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (sh<<11) | (0<<6) | (31<<1));
+	}
+	| OP_slwi              c GPR ',' GPR ',' u5
+	{
+		word_t me = 31 - $7;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      ($7<<11) | (0<<6) | (me<<1));
+	}
+	| OP_srwi              c GPR ',' GPR ',' u5
+	{
+		word_t sh = (32 - $7) & 0x1f;
+		emit4($1 | $2 | ($5<<21) | ($3<<16) |
+		      (sh<<11) | ($7<<6) | (31<<1));
+	}
 	;
 
 c
 	: /* nothing */                          { $$ = 0; }
 	| C                                      { $$ = 1; }
 	;
-	
+
 e16
 	: absexp
 	{
@@ -74,9 +217,24 @@ e16
 		if (($1 < -0x8000) || ($1 > 0xffff))
 			serror("16-bit value out of range");
 		$$ = (uint16_t) $1;
+		no_hl();
+	}
+	| OP_HI ASC_LPAR expr ASC_RPAR           { $$ = eval_hl(&$3, OP_HI); }
+	| OP_HA ASC_LPAR expr ASC_RPAR           { $$ = eval_hl(&$3, OP_HA); }
+	| OP_LO ASC_LPAR expr ASC_RPAR           { $$ = eval_hl(&$3, OP_LO); }
+	;
+
+negate16
+	: absexp
+	{
+		/* To encode subi, we negate the immediate value, then
+		 * it must fit as signed 16-bit. */
+		$$ = -$1;
+		fit(fitx($$, 16));
+		$$ = (uint16_t) $$;
 	}
 	;
-		
+
 u8
 	: absexp
 	{
@@ -85,7 +243,7 @@ u8
 		$$ = $1;
 	}
 	;
-	
+
 u7
 	: absexp
 	{
@@ -94,7 +252,7 @@ u7
 		$$ = $1;
 	}
 	;
-	
+
 u6
 	: absexp
 	{
@@ -103,7 +261,7 @@ u6
 		$$ = $1;
 	}
 	;
-	
+
 u5
 	: absexp
 	{
@@ -112,7 +270,7 @@ u5
 		$$ = $1;
 	}
 	;
-	
+
 u4
 	: absexp
 	{
@@ -121,7 +279,7 @@ u4
 		$$ = $1;
 	}
 	;
-	
+
 u1
 	: absexp
 	{
@@ -130,7 +288,7 @@ u1
 		$$ = $1;
 	}
 	;
-	
+
 u2
 	: absexp
 	{
@@ -139,7 +297,20 @@ u2
 		$$ = $1;
 	}
 	;
-	
+
+/* Optional comma, branch hint. */
+opt_bh
+	: /* nothing */         { $$ = 0; }
+	| ',' u2                { $$ = ($2<<11); }
+
+/*
+ * Optional condition register, comma.  This checks if the token is a
+ * CR register name.  This wouldn't work if we allowed CR as a number.
+ */
+cr_opt
+	: /* nothing */         { $$ = 0; }
+	| CR ','                { $$ = $1; }
+
 ds
 	: e16
 	{
@@ -148,26 +319,26 @@ ds
 		$$ = $1;
 	}
 	;
-	
+
 nb
 	: absexp
 	{
 		if (($1 < 1) || ($1 > 32))
 			serror("register count must be in the range 1..32");
-	
+
 		if ($1 == 32)
 			$$ = 0;
 		else
-			$$ = $1;	
+			$$ = $1;
 	}
 	;
-	
+
 bdl
 	: expr
 	{
 		int dist = $1.val - DOTVAL;
 		fit(fitx(dist, 25));
-		
+
 		if (dist & 0x3)
 			serror("jump targets must be 4-aligned");
 
@@ -183,7 +354,7 @@ bda
 	{
 		int target = $1.val;
 		fit(fitx(target, 16));
-		
+
 		if (target & 0x3)
 			serror("jump targets must be 4-aligned");
 
@@ -193,12 +364,12 @@ bda
 		$$ = target & 0xFFFD;
 	}
 	;
-	
+
 li32
 	: GPR ',' expr
 	{
-		quad type = $3.typ & S_TYP;
-		quad val = $3.val;
+		word_t type = $3.typ & S_TYP;
+		word_t val = $3.val;
 		if ((type == S_ABS) && (val <= 0xffff))
 			emit4((14<<26) | ($1<<21) | (0<<16)  | val); /* addi */
 		else
@@ -215,7 +386,7 @@ lil
 	{
 		int dist = $1.val - DOTVAL;
 		fit(fitx(dist, 26));
-		
+
 		if (dist & 0x3)
 			serror("jump targets must be 4-aligned");
 
@@ -223,13 +394,13 @@ lil
 		$$ = dist & 0x03FFFFFD;
 	}
 	;
-	
+
 lia
 	: expr
 	{
 		int target = $1.val;
 		fit(fitx(target, 26));
-		
+
 		if (target & 0x3)
 			serror("jump targets must be 4-aligned");
 
@@ -237,4 +408,14 @@ lia
 		$$ = target & 0x03FFFFFD;
 	}
 	;
-	
+
+spr_num
+	: SPR { $$ = $1; }
+	| absexp
+	{
+		if (($1 < 0) || ($1 > 0x3ff))
+			serror("spr number out of range");
+		/* mfspr, mtspr swap the low and high 5 bits */
+		$$ = ($1 >> 5) | (($1 & 0x1f) << 5);
+	}
+	;
diff --git a/mach/powerpc/as/mach5.c b/mach/powerpc/as/mach5.c
index 998cd8d9c..d72b8514a 100644
--- a/mach/powerpc/as/mach5.c
+++ b/mach/powerpc/as/mach5.c
@@ -1,5 +1,75 @@
-/*
- * $Source$
- * $State$
- */
+static int hl_token;
+static expr_t hl_expr;
 
+void no_hl(void) {
+	hl_token = 0;
+}
+
+word_t eval_hl(expr_t* expr, int token)
+{
+	word_t val = expr->val;
+	uint16_t hi = val >> 16;
+	uint16_t lo = val & 0xffff;
+
+	hl_token = token;
+	hl_expr = *expr;
+
+	switch (token) {
+	case OP_HI:  /* hi16[expr] */
+		return hi;
+	case OP_HA:  /* ha16[expr]*/
+		/*
+		 * If the low half will be treated as a signed value,
+		 * then values greater than 0x7fff will cause the high
+		 * half to have 1 subtracted from it; so we apply an
+		 * adjustment here.
+		 */
+		if (lo > 0x7fff)
+			hi++;
+		return hi;
+	case OP_LO:  /* lo16[expr] */
+		return lo;
+	}
+}
+
+void emit_hl(word_t in)
+{
+	word_t reg;
+	int type;
+
+	switch (hl_token) {
+	case OP_HI:  /* hi16[expr] */
+	case OP_HA:  /* ha16[expr] */
+		if (PASS_RELO && (hl_expr.typ & S_TYP) != S_ABS) {
+			/*
+			 * RELOLIS only works with lis _, _ (same as
+			 * addis _, r0, _).  Check if instruction
+			 * isn't addis or register RA isn't r0.
+			 */
+			if ((in & 0xfc1f0000) != (0x3c000000))
+				serror("relocation only works with lis");
+
+			/*
+			 * High bit: ha16 flag
+			 * Next 5 bits: register RT
+			 * Low 26 bits: signed offset
+			 */
+			fit(fitx(hl_expr.val, 26));
+			newrelo(hl_expr.typ, RELOLIS | FIXUPFLAGS);
+			reg = (in >> 21) & 0x1f;
+			in = (hl_token == OP_HA) << 31;
+			in |= reg << 26;
+			in |= hl_expr.val & 0x03ffffff;
+		}
+		break;
+	case OP_LO:  /* lo16[expr] */
+		if (PASS_RELO && (hl_expr.typ & S_TYP) != S_ABS) {
+			DOTVAL += 2;
+			newrelo(hl_expr.typ, RELO2 | FIXUPFLAGS);
+			DOTVAL -= 2;
+		}
+		break;
+	}
+
+	emit4(in);
+}
diff --git a/mach/powerpc/libem/aar4.s b/mach/powerpc/libem/aar4.s
index 2c65af643..5e4155091 100644
--- a/mach/powerpc/libem/aar4.s
+++ b/mach/powerpc/libem/aar4.s
@@ -1,12 +1,5 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-
 .sect .text
-	
+
 ! Index into a bounds-checked array.
 !
 ! On entry:
@@ -20,19 +13,20 @@
 
 .define .aar4
 .aar4:
-	li32 r0, .trap_earray
+	lis r0, hi16[.trap_earray]
+	ori r0, r0, lo16[.trap_earray]
 	mtspr ctr, r0            ! load CTR with trap address
 
 	lwz r0, 0(r3)
 	subf. r4, r0, r4         ! adjust range
-	bcctr IFTRUE, LT, 0      ! check lower bound
-	
+	bltctr                   ! check lower bound
+
 	lwz r0, 4(r3)
-	cmpl cr0, 0, r4, r3
-	bcctr IFFALSE, LT, 0     ! check upper bound
-	
+	cmplw r4, r3
+	bgectr                   ! check upper bound
+
 	lwz r0, 8(r3)
 	mullw r4, r4, r0         ! scale index
 	add r3, r4, r5           ! calculate element address
-	
-	bclr ALWAYS, 0, 0
+
+	blr
diff --git a/mach/powerpc/libem/and.s b/mach/powerpc/libem/and.s
new file mode 100644
index 000000000..cb4e1e54a
--- /dev/null
+++ b/mach/powerpc/libem/and.s
@@ -0,0 +1,24 @@
+.sect .text
+
+! Set intersection.
+!  Stack: ( b a size -- a*b )
+
+.define .and
+.and:
+	lwz r3, 0 (sp)      ! r3 = size
+	addi sp, sp, 4
+
+	mr	r4, sp			! r4 = ptr to set a
+	add	r5, sp, r3		! r5 = ptr to set b
+	srwi	r6, r3, 2
+	mtspr	ctr, r6			! ctr = r3 / 4
+1:
+	lwz	r7, 0(r4)
+	lwz	r8, 0(r5)
+	and	r8, r7, r8		! intersection of words
+	stw	r8, 0(r5)
+	addi	r4, r4, 4
+	addi	r5, r5, 4
+	bdnz	1b			! loop ctr times
+	add	sp, sp, r3
+	blr
diff --git a/mach/powerpc/libem/build.lua b/mach/powerpc/libem/build.lua
index 318be381d..466a28fb3 100644
--- a/mach/powerpc/libem/build.lua
+++ b/mach/powerpc/libem/build.lua
@@ -1,14 +1,12 @@
 for _, plat in ipairs(vars.plats) do
 	acklibrary {
 		name = "headers_"..plat,
-		hdrs = { "./*.h" }
 	}
 
 	acklibrary {
 		name = "lib_"..plat,
 		srcs = {
 			"./*.s",
-			"./*.e",
 		},
 		vars = { plat = plat },
 		deps = {
diff --git a/mach/powerpc/libem/cfi8.s b/mach/powerpc/libem/cfi8.s
index 7142c694b..9a87e99ae 100644
--- a/mach/powerpc/libem/cfi8.s
+++ b/mach/powerpc/libem/cfi8.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-	
 .sect .text
 
 ! Converts a 64-bit double into a 32-bit integer.
@@ -17,4 +10,4 @@
 	fctiwz f0, f0
 	stfd f0, 0(sp)
 	addi sp, sp, 4
-	bclr ALWAYS, 0, 0        ! ...and return 
+	blr
diff --git a/mach/powerpc/libem/cfu8.s b/mach/powerpc/libem/cfu8.s
index 758df8572..915f84dd2 100644
--- a/mach/powerpc/libem/cfu8.s
+++ b/mach/powerpc/libem/cfu8.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-
 .sect .text
 
 ! Converts a 64-bit double into a 32-bit unsigned integer.
@@ -13,17 +6,17 @@
 
 .define .cfu8
 .cfu8:
-	li32 r3, .fd_00000000
-	lfd f0, 0(r3)            ! f0 = 0.0
-	
+	lis r3, ha16[.fd_00000000]
+	lfd f0, lo16[.fd_00000000](r3) ! f0 = 0.0
+
 	lfd f1, 0(sp)            ! value to be converted
 
-	li32 r3, .fd_FFFFFFFF
-	lfd f3, 0(r3)            ! f3 = 0xFFFFFFFF	
+	lis r3, ha16[.fd_FFFFFFFF]
+	lfd f3, lo16[.fd_FFFFFFFF](r3) ! f3 = 0xFFFFFFFF
+
+	lis r3, ha16[.fd_80000000]
+	lfd f4, lo16[.fd_80000000](r3) ! f4 = 0x80000000
 
-	li32 r3, .fd_80000000
-	lfd f4, 0(r3)            ! f4 = 0x80000000 	
-	
 	fsel f2, f1, f1, f0
 	fsub f5, f3, f1
 	fsel f2, f5, f2, f3
@@ -34,11 +27,11 @@
 	
 	stfd f2, 0(sp)
 	addi sp, sp, 4
-	
-	bclr IFTRUE, LT, 0
-	
+
+	bltlr
+
 	lwz r3, 0(sp)
 	xoris r3, r3, 0x8000
 	stw r3, 0(sp)
 
-	bclr ALWAYS, 0, 0 
+	blr
diff --git a/mach/powerpc/libem/cif8.s b/mach/powerpc/libem/cif8.s
index d2c82e54e..13abbcade 100644
--- a/mach/powerpc/libem/cif8.s
+++ b/mach/powerpc/libem/cif8.s
@@ -1,9 +1,4 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
+.sect .text; .sect .rom; .sect .data; .sect .bss
 
 .sect .text
 
@@ -14,22 +9,22 @@
 .define .cif8
 .cif8:
 	addi sp, sp, -4          ! make space for the double
-	
+
 	lwz r3, 4(sp)
 	xoris r3, r3, 0x8000
 	stw r3, 4(sp)            ! flip sign of integer value
-	
+
 	addis r3, r0, 0x4330
 	stw r3, 0(sp)            ! set high word to construct a double
-	
+
 	lfd f0, 0(sp)            ! load value
 
-	li32 r3, pivot
-	lfd f1, 0(r3)            ! load pivot value
+	lis r3, ha16[pivot]
+	lfd f1, lo16[pivot](r3)  ! load pivot value
 	fsub f0, f0, f1          ! adjust
-	                         
+
 	stfd f0, 0(sp)           ! save value again...
-	bclr ALWAYS, 0, 0        ! ...and return 
+	blr                      ! ...and return 
 
 .sect .rom
 pivot:
diff --git a/mach/powerpc/libem/cms.s b/mach/powerpc/libem/cms.s
new file mode 100644
index 000000000..30aaccd20
--- /dev/null
+++ b/mach/powerpc/libem/cms.s
@@ -0,0 +1,30 @@
+.sect .text
+
+! Compare sets a, b.
+!  Stack: ( b a -- )
+!  With r3 = size of each set
+!  Yields r3 = 0 if equal, nonzero if not equal
+
+.define .cms
+.cms:
+	mr	r4, sp			! r4 = ptr to set a
+	add	r5, sp, r3		! r5 = ptr to set b
+	mr	r6, r3			! r6 = size
+	srwi	r3, r3, 2
+	mtspr	ctr, r3			! ctr = size / 4
+1:
+	lwz	r7, 0(r4)
+	lwz	r8, 0(r5)
+	cmpw	cr0, r7, r8		! compare words in sets
+	addi	r4, r4, 4
+	addi	r5, r5, 4
+	bne	cr0, 2f			! branch if not equal
+	bdnz	1b			! loop ctr times
+	addi	r3, r0, 0		! equal: return 0
+	b	3f
+2:
+	addi	r3, r0, 1		! not equal: return 1
+3:
+	slwi	r6, r6, 1		! r6 = size * 2
+	add	sp, sp, r6		! remove sets from stack
+	blr
diff --git a/mach/powerpc/libem/com.s b/mach/powerpc/libem/com.s
new file mode 100644
index 000000000..3168cfe17
--- /dev/null
+++ b/mach/powerpc/libem/com.s
@@ -0,0 +1,20 @@
+.sect .text
+
+! Set complement.
+!  Stack: ( a size -- ~a )
+
+.define .com
+.com:
+	lwz r3, 0 (sp)       ! size
+	addi sp, sp, 4
+
+	mr	r4, sp			! r4 = pointer to set a
+	srwi	r5, r3, 2
+	mtspr	ctr, r5			! ctr = r3 / 4
+1:
+	lwz	r6, 0(r4)
+	nor	r6, r6, r6		! complement of word
+	stw	r6, 0(r4)
+	addi	r4, r4, 4
+	bdnz	1b			! loop ctr times
+	blr
diff --git a/mach/powerpc/libem/csa.s b/mach/powerpc/libem/csa.s
index 88e6e176a..3898241c4 100644
--- a/mach/powerpc/libem/csa.s
+++ b/mach/powerpc/libem/csa.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-	
 .sect .text
 
 ! this is not a subroutine, but just a
@@ -25,23 +18,17 @@
 	
 	lwz r5, 4(r3)            ! fetch lower bound
 	subf. r4, r5, r4         ! adjust value
-	bcctr IFTRUE, LT, 0      ! jump to default if out of range
-	
+	bltctr                   ! jump to default if out of range
+
 	lwz r5, 8(r3)            ! fetch range
-	cmp cr0, 0, r4, r5
-	bcctr IFTRUE, GT, 0      ! jump to default if out of range
-	
+	cmplw r4, r5
+	bgtctr                   ! jump to default if out of range
+
 	addi r3, r3, 12          ! skip header
-	rlwinm r4, r4, 2, 0, 31-2 ! scale value (<<2)
-	b 1f
-1:
+	slwi r4, r4, 2           ! scale value (<<2)
 	lwzx r5, r3, r4          ! load target
-	b 1f
-1:
 	mtspr ctr, r5
-	 
+
 	or. r5, r5, r5           ! test it
-	b 1f
-1:
-	bcctr IFFALSE, EQ, 0     ! jump to target if non-zero
+	bnectr                   ! jump to target if non-zero
 	b .trap_ecase            ! otherwise trap
diff --git a/mach/powerpc/libem/csb.s b/mach/powerpc/libem/csb.s
index a8df85d7f..571bfc210 100644
--- a/mach/powerpc/libem/csb.s
+++ b/mach/powerpc/libem/csb.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-	
 .sect .text
 
 ! this is not a subroutine, but just a
@@ -22,21 +15,21 @@
 
 	lwz r5, 0(r3)            ! load default
 	mtspr ctr, r5
-	
+
 	lwz r6, 4(r3)            ! fetch count
-	
+
 1:
 	or. r6, r6, r6           ! test count
-	bcctr IFTRUE, EQ, 0      ! exit if zero
+	beqctr                   ! exit if zero
 	addi r6, r6, -1          ! otherwise decrement
-	
+
 	lwzu r7, 8(r3)           ! fetch target index, increment pointer
-	cmp cr0, 0, r4, r7       ! compare with value
-	bc IFFALSE, EQ, 1b       ! if not equal, go again
-	
+	cmpw r4, r7              ! compare with value
+	bne 1b                   ! if not equal, go again
+
 	lwz r7, 4(r3)            ! fetch target address
 	mtspr ctr, r7
-	
+
 	or. r7, r7, r7           ! test it
-	bcctr IFFALSE, EQ, 0     ! jump to target if non-zero
+	bnectr                   ! jump to target if non-zero
 	b .trap_ecase            ! otherwise trap
diff --git a/mach/powerpc/libem/cuf8.s b/mach/powerpc/libem/cuf8.s
index 5d5a12988..ce9932aa1 100644
--- a/mach/powerpc/libem/cuf8.s
+++ b/mach/powerpc/libem/cuf8.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-	
 .sect .text
 
 ! Converts a 32-bit unsigned integer into a 64-bit double.
@@ -14,18 +7,18 @@
 .define .cuf8
 .cuf8:
 	addi sp, sp, -4          ! make space for the double
-	
-	addis r3, r0, 0x4330
+
+	lis r3, 0x4330
 	stw r3, 0(sp)            ! set high word to construct a double
-	
+
 	lfd f0, 0(sp)            ! load value
-	
-	li32 r3, pivot
-	lfd f1, 0(r3)            ! load pivot value
+
+	lis r3, ha16[pivot]
+	lfd f1, lo16[pivot](r3)  ! load pivot value
 	fsub f0, f0, f1          ! adjust
-	                         
+
 	stfd f0, 0(sp)           ! save value again...
-	bclr ALWAYS, 0, 0        ! ...and return 
+	blr                      ! ...and return
 
 .sect .rom
 pivot:
diff --git a/mach/powerpc/libem/fd_00000000.s b/mach/powerpc/libem/fd_00000000.s
index cefa91b8e..8ffe44a24 100644
--- a/mach/powerpc/libem/fd_00000000.s
+++ b/mach/powerpc/libem/fd_00000000.s
@@ -1,10 +1,5 @@
-#
-! $Source$
-! $State$
-! $Revision$
+.sect .text; .sect .rom; .sect .data; .sect .bss
 
-#include "powerpc.h"
-	
 .sect .rom
 
 ! Contains a handy double-precision zero. (Also works as a single-precision
diff --git a/mach/powerpc/libem/fd_80000000.s b/mach/powerpc/libem/fd_80000000.s
index 50eacd586..5c153bba8 100644
--- a/mach/powerpc/libem/fd_80000000.s
+++ b/mach/powerpc/libem/fd_80000000.s
@@ -1,10 +1,5 @@
-#
-! $Source$
-! $State$
-! $Revision$
+.sect .text; .sect .rom; .sect .data; .sect .bss
 
-#include "powerpc.h"
-	
 .sect .rom
 
 ! Contains a handy double-precision 0x80000000.
diff --git a/mach/powerpc/libem/fd_FFFFFFFF.s b/mach/powerpc/libem/fd_FFFFFFFF.s
index 9218f2726..88cf04bd9 100644
--- a/mach/powerpc/libem/fd_FFFFFFFF.s
+++ b/mach/powerpc/libem/fd_FFFFFFFF.s
@@ -1,15 +1,10 @@
-#
-! $Source$
-! $State$
-! $Revision$
+.sect .text; .sect .rom; .sect .data; .sect .bss
 
-#include "powerpc.h"
-	
 .sect .rom
 
 ! Contains a handy double-precision 0xFFFFFFFF.
 
 .define .fd_FFFFFFFF
-.fd_FFFFFFFF:	
+.fd_FFFFFFFF:
 	!float 4.294967295e+9 sz 8
 	.data1 0101,0357,0377,0377,0377,0340,00,00
diff --git a/mach/powerpc/libem/fef8.s b/mach/powerpc/libem/fef8.s
index fc72b04f2..f71ab8e38 100644
--- a/mach/powerpc/libem/fef8.s
+++ b/mach/powerpc/libem/fef8.s
@@ -1,4 +1,4 @@
-#include "powerpc.h"
+.sect .text; .sect .rom; .sect .data; .sect .bss
 
 .sect .text
 
@@ -10,46 +10,44 @@
 !  r3 = fraction, high word (bits 0..31)
 !  r4 = fraction, low word (bits 32..63)
 !  r5 = exponent
-! Kills: cr0 f0 f1 r6 r7
 
 .define .fef8
 .fef8:
 	! IEEE double-precision format:
 	!   sign  exponent  fraction
 	!   0     1..11     12..63
-	rlwinm r6, r3, 12, 21, 31	! r6 = IEEE exponent
-	addis r7, r0, 0x7ff0		! r7 = exponent mask
+	extrwi r6, r3, 11, 1		! r6 = IEEE exponent
 	addi r5, r6, -1022		! r5 = true exponent
-	cmpi cr0, 0, r6, 2047
-	bclr IFTRUE, EQ, 0		! return if infinity or NaN
-	cmpi cr0, 0, r6, 0
-	bc IFFALSE, EQ, 1f		! jump if normalized number
+	cmpwi r6, 2047
+	beqlr				! return if infinity or NaN
+	cmpwi r6, 0
+	bne 1f				! jump if normalized number
 
 	! Got denormalized number or zero, probably zero.
-	rlwinm r6, r3, 0, 12, 31
+	extrwi r6, r3, 22, 12
 	addi r5, r0, 0			! r5 = true exponent = 0
 	or. r6, r6, r4			! r6 = high|low fraction
-	bclr IFTRUE, EQ, 0		! return if zero
+	beqlr				! return if zero
 
 	! Got denormalized number, not zero.
 	stwu r4, -4(sp)
 	stwu r3, -4(sp)
-	li32 r6, _2_64
 	lfd f0, 0(sp)
-	lfd f1, 0(r6)
+	lis r6, ha16[_2_64]
+	lfd f1, lo16[_2_64](r6)
 	fmul f0, f0, f1			! multiply it by 2**64
 	stfd f0, 0(sp)
 	lwz r3, 0(sp)
 	lwz r4, 4(sp)
-	rlwinm r6, r3, 12, 21, 31	! r6 = IEEE exponent
+	extrwi r6, r3, 11, 1		! r6 = IEEE exponent
 	addi sp, sp, 8
 	addi r5, r6, -1022 - 64		! r5 = true exponent
 1:
 	! Put fraction in [0.5, 1) or (-1, -0.5] by setting its
 	! exponent to true 0, IEEE 1022.
-	andc r3, r3, r7			! clear old exponent
+	rlwinm r3, r3, 0, 12, 0		! clear old exponent
 	oris r3, r3, 1022 << 4		! set new exponent
-	bclr ALWAYS, 0, 0
+	blr
 
 .sect .rom
 _2_64:
diff --git a/mach/powerpc/libem/fif8.s b/mach/powerpc/libem/fif8.s
index a26c77830..eda9b04f2 100644
--- a/mach/powerpc/libem/fif8.s
+++ b/mach/powerpc/libem/fif8.s
@@ -1,5 +1,3 @@
-#include "powerpc.h"
-
 .sect .text
 
 ! Multiplies two double-precision floats, then splits the product into
@@ -9,7 +7,6 @@
 ! Yields:
 !  f1 = fraction
 !  f2 = integer
-! Kills: cr0 f1 f2 r3 r4 r5 r6
 
 .define .fif8
 .fif8:
@@ -25,17 +22,16 @@
 	! 0 to 51, then the IEEE fraction has that many integer bits.
 	! (IEEE has an implicit 1 before its fraction.  If the IEEE
 	! fraction has 0 integer bits, we still have an integer.)
-	rlwinm r5, r3, 12, 21, 31	! r5 = IEEE exponent
+	extrwi r5, r3, 11, 1		! r5 = IEEE exponent
 	addic. r5, r5, -1023		! r5 = nr of integer bits
-	bc IFTRUE, LT, no_int
-	cmpi cr0, 0, r5, 21
-	bc IFTRUE, LT, small_int
-	cmpi cr0, 0, r5, 52
-	bc IFTRUE, LT, big_int
+	blt no_int
+	cmpwi r5, 21
+	blt small_int
+	cmpwi r5, 52
+	blt big_int
 
-	! f1 is an integer without fraction.  Jump to calculate
-	! fraction f1 = f2 - f1.  It will be zero (or perhaps NaN).
-	fmr f2, f1
+	! f1 is an integer without fraction (or infinity or NaN).
+	fmr f2, f1			! integer = f1
 	b subtract
 
 no_int:
@@ -46,17 +42,17 @@ no_int:
 small_int:
 	! f1 has r5 = 0 to 20 integer bits in the IEEE fraction.
 	! High word has 20 - r5 fraction bits.
-	addi r6, r0, 20
+	li r6, 20
 	subf r6, r5, r6
 	srw r3, r3, r6
-	addi r4, r0, 0			! clear low word
+	li r4, 0			! clear low word
 	slw r3, r3, r6			! clear fraction in high word
 	b move_int
 
 big_int:
 	! f1 has r5 = 21 to 51 to integer bits.
 	! Low word has 52 - r5 fraction bits.
-	addi r6, r0, 52
+	li r6, 52
 	subf r6, r5, r6
 	srw r4, r4, r6
 	slw r4, r4, r6			! clear fraction in low word
@@ -68,4 +64,4 @@ subtract:
 	fsub f1, f1, f2			! fraction = value - integer
 done:
 	addi sp, sp, 8			! restore stack pointer
-	bclr ALWAYS, 0, 0
+	blr
diff --git a/mach/powerpc/libem/inn.s b/mach/powerpc/libem/inn.s
index f5ae4c63e..8925e776e 100644
--- a/mach/powerpc/libem/inn.s
+++ b/mach/powerpc/libem/inn.s
@@ -1,4 +1,4 @@
-#include "powerpc.h"
+#
 
 .sect .text
 
@@ -13,14 +13,14 @@
     lwz r4, 4(sp)       /* r4 = bit number */
     addi r5, sp, 8      /* r5 = base address of bit set */
 
-    srawi r6, r4, 3     /* r6 = byte address into set */
-    andi. r7, r4, 7     /* r7 = bit within byte */
+    rlwinm r6, r4, 29, 3, 29 /* r6 = byte index of word in set */
+    extrwi r7, r4, 5, 27     /* r7 = bit number within word */
 
-    lbzx r8, r5, r6     /* r8 = individual byte from set */
-    sraw r8, r8, r7
-    rlwinm r8, r8, 0, 31, 31
+    lwzx r8, r5, r6     /* r8 = individual word from set */
+    srw r8, r8, r7
+    extrwi r8, r8, 1, 31
 
     addi sp, sp, 8      /* retract over the two words */
     add sp, sp, r3      /* retract over bitfield */
     stwu r8, -4(sp)     /* push result */
-    bclr ALWAYS, 0, 0   /* return */
+    blr                 /* return */
diff --git a/mach/powerpc/libem/ior.s b/mach/powerpc/libem/ior.s
new file mode 100644
index 000000000..e6cd1844e
--- /dev/null
+++ b/mach/powerpc/libem/ior.s
@@ -0,0 +1,24 @@
+.sect .text
+
+! Set union.
+!  Stack: ( b a size -- a+b )
+
+.define .ior
+.ior:
+	lwz r3, 0 (sp)
+	addi sp, sp, 4
+
+	mr	r4, sp			! r4 = ptr to set a
+	add	r5, sp, r3		! r5 = ptr to set b
+	srwi	r6, r3, 2
+	mtspr	ctr, r6			! ctr = r3 / 4
+1:
+	lwz	r7, 0(r4)
+	lwz	r8, 0(r5)
+	or	r8, r7, r8		! union of words
+	stw	r8, 0(r5)
+	addi	r4, r4, 4
+	addi	r5, r5, 4
+	bdnz	1b			! loop ctr times
+	add	sp, sp, r3
+	blr
diff --git a/mach/powerpc/libem/lar4.s b/mach/powerpc/libem/lar4.s
index 6375979c4..2f5c3683c 100644
--- a/mach/powerpc/libem/lar4.s
+++ b/mach/powerpc/libem/lar4.s
@@ -1,6 +1,3 @@
-#
-#include "powerpc.h"
-
 .sect .text
 
 ! Load from bounds-checked array.
@@ -18,19 +15,19 @@
 	! r3 = ptr to element
 	! r0 = size of element
 
-	cmpi cr0, 0, r0, 1
-	bc IFFALSE, EQ, 1f
+	cmpwi r0, 1
+	bne 1f
 	! Load 1 byte.
 	lbz r4, 0(r3)
 	stwu r4, -4(sp)
-	bclr ALWAYS, 0, 0
+	blr
 1:
-	cmpi cr0, 0, r0, 2
-	bc IFFALSE, EQ, 2f
+	cmpwi r0, 2
+	bne 2f
 	! Load 2 bytes.
 	lhz r4, 0(r3)
 	stwu r4, -4(sp)
-	bclr ALWAYS, 0, 0
+	blr
 2:
 	! Load r0 bytes, where r0 must be a positive multiple of 4.
 	subf sp, r0, sp		! move stack pointer down
@@ -39,5 +36,5 @@
 	addic. r5, r5, -4	! r5 -= 4
 	lwzx r4, r5, r3
 	stwx r4, r5, sp
-	bc IFTRUE, GT, 3b	! loop if r5 > 0
-	bclr ALWAYS, 0, 0
+	bgt 3b			! loop if r5 > 0
+	blr
diff --git a/mach/powerpc/libem/los.s b/mach/powerpc/libem/los.s
index f867fe770..2d412bce8 100644
--- a/mach/powerpc/libem/los.s
+++ b/mach/powerpc/libem/los.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-	
 .sect .text
 
 ! Loads a variable-sized structure onto the stack.
@@ -15,32 +8,32 @@
 .define .los
 .los:
 	! These sizes are handled specially.
-	
-	cmpi cr0, 0, r3, 1
-	bc IFFALSE, GT, size1
-	
-	cmpi cr0, 0, r3, 2
-	bc IFFALSE, GT, size2
-	
-	cmpi cr0, 0, r3, 4
-	bc IFFALSE, GT, size4
-	
+
+	cmplwi r3, 1
+	ble size1
+
+	cmplwi r3, 2
+	ble size2
+
+	cmplwi r3, 4
+	ble size4
+
 	! Variable-sized structure.
-	
+
 	addi r3, r3, 3
-	andi. r3, r3, ~3         ! align size
-	
+	clrrwi r3, r3, 2         ! align size
+
 	add r4, r4, r3           ! adjust address to top of block
 
-	srawi r3, r3, 2          ! convert size to the number of words
+	srwi r3, r3, 2           ! convert size to the number of words
 	mtspr ctr, r3
-	
+
 1:
 	lwzu r5, -4(r4)
 	stwu r5, -4(sp)
-	bc DNZ, 0, 1b            ! decrement CTR, jump if non-zero
-	bclr ALWAYS, 0, 0
-	
+	bdnz 1b                  ! decrement CTR, jump if non-zero
+	blr
+
 size1:
 	lbz r3, 0(r4)
 	b 1f
@@ -51,4 +44,4 @@ size4:
 	lwz r3, 0(r4)
 1:
 	stwu r3, -4(sp)
-	bclr ALWAYS, 0, 0
+	blr
diff --git a/mach/powerpc/libem/powerpc.h b/mach/powerpc/libem/powerpc.h
deleted file mode 100644
index 3540a6856..000000000
--- a/mach/powerpc/libem/powerpc.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-! Declare segments (the order is important).
-
-.sect .text
-.sect .rom
-.sect .data
-.sect .bss
-
-#define IFFALSE 4
-#define IFTRUE 12
-#define ALWAYS 20
-#define DNZ 16
-
-#define LT 0
-#define GT 1
-#define EQ 2
-#define OV 3
-	
diff --git a/mach/powerpc/libem/rck.s b/mach/powerpc/libem/rck.s
new file mode 100644
index 000000000..9008be610
--- /dev/null
+++ b/mach/powerpc/libem/rck.s
@@ -0,0 +1,20 @@
+.sect .text
+
+! Bounds check. Traps if the value is out of range.
+!  Stack: ( value descriptor -- value )
+
+.define .rck
+.rck:
+    lwz r3, 0 (sp)
+    lwz r4, 4 (sp)
+    addi sp, sp, 4 ! leave value on stack
+
+    lwz r5, 0 (r3)
+    cmpw r4, r5
+    blt .trap_erange
+
+    lwz r5, 4 (r3)
+    cmpw r4, r5
+    bgt .trap_erange
+
+    blr
diff --git a/mach/powerpc/libem/ret.s b/mach/powerpc/libem/ret.s
index cca79ae86..c498af240 100644
--- a/mach/powerpc/libem/ret.s
+++ b/mach/powerpc/libem/ret.s
@@ -1,19 +1,12 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-
 .sect .text
-	
+
 ! Standard boilerplate for returning from functions.
 
 .define .ret
 .ret:
 	lwz r0, 4(fp)
 	mtspr lr, r0
-	lwz r0, 0(fp)            ! our stack frame becomes invalid as soon as...
-	addi sp, fp, 8           ! ...we change sp
-	or fp, r0, r0
-	bclr ALWAYS, 0, 0
+	lwz r0, 0(fp)   ! our stack frame becomes invalid as soon as...
+	addi sp, fp, 8  ! ...we change sp
+	mr fp, r0
+	blr
diff --git a/mach/powerpc/libem/sar4.s b/mach/powerpc/libem/sar4.s
index 0c1368af1..7c9778958 100644
--- a/mach/powerpc/libem/sar4.s
+++ b/mach/powerpc/libem/sar4.s
@@ -1,6 +1,3 @@
-#
-#include "powerpc.h"
-
 .sect .text
 
 ! Store to bounds-checked array.
@@ -18,21 +15,21 @@
 	! r3 = ptr to element
 	! r0 = size of element
 
-	cmpi cr0, 0, r0, 1
-	bc IFFALSE, EQ, 1f
+	cmpwi r0, 1
+	bne 1f
 	! Store 1 byte.
 	lwz r4, 0(sp)
 	addi sp, sp, 4
 	stb r4, 0(r3)
-	bclr ALWAYS, 0, 0
+	blr
 1:
-	cmpi cr0, 0, r0, 2
-	bc IFFALSE, EQ, 2f
+	cmpwi r0, 2
+	bne 2f
 	! Store 2 bytes.
 	lwz r4, 0(sp)
 	addi sp, sp, 4
 	sth r4, 0(r3)
-	bclr ALWAYS, 0, 0
+	blr
 2:
 	! Store r0 bytes, where r0 must be a positive multiple of 4.
 	or r5, r0, r0		! index r5 = length r0
@@ -40,6 +37,6 @@
 	addic. r5, r5, -4	! r5 -= 4
 	lwzx r4, r5, sp
 	stwx r4, r5, r3
-	bc IFTRUE, GT, 3b	! loop if r5 > 0
+	bgt 3b			! loop if r5 > 0
 	add sp, r0, sp		! move stack pointer up
-	bclr ALWAYS, 0, 0
+	blr
diff --git a/mach/powerpc/libem/set.s b/mach/powerpc/libem/set.s
new file mode 100644
index 000000000..3c4a9e579
--- /dev/null
+++ b/mach/powerpc/libem/set.s
@@ -0,0 +1,30 @@
+.sect .text
+
+! Create singleton set.
+!  Stack: ( bitnumber size -- set )
+
+.define .set
+.set:
+	lwz     r3, 0 (sp)
+	lwz     r4, 4 (sp)
+	addi    sp, sp, 8
+
+	srwi	r7, r3, 2
+	neg	r5, r3
+	add	sp, sp, r5		! allocate set
+	mr	r6, sp			! r6 = ptr to set
+	mtspr	ctr, r7			! ctr = r3 / 4
+1:
+	clrrwi.	r7, r4, 5		! r7 = r4 & ~31
+	beq	2f			! branch if r4 in 0..31
+	li	r5, 0			! no bit, word is zero
+	b	3f
+2:
+	li	r5, 1
+	slw	r5, r5, r4		! yes bit, set bit in word
+3:
+	stw	r5, 0(r6)		! store word in set
+	addi	r4, r4, -32
+	addi	r6, r6, 4
+	bdnz	1b			! loop ctr times
+	blr
diff --git a/mach/powerpc/libem/sts.s b/mach/powerpc/libem/sts.s
index 2f8022ad9..411b0fb66 100644
--- a/mach/powerpc/libem/sts.s
+++ b/mach/powerpc/libem/sts.s
@@ -1,10 +1,3 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-	
 .sect .text
 
 ! Stores a variable-sized structure from the stack.
@@ -15,35 +8,35 @@
 .define .sts
 .sts:
 	! These sizes are handled specially.
-	
+
 	lwz r5, 0(sp)
 
-	cmpi cr0, 0, r3, 1
-	bc IFFALSE, GT, size1
-	
-	cmpi cr0, 0, r3, 2
-	bc IFFALSE, GT, size2
-	
-	cmpi cr0, 0, r3, 4
-	bc IFFALSE, GT, size4
-	
+	cmplwi r3, 1
+	ble size1
+
+	cmplwi r3, 2
+	ble size2
+
+	cmplwi r3, 4
+	ble size4
+
 	! Variable-sized structure.
-	
+
 	addi r3, r3, 3
-	andi. r3, r3, ~3         ! align size
-	
-	srawi r3, r3, 2          ! convert size to the number of words
+	clrrwi r3, r3, 2         ! align size
+
+	srwi r3, r3, 2           ! convert size to the number of words
 	mtspr ctr, r3
-	
+
 1:
 	lwz r5, 0(sp)
 	addi sp, sp, 4
 	stw r5, 0(r4)
 	addi r4, r4, 4
 
-	bc DNZ, 0, 1b            ! decrement CTR, jump if non-zero
-	bclr ALWAYS, 0, 0
-	
+	bdnz 1b                  ! decrement CTR, jump if non-zero
+	blr
+
 size1:
 	stb r5, 0(r4)
 	b 1f
@@ -54,4 +47,4 @@ size4:
 	stw r5, 0(r4)
 1:
 	addi sp, sp, 4
-	bclr ALWAYS, 0, 0
+	blr
diff --git a/mach/powerpc/libem/tge.s b/mach/powerpc/libem/tge.s
deleted file mode 100644
index 4740d8436..000000000
--- a/mach/powerpc/libem/tge.s
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-! $Source$
-! $State$
-! $Revision$
-
-#include "powerpc.h"
-
-.sect .rom
-
-! Lookup table for tge.
-
-.define .teq_table
-.teq_table:
-	.data4 1       ! . .
-	.data4 0       ! . G
-	.data4 0       ! L .
-
-.define .tne_table
-.tne_table:
-	.data4 0       ! . .
-	.data4 1       ! . G
-	.data4 1       ! L .
-
-.define .tgt_table
-.tgt_table:
-	.data4 0       ! . .
-	.data4 1       ! . G
-	.data4 0       ! L .
-
-.define .tge_table
-.tge_table:
-	.data4 1       ! . .
-	.data4 1       ! . G
-	.data4 0       ! L .
-
-.define .tlt_table
-.tlt_table:
-	.data4 0       ! . .
-	.data4 0       ! . G
-	.data4 1       ! L .
-
-.define .tle_table
-.tle_table:
-	.data4 1       ! . .
-	.data4 0       ! . G
-	.data4 1       ! L .
diff --git a/mach/powerpc/libem/xor.s b/mach/powerpc/libem/xor.s
new file mode 100644
index 000000000..acb02a032
--- /dev/null
+++ b/mach/powerpc/libem/xor.s
@@ -0,0 +1,22 @@
+.sect .text
+
+! Set symmetric difference.
+!  Stack: ( b a -- a/b )
+!  With r3 = size of set
+
+.define .xor
+.xor:
+	mr	r4, sp			! r4 = ptr to set a
+	add	r5, sp, r3		! r5 = ptr to set b
+	srwi	r6, r3, 2
+	mtspr	ctr, r6			! ctr = r3 / 4
+1:
+	lwz	r7, 0(r4)
+	lwz	r8, 0(r5)
+	xor	r8, r7, r8		! symmetric difference of words
+	stw	r8, 0(r5)
+	addi	r4, r4, 4
+	addi	r5, r5, 4
+	bdnz	1b			! loop ctr times
+	add	sp, sp, r3
+	blr
diff --git a/mach/powerpc/libem/zer.s b/mach/powerpc/libem/zer.s
new file mode 100644
index 000000000..a47a150cc
--- /dev/null
+++ b/mach/powerpc/libem/zer.s
@@ -0,0 +1,21 @@
+.sect .text
+
+! Create empty set.
+!  Stack: ( size -- set )
+
+.define .zer
+.zer:
+	lwz     r3, 0(sp)
+	addi    sp, sp, 4
+
+	srwi	r7, r3, 2
+	li	r4, 0			! r4 = zero
+	neg	r5, r3
+	add	sp, sp, r5		! allocate set
+	mr	r6, sp			! r6 = ptr to set
+	mtspr	ctr, r7			! ctr = r3 / 4
+1:
+	stw	r4, 0(r6)		! store zero in set
+	addi	r6, r6, 4
+	bdnz	1b			! loop ctr times
+	blr
diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table
index 8511dbb5b..b72990c36 100644
--- a/mach/powerpc/mcg/table
+++ b/mach/powerpc/mcg/table
@@ -572,26 +572,26 @@ PATTERNS
 
     out:(int)reg = IFEQ.I(in:(cr)cr)
         emit "mfcr %out" /* get cr0 */
-        emit "rlwinm %out, %out, [32-2], 2, 31" /* extract just EQ */
+        emit "rlwinm %out, %out, 3, 31, 31"      /* extract just EQ */
         cost 8;
 
+#if 0
     out:(int)reg = IFEQ.I(in:(int)reg)
         emit "cntlzw %out, %in" /* returns 0..32 */
-        emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */
+        emit "rlwinm %out, %out, [32-5], 31, 31" /* if 32, return 1, otherwise 0 */
         cost 8;
+#endif
 
     out:(int)reg = IFLT.I(in:(cr)cr)
         emit "mfcr %out" /* get cr0 */
-        emit "andi. %out, %out, 1" /* leave just LT */
+        emit "rlwinm %out, %out, 1, 31, 31"     /* leave just LT */
         cost 8;
 
     out:(int)reg = IFLE.I(in:(cr)cr)
         emit "mfcr %out"                        /* get cr0 */
-        emit "andi. %out, %out, 5"              /* leave just LT and EQ */
-        emit "cntlzw %out, %out"                /* returns 0..32 */
-        emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */
+        emit "rlwinm %out, %out, 2, 31, 31"     /* leave just GT */
         emit "xori %out, %out, 1"               /* negate */
-        cost 8;
+        cost 12;
 
 
 
@@ -673,10 +673,9 @@ PATTERNS
         emit "neg %out, %left"
         cost 4;
 
-    out:(int)reg = NOT.I(left:(int)reg)
-        emit "cntlzw %out, %left"
-        emit "rlwinm %out, %out, 32-5, 5, 31"
-        cost 8;
+    out:(int)reg = NOT.I(in:(int)reg)
+        emit "nor %out, %in, %in"
+        cost 4;
 
     ALUR(AND.I, "and")
     ALUCC(AND.I, "andi.")
diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table
index 77fdaedf1..24822482c 100644
--- a/mach/powerpc/ncg/table
+++ b/mach/powerpc/ncg/table
@@ -10,7 +10,7 @@ INT64 = 8
 FP_OFFSET = 0   /* Offset of saved FP relative to our FP */
 PC_OFFSET = 4   /* Offset of saved PC relative to our FP */
 
-#define COMMENT(n) /* noop */
+#define COMMENT(n) /* comment {LABEL, n} */
 
 
 #define nicesize(x) ((x)==INT8 || (x)==INT16 || (x)==INT32 || (x)==INT64)
@@ -27,44 +27,33 @@ PC_OFFSET = 4   /* Offset of saved PC relative to our FP */
 #define los(n) (lo(n) | (((0-(lo(n)>>15)) & ~0xFFFF)))
 #define his(n) ((hi(n) + (lo(n)>>15)) & 0xFFFF)
 
-#define IFFALSE {CONST, 4}
-#define IFTRUE {CONST, 12}
-#define ALWAYS {CONST, 20}
-#define DCTRZ {CONST, 34}
-
-#define LT {CONST, 0}
-#define GT {CONST, 1}
-#define EQ {CONST, 2}
-
-
 
 PROPERTIES
 
 	GPR             /* any GPR */
 	REG             /* any allocatable GPR */
-	REG_PAIR        /* speed hack for sti 8 */
-	FPR             /* any FPR */
-	FREG            /* any allocatable FPR */
+	REG_PAIR(8)     /* speed hack for sti 8 */
+	FPR(8)          /* any FPR */
+	FREG(8)         /* any allocatable FPR */
 	FSREG           /* any allocatable single-precision FPR */
 	SPR             /* any SPR */
 	CR              /* any CR */
-	
+
 	GPR0  GPRSP GPRFP GPR3  GPR4  GPR5  GPR6  GPR7
 	GPR8  GPR9  GPR10 GPR11 GPR12 GPR13 GPR14 GPR15
 	GPR16 GPR17 GPR18 GPR19 GPR20 GPR21 GPR22 GPR23
 	GPR24 GPR25 GPR26 GPR27 GPR28 GPR29 GPR30 GPR31
-	
-	CR0   CR1
 
-	FPR0  FPR1  FPR2  FPR3  FPR4  FPR5  FPR6  FPR7
-	FPR8  FPR9  FPR10 FPR11 FPR12 FPR13 FPR14 FPR15
-	FPR16 FPR17 FPR18 FPR19 FPR20 FPR21 FPR22 FPR23
-	FPR24 FPR25 FPR26 FPR27 FPR28 FPR29 FPR30 FPR31
+	FPR0(8)  FPR1(8)  FPR2(8)  FPR3(8)  FPR4(8)  FPR5(8)  FPR6(8)  FPR7(8)
+	FPR8(8)  FPR9(8)  FPR10(8) FPR11(8) FPR12(8) FPR13(8) FPR14(8) FPR15(8)
+	FPR16(8) FPR17(8) FPR18(8) FPR19(8) FPR20(8) FPR21(8) FPR22(8) FPR23(8)
+	FPR24(8) FPR25(8) FPR26(8) FPR27(8) FPR28(8) FPR29(8) FPR30(8) FPR31(8)
+
 
 REGISTERS
 
 	/* Reverse order to encourage ncg to allocate them from r31 down */
-	
+
 	R31("r31")         : GPR, REG, GPR31 regvar.
 	R30("r30")         : GPR, REG, GPR30 regvar.
 	R29("r29")         : GPR, REG, GPR29 regvar.
@@ -85,7 +74,7 @@ REGISTERS
 	R14("r14")         : GPR, REG, GPR14 regvar.
 	R13("r13")         : GPR, REG, GPR13 regvar.
 	R12("r12")         : GPR, REG, GPR12.
-	R11("r11")         : GPR, GPR11.
+	R11("r11")         : GPR, REG, GPR11.
 	R10("r10")         : GPR, REG, GPR10.
 	R9("r9")           : GPR, REG, GPR9.
 	R8("r8")           : GPR, REG, GPR8.
@@ -158,23 +147,22 @@ REGISTERS
 
 	LR("lr")           : SPR.
 	CTR("ctr")         : SPR.
-	C0("cr0")          : CR, CR0.
+	CR0("cr0")         : CR.
 
-#define RSCRATCH R11
+#define RSCRATCH R0
 #define FSCRATCH F0
 
 
 TOKENS
 
-/* Used only in instruction descriptions (to generate the correct syntax). */
-
-	GPRINDIRECT        = { GPR reg; INT off; }    4    off "(" reg ")".
-	CONST              = { INT val; }             4    val.
-
 /* Primitives */
 
+	CONST              = { INT val; }             4    val.
 	LABEL              = { ADDR adr; }            4    adr.
-	LOCAL              = { INT off; }             4.
+	LABEL_HI           = { ADDR adr; }            4    "hi16[" adr "]".
+	LABEL_HA           = { ADDR adr; }            4    "ha16[" adr "]".
+	LABEL_LO           = { ADDR adr; }            4    "lo16[" adr "]".
+	LOCAL              = { INT off; }             4    ">>> BUG IN LOCAL".
 
 /* Allows us to use regvar() to refer to registers */
 
@@ -192,33 +180,32 @@ TOKENS
 
 /* Expression partial results */
 
-	SUM_RIS            = { GPR reg; INT offhi; }  4.
-	SUM_RC             = { GPR reg; INT off; }    4.
-	SUM_RR             = { GPR reg1; GPR reg2; }  4.
-	
-	TRISTATE_RC_S      = { GPR reg; INT val; }    4.
-	TRISTATE_RC_U      = { GPR reg; INT val; }    4.
-	TRISTATE_RR_S      = { GPR reg1; GPR reg2; }  4.
-	TRISTATE_RR_U      = { GPR reg1; GPR reg2; }  4.
-	
-	TRISTATE_FF        = { FPR reg1; FPR reg2; }  4.
-	
+	SUM_RIS     = { GPR reg; INT offhi; }  4.   /* reg + (offhi << 16) */
+	SUM_RC      = { GPR reg; INT off; }    4.   /* reg + off */
+	SUM_RL      = { GPR reg; ADDR adr; }   4.   /* reg + lo16[adr] */
+	SUM_RR      = { GPR reg1; GPR reg2; }  4.   /* reg1 + reg2 */
+
 	SEX_B              = { GPR reg; }             4.
 	SEX_H              = { GPR reg; }             4.
-	
-	IND_RC_B           = { GPR reg; INT off; }    4.
-	IND_RR_B           = { GPR reg1; GPR reg2; }  4.
-	IND_RC_H           = { GPR reg; INT off; }    4.
-	IND_RR_H           = { GPR reg1; GPR reg2; }  4.
-	IND_RC_H_S         = { GPR reg; INT off; }    4.
-	IND_RR_H_S         = { GPR reg1; GPR reg2; }  4.
-	IND_RC_W           = { GPR reg; INT off; }    4.
-	IND_RR_W           = { GPR reg1; GPR reg2; }  4.
-	IND_RC_D           = { GPR reg; INT off; }    8.
-	IND_RR_D           = { GPR reg1; GPR reg2; }  8.
-	
+
+	IND_RC_B    = { GPR reg; INT off; }    4    off "(" reg ")".
+	IND_RL_B    = { GPR reg; ADDR adr; }   4    "lo16[" adr "](" reg ")".
+	IND_RR_B    = { GPR reg1; GPR reg2; }  4.
+	IND_RC_H    = { GPR reg; INT off; }    4    off "(" reg ")".
+	IND_RL_H    = { GPR reg; ADDR adr; }   4    "lo16[" adr "](" reg ")".
+	IND_RR_H    = { GPR reg1; GPR reg2; }  4.
+	IND_RC_H_S  = { GPR reg; INT off; }    4    off "(" reg ")".
+	IND_RL_H_S  = { GPR reg; ADDR adr; }   4    "lo16[" adr "](" reg ")".
+	IND_RR_H_S  = { GPR reg1; GPR reg2; }  4.
+	IND_RC_W    = { GPR reg; INT off; }    4    off "(" reg ")".
+	IND_RL_W    = { GPR reg; ADDR adr; }   4    "lo16[" adr "](" reg ")".
+	IND_RR_W    = { GPR reg1; GPR reg2; }  4.
+	IND_RC_D    = { GPR reg; INT off; }    8    off "(" reg ")".
+	IND_RL_D    = { GPR reg; ADDR adr; }   8    "lo16[" adr "](" reg ")".
+	IND_RR_D    = { GPR reg1; GPR reg2; }  8.
+
 	NOT_R              = { GPR reg; }             4.
-	
+
 	AND_RR             = { GPR reg1; GPR reg2; }  4.
 	OR_RR              = { GPR reg1; GPR reg2; }  4.
 	OR_RIS             = { GPR reg; INT valhi; }  4.
@@ -227,6 +214,20 @@ TOKENS
 	XOR_RIS            = { GPR reg; INT valhi; }  4.
 	XOR_RC             = { GPR reg; INT val; }    4.
 
+	COND_RC            = { GPR reg; INT val; }    4.
+	COND_RR            = { GPR reg1; GPR reg2; }  4.
+	CONDL_RC           = { GPR reg; INT val; }    4.
+	CONDL_RR           = { GPR reg1; GPR reg2; }  4.
+	COND_FS            = { FSREG reg1; FSREG reg2; } 4.
+	COND_FD            = { FREG reg1; FREG reg2; }   4.
+
+	XEQ                = { GPR reg; }             4.
+	XNE                = { GPR reg; }             4.
+	XGT                = { GPR reg; }             4.
+	XGE                = { GPR reg; }             4.
+	XLT                = { GPR reg; }             4.
+	XLE                = { GPR reg; }             4.
+
 
 SETS
 
@@ -237,32 +238,29 @@ SETS
 	/* unsigned 16-bit integer */
 	UCONST2         = CONST_0000_7FFF + CONST_8000 + CONST_8001_FFFF.
 	/* any constant on stack */
-	CONST_ALL       = CONST_N8000 + CONST_N7FFF_N0001 + CONST_0000_7FFF +
+	CONST_STACK     = CONST_N8000 + CONST_N7FFF_N0001 + CONST_0000_7FFF +
 	                  CONST_8000 + CONST_8001_FFFF + CONST_HZ + CONST_HL.
 
-	SUM_ALL            = SUM_RC + SUM_RR.
-	
-	TRISTATE_ALL       = TRISTATE_RC_S + TRISTATE_RC_U + TRISTATE_RR_S +
-	                     TRISTATE_RR_U + TRISTATE_FF.
-	
+	SUM_ALL            = SUM_RC + SUM_RL + SUM_RR.
+
 	SEX_ALL            = SEX_B + SEX_H.
-	
+
 	LOGICAL_ALL        = NOT_R + AND_RR + OR_RR + OR_RC + XOR_RR +
 	                     XOR_RC.
 
-	/* indirect 4-byte value */
-	IND_ALL_W          = IND_RC_W + IND_RR_W.
-	/* indirect 8-byte value */
-	IND_ALL_D          = IND_RC_D + IND_RR_D.
-	/* any indirect value that fits in a GPR */
-	IND_ALL_BHW        = IND_RC_B + IND_RR_B + IND_RC_H + IND_RR_H +
-	                     IND_RC_H_S + IND_RR_H_S + IND_ALL_W.
+	IND_ALL_B          = IND_RC_B + IND_RL_B + IND_RR_B.
+	IND_ALL_H          = IND_RC_H + IND_RL_H + IND_RR_H +
+	                     IND_RC_H_S + IND_RL_H_S + IND_RR_H_S.
+	IND_ALL_W          = IND_RC_W + IND_RL_W + IND_RR_W.
+	IND_ALL_D          = IND_RC_D + IND_RL_D + IND_RR_D.
+	IND_ALL_BHW        = IND_ALL_B + IND_ALL_H + IND_ALL_W.
 
 	/* anything killed by sti (store indirect) */
 	MEMORY             = IND_ALL_BHW + IND_ALL_D.
 
-	OP_ALL_W           = SUM_ALL + TRISTATE_ALL + SEX_ALL + LOGICAL_ALL +
-	                     IND_ALL_W.
+	/* any stack token that we can easily move to GPR */
+	ANY_BHW            = REG + CONST_STACK + SEX_ALL +
+	                     SUM_ALL + IND_ALL_BHW + LOGICAL_ALL.
 
 
 INSTRUCTIONS
@@ -281,22 +279,37 @@ INSTRUCTIONS
 
   add             GPR:wo, GPR:ro, GPR:ro.
   addX "add."     GPR:wo, GPR:ro, GPR:ro.
-  addi            GPR:wo, GPR:ro, CONST:ro.
-  addis           GPR:wo, GPR:ro, CONST:ro.
+  addi            GPR:wo, GPR:ro, CONST+LABEL_LO:ro.
+    li            GPR:wo, CONST:ro.
+  addis           GPR:wo, GPR:ro, CONST+LABEL_HI+LABEL_HA:ro.
+    lis           GPR:wo, CONST+LABEL_HI+LABEL_HA:ro.
   and             GPR:wo, GPR:ro, GPR:ro.
   andc            GPR:wo, GPR:ro, GPR:ro.
   andiX  "andi."  GPR:wo:cc, GPR:ro, CONST:ro.
   andisX "andis." GPR:wo:cc, GPR:ro, CONST:ro.
   b               LABEL:ro.
   bc              CONST:ro, CONST:ro, LABEL:ro.
+    beq           LABEL:ro.
+    bne           LABEL:ro.
+    bgt           LABEL:ro.
+    bge           LABEL:ro.
+    blt           LABEL:ro.
+    ble           LABEL:ro.
+    bxx           LABEL:ro. /* dummy */
   bcctr           CONST:ro, CONST:ro, CONST:ro.
+    bctr.
   bcctrl          CONST:ro, CONST:ro, CONST:ro.
+    bctrl.
   bclr            CONST:ro, CONST:ro, CONST:ro.
   bl              LABEL:ro.
   cmp             CR:ro, CONST:ro, GPR:ro, GPR:ro kills :cc.
+    cmpw          GPR:ro, GPR:ro kills :cc.
   cmpi            CR:ro, CONST:ro, GPR:ro, CONST:ro kills :cc.
+    cmpwi         GPR:ro, CONST:ro kills :cc.
   cmpl            CR:ro, CONST:ro, GPR:ro, GPR:ro kills :cc.
+    cmplw         GPR:ro, GPR:ro kills :cc.
   cmpli           CR:ro, CONST:ro, GPR:ro, CONST:ro kills :cc.
+    cmplwi        GPR:ro, CONST:ro kills :cc.
   divw            GPR:wo, GPR:ro, GPR:ro cost(4, 23).
   divwu           GPR:wo, GPR:ro, GPR:ro cost(4, 23).
   eqv             GPR:wo, GPR:ro, GPR:ro.
@@ -304,7 +317,8 @@ INSTRUCTIONS
   extsh           GPR:wo, GPR:ro.
   fadd            FREG:wo, FREG:ro, FREG:ro cost(4, 5).
   fadds           FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
-  fcmpo           CR:wo, FPR:ro, FPR:ro cost(4, 5).
+  fcmpo           CR:wo, FREG:ro, FREG:ro cost(4, 5).
+  fcmpo           CR:wo, FSREG:ro, FSREG:ro cost(4, 5).
   fdiv            FREG:wo, FREG:ro, FREG:ro cost(4, 35).
   fdivs           FSREG:wo, FSREG:ro, FSREG:ro cost(4, 21).
   fmr             FPR:wo, FPR:ro cost(4, 5).
@@ -316,23 +330,21 @@ INSTRUCTIONS
   frsp            FSREG:wo, FREG:ro cost(4, 5).
   fsub            FREG:wo, FREG:ro, FREG:ro cost(4, 5).
   fsubs           FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
-  lbz             GPR:wo, GPRINDIRECT:ro cost(4, 3).
+  lbz             GPR:wo, IND_RC_B+IND_RL_B:ro cost(4, 3).
   lbzx            GPR:wo, GPR:ro, GPR:ro cost(4, 3).
-  lfd             FPR:wo, GPRINDIRECT:ro cost(4, 5).
-  lfdu            FPR:wo, GPRINDIRECT:ro cost(4, 5).
+  lfd             FPR:wo, IND_RC_D+IND_RL_D:ro cost(4, 5).
+  lfdu            FPR:wo, IND_RC_D:ro cost(4, 5).
   lfdx            FPR:wo, GPR:ro, GPR:ro cost(4, 5).
-  lfs             FSREG:wo, GPRINDIRECT:ro cost(4, 4).
-  lfsu            FSREG:wo, GPRINDIRECT:rw cost(4, 4).
+  lfs             FSREG:wo, IND_RC_W+IND_RL_W:ro cost(4, 4).
+  lfsu            FSREG:wo, IND_RC_W:rw cost(4, 4).
   lfsx            FSREG:wo, GPR:ro, GPR:ro cost(4, 4).
-  lha             GPR:wo, GPRINDIRECT:ro cost(4, 3).
+  lha             GPR:wo, IND_RC_H_S+IND_RL_H_S:ro cost(4, 3).
   lhax            GPR:wo, GPR:ro, GPR:ro cost(4, 3).
-  lhz             GPR:wo, GPRINDIRECT:ro cost(4, 3).
+  lhz             GPR:wo, IND_RC_H+IND_RL_H:ro cost(4, 3).
   lhzx            GPR:wo, GPR:ro, GPR:ro cost(4, 3).
-  li32            GPR:wo, CONST:ro cost(8, 2).
-  li32            GPR:wo, LABEL:ro cost(8, 2).
-  lwzu            GPR:wo, GPRINDIRECT:ro cost(4, 3).
+  lwzu            GPR:wo, IND_RC_W:ro cost(4, 3).
   lwzx            GPR:wo, GPR:ro, GPR:ro cost(4, 3).
-  lwz             GPR:wo, GPRINDIRECT:ro cost(4, 3).
+  lwz             GPR:wo, IND_RC_W+IND_RL_W:ro cost(4, 3).
   nand            GPR:wo, GPR:ro, GPR:ro.
   neg             GPR:wo, GPR:ro.
   nor             GPR:wo, GPR:ro, GPR:ro.
@@ -341,63 +353,61 @@ INSTRUCTIONS
   mfspr           GPR:wo, SPR:ro cost(4, 3).
   mtspr           SPR:wo, GPR:ro cost(4, 2).
   or              GPR:wo, GPR:ro, GPR:ro.
-  orc             GPR:wo, GPR:ro, GPR:ro.
-  ori             GPR:wo, GPR:ro, CONST:ro.
-  oris            GPR:wo, GPR:ro, CONST:ro.
+    mr            GPR:wo, GPR:ro.
   orX "or."       GPR:wo:cc, GPR:ro, GPR:ro.
+    orX_readonly "or." GPR:ro:cc, GPR:ro, GPR:ro.
+  orc             GPR:wo, GPR:ro, GPR:ro.
+  ori             GPR:wo, GPR:ro, CONST+LABEL_LO:ro.
+  oris            GPR:wo, GPR:ro, CONST:ro.
   rlwinm          GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro.
+    extlwi        GPR:wo, GPR:ro, CONST:ro, CONST:ro.
+    extrwi        GPR:wo, GPR:ro, CONST:ro, CONST:ro.
   slw             GPR:wo, GPR:ro, GPR:ro.
   subf            GPR:wo, GPR:ro, GPR:ro.
   sraw            GPR:wo, GPR:ro, GPR:ro cost(4, 2).
   srawi           GPR:wo, GPR:ro, CONST:ro cost(4, 2).
   srw             GPR:wo, GPR:ro, GPR:ro.
-  stb             GPR:ro, GPRINDIRECT:rw cost(4, 3).
+  stb             GPR:ro, IND_RC_B+IND_RL_B:rw cost(4, 3).
   stbx            GPR:ro, GPR:ro, GPR:ro cost(4, 3).
-  stfd            FPR:ro, GPRINDIRECT:rw cost(4, 4).
-  stfdu           FPR:ro, GPRINDIRECT:rw cost(4, 4).
+  stfd            FPR:ro, IND_RC_D+IND_RL_D:rw cost(4, 4).
+  stfdu           FPR:ro, IND_RC_D:rw cost(4, 4).
   stfdx           FPR:ro, GPR:ro, GPR:ro cost(4, 4).
-  stfs            FSREG:ro, GPRINDIRECT:rw cost(4, 3).
-  stfsu           FSREG:ro, GPRINDIRECT:rw cost(4, 3).
+  stfs            FSREG:ro, IND_RC_W+IND_RL_W:rw cost(4, 3).
+  stfsu           FSREG:ro, IND_RC_W:rw cost(4, 3).
   stfsx           FSREG:ro, GPR:ro, GPR:ro cost(4, 3).
-  sth             GPR:ro, GPRINDIRECT:rw cost(4, 3).
+  sth             GPR:ro, IND_RC_H+IND_RL_H:rw cost(4, 3).
   sthx            GPR:ro, GPR:ro, GPR:ro cost(4, 3).
-  stw             GPR:ro, GPRINDIRECT:rw cost(4, 3).
+  stw             GPR:ro, IND_RC_W+IND_RL_W:rw cost(4, 3).
   stwx            GPR:ro, GPR:ro, GPR:ro cost(4, 3).
-  stwu            GPR+GPRE:ro, GPRINDIRECT:rw cost(4, 3).
+  stwu            GPR+LOCAL:ro, IND_RC_W:rw cost(4, 3).
   xor             GPR:wo, GPR:ro, GPR:ro.
   xori            GPR:wo, GPR:ro, CONST:ro.
   xoris           GPR:wo, GPR:ro, CONST:ro.
 
-  comment "!" LABEL:ro cost(0, 0).
+  comment "!"             LABEL:ro cost(0, 0).
 
 
-  
 MOVES
 
 	from GPR to GPR
-		gen
-			COMMENT("move GPR->GPR")
-			or %2, %1, %1
+		gen mr %2, %1
 
-/* GPRE exists solely to allow us to use regvar() (which can only be used in
-   an expression) as a register constant. */
-   
-	from GPR to GPRE
-		gen
-			COMMENT("move GPR->GPRE")
-			or %2.reg, %1, %1
-		
 /* Constants */
 
-	from CONST_ALL smalls(%val) to GPR
+	from CONST + CONST_STACK smalls(%val) to GPR
 		gen
-			COMMENT("move CONST_ALL->GPR smalls")
-			addi %2, R0, {CONST, %1.val}
+			COMMENT("move CONST->GPR smalls")
+			li %2, {CONST, %1.val}
 
-	from CONST_ALL + CONST to GPR
+	from CONST + CONST_STACK lo(%val)==0 to GPR
 		gen
-			COMMENT("move CONST_ALL->GPR")
-			addis %2, R0, {CONST, hi(%1.val)}
+			COMMENT("move CONST->GPR shifted")
+			lis %2, {CONST, hi(%1.val)}
+
+	from CONST + CONST_STACK to GPR
+		gen
+			COMMENT("move CONST->GPR")
+			lis %2, {CONST, hi(%1.val)}
 			ori %2, %2, {CONST, lo(%1.val)}
 			/* Can't use addi %2, %2, {CONST, los(%1.val)}
 			 * because %2 might be R0. */
@@ -405,279 +415,225 @@ MOVES
 	from LABEL to GPR
 		gen
 			COMMENT("move LABEL->GPR")
-			li32 %2, {LABEL, %1.adr}
-	
+			lis %2, {LABEL_HI, %1.adr}
+			ori %2, %2, {LABEL_LO, %1.adr}
+
+	from LABEL_HA to GPR
+		gen lis %2, %1
+
 /* Sign extension */
 
 	from SEX_B to GPR
-		gen
-			COMMENT("move SEX_B->GPR")
-			extsb %2, %1.reg
-			
+		gen extsb %2, %1.reg
+
 	from SEX_H to GPR
-		gen
-			COMMENT("move SEX_H->GPR")
-			extsh %2, %1.reg
-					
+		gen extsh %2, %1.reg
+
 /* Register + something */
 
 	from SUM_RIS to GPR
-		gen
-			COMMENT("move SUM_RIS->GPR")
-			addis %2, %1.reg, {CONST, %1.offhi}
+		gen addis %2, %1.reg, {CONST, %1.offhi}
 
 	from SUM_RC to GPR
-		gen
-			COMMENT("move SUM_RC->GPR")
-			addi %2, %1.reg, {CONST, %1.off}
+		gen addi %2, %1.reg, {CONST, %1.off}
+
+	from SUM_RL to GPR
+		gen addi %2, %1.reg, {LABEL_LO, %1.adr}
 
 	from SUM_RR to GPR
-		gen
-			COMMENT("move SUM_RR->GPR")
-			add %2, %1.reg1, %1.reg2
+		gen add %2, %1.reg1, %1.reg2
 
 /* Read byte */
 
-	from IND_RC_B to GPR
-		gen
-			COMMENT("move IND_RC_B->GPR")
-			lbz %2, {GPRINDIRECT, %1.reg, %1.off}
+	from IND_RC_B+IND_RL_B to GPR
+		gen lbz %2, %1
 
 	from IND_RR_B to GPR
-		gen
-			COMMENT("move IND_RR_B->GPR")
-			lbzx %2, %1.reg1, %1.reg2
+		gen lbzx %2, %1.reg1, %1.reg2
 
 /* Write byte */
 
-	from GPR to IND_RC_B
-		gen
-			COMMENT("move GPR->IND_RC_B")
-			stb %1, {GPRINDIRECT, %2.reg, %2.off}
+	from GPR to IND_RC_B+IND_RL_B
+		gen stb %1, %2
 
 	from GPR to IND_RR_B
-		gen
-			COMMENT("move GPR->IND_RR_B")
-			stbx %1, %2.reg1, %2.reg2
+		gen stbx %1, %2.reg1, %2.reg2
 
 /* Read halfword (short) */
 
-	from IND_RC_H to GPR
-		gen
-			COMMENT("move IND_RC_H->GPR")
-			lhz %2, {GPRINDIRECT, %1.reg, %1.off}
+	from IND_RC_H+IND_RL_H to GPR
+		gen lhz %2, %1
 
 	from IND_RR_H to GPR
-		gen
-			COMMENT("move IND_RR_H->GPR")
-			lhzx %2, %1.reg1, %1.reg2
+		gen lhzx %2, %1.reg1, %1.reg2
 
-	from IND_RC_H_S to GPR
-		gen
-			COMMENT("move IND_RC_H_S->GPR")
-			lha %2, {GPRINDIRECT, %1.reg, %1.off}
+	from IND_RC_H_S+IND_RL_H_S to GPR
+		gen lha %2, %1
 
 	from IND_RR_H_S to GPR
-		gen
-			COMMENT("move IND_RR_H_S->GPR")
-			lhax %2, %1.reg1, %1.reg2
+		gen lhax %2, %1.reg1, %1.reg2
 
 /* Write halfword */
 
-	from GPR to IND_RC_H
-		gen
-			COMMENT("move GPR->IND_RC_H")
-			sth %1, {GPRINDIRECT, %2.reg, %2.off}
+	from GPR to IND_RC_H+IND_RL_H
+		gen sth %1, %2
 
 	from GPR to IND_RR_H
-		gen
-			COMMENT("move GPR->IND_RR_H")
-			sthx %1, %2.reg1, %2.reg2
+		gen sthx %1, %2.reg1, %2.reg2
 
 /* Read word */
 
-	from IND_RC_W to GPR
-		gen
-			COMMENT("move IND_RC_W->GPR")
-			lwz %2, {GPRINDIRECT, %1.reg, %1.off}
+	from IND_RC_W+IND_RL_W to GPR
+		gen lwz %2, %1
 
 	from IND_RR_W to GPR
-		gen
-			COMMENT("move IND_RR_W->GPR")
-			lwzx %2, %1.reg1, %1.reg2
+		gen lwzx %2, %1.reg1, %1.reg2
 
-	from IND_RC_W to FSREG
-		gen
-			COMMENT("move IND_RC_W->FSREG")
-			lfs %2, {GPRINDIRECT, %1.reg, %1.off}
+	from IND_RC_W+IND_RL_W to FSREG
+		gen lfs %2, %1
 
 	from IND_RR_W to FSREG
-		gen
-			COMMENT("move IND_RR_W->FSREG")
-			lfsx %2, %1.reg1, %1.reg2
+		gen lfsx %2, %1.reg1, %1.reg2
 
 /* Write word */
 
-	from GPR to IND_RC_W
-		gen
-			COMMENT("move GPR->IND_RC_W")
-			stw %1, {GPRINDIRECT, %2.reg, %2.off}
+	from GPR to IND_RC_W+IND_RL_W
+		gen stw %1, %2
 
 	from GPR to IND_RR_W
-		gen
-			COMMENT("move GPR->IND_RR_W")
-			stwx %1, %2.reg1, %2.reg2
+		gen stwx %1, %2.reg1, %2.reg2
 
-	from FSREG to IND_RC_W
-		gen
-			COMMENT("move FSREG->IND_RC_W")
-			stfs %1, {GPRINDIRECT, %2.reg, %2.off}
+	from FSREG to IND_RC_W+IND_RL_W
+		gen stfs %1, %2
 
 	from FSREG to IND_RR_W
-		gen
-			COMMENT("move FSREG->IND_RR_W")
-			stfsx %1, %2.reg1, %2.reg2
+		gen stfsx %1, %2.reg1, %2.reg2
 
 /* Read double */
 
-	from IND_RC_D to FPR
-		gen
-			COMMENT("move IND_RC_D->FPR")
-			lfd %2, {GPRINDIRECT, %1.reg, %1.off}
+	from IND_RC_D+IND_RL_D to FPR
+		gen lfd %2, %1
 
 	from IND_RR_D to FPR
-		gen
-			COMMENT("move IND_RR_D->FPR")
-			lfdx %2, %1.reg1, %1.reg2
+		gen lfdx %2, %1.reg1, %1.reg2
 
 /* Write double */
 
-	from FPR to IND_RC_D
-		gen
-			COMMENT("move FPR->IND_RC_D")
-			stfd %1, {GPRINDIRECT, %2.reg, %2.off}
+	from FPR to IND_RC_D+IND_RL_D
+		gen stfd %1, %2
 
 	from FPR to IND_RR_D
-		gen
-			COMMENT("move FPR->IND_RR_W")
-			stfdx %1, %2.reg1, %2.reg2
-
-/* Extract condition code field (actually produces (CC&3)<<2) */
-
-	from CR0 to GPR
-		gen
-			COMMENT("move CR0->GPR")
-			mfcr %2
-			rlwinm %2, %2, {CONST, 4}, {CONST, 32-4}, {CONST, 31-2}
-
-/* Comparisons */
-
-	from TRISTATE_RR_S to CR0
-		gen
-			cmp %2, {CONST, 0}, %1.reg1, %1.reg2
-			
-	from TRISTATE_RR_U to CR0
-		gen
-			cmpl %2, {CONST, 0}, %1.reg1, %1.reg2
-		
-	from TRISTATE_RC_S to CR0
-		gen
-			COMMENT("move TRISTATE_RC_S->CR0 large")
-			move {CONST, %1.val}, RSCRATCH
-			cmp %2, {CONST, 0}, %1.reg, RSCRATCH
-			
-	from TRISTATE_RC_U smallu(%val) to CR0
-		gen
-			COMMENT("move TRISTATE_RC_U->CR0 small")
-			cmpli %2, {CONST, 0}, %1.reg, {CONST, %1.val}
-		
-	from TRISTATE_RC_U to CR0
-		gen
-			COMMENT("move TRISTATE_RC_U->CR0")
-			move {CONST, %1.val}, RSCRATCH
-			cmpl %2, {CONST, 0}, %1.reg, RSCRATCH
-		
-	from TRISTATE_FF to CR0
-		gen
-			COMMENT("move TRISTATE_FF->CR0")
-			fcmpo %2, %1.reg1, %1.reg2
-			
-	from GPR to CR0
-		gen
-			COMMENT("move GPR->CR0")
-			orX RSCRATCH, %1, %1 /* alas, can't call test */
-			
-	from TRISTATE_RR_S + TRISTATE_RC_S + TRISTATE_FF to GPR
-		gen
-			COMMENT("move TRISTATE_R*_S->GPR")
-			move %1, C0
-			move C0, RSCRATCH
-			move {LABEL, ".tristate_s_table"}, %2
-			lwzx %2, %2, RSCRATCH
-
-	from TRISTATE_RR_U + TRISTATE_RC_U to GPR
-		gen
-			COMMENT("move TRISTATE_R*_U->GPR")
-			move %1, C0
-			move C0, RSCRATCH
-			move {LABEL, ".tristate_u_table"}, %2
-			lwzx %2, %2, RSCRATCH
+		gen stfdx %1, %2.reg1, %2.reg2
 
 /* Logicals */
 
 	from NOT_R to GPR
-		gen
-			COMMENT("move NOT_R->GPR")
-			nor %2, %1.reg, %1.reg
+		gen nor %2, %1.reg, %1.reg
 
 	from AND_RR to GPR
-		gen
-			COMMENT("move AND_RR->GPR")
-			and %2, %1.reg1, %1.reg2
+		gen and %2, %1.reg1, %1.reg2
 
 	from OR_RR to GPR
-		gen
-			COMMENT("move OR_RR->GPR")
-			or %2, %1.reg1, %1.reg2
+		gen or %2, %1.reg1, %1.reg2
 
 	from OR_RIS to GPR
-		gen
-			COMMENT("move OR_RIS->GPR")
-			oris %2, %1.reg, {CONST, %1.valhi}
+		gen oris %2, %1.reg, {CONST, %1.valhi}
 
 	from OR_RC to GPR
-		gen
-			COMMENT("move OR_RC->GPR")
-			ori %2, %1.reg, {CONST, %1.val}
+		gen ori %2, %1.reg, {CONST, %1.val}
 
 	from XOR_RR to GPR
-		gen
-			COMMENT("move XOR_RR->GPR")
-			xor %2, %1.reg1, %1.reg2
+		gen xor %2, %1.reg1, %1.reg2
 
 	from XOR_RIS to GPR
-		gen
-			COMMENT("move XOR_RIS->GPR")
-			xoris %2, %1.reg, {CONST, %1.valhi}
+		gen xoris %2, %1.reg, {CONST, %1.valhi}
 
 	from XOR_RC to GPR
+		gen xori %2, %1.reg, {CONST, %1.val}
+
+/* Conditions */
+
+	/* Compare values, then copy cr0 to GPR. */
+
+	from COND_RC to GPR
 		gen
-			COMMENT("move XOR_RC->GPR")
-			xori %2, %1.reg, {CONST, %1.val}
+			cmpwi %1.reg, {CONST, %1.val}
+			mfcr %2
 
-/* Miscellaneous */
-
-	from OP_ALL_W + LABEL + CONST_ALL to GPRE
+	from COND_RR to GPR
 		gen
-			move %1, %2.reg
+			cmpw %1.reg1, %1.reg2
+			mfcr %2
+
+	from CONDL_RC to GPR
+		gen
+			cmplwi %1.reg, {CONST, %1.val}
+			mfcr %2
+
+	from CONDL_RR to GPR
+		gen
+			cmplw %1.reg1, %1.reg2
+			mfcr %2
+
+	from COND_FS to GPR
+		gen
+			fcmpo CR0, %1.reg1, %1.reg2
+			mfcr %2
+
+	from COND_FD to GPR
+		gen
+			fcmpo CR0, %1.reg1, %1.reg2
+			mfcr %2
+
+	/* Given a copy of cr0 in %1.reg, extract a condition bit
+	 * (lt, gt, eq) and perhaps flip it.
+	 */
+
+	from XEQ to GPR
+		gen
+			extrwi %2, %1.reg, {CONST, 1}, {CONST, 2}
+
+	from XNE to GPR
+		gen
+			extrwi %2, %1.reg, {CONST, 1}, {CONST, 2}
+			xori %2, %2, {CONST, 1}
+
+	from XGT to GPR
+		gen
+			extrwi %2, %1.reg, {CONST, 1}, {CONST, 1}
+
+	from XGE to GPR
+		gen
+			extrwi %2, %1.reg, {CONST, 1}, {CONST, 0}
+			xori %2, %2, {CONST, 1}
+
+	from XLT to GPR
+		gen
+			extrwi %2, %1.reg, {CONST, 1}, {CONST, 0}
+
+	from XLE to GPR
+		gen
+			extrwi %2, %1.reg, {CONST, 1}, {CONST, 1}
+			xori %2, %2, {CONST, 1}
+
+/* GPRE exists solely to allow us to use regvar() (which can only be used in
+   an expression) as a register constant. */
+
+	from ANY_BHW to GPRE
+		gen move %1, %2.reg
+
 
-		
 TESTS
-	
+
+	/* Given orX %1, %1, %1, ncgg says, "Instruction destroys %1,
+	 * not allowed here".  We use orX_readonly to trick ncgg.
+	 *
+	 * Using "or." and not "mr." because mach/powerpc/top/table
+	 * was optimizing "or." and not "mr.".
+	 */
 	to test GPR
 		gen
-			orX RSCRATCH, %1, %1
-
+			orX_readonly %1, %1, %1
 
 
 STACKINGRULES
@@ -685,95 +641,57 @@ STACKINGRULES
 	from LOCAL to STACK
 		gen
 			COMMENT("stack LOCAL")
-			stwu {GPRE, regvar(%1.off)}, {GPRINDIRECT, SP, 0-4}
+			stwu %1, {IND_RC_W, SP, 0-4}
 
 	from REG to STACK
 		gen
 			COMMENT("stack REG")
-			stwu %1, {GPRINDIRECT, SP, 0-4}
+			stwu %1, {IND_RC_W, SP, 0-4}
 
 	from REG_PAIR to STACK
 		gen
 			COMMENT("stack REG_PAIR")
-			stwu %1.2, {GPRINDIRECT, SP, 0-4}
-			stwu %1.1, {GPRINDIRECT, SP, 0-4}
+			stwu %1.2, {IND_RC_W, SP, 0-4}
+			stwu %1.1, {IND_RC_W, SP, 0-4}
 
-	from CONST_ALL + LABEL to STACK
+	from ANY_BHW-REG to STACK
 		gen
-			COMMENT("stack CONST_ALL + LABEL")
+			COMMENT("stack ANY_BHW-REG")
 			move %1, RSCRATCH
-			stwu RSCRATCH, {GPRINDIRECT, SP, 0-4}
+			stwu RSCRATCH, {IND_RC_W, SP, 0-4}
 
-	from SEX_B to STACK
-		gen
-			COMMENT("stack SEX_B")
-			extsb RSCRATCH, %1.reg
-			stwu RSCRATCH, {GPRINDIRECT, SP, 0-4}
-			
-	from SEX_H to STACK
-		gen
-			COMMENT("stack SEX_H")
-			extsh RSCRATCH, %1.reg
-			stwu RSCRATCH, {GPRINDIRECT, SP, 0-4}
-			
-	from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL to STACK
-		gen
-			COMMENT("stack SUM_ALL + TRISTATE_ALL + LOGICAL_ALL")
-			move %1, RSCRATCH
-			stwu RSCRATCH, {GPRINDIRECT, SP, 0-4}
-			
-	from IND_ALL_BHW to STACK
-		gen
-			COMMENT("stack IND_ALL_BHW")
-			move %1, RSCRATCH
-			stwu RSCRATCH, {GPRINDIRECT, SP, 0-4}
-			
 	from IND_ALL_D to STACK
 		gen
 			COMMENT("stack IND_ALL_D")
 			move %1, FSCRATCH
-			stfdu FSCRATCH, {GPRINDIRECT, SP, 0-8}
-			
+			stfdu FSCRATCH, {IND_RC_D, SP, 0-8}
+
 	from FREG to STACK
 		gen
 			COMMENT("stack FPR")
-			stfdu %1, {GPRINDIRECT, SP, 0-8}
-			
+			stfdu %1, {IND_RC_D, SP, 0-8}
+
 	from FSREG to STACK
 		gen
 			COMMENT("stack FSREG")
-			stfsu %1, {GPRINDIRECT, SP, 0-4}
+			stfsu %1, {IND_RC_W, SP, 0-4}
 
 
 
 COERCIONS
 
-	from REG
+	from ANY_BHW
 		uses REG
 		gen
-			COMMENT("coerce REG->REG")
+			COMMENT("coerce ANY_BHW->REG")
 			move %1, %a
 		yields %a
 
-	from CONST_ALL
-		uses REG
-		gen
-			COMMENT("coerce CONST_ALL->REG")
-			move %1, %a
-		yields %a
-		
-	from LABEL
-		uses REG
-		gen
-			COMMENT("coerce LABEL->REG")
-			move %1, %a
-		yields %a
-		
 	from STACK
 		uses REG
 		gen
 			COMMENT("coerce STACK->REG")
-			lwz %a, {GPRINDIRECT, SP, 0}
+			lwz %a, {IND_RC_W, SP, 0}
 			addi SP, SP, {CONST, 4}
 		yields %a
 
@@ -781,48 +699,28 @@ COERCIONS
 		uses REG_PAIR
 		gen
 			COMMENT("coerce STACK->REG_PAIR")
-			lwz %a.1, {GPRINDIRECT, SP, 0}
-			lwz %a.2, {GPRINDIRECT, SP, 4}
+			lwz %a.1, {IND_RC_W, SP, 0}
+			lwz %a.2, {IND_RC_W, SP, 4}
 			addi SP, SP, {CONST, 8}
 		yields %a
 
-	from SEX_B
-		uses REG
-		gen
-			COMMENT("coerce SEX_B->REG")
-			extsb %a, %1.reg
-		yields %a
-		
-	from SEX_H
-		uses REG
-		gen
-			COMMENT("coerce SEX_H->REG")
-			extsh %a, %1.reg
-		yields %a
-	
-	from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL
-		uses REG
-		gen
-			move %1, %a
-		yields %a
-	
 	from FSREG
 		uses FSREG
 		gen
 			fmr %a, %1
 		yields %a
-		
+
 	from FREG
 		uses FREG
 		gen
 			fmr %a, %1
 		yields %a
-		
+
 	from STACK
 		uses FREG
 		gen
 			COMMENT("coerce STACK->FREG")
-			lfd %a, {GPRINDIRECT, SP, 0}
+			lfd %a, {IND_RC_D, SP, 0}
 			addi SP, SP, {CONST, 8}
 		yields %a
 
@@ -830,16 +728,10 @@ COERCIONS
 		uses FSREG
 		gen
 			COMMENT("coerce STACK->FSREG")
-			lfs %a, {GPRINDIRECT, SP, 0}
+			lfs %a, {IND_RC_W, SP, 0}
 			addi SP, SP, {CONST, 4}
 		yields %a
 
-	from IND_ALL_BHW
-		uses REG
-		gen
-			move %1, %a
-		yields %a
-
 	from IND_ALL_W
 		uses FSREG
 		gen
@@ -884,17 +776,17 @@ PATTERNS
 			yields %1 %1
 		with FSREG
 			yields %1 %1
-								
+
 	pat dup $1==INT64                  /* Duplicate double-word on top of stack */
 		with REG REG
 			yields %2 %1 %2 %1
 		with FREG
 			yields %1 %1
-								
+
 	pat exg $1==INT32                  /* Exchange top two words on stack */
 		with REG REG
 			yields %1 %2
-		
+
 	pat stl lol $1==$2                 /* Store then load local */
 		leaving
 			dup 4
@@ -910,33 +802,21 @@ PATTERNS
 			dup INT32
 			lal $1
 			sti $2
-			
+
 	pat ste loe $1==$2                 /* Store then load external */
 		leaving
 			dup 4
 			ste $1
-		
-		
+
+
 /* Type conversions */
 
-	pat loc loc cii loc loc cii $1==$4 && $2==$5 /* madness, generated by the C compiler */
-		leaving
-			loc $1
-			loc $2
-			cii
-			
-	pat loc loc cii loc loc cii $2==INT32 && $5==INT32 && $4<$2 /* madness, generated by the C compiler */
-		leaving
-			loc $4
-			loc $5
-			cii
-			
 	pat loc loc ciu                    /* signed X -> unsigned X */
 		leaving
 			loc $1
 			loc $2
 			cuu
-			
+
 	pat loc loc cuu $1==$2             /* unsigned X -> unsigned X */
 		/* nop */
 
@@ -945,25 +825,22 @@ PATTERNS
 
 	pat loc loc cui $1==$2             /* unsigned X -> signed X */
 		/* nop */
-		
+
 	pat loc loc cui $1==INT8 && $2==INT32 /* unsigned char -> signed int */
 		/* nop */
-	
+
 	pat loc loc cui $1==INT16 && $2==INT32 /* unsigned short -> signed int */
 		/* nop */
-	
-	pat loc loc cii $1==INT8 && $2==INT32 /* signed char -> signed int */
-		with GPR
-			yields {SEX_B, %1}
-	
-	pat loc loc cii $1==2 && $2==4     /* signed char -> signed short */
-		with GPR
-			yields {SEX_H, %1}
-	
 
-		
-	
-		
+	pat loc loc cii $1==INT8 && $2==INT32 /* signed char -> signed int */
+		with REG
+			yields {SEX_B, %1}
+
+	pat loc loc cii $1==2 && $2==4     /* signed char -> signed short */
+		with REG
+			yields {SEX_H, %1}
+
+
 /* Local variables */
 
 	pat lal smalls($1)                 /* Load address of local */
@@ -975,7 +852,7 @@ PATTERNS
 
 	pat lol inreg($1)>0                /* Load from local */
 		yields {LOCAL, $1}
-		
+
 	pat lol                            /* Load from local */
 		leaving
 			lal $1
@@ -985,34 +862,31 @@ PATTERNS
 		leaving
 			lal $1
 			loi INT32*2
-			
+
 	pat stl inreg($1)>0                /* Store to local */
-		with CONST_ALL + LABEL + GPR + OP_ALL_W
+		with ANY_BHW
 			kills regvar($1), LOCAL %off==$1
 			gen
 				move %1, {GPRE, regvar($1)}
-		
+
 	pat stl                            /* Store to local */
 		leaving
 			lal $1
 			sti INT32
-		
+
 	pat sdl                            /* Store double-word to local */
 		leaving
 			lal $1
 			sti INT32*2
-			
+
 	pat lil inreg($1)>0                /* Load from indirected local */
-		uses REG
-		gen
-			lwz %a, {GPRINDIRECT, regvar($1), 0}
-		yields %a
-		
+		yields {IND_RC_W, regvar($1), 0}
+
 	pat lil                            /* Load from indirected local */
 		leaving
 			lol $1
 			loi INT32
-			
+
 	pat sil                            /* Save to indirected local */
 		leaving
 			lol $1
@@ -1022,14 +896,14 @@ PATTERNS
 		leaving
 			loc 0
 			stl $1
-	
+
 	pat inl                             /* Increment local */
 		leaving
 			lol $1
 			loc 1
 			adi 4
 			stl $1
-					
+
 	pat del                             /* Decrement local */
 		leaving
 			lol $1
@@ -1039,14 +913,15 @@ PATTERNS
 
 
 /* Global variables */
-		
+
 	pat lpi                            /* Load address of external function */
 		leaving
 			lae $1
-				
+
 	pat lae                            /* Load address of external */
-		yields {LABEL, $1}
-		
+		uses REG={LABEL_HA, $1}
+		yields {SUM_RL, %a, $1}
+
 	pat loe                            /* Load word external */
 		leaving
 			lae $1
@@ -1056,36 +931,33 @@ PATTERNS
 		leaving
 			lae $1
 			sti INT32
-			
+
 	pat lde                            /* Load double-word external */
 		leaving
 			lae $1
 			loi INT64
-			
+
 	pat sde                            /* Store double-word external */
 		leaving
 			lae $1
 			sti INT64
-			
+
 	pat zre                             /* Zero external */
 		leaving
 			loc 0
 			ste $1
-	
+
 	pat ine                             /* Increment external */
-		uses REG={LABEL, $1}, REG
-			gen
-				lwz %b, {GPRINDIRECT, %a, 0}
-				addi %b, %b, {CONST, 1}
-				stw %b, {GPRINDIRECT, %a, 0}
-					
+		leaving
+			loe $1
+			inc
+			ste $1
+
 	pat dee                             /* Decrement external */
-		uses REG={LABEL, $1}, REG
-			gen
-				lwz %b, {GPRINDIRECT, %a, 0}
-				addi %b, %b, {CONST, 0-1}
-				stw %b, {GPRINDIRECT, %a, 0}
-					
+		leaving
+			loe $1
+			dec
+			ste $1
 
 
 /* Structures */
@@ -1094,157 +966,142 @@ PATTERNS
 		leaving
 			adp $1
 			loi INT32
-			
+
 	pat ldf                            /* Load double-word offsetted */
 		leaving
 			adp $1
 			loi INT64
-			
+
 	pat stf                            /* Store word offsetted */
 		leaving
 			adp $1
 			sti INT32
-			
+
 	pat sdf                            /* Store double-word offsetted */
 		leaving
 			adp $1
 			sti INT64
-			
 
 
 /* Loads and stores */
 
 	pat loi $1==INT8                   /* Load byte indirect */
-		with GPR
+		with REG
 			yields {IND_RC_B, %1, 0}
-		with SUM_RR
-			yields {IND_RR_B, %1.reg1, %1.reg2}
-		with SUM_RC
+		with exact SUM_RC
 			yields {IND_RC_B, %1.reg, %1.off}
+		with exact SUM_RL
+			yields {IND_RL_B, %1.reg, %1.adr}
+		with exact SUM_RR
+			yields {IND_RR_B, %1.reg1, %1.reg2}
 
 	pat loi loc loc cii $1==INT16 && $2==INT16 && $3==INT32
 	/* Load half-word indirect and sign extend */
-		with GPR
+		with REG
 			yields {IND_RC_H_S, %1, 0}
-		with SUM_RR
-			yields {IND_RR_H_S, %1.reg1, %1.reg2}
-		with SUM_RC
+		with exact SUM_RC
 			yields {IND_RC_H_S, %1.reg, %1.off}
+		with exact SUM_RL
+			yields {IND_RL_H_S, %1.reg, %1.adr}
+		with exact SUM_RR
+			yields {IND_RR_H_S, %1.reg1, %1.reg2}
 
 	pat loi $1==INT16                  /* Load half-word indirect */
-		with GPR
+		with REG
 			yields {IND_RC_H, %1, 0}
-		with SUM_RR
-			yields {IND_RR_H, %1.reg1, %1.reg2}
-		with SUM_RC
+		with exact SUM_RC
 			yields {IND_RC_H, %1.reg, %1.off}
+		with exact SUM_RL
+			yields {IND_RL_H, %1.reg, %1.adr}
+		with exact SUM_RR
+			yields {IND_RR_H, %1.reg1, %1.reg2}
 
 	pat loi $1==INT32                  /* Load word indirect */
-		with GPR
+		with REG
 			yields {IND_RC_W, %1, 0}
-		with SUM_RC
+		with exact SUM_RC
 			yields {IND_RC_W, %1.reg, %1.off}
-		with SUM_RR
+		with exact SUM_RL
+			yields {IND_RL_W, %1.reg, %1.adr}
+		with exact SUM_RR
 			yields {IND_RR_W, %1.reg1, %1.reg2}
 
 	pat loi $1==INT64                  /* Load double-word indirect */
-		with GPR
+		with REG
 			yields {IND_RC_D, %1, 0}
-		with SUM_RC
+		with exact SUM_RC
 			yields {IND_RC_D, %1.reg, %1.off}
-		with SUM_RR
+		with exact SUM_RL
+			yields {IND_RL_D, %1.reg, %1.adr}
+		with exact SUM_RR
 			yields {IND_RR_D, %1.reg1, %1.reg2}
 
 	pat loi                            /* Load arbitrary size */
 		leaving
 			loc $1
 			los INT32
-					
-	pat los                            /* Load arbitrary size */
+
+	pat los $1==INT32                  /* Load arbitrary size */
 		with GPR3 GPR4 STACK
 			kills ALL
 			gen
 				bl {LABEL, ".los"}
 
 	pat sti $1==INT8                   /* Store byte indirect */
-		with GPR GPR
+		with REG REG
 			kills MEMORY
-			gen
-				stb %2, {GPRINDIRECT, %1, 0}
-		with SUM_RR GPR
+			gen move %2, {IND_RC_B, %1, 0}
+		with SUM_RC REG
 			kills MEMORY
-			gen
-				stbx %2, %1.reg1, %1.reg2
-		with SUM_RC GPR
+			gen move %2, {IND_RC_B, %1.reg, %1.off}
+		with SUM_RL REG
 			kills MEMORY
-			gen
-				move %2, {IND_RC_B, %1.reg, %1.off}
-		with GPR SEX_B
+			gen move %2, {IND_RL_B, %1.reg, %1.adr}
+		with SUM_RR REG
 			kills MEMORY
-			gen
-				stb %2.reg, {GPRINDIRECT, %1, 0}
-		with SUM_RR SEX_B
-			kills MEMORY
-			gen
-				stbx %2.reg, %1.reg1, %1.reg2
-		with SUM_RC SEX_B
-			kills MEMORY
-			gen
-				move %2.reg, {IND_RC_B, %1.reg, %1.off}
+			gen move %2, {IND_RR_B, %1.reg1, %1.reg2}
 
 	pat sti $1==INT16                  /* Store half-word indirect */
-		with GPR GPR
+		with REG REG
 			kills MEMORY
-			gen
-				sth %2, {GPRINDIRECT, %1, 0}
-		with SUM_RR GPR
+			gen move %2, {IND_RC_H, %1, 0}
+		with SUM_RC REG
 			kills MEMORY
-			gen
-				sthx %2, %1.reg1, %1.reg2
-		with SUM_RC GPR
+			gen move %2, {IND_RC_H, %1.reg, %1.off}
+		with SUM_RL REG
 			kills MEMORY
-			gen
-				move %2, {IND_RC_H, %1.reg, %1.off}
-		with GPR SEX_H
+			gen move %2, {IND_RL_H, %1.reg, %1.adr}
+		with SUM_RR REG
 			kills MEMORY
-			gen
-				sth %2.reg, {GPRINDIRECT, %1, 0}
-		with SUM_RR SEX_H
-			kills MEMORY
-			gen
-				sthx %2.reg, %1.reg1, %1.reg2
-		with SUM_RC SEX_H
-			kills MEMORY
-			gen
-				move %2.reg, {IND_RC_H, %1.reg, %1.off}
+			gen move %2, {IND_RR_H, %1.reg1, %1.reg2}
 
 	pat sti $1==INT32                  /* Store word indirect */
-		with GPR GPR+FSREG
+		with REG REG+FSREG
 			kills MEMORY
-			gen
-				move %2, {IND_RC_W, %1, 0}
-		with SUM_RR GPR+FSREG
+			gen move %2, {IND_RC_W, %1, 0}
+		with SUM_RC REG+FSREG
 			kills MEMORY
-			gen
-				move %2, {IND_RR_W, %1.reg1, %1.reg2}
-		with SUM_RC GPR+FSREG
+			gen move %2, {IND_RC_W, %1.reg, %1.off}
+		with SUM_RL REG+FSREG
 			kills MEMORY
-			gen
-				move %2, {IND_RC_W, %1.reg, %1.off}
+			gen move %2, {IND_RL_W, %1.reg, %1.adr}
+		with SUM_RR REG+FSREG
+			kills MEMORY
+			gen move %2, {IND_RR_W, %1.reg1, %1.reg2}
 
 	pat sti $1==INT64                  /* Store double-word indirect */
 		with REG FREG
 			kills MEMORY
-			gen
-				move %2, {IND_RC_D, %1, 0}
-		with SUM_RR FREG
-			kills MEMORY
-			gen
-				move %2, {IND_RR_D, %1.reg1, %1.reg2}
+			gen move %2, {IND_RC_D, %1, 0}
 		with SUM_RC FREG
 			kills MEMORY
-			gen
-				move %2, {IND_RC_D, %1.reg, %1.off}
+			gen move %2, {IND_RC_D, %1.reg, %1.off}
+		with SUM_RL FREG
+			kills MEMORY
+			gen move %2, {IND_RL_D, %1.reg, %1.adr}
+		with SUM_RR FREG
+			kills MEMORY
+			gen move %2, {IND_RR_D, %1.reg1, %1.reg2}
 		/*
 		 * This pattern would be too slow:
 		 *   with REG REG REG
@@ -1283,22 +1140,21 @@ PATTERNS
 			loc $1
 			sts INT32
 
-	pat sts                            /* Store arbitrary size */
+	pat sts $1==INT32                  /* Store arbitrary size */
 		with GPR3 GPR4 STACK
 			kills ALL
 			gen
 				bl {LABEL, ".sts"}
-				
 
 
 /* Arithmetic wrappers */
 
 	pat ads $1==4                      /* Add var to pointer */
 		leaving adi $1
-	
+
 	pat sbs $1==4                      /* Subtract var from pointer */
 		leaving sbi $1
-		
+
 	pat adp                            /* Add constant to pointer */
 		leaving
 			loc $1
@@ -1307,41 +1163,30 @@ PATTERNS
 	pat adu                            /* Add unsigned */
 		leaving
 			adi $1
-			
+
 	pat sbu                            /* Subtract unsigned */
 		leaving
 			sbi $1
-			
+
 	pat inc                            /* Add 1 */
 		leaving
 			loc 1
 			adi 4
-			
+
 	pat dec                            /* Subtract 1 */
 		leaving
 			loc 1
 			sbi 4
-	
-	pat loc mlu $2==2                  /* Unsigned multiply by constant */
-		leaving
-			loc $1
-			mli 4
-			
-	pat mlu                            /* Unsigned multiply by var */
+
+	pat mlu                            /* Multiply unsigned */
 		leaving
 			mli $1
-			
-	pat loc slu                        /* Shift left unsigned by constant amount */
-		leaving
-			loc $1
-			sli $2
-			
-	pat slu                            /* Shift left unsigned by variable amount */
+
+	pat slu                            /* Shift left unsigned */
 		leaving
 			sli $1
 
-			
-			
+
 /* Word arithmetic */
 
 	pat adi $1==4                      /* Add word (second + top) */
@@ -1357,14 +1202,12 @@ PATTERNS
 		with REG CONST_HZ
 			uses reusing %1, REG={SUM_RIS, %1, his(%2.val)}
 			yields %a
-		with CONST_ALL-CONST2-CONST_HZ REG
+		with CONST_STACK-CONST2-CONST_HZ REG
 			uses reusing %2, REG={SUM_RIS, %2, his(%1.val)}
 			yields {SUM_RC, %a, los(%1.val)}
-		with REG CONST_ALL-CONST2-CONST_HZ
+		with REG CONST_STACK-CONST2-CONST_HZ
 			uses reusing %1, REG={SUM_RIS, %1, his(%2.val)}
 			yields {SUM_RC, %a, los(%2.val)}
-		with CONST_ALL LABEL
-			yields {LABEL, %2.adr+%1.val}
 
 	pat sbi $1==4                      /* Subtract word (second - top) */
 		with REG REG
@@ -1377,11 +1220,9 @@ PATTERNS
 		with CONST_HZ REG
 			uses reusing %2, REG={SUM_RIS, %2, his(0-%1.val)}
 			yields %a
-		with CONST_ALL-CONST2_WHEN_NEG-CONST_HZ REG
+		with CONST_STACK-CONST2_WHEN_NEG-CONST_HZ REG
 			uses reusing %2, REG={SUM_RIS, %2, his(0-%1.val)}
 			yields {SUM_RC, %a, los(0-%1.val)}
-		with CONST_ALL LABEL
-			yields {LABEL, %2.adr+(0-%1.val)}
 
 	pat ngi $1==4                      /* Negate word */
 		with REG
@@ -1389,21 +1230,21 @@ PATTERNS
 			gen
 				neg %a, %1
 			yields %a
-		
+
 	pat mli $1==4                      /* Multiply word (second * top) */
 		with REG REG
 			uses reusing %2, REG
 			gen
 				mullw %a, %2, %1
 			yields %a
-		
+
 	pat dvi $1==4                      /* Divide word (second / top) */
 		with REG REG
 			uses reusing %2, REG
 			gen
 				divw %a, %2, %1
 			yields %a
-					
+
 	pat dvu $1==4                      /* Divide unsigned word (second / top) */
 		with REG REG
 			uses reusing %2, REG
@@ -1419,7 +1260,7 @@ PATTERNS
 				mullw %a, %a, %1
 				subf %a, %a, %2
 			yields %a
-								
+
 	pat rmu $1==4                      /* Remainder unsigned word (second % top) */
 		with REG REG
 			uses REG
@@ -1430,43 +1271,47 @@ PATTERNS
 			yields %a
 
 	pat and $1==4                      /* AND word */
-		with GPR NOT_R
+		with REG NOT_R
 			uses reusing %1, REG
 			gen
 				andc %a, %1, %2.reg
 			yields %a
-		with NOT_R GPR
+		with NOT_R REG
 			uses reusing %1, REG
 			gen
 				andc %a, %2, %1.reg
 			yields %a
-		with GPR GPR
+		with REG REG
 			yields {AND_RR, %1, %2}
-		with GPR UCONST2
+		with REG UCONST2
 			uses reusing %1, REG
 			gen
 				andiX %a, %1, {CONST, %2.val}
 			yields %a
-		with UCONST2 GPR
+		with UCONST2 REG
 			uses reusing %2, REG
 			gen
 				andiX %a, %2, {CONST, %1.val}
 			yields %a
-		with GPR CONST_HZ
+		with REG CONST_HZ
 			uses reusing %1, REG
 			gen
 				andisX %a, %1, {CONST, hi(%2.val)}
 			yields %a
-		with CONST_HZ GPR
+		with CONST_HZ REG
 			uses reusing %2, REG
 			gen
 				andisX %a, %2, {CONST, hi(%1.val)}
 			yields %a
 
-	pat and !defined($1)               /* AND set */
-		with STACK
-			gen
-				bl {LABEL, ".and"}
+	pat and defined($1)                /* AND set */
+		leaving
+			loc $1
+			cal ".and"
+
+	pat and !defined($1)
+		leaving
+			cal ".and"
 
 	pat ior $1==4                      /* OR word */
 		with REG NOT_R
@@ -1491,17 +1336,22 @@ PATTERNS
 		with CONST_HZ REG
 			uses reusing %2, REG={OR_RIS, %2, hi(%1.val)}
 			yields %a
-		with REG CONST_ALL-UCONST2-CONST_HZ
+		with REG CONST_STACK-UCONST2-CONST_HZ
 			uses reusing %1, REG={OR_RIS, %1, hi(%2.val)}
 			yields {OR_RC, %1, lo(%2.val)}
-		with CONST_ALL-UCONST2-CONST_HZ REG
+		with CONST_STACK-UCONST2-CONST_HZ REG
 			uses reusing %2, REG={OR_RIS, %2, hi(%1.val)}
 			yields {OR_RC, %2, lo(%1.val)}
 
-	pat ior !defined($1)               /* OR set */
-		with STACK
-			gen
-				bl {LABEL, ".ior"}
+	pat ior defined($1)                /* OR set */
+		leaving
+			loc $1
+			cal ".ior"
+
+	/* OR set (variable), used in lang/m2/libm2/LtoUset.e */
+	pat ior !defined($1)
+		leaving
+			cal ".ior"
 
 	pat xor $1==4                      /* XOR word */
 		with REG REG
@@ -1516,18 +1366,20 @@ PATTERNS
 		with CONST_HZ REG
 			uses reusing %2, REG={XOR_RIS, %2, hi(%1.val)}
 			yields %a
-		with REG CONST_ALL-UCONST2-CONST_HZ
+		with REG CONST_STACK-UCONST2-CONST_HZ
 			uses reusing %1, REG={XOR_RIS, %1, hi(%2.val)}
 			yields {XOR_RC, %1, lo(%2.val)}
-		with CONST_ALL-UCONST2-CONST_HZ REG
+		with CONST_STACK-UCONST2-CONST_HZ REG
 			uses reusing %2, REG={XOR_RIS, %2, hi(%1.val)}
 			yields {XOR_RC, %2, lo(%1.val)}
 
-	pat xor !defined($1)               /* XOR set */
+	pat xor defined($1)                /* XOR set */
 		with STACK
+			kills ALL
 			gen
+				move {CONST, $1}, R3
 				bl {LABEL, ".xor"}
-				
+
 	pat com $1==INT32                  /* NOT word */
 		with AND_RR
 			uses REG
@@ -1544,72 +1396,86 @@ PATTERNS
 			gen
 				eqv %a, %1.reg1, %1.reg2
 			yields %a
-		with GPR
+		with REG
 			yields {NOT_R, %1}
-				
-	pat com !defined($1)               /* NOT set */
-		with STACK
-			gen
-				bl {LABEL, ".com"}
-				
+
+	pat com defined($1)                /* NOT set */
+		leaving
+			loc $1
+			cal ".com"
+
+	pat com !defined($1)
+		leaving
+			cal ".com"
+
+	pat zer $1==4                      /* Push zero */
+		leaving
+			loc 0
+
+	pat zer defined($1)	   	           /* Create empty set */
+		leaving
+			loc $1
+			cal ".zer"
+
 	pat sli $1==4                      /* Shift left (second << top) */
-		with CONST_ALL GPR
+		with CONST_STACK REG
 			uses reusing %2, REG
 			gen
 				rlwinm %a, %2, {CONST, (%1.val & 0x1F)}, {CONST, 0}, {CONST, 31-(%1.val & 0x1F)}
 			yields %a
-		with GPR GPR
+		with REG REG
 			uses reusing %2, REG
 			gen
 				slw %a, %2, %1
 			yields %a
-			
+
 	pat sri $1==4                      /* Shift right signed (second >> top) */
-		with CONST_ALL GPR
+		with CONST_STACK REG
 			uses reusing %2, REG
 			gen
 				srawi %a, %2, {CONST, %1.val & 0x1F}
 			yields %a
-		with GPR GPR
+		with REG REG
 			uses reusing %2, REG
 			gen
 				sraw %a, %2, %1
 			yields %a
 
 	pat sru $1==4                      /* Shift right unsigned (second >> top) */
-		with CONST_ALL GPR
+		with CONST_STACK REG
 			uses reusing %2, REG
 			gen
 				rlwinm %a, %2, {CONST, 32-(%1.val & 0x1F)}, {CONST, (%1.val & 0x1F)}, {CONST, 31}
 			yields %a
-		with GPR GPR
+		with REG REG
 			uses reusing %2, REG
 			gen
 				srw %a, %2, %1
 			yields %a
-			
+
 
 
 /* Arrays */
 
 	pat aar $1==INT32                  /* Index array */
 		with GPR3 GPR4 GPR5
+			kills ALL
 			gen
 				bl {LABEL, ".aar4"}
 			yields R3
-			
+
 	pat lae lar $2==INT32 && nicesize(rom($1, 3)) /* Load array */
 		leaving
 			lae $1
 			aar INT32
 			loi rom($1, 3)
-			
+
 	pat lar $1==INT32                  /* Load array */
 		with GPR3 GPR4 GPR5 STACK
 			kills ALL
 			gen
 				bl {LABEL, ".lar4"}
-			
+
 	pat lae sar $2==INT32 && nicesize(rom($1, 3)) /* Store array */
 		leaving
 			lae $1
@@ -1621,224 +1487,408 @@ PATTERNS
 			kills ALL
 			gen
 				bl {LABEL, ".sar4"}
-			
 
 
-			
 /* Sets */
 
-	pat set defined($1)                /* Create word with set bit */
+	pat set defined($1)                /* Create singleton set */
 		leaving
-			loc 1
-			exg INT32
-			sli INT32
-			
-	pat set !defined($1)               /* Create structure with set bit (variable) */
-		with GPR3 GPR4 STACK
-			gen
-				bl {LABEL, ".set"}
-			
-	pat inn                            /* Test for set bit */
-		with STACK
-			kills ALL
-			uses REG
-			gen
-				li32 %a, {CONST, $1}
-				stwu %a, {GPRINDIRECT, SP, 0-4}
-				bl {LABEL, ".inn"}
-			
-			
-			
+			loc $1
+			cal ".set"
+
+	/* Create set (variable), used in lang/m2/libm2/LtoUset.e */
+	pat set !defined($1)
+		leaving
+			cal ".set"
+
+	pat inn defined($1)                /* Test for set bit */
+		leaving
+			loc $1
+			cal ".inn"
+
+	pat inn !defined($1)
+		leaving
+			cal ".inn"
+
+
 /* Boolean resolutions */
 
 	pat teq                            /* top = (top == 0) */
-		with TRISTATE_ALL + GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				move %1, C0
-				move C0, RSCRATCH
-				move {LABEL, ".teq_table"}, %a
-				lwzx %a, %a, RSCRATCH
+				test %1
+				mfcr %a
+				move {XEQ, %a}, %a
 			yields %a
-				
+
 	pat tne                            /* top = (top != 0) */
-		with TRISTATE_ALL + GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				move %1, C0
-				move C0, RSCRATCH
-				move {LABEL, ".tne_table"}, %a
-				lwzx %a, %a, RSCRATCH
+				test %1
+				mfcr %a
+				move {XNE, %a}, %a
 			yields %a
-				
+
 	pat tlt                            /* top = (top < 0) */
-		with TRISTATE_ALL + GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				move %1, C0
-				move C0, RSCRATCH
-				move {LABEL, ".tlt_table"}, %a
-				lwzx %a, %a, RSCRATCH
+				test %1
+				mfcr %a
+				move {XLT, %a}, %a
 			yields %a
-				
+
 	pat tle                            /* top = (top <= 0) */
-		with TRISTATE_ALL + GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				move %1, C0
-				move C0, RSCRATCH
-				move {LABEL, ".tle_table"}, %a
-				lwzx %a, %a, RSCRATCH
+				test %1
+				mfcr %a
+				move {XLE, %a}, %a
 			yields %a
-				
+
 	pat tgt                            /* top = (top > 0) */
-		with TRISTATE_ALL + GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				move %1, C0
-				move C0, RSCRATCH
-				move {LABEL, ".tgt_table"}, %a
-				lwzx %a, %a, RSCRATCH
+				test %1
+				mfcr %a
+				move {XGT, %a}, %a
 			yields %a
 
 	pat tge                            /* top = (top >= 0) */
-		with TRISTATE_ALL + GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				move %1, C0
-				move C0, RSCRATCH
-				move {LABEL, ".tge_table"}, %a
-				lwzx %a, %a, RSCRATCH
+				test %1
+				mfcr %a
+				move {XGE, %a}, %a
 			yields %a
-				
 
+	pat cmi teq $1==4                  /* Signed second == top */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen move {XEQ, %a}, %a
+			yields %a
+		with CONST2 REG
+			uses reusing %1, REG={COND_RC, %2, %1.val}
+			gen move {XEQ, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen move {XEQ, %a}, %a
+			yields %a
+
+	pat cmi tne $1==4                  /* Signed second != top */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen move {XNE, %a}, %a
+			yields %a
+		with CONST2 REG
+			uses reusing %1, REG={COND_RC, %2, %1.val}
+			gen move {XNE, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen move {XNE, %a}, %a
+			yields %a
+
+	pat cmi tgt $1==4                  /* Signed second > top */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen move {XLT, %a}, %a
+			yields %a
+		with CONST2 REG
+			uses reusing %1, REG={COND_RC, %2, %1.val}
+			gen move {XGT, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen move {XGT, %a}, %a
+			yields %a
+
+	pat cmi tge $1==4                  /* Signed second >= top */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen move {XLE, %a}, %a
+			yields %a
+		with CONST2 REG
+			uses reusing %1, REG={COND_RC, %2, %1.val}
+			gen move {XGE, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen move {XGE, %a}, %a
+			yields %a
+
+	pat cmi tlt $1==4                  /* Signed second < top */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen move {XGT, %a}, %a
+			yields %a
+		with CONST2 REG
+			uses reusing %1, REG={COND_RC, %2, %1.val}
+			gen move {XLT, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen move {XLT, %a}, %a
+			yields %a
+
+	pat cmi tle $1==4                  /* Signed second <= top */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen move {XGE, %a}, %a
+			yields %a
+		with CONST2 REG
+			uses reusing %1, REG={COND_RC, %2, %1.val}
+			gen move {XLE, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen move {XLE, %a}, %a
+			yields %a
+
+	pat cmu teq $1==4                  /* Unsigned second == top */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen move {XEQ, %a}, %a
+			yields %a
+		with UCONST2 REG
+			uses reusing %1, REG={CONDL_RC, %2, %1.val}
+			gen move {XEQ, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen move {XEQ, %a}, %a
+			yields %a
+
+	pat cmu tne $1==4                  /* Unsigned second != top */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen move {XNE, %a}, %a
+			yields %a
+		with UCONST2 REG
+			uses reusing %1, REG={CONDL_RC, %2, %1.val}
+			gen move {XNE, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen move {XNE, %a}, %a
+			yields %a
+
+	pat cmu tgt $1==4                  /* Unsigned second > top */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen move {XLT, %a}, %a
+			yields %a
+		with UCONST2 REG
+			uses reusing %1, REG={CONDL_RC, %2, %1.val}
+			gen move {XGT, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen move {XGT, %a}, %a
+			yields %a
+
+	pat cmu tge $1==4                  /* Unsigned second >= top */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen move {XLE, %a}, %a
+			yields %a
+		with UCONST2 REG
+			uses reusing %1, REG={CONDL_RC, %2, %1.val}
+			gen move {XGE, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen move {XGE, %a}, %a
+			yields %a
+
+	pat cmu tlt $1==4                  /* Unsigned second < top */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen move {XGT, %a}, %a
+			yields %a
+		with UCONST2 REG
+			uses reusing %1, REG={CONDL_RC, %2, %1.val}
+			gen move {XLT, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen move {XLT, %a}, %a
+			yields %a
+
+	pat cmu tle $1==4                  /* Unsigned second <= top */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen move {XGE, %a}, %a
+			yields %a
+		with UCONST2 REG
+			uses reusing %1, REG={CONDL_RC, %2, %1.val}
+			gen move {XLE, %a}, %a
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen move {XLE, %a}, %a
+			yields %a
 
 
 /* Simple branches */
 
-	pat zeq                            /* Branch if signed top == 0 */
-		with TRISTATE_ALL+GPR STACK
+	proc zxx example zeq
+		with REG STACK
 			gen
-				move %1, C0
-				bc IFTRUE, EQ, {LABEL, $1}
+				test %1
+				bxx* {LABEL, $1}
 
-	pat beq
-		leaving
-			cmi INT32
-			zeq $1
-			
-	pat zne                            /* Branch if signed top != 0 */
-		with TRISTATE_ALL+GPR STACK
+	/* Pop signed int, branch if... */
+	pat zeq    call zxx("beq")         /* top == 0 */
+	pat zne    call zxx("bne")         /* top != 0 */
+	pat zgt    call zxx("bgt")         /* top > 0 */
+	pat zge    call zxx("bge")         /* top >= 0 */
+	pat zlt    call zxx("blt")         /* top < 0 */
+	pat zle    call zxx("ble")         /* top >= 0 */
+
+	/* The peephole optimizer rewrites
+	 *   cmi 4 zeq
+	 * as beq, and does same for bne, bgt, and so on.
+	 */
+
+	proc bxx example beq
+		with REG CONST2 STACK
 			gen
-				move %1, C0
-				bc IFFALSE, EQ, {LABEL, $1}
-
-	pat bne
-		leaving
-			cmi INT32
-			zne $1
-			
-	pat zgt                            /* Branch if signed top > 0 */
-		with TRISTATE_ALL+GPR STACK
+				cmpwi %1, {CONST, %2.val}
+				bxx[2] {LABEL, $1}
+		with CONST2 REG STACK
 			gen
-				move %1, C0
-				bc IFTRUE, GT, {LABEL, $1}
-
-	pat bgt
-		leaving
-			cmi INT32
-			zgt $1
-			
-	pat zge                            /* Branch if signed top >= 0 */
-		with TRISTATE_ALL+GPR STACK
+				cmpwi %2, {CONST, %1.val}
+				bxx[1] {LABEL, $1}
+		with REG REG STACK
 			gen
-				move %1, C0
-				bc IFFALSE, LT, {LABEL, $1}
+				cmpw %2, %1
+				bxx[1] {LABEL, $1}
 
-	pat bge
-		leaving
-			cmi INT32
-			zge $1
-			
-	pat zlt                            /* Branch if signed top < 0 */
-		with TRISTATE_ALL+GPR STACK
+	/* Pop two signed ints, branch if... */
+	pat beq    call bxx("beq", "beq")  /* second == top */
+	pat bne    call bxx("bne", "bne")  /* second != top */
+	pat bgt    call bxx("bgt", "blt")  /* second > top */
+	pat bge    call bxx("bge", "ble")  /* second >= top */
+	pat blt    call bxx("blt", "bgt")  /* second < top */
+	pat ble    call bxx("ble", "bge")  /* second >= top */
+
+	proc cmu4zxx example cmu zeq
+		with REG CONST2 STACK
 			gen
-				move %1, C0
-				bc IFTRUE, LT, {LABEL, $1}
-
-	pat blt
-		leaving
-			cmi INT32
-			zlt $1
-			
-	pat zle                            /* Branch if signed top >= 0 */
-		with TRISTATE_ALL+GPR STACK
+				cmplwi %1, {CONST, %2.val}
+				bxx[2] {LABEL, $2}
+		with CONST2 REG STACK
 			gen
-				move %1, C0
-				bc IFFALSE, GT, {LABEL, $1}
+				cmplwi %2, {CONST, %1.val}
+				bxx[1] {LABEL, $2}
+		with REG REG STACK
+			gen
+				cmplw %2, %1
+				bxx[1] {LABEL, $2}
 
-	pat ble
-		leaving
-			cmi INT32
-			zle $1
-			
+	/* Pop two unsigned ints, branch if... */
+	pat cmu zeq $1==4    call cmu4zxx("beq", "beq")
+	pat cmu zne $1==4    call cmu4zxx("bne", "bne")
+	pat cmu zgt $1==4    call cmu4zxx("bgt", "blt")
+	pat cmu zge $1==4    call cmu4zxx("bge", "ble")
+	pat cmu zlt $1==4    call cmu4zxx("blt", "bgt")
+	pat cmu zle $1==4    call cmu4zxx("ble", "bge")
 
-/* Compare and jump */
 
-	pat cmi                            /* Signed tristate compare */
-		with CONST_ALL GPR
-			yields {TRISTATE_RC_S, %2, %1.val}
-		with GPR GPR
-			yields {TRISTATE_RR_S, %2, %1}
-			
-	pat cmu                            /* Unsigned tristate compare */
-		with CONST_ALL GPR
-			yields {TRISTATE_RC_U, %2, %1.val}
-		with GPR GPR
-			yields {TRISTATE_RR_U, %2, %1}
-						
+/* Comparisons */
+
+	/* Each comparison extracts the lt and gt bits from cr0.
+	 *   extlwi %a, %a, 2, 0
+	 * puts lt in the sign bit, so lt yields a negative result,
+	 * gt yields positive.
+	 *   rlwinm %a, %a, 1, 31, 0
+	 * puts gt in the sign bit, to reverse the comparison.
+	 */
+
+	pat cmi $1==INT32                  /* Signed tristate compare */
+		with REG CONST2
+			uses reusing %1, REG={COND_RC, %1, %2.val}
+			gen rlwinm %a, %a, {CONST, 1}, {CONST, 31}, {CONST, 0}
+			yields %a
+		with CONST2 REG
+			uses reusing %2, REG={COND_RC, %2, %1.val}
+			gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
+			yields %a
+		with REG REG
+			uses reusing %1, REG={COND_RR, %2, %1}
+			gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
+			yields %a
+
+	pat cmu $1==INT32                  /* Unsigned tristate compare */
+		with REG UCONST2
+			uses reusing %1, REG={CONDL_RC, %1, %2.val}
+			gen rlwinm %a, %a, {CONST, 1}, {CONST, 31}, {CONST, 0}
+			yields %a
+		with UCONST2 REG
+			uses reusing %2, REG={CONDL_RC, %2, %1.val}
+			gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
+			yields %a
+		with REG REG
+			uses reusing %1, REG={CONDL_RR, %2, %1}
+			gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
+			yields %a
+
 	pat cmp                            /* Compare pointers */
 		leaving
 			cmu INT32
-			
+
 	pat cms $1==INT32                  /* Compare blocks (word sized) */
 		leaving
 			cmi INT32
-			
-			
-			
+
+	pat cms defined($1)
+		with STACK
+			kills ALL
+			gen
+				move {CONST, $1}, R3
+				bl {LABEL, ".cms"}
+			yields R3
+
 
 /* Other branching and labelling */
 
 	pat lab topeltsize($1)==4 && !fallthrough($1)
+		kills ALL
 		gen
 			labeldef $1
 			yields R3
-			
+
 	pat lab topeltsize($1)==4 && fallthrough($1)
-		with GPR3
+		with GPR3 STACK
+		kills ALL
 		gen
 			labeldef $1
 		yields %1
-			
+
 	pat lab topeltsize($1)!=4
 		with STACK
 		kills ALL
 		gen
 			labeldef $1
-			
+
 	pat bra topeltsize($1)==4          /* Unconditional jump with TOS GPRister */
 		with GPR3 STACK
 		gen
 			b {LABEL, $1}
-			
+
 	pat bra topeltsize($1)!=4          /* Unconditional jump without TOS GPRister */
 		with STACK
 		gen
 			b {LABEL, $1}
-			
-				
-						
+
+
 /* Miscellaneous */
 
 	pat cal                            /* Call procedure */
@@ -1848,23 +1898,23 @@ PATTERNS
 				bl {LABEL, $1}
 
 	pat cai                            /* Call procedure indirect */
-		with GPR STACK
+		with REG STACK
 			kills ALL
 			gen
 				mtspr CTR, %1
-				bcctrl ALWAYS, {CONST, 0}, {CONST, 0}
-				
+				bctrl.
+
 	pat lfr $1==INT32                  /* Load function result, word */
 		yields R3
-		
+
 	pat lfr $1==INT64                  /* Load function result, double-word */
 		yields R4 R3
-		
+
 	pat ret $1==0                      /* Return from procedure */
 		gen
 			return
 			b {LABEL, ".ret"}
-			
+
 	pat ret $1==INT32                  /* Return from procedure, word */
 		with GPR3
 		gen
@@ -1878,36 +1928,35 @@ PATTERNS
 			b {LABEL, ".ret"}
 
 	pat blm                            /* Block move constant length */
-		with GPR GPR STACK
+		with REG REG STACK
 			uses REG
 			gen
 				move {CONST, $1}, %a
-				stwu %a, {GPRINDIRECT, SP, 0-4}
-				stwu %2, {GPRINDIRECT, SP, 0-4}
-				stwu %1, {GPRINDIRECT, SP, 0-4}
+				stwu %a, {IND_RC_W, SP, 0-4}
+				stwu %2, {IND_RC_W, SP, 0-4}
+				stwu %1, {IND_RC_W, SP, 0-4}
 				bl {LABEL, "_memmove"}
 				addi SP, SP, {CONST, 12}
-				
+
 	pat bls                            /* Block move variable length */
-		with GPR GPR GPR STACK
+		with REG REG REG STACK
 			gen
-				stwu %1, {GPRINDIRECT, SP, 0-4}
-				stwu %3, {GPRINDIRECT, SP, 0-4}
-				stwu %2, {GPRINDIRECT, SP, 0-4}
+				stwu %1, {IND_RC_W, SP, 0-4}
+				stwu %3, {IND_RC_W, SP, 0-4}
+				stwu %2, {IND_RC_W, SP, 0-4}
 				bl {LABEL, "_memmove"}
 				addi SP, SP, {CONST, 12}
-				
+
 	pat csa                            /* Array-lookup switch */
 		with STACK
 			gen
 				b {LABEL, ".csa"}
-				
+
 	pat csb                            /* Table-lookup switch */
 		with STACK
 			gen
 				b {LABEL, ".csb"}
 
-				
 
 /* EM specials */
 
@@ -1915,7 +1964,7 @@ PATTERNS
 		leaving
 			lae $1
 			ste "hol0+4"
-			
+
 	pat lin                            /* Set current line number */
 		leaving
 			loc $1
@@ -1924,53 +1973,53 @@ PATTERNS
 	pat lni                            /* Increment line number */
 		leaving
 			ine "hol0"
-			
+
 	pat lim                            /* Load EM trap ignore mask */
 		leaving
 			lde ".ignmask"
-			
+
 	pat sim                            /* Store EM trap ignore mask */
 		leaving
 			ste ".ignmask"
-			
+
 	pat trp                            /* Raise EM trap */
 		with GPR3
 			gen
 				bl {LABEL, ".trap"}
-				
+
 	pat sig                            /* Set trap handler */
 		leaving
 			ste ".trppc"
-			
+
 	pat rtt                            /* Return from trap */
 		leaving
 			ret 0
-			
+
 	pat lxl $1==0                      /* Load FP */
 		leaving
 			lor 0
-		
+
 	pat lxl $1==1                      /* Load caller's FP */
 		leaving
 			lxl 0
 			dch
-			
+
 	pat dch                            /* FP -> caller FP */
-		with GPR
+		with REG
 			uses reusing %1, REG
 			gen
-				lwz %a, {GPRINDIRECT, %1, FP_OFFSET}
+				lwz %a, {IND_RC_W, %1, FP_OFFSET}
 			yields %a
 
 	pat lpb                            /* Convert FP to argument address */
 		leaving
 			adp EM_BSIZE
-			
+
 	pat lxa                            /* Load caller's SP */
 		leaving
 			lxl $1
 			lpb
-			
+
 	pat gto                            /* longjmp */
 		uses REG
 		gen
@@ -1979,92 +2028,92 @@ PATTERNS
 			move {IND_RC_W, %a, 4}, SP
 			move {IND_RC_W, %a, 0}, %a
 			mtspr CTR, %a
-			bcctr ALWAYS, {CONST, 0}, {CONST, 0}
+			bctr.
 
 	pat lor $1==0                      /* Load FP */
 		uses REG
 		gen
 			move FP, %a
 		yields %a
-		
+
 	pat lor $1==1                      /* Load SP */
 		uses REG
 		gen
 			move SP, %a
 		yields %a
-		
-	pat lor $1==2                      /* Load HP */
-		leaving
-			loe ".reghp"
-			
+
 	pat str $1==0                      /* Store FP */
-		with GPR
+		with REG
 			gen
 				move %1, FP
-				
+
 	pat str $1==1                      /* Store SP */
-		with GPR
+		with REG
 			gen
 				move %1, SP
-			
-	pat str $1==2                      /* Store HP */
-		leaving
-			ste ".reghp"
 
-	pat loc ass $1==4                  /* Drop 4 bytes from stack */
-		with exact GPR
+	pat loc ass $1==4 && $2==4         /* Drop 4 bytes from stack */
+		with exact REG
 			/* nop */
 		with STACK
 			gen
 				addi SP, SP, {CONST, 4}
 
-	pat ass                            /* Adjust stack by variable amount */
+	pat ass $1==4                      /* Adjust stack by variable amount */
 		with CONST2 STACK
 			gen
 				move {SUM_RC, SP, %1.val}, SP
 		with CONST_HZ STACK
 			gen
 				move {SUM_RC, SP, his(%1.val)}, SP
-		with CONST_ALL-CONST2-CONST_HZ STACK
+		with CONST_STACK-CONST2-CONST_HZ STACK
 			gen
 				move {SUM_RC, SP, his(%1.val)}, SP
 				move {SUM_RC, SP, los(%1.val)}, SP
-		with GPR STACK
+		with REG STACK
 			gen
 				move {SUM_RR, SP, %1}, SP
-				
+
 	pat asp                            /* Adjust stack by constant amount */
 		leaving
 			loc $1
-			ass
-			
-			
-			
+			ass 4
+
+	pat lae rck $2==4                  /* Range check */
+		with REG
+			gen
+				cmpwi %1, {CONST, rom($1, 1)}
+				blt {LABEL, ".trap_erange"}
+				cmpwi %1, {CONST, rom($1, 2)}
+				bgt {LABEL, ".trap_erange"}
+			yields %1
+
+
 /* Floating point support */
 
 	/* All very cheap and nasty --- this needs to be properly integrated into
 	 * the code generator. ncg doesn't like having separate FPU registers. */
 
 	/* Single-precision */
-	
+
 	pat zrf $1==INT32                  /* Push zero */
 		leaving
 			loe ".fs_00000000"
-		
+
 	pat adf $1==INT32                  /* Add single */
 		with FSREG FSREG
 			uses reusing %1, FSREG
 			gen
 				fadds %a, %2, %1
 			yields %a
-				
+
 	pat sbf $1==INT32                  /* Subtract single */
 		with FSREG FSREG
 			uses reusing %1, FSREG
 			gen
 				fsubs %a, %2, %1
 			yields %a
-				
+
 	pat mlf $1==INT32                  /* Multiply single */
 		with FSREG FSREG
 			uses reusing %1, FSREG
@@ -2088,57 +2137,110 @@ PATTERNS
 
 	pat cmf $1==INT32                  /* Compare single */
 		with FSREG FSREG
-			yields {TRISTATE_FF, %2.1, %1.1}
-			
+			uses REG={COND_FS, %2, %1}
+			gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
+			yields %a
+
+	pat cmf teq $1==4                  /* Single second == top */
+		with FSREG FSREG
+			uses REG={COND_FS, %2, %1}
+			gen move {XEQ, %a}, %a
+			yields %a
+
+	pat cmf tne $1==4                  /* Single second == top */
+		with FSREG FSREG
+			uses REG={COND_FS, %2, %1}
+			gen move {XNE, %a}, %a
+			yields %a
+
+	pat cmf tgt $1==4                  /* Single second > top */
+		with FSREG FSREG
+			uses REG={COND_FS, %2, %1}
+			gen move {XGT, %a}, %a
+			yields %a
+
+	pat cmf tge $1==4                  /* Single second >= top */
+		with FSREG FSREG
+			uses REG={COND_FS, %2, %1}
+			gen move {XGE, %a}, %a
+			yields %a
+
+	pat cmf tlt $1==4                  /* Single second < top */
+		with FSREG FSREG
+			uses REG={COND_FS, %2, %1}
+			gen move {XLT, %a}, %a
+			yields %a
+
+	pat cmf tle $1==4                  /* Single second <= top */
+		with FSREG FSREG
+			uses REG={COND_FS, %2, %1}
+			gen move {XLE, %a}, %a
+			yields %a
+
+	proc cmf4zxx example cmf zeq
+		with FREG FREG STACK
+			uses REG
+			gen
+				fcmpo CR0, %2, %1
+				bxx* {LABEL, $2}
+
+	/* Pop 2 singles, branch if... */
+	pat cmf zeq $1==4    call cmf4zxx("beq")
+	pat cmf zne $1==4    call cmf4zxx("bne")
+	pat cmf zgt $1==4    call cmf4zxx("bgt")
+	pat cmf zge $1==4    call cmf4zxx("bge")
+	pat cmf zlt $1==4    call cmf4zxx("blt")
+	pat cmf zle $1==4    call cmf4zxx("ble")
+
 	pat loc loc cff $1==INT32 && $2==INT64 /* Convert single to double */
 		with FSREG
 			yields %1.1
-					
+
 	pat loc loc cfu $1==INT32 && $2==INT32 /* Convert single to unsigned int */
 		with STACK
 			gen
 				bl {LABEL, ".cfu4"}
-				
+
 	pat loc loc cfi $1==INT32 && $2==INT32 /* Convert single to signed int */
 		with STACK
 			gen
 				bl {LABEL, ".cfi4"}
-				
+
 	pat loc loc cif $1==INT32 && $2==INT32 /* Convert integer to single */
 		with STACK
 			gen
 				bl {LABEL, ".cif4"}
-				
+
 	pat loc loc cuf $1==INT32 && $2==INT32 /* Convert unsigned int to single */
 		with STACK
 			gen
 				bl {LABEL, ".cuf4"}
-				
+
 	pat fef $1==INT32                  /* Split single */
 		with STACK
 			gen
 				bl {LABEL, ".fef4"}
-				
+
 	/* Double-precision */
-	
+
 	pat zrf $1==INT64                  /* Push zero */
 		leaving
 			lde ".fd_00000000"
-		
+
 	pat adf $1==INT64                  /* Add double */
 		with FREG FREG
 			uses FREG
 			gen
 				fadd %a, %2, %1
 			yields %a
-				
+
 	pat sbf $1==INT64                  /* Subtract double */
 		with FREG FREG
 			uses FREG
 			gen
 				fsub %a, %2, %1
 			yields %a
-				
+
 	pat mlf $1==INT64                  /* Multiply double */
 		with FREG FREG
 			uses reusing %1, FREG
@@ -2162,31 +2264,84 @@ PATTERNS
 
 	pat cmf $1==INT64                  /* Compare double */
 		with FREG FREG
-			yields {TRISTATE_FF, %2, %1}
-				
+			uses REG={COND_FD, %2, %1}
+			gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
+			yields %a
+
+	pat cmf teq $1==8                  /* Double second == top */
+		with FREG FREG
+			uses REG={COND_FD, %2, %1}
+			gen move {XEQ, %a}, %a
+			yields %a
+
+	pat cmf tne $1==8                  /* Single second == top */
+		with FREG FREG
+			uses REG={COND_FD, %2, %1}
+			gen move {XNE, %a}, %a
+			yields %a
+
+	pat cmf tgt $1==8                  /* Double second > top */
+		with FREG FREG
+			uses REG={COND_FD, %2, %1}
+			gen move {XGT, %a}, %a
+			yields %a
+
+	pat cmf tge $1==8                  /* Double second >= top */
+		with FREG FREG
+			uses REG={COND_FD, %2, %1}
+			gen move {XGE, %a}, %a
+			yields %a
+
+	pat cmf tlt $1==8                  /* Double second < top */
+		with FREG FREG
+			uses REG={COND_FD, %2, %1}
+			gen move {XLT, %a}, %a
+			yields %a
+
+	pat cmf tle $1==8                  /* Double second <= top */
+		with FREG FREG
+			uses REG={COND_FD, %2, %1}
+			gen move {XLE, %a}, %a
+			yields %a
+
+	proc cmf8zxx example cmf zeq
+		with FREG FREG STACK
+			uses REG
+			gen
+				fcmpo CR0, %2, %1
+				bxx* {LABEL, $2}
+
+	/* Pop 2 doubles, branch if... */
+	pat cmf zeq $1==8    call cmf8zxx("beq")
+	pat cmf zne $1==8    call cmf8zxx("bne")
+	pat cmf zgt $1==8    call cmf8zxx("bgt")
+	pat cmf zge $1==8    call cmf8zxx("bge")
+	pat cmf zlt $1==8    call cmf8zxx("blt")
+	pat cmf zle $1==8    call cmf8zxx("ble")
+
 	pat loc loc cff $1==INT64 && $2==INT32 /* Convert double to single */
 		with FREG
 			uses reusing %1, FSREG
 			gen
 				frsp %a, %1
 			yields %a
-					
+
 	pat loc loc cfu $1==INT64 && $2==INT32 /* Convert double to unsigned int */
 		with STACK
 			gen
 				bl {LABEL, ".cfu8"}
-				
+
 	pat loc loc cfi $1==INT64 && $2==INT32 /* Convert double to signed int */
 		with STACK
 			gen
 				bl {LABEL, ".cfi8"}
-				
+
 	pat loc loc cif $1==INT32 && $2==INT64 /* Convert integer to double */
 		with STACK
 			kills ALL
 			gen
 				bl {LABEL, ".cif8"}
-		
+
 	pat loc loc cuf $1==INT32 && $2==INT64 /* Convert unsigned int to double */
 		with STACK
 			gen
@@ -2194,14 +2349,14 @@ PATTERNS
 
 	pat fef $1==INT64                  /* Split exponent, fraction */
 		with GPR3 GPR4
-			kills FPR0, FPR1, GPR6, GPR7
+			kills ALL
 			gen
 				bl {LABEL, ".fef8"}
 			yields R4 R3 R5
 
 	pat fif $1==INT64                  /* Multiply then split integer, fraction */
 		with FPR1 FPR2
-			kills FPR1, FPR2, GPR3, GPR4, GPR5, GPR6
+			kills ALL
 			gen
 				bl {LABEL, ".fif8"}
 			yields F1 F2
diff --git a/mach/powerpc/top/table b/mach/powerpc/top/table
index acbe543a7..fdec03b2e 100644
--- a/mach/powerpc/top/table
+++ b/mach/powerpc/top/table
@@ -6,15 +6,15 @@ LABEL_STARTER '.';
 
 %%;
 
-P, Q, R             { TRUE };
+RNZ                 { strcmp(VAL, "r0") };  /* not r0 */
 X, Y, Z             { TRUE };
 
 %%;
 
 /* Whitespace is significant here! */
 
-addi  X, X, 0                -> ;
-addis X, X, 0                -> ;
+addi  RNZ, RNZ, 0            -> ;
+addis RNZ, RNZ, 0            -> ;
 
 mr X, X                      -> ;
 fmr X, X                     -> ;
diff --git a/mach/proto/as/comm0.h b/mach/proto/as/comm0.h
index dedafa4c7..2d00c8e45 100644
--- a/mach/proto/as/comm0.h
+++ b/mach/proto/as/comm0.h
@@ -8,7 +8,21 @@
  * All preprocessor based options/constants/functions
  */
 
-#include <stdint.h>
+#ifdef _include
+_include	<ctype.h>
+_include	<signal.h>
+_include	<stdint.h>
+_include	<stdio.h>
+_include	<stdlib.h>
+_include	<string.h>
+#else
+#include	<ctype.h>
+#include	<signal.h>
+#include	<stdint.h>
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<string.h>
+#endif
 
 /* ========== ON/OFF options (use #define in mach0.c) ========== */
 
@@ -80,23 +94,16 @@ separate linker only possible if relocation info produced
 /* ========== Machine independent type declarations ========== */
 
 #ifdef _include
-_include    <stdlib.h>
-_include	<stdio.h>
-_include    <string.h>
-_include	<ctype.h>
-_include	<signal.h>
-#else
-#include    <stdlib.h>
-#include	<stdio.h>
-#include    <string.h>
-#include	<ctype.h>
-#include	<signal.h>
+#ifdef ASLD
+_include	"arch.h"
 #endif
-
+_include	"out.h"
+#else
 #ifdef ASLD
 #include	"arch.h"
 #endif
 #include	"out.h"
+#endif
 
 #if DEBUG == 0
 #define	assert(ex)	/* nothing */
@@ -265,6 +272,3 @@ typedef	struct sect_t	sect_t;
 #define	MACHREL_BWR	(0)
 #endif
 #endif
-
-extern FILE *fopen();   /* some systems don't have this in stdio.h */
-
diff --git a/mach/proto/as/comm1.h b/mach/proto/as/comm1.h
index 6a40a2e90..b3011ac97 100644
--- a/mach/proto/as/comm1.h
+++ b/mach/proto/as/comm1.h
@@ -104,21 +104,28 @@ extern struct outhead	outhead;
 extern int	curr_token;
 
 /* forward function declarations */
+/* comm5.c */
+int	 yylex(void);
+void	 putval(int);
+int	 getval(int);
+int	 nextchar(void);
 #ifdef ASLD
-extern char	*readident();
+char	*readident(int);
 #endif
-extern char	*remember();
-extern item_t	*fb_shift();
-extern item_t	*fb_alloc();
-extern item_t	*item_alloc();
-extern item_t	*item_search();
-extern valu_t	load();
-extern FILE	*ffcreat();
-extern FILE	*fftemp();
-
-extern void fatal(const char* s, ...);
-extern void serror(const char* s, ...);
-extern void warning(const char* s, ...);
+int	 hash(char *);
+item_t	*item_search(char *);
+void	 item_insert(item_t *, int);
+item_t	*item_alloc(int);
+item_t	*fb_alloc(int);
+item_t	*fb_shift(int);
+/* comm7.c */
+valu_t	 load();
+char	*remember();
+FILE	*ffcreat();
+FILE	*fftemp();
+void	 fatal(const char *, ...);
+void	 serror(const char *, ...);
+void	 warning(const char *, ...);
 
 /* ========== Machine dependent C declarations ========== */
 
diff --git a/mach/proto/as/comm5.c b/mach/proto/as/comm5.c
index 7dee7c1a9..1fa84537d 100644
--- a/mach/proto/as/comm5.c
+++ b/mach/proto/as/comm5.c
@@ -11,11 +11,18 @@
 
 extern YYSTYPE	yylval;
 
-void putval();
+static void	readcode(int);
+static int	induo(int);
+static int	inident(int);
+static int	innumber(int);
+static int	instring(int);
+static int	inescape(void);
+static int	infbsym(char *);
 
-yylex()
+int
+yylex(void)
 {
-	register c;
+	int c, c0, c1;
 
 	if (pass == PASS_1) {
 		/* scan the input file */
@@ -52,32 +59,37 @@ yylex()
 		/* produce the intermediate token file */
 		if (c <= 0)
 			return(0);
-		if (c <= 127)
+		if (c < 256) {
 			putc(c, tempfile);
-		else
+			putc(0, tempfile);
+		} else {
 			putval(c);
+		}
 	} else {
 		/* read from intermediate token file */
-		c = getc(tempfile);
-		if (c == EOF)
+		c0 = getc(tempfile);
+		if (c0 == EOF)
 			return(0);
-		if (c > 127) {
-			c += 128;
+		c1 = getc(tempfile);
+		if (c1 == EOF)
+			return(0);
+
+		c = c0 + (c1 << 8);
+		if (c >= 256)
 			c = getval(c);
-		}
 	}
 	curr_token = c;
 	return(c);
 }
 
 void
-putval(c)
+putval(int c)
 {
 	register valu_t v;
 	register n = 0;
 	register char *p = 0;
 
-	assert(c >= 256 && c < 256+128);
+	assert(c == (c & 0xffff));
 	switch (c) {
 	case CODE1:
 		n = 1; goto putnum;
@@ -92,9 +104,11 @@ putval(c)
 				break;
 			v >>= 8;
 		}
+		assert(n <= 4);
 		c = NUMBER0 + n;
 	putnum:
-		putc(c-128, tempfile);
+		putc(c, tempfile);
+		putc(c >> 8, tempfile);
 		v = yylval.y_valu;
 		while (--n >= 0)
 			putc((int) (v >> (n*8)), tempfile);
@@ -110,14 +124,15 @@ putval(c)
 #endif
 	case STRING:
 		v = stringlen;
-		putc(c-128, tempfile);
+		putc(c, tempfile);
+		putc(c >> 8, tempfile);
 		for (n = 0; n < sizeof(v); n++) {
 			if (v == 0)
 				break;
 			v >>= 8;
 		}
-		c = NUMBER0 + n;
-		putc(c-128, tempfile);
+		assert(n <= 4);
+		putc(n, tempfile);
 		v = stringlen;
 		while (--n >= 0)
 			putc((int) (v >> (n*8)), tempfile);
@@ -139,12 +154,14 @@ putval(c)
 		n = sizeof(word_t);
 		p = (char *) &yylval.y_word; break;
 	}
-	putc(c-128, tempfile);
+	putc(c, tempfile);
+	putc(c >> 8, tempfile);
 	while (--n >= 0)
 		putc(*p++, tempfile);
 }
 
-getval(c)
+int
+getval(int c)
 {
 	register n = 0;
 	register valu_t v;
@@ -185,7 +202,7 @@ getval(c)
 		p = (char *) &yylval.y_strp; break;
 #endif
 	case STRING:
-		getval(getc(tempfile)+128);
+		getval(getc(tempfile)+NUMBER0);
 		stringlen = n = yylval.y_valu;
 		p = stringbuf;
 		p[n] = '\0'; break;
@@ -209,7 +226,8 @@ getval(c)
 
 /* ---------- lexical scan in pass 1 ---------- */
 
-nextchar()
+int
+nextchar(void)
 {
 	register c;
 
@@ -233,7 +251,8 @@ nextchar()
 	return(c);
 }
 
-readcode(n)
+static void
+readcode(int n)
 {
 	register c;
 
@@ -252,8 +271,8 @@ readcode(n)
 	} while (--n);
 }
 
-induo(c)
-register c;
+static int
+induo(int c)
 {
 	static short duo[] = {
 		('='<<8) | '=', OP_EQ,
@@ -277,8 +296,8 @@ register c;
 
 static char name[NAMEMAX+1];
 
-inident(c)
-register  c;
+static int
+inident(int c)
 {
 	register char *p = name;
 	register item_t *ip;
@@ -309,8 +328,7 @@ register  c;
 
 #ifdef ASLD
 char *
-readident(c)
-register c;
+readident(int c)
 {
 	register n = NAMEMAX;
 	register char *p = name;
@@ -326,8 +344,8 @@ register c;
 }
 #endif
 
-innumber(c)
-register c;
+static int
+innumber(int c)
 {
 	register char *p;
 	register radix;
@@ -373,7 +391,8 @@ register c;
 	return(NUMBER);
 }
 
-instring(termc)
+static int
+instring(int termc)
 {
 	register char *p;
 	register c;
@@ -412,7 +431,8 @@ instring(termc)
 	return(STRING);
 }
 
-inescape()
+static int
+inescape(void)
 {
 	register c, j, r;
 
@@ -442,8 +462,8 @@ inescape()
 	return(c);
 }
 
-infbsym(p)
-register char *p;
+static int
+infbsym(char *p)
 {
 	register lab;
 	register item_t *ip;
@@ -469,8 +489,8 @@ ok:
 	return(FBSYM);
 }
 
-hash(p)
-register char *p;
+int
+hash(char *p)
 {
 	register unsigned short h;
 	register c;
@@ -484,8 +504,7 @@ register char *p;
 }
 
 item_t *
-item_search(p)
-char *p;
+item_search(char *p)
 {
 	register h;
 	register item_t *ip;
@@ -503,15 +522,15 @@ done:
 	return(ip);
 }
 
-item_insert(ip, h)
-item_t *ip;
+void
+item_insert(item_t *ip, int h)
 {
 	ip->i_next = hashtab[h];
 	hashtab[h] = ip;
 }
 
 item_t *
-item_alloc(typ)
+item_alloc(int typ)
 {
 	register item_t *ip;
 	static nleft = 0;
@@ -532,8 +551,7 @@ item_alloc(typ)
 }
 
 item_t *
-fb_alloc(lab)
-register lab;
+fb_alloc(int lab)
 {
 	register item_t *ip, *p;
 
@@ -548,8 +566,7 @@ register lab;
 }
 
 item_t *
-fb_shift(lab)
-register lab;
+fb_shift(int lab)
 {
 	register item_t *ip;
 
diff --git a/mach/proto/as/comm6.c b/mach/proto/as/comm6.c
index 9cb943cba..fdbeb77ff 100644
--- a/mach/proto/as/comm6.c
+++ b/mach/proto/as/comm6.c
@@ -354,8 +354,6 @@ valu_t valu;
 	outname.on_type = type;
 	outname.on_desc = desc;
 	outname.on_valu = valu;
-	if (sizeof(valu) != sizeof(long))
-		outname.on_valu &= ~(((0xFFFFFFFF)<<(4*sizeof(valu_t)))<<(4*sizeof(valu_t)));
 	wr_name(&outname, 1);
 }
 
diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c
index 13352ed37..ff4ddb5bd 100644
--- a/mach/proto/mcg/data.c
+++ b/mach/proto/mcg/data.c
@@ -12,14 +12,19 @@ static struct symbol* pending;
 
 void data_label(const char* label)
 {
-	if (pending)
-		fatal("two consecutive data labels ('%s' and '%s')",
-            pending->name, label);
+    struct symbol* sym = symbol_get(label);
+    if (sym->is_defined)
+        fatal("label '%s' defined twice", sym->name);
 
-	pending = symbol_get(label);
-    if (pending->is_defined)
-        fatal("label '%s' defined twice", pending->name);
-    pending->is_defined = true;
+	if (pending)
+        fprintf(outputfile, "%s = %s\n",
+            platform_label(label), platform_label(pending->name));
+    else
+    {
+        pending = sym;
+        pending = symbol_get(label);
+        pending->is_defined = true;
+    }
 }
 
 static const char* section_to_str(int section)
diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c
index 2ead527fc..eed770170 100644
--- a/mach/proto/mcg/treebuilder.c
+++ b/mach/proto/mcg/treebuilder.c
@@ -30,6 +30,18 @@ static void push(struct ir* ir)
     stack[stackptr++] = ir;
 }
 
+/* Returns the size of the top item on the stack. */
+static int peek(int delta)
+{
+    if (stackptr <= delta)
+        return EM_wordsize;
+    else
+    {
+        struct ir* ir = stack[stackptr-1-delta];
+        return ir->size;
+    }
+}
+
 static struct ir* pop(int size)
 {
     if (size < EM_wordsize)
@@ -54,11 +66,10 @@ static struct ir* pop(int size)
 
 #if 0
         /* If we try to pop something which is smaller than a word, convert it first. */
-        
+
         if (size < EM_wordsize)
             ir = convertu(ir, size);
 #endif
-
         if (ir->size != size)
         {
             if ((size == (EM_wordsize*2)) && (ir->size == EM_wordsize))
@@ -119,6 +130,25 @@ static struct ir* appendir(struct ir* ir)
     return ir;
 }
 
+static void sequence_point(void)
+{
+    int i;
+
+    /* Ensures that any partially-evaluated expressions on the stack are executed right
+     * now. This typically needs to happen before store operations, to prevents loads of
+     * the same address being delayed until after the store (at which point they'll
+     * return incorrect values).
+     */
+
+    assert(current_bb != NULL);
+
+    for (i=0; i<stackptr; i++)
+    {
+        struct ir* ir = stack[i];
+        array_appendu(&current_bb->irs, ir);
+    }
+}
+
 static void materialise_stack(void)
 {
     int i;
@@ -170,7 +200,7 @@ static struct ir* address_of_external(const char* label, arith offset)
 
 static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode)
 {
-    if (srcsize == 1) 
+    if (srcsize == 1)
     {
         if ((opcode == IR_FROMSI) || (opcode == IR_FROMSL))
         {
@@ -229,6 +259,8 @@ static struct ir* store(int size, struct ir* address, int offset, struct ir* val
 {
     int opcode;
 
+    sequence_point();
+
     if (size == 1)
     {
         opcode = IR_STOREB;
@@ -401,7 +433,7 @@ static void insn_simple(int opcode)
             );
             break;
         }
-            
+
         case op_cii: simple_convert(IR_FROMSI); break;
         case op_ciu: simple_convert(IR_FROMSI); break;
         case op_cui: simple_convert(IR_FROMUI); break;
@@ -475,6 +507,7 @@ static void insn_simple(int opcode)
 
         case op_sim:
         {
+            sequence_point();
             appendir(
                 new_ir2(
                     (EM_wordsize == 2) ? IR_STORE : IR_STOREH, EM_wordsize,
@@ -486,7 +519,19 @@ static void insn_simple(int opcode)
         }
 
         case op_trp: helper_function(".trp"); break;
-        case op_sig: helper_function(".sig"); break;
+
+        case op_sig:
+        {
+            struct ir* value = pop(EM_pointersize);
+            appendir(
+                store(
+                    EM_pointersize,
+                    new_labelir(".trppc"), 0,
+                    value
+                )
+            );
+            break;
+        }
 
         case op_rtt:
         {
@@ -495,10 +540,12 @@ static void insn_simple(int opcode)
         }
 
         /* FIXME: These instructions are really complex and barely used
-         * (Modula-2 bitset support, I believe). Leave them until later. */
+         * (Modula-2 and Pascal set support, I believe). Leave them until
+         * later. */
         case op_set: helper_function(".unimplemented_set"); break;
         case op_ior: helper_function(".unimplemented_ior"); break;
 
+
         case op_dch:
             push(
                 new_ir1(
@@ -507,7 +554,7 @@ static void insn_simple(int opcode)
                 )
             );
             break;
-            
+
         case op_lpb:
             push(
                 new_ir1(
@@ -574,29 +621,53 @@ static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock
     }
 }
 
-static void simple_alu1(int opcode, int size, int irop)
+static void simple_alu1(int opcode, int size, int irop, const char* fallback)
 {
-    struct ir* val = pop(size);
+    if (size > (2*EM_wordsize))
+    {
+        if (!fallback)
+            fatal("treebuilder: can't do opcode %s with size %d", em_mnem[opcode - sp_fmnem], size);
+        push(
+            new_wordir(size)
+        );
+        helper_function(fallback);
+    }
+    else
+    {
+        struct ir* val = pop(size);
 
-    push(
-        new_ir1(
-            irop, size,
-            val
-        )
-    );
+        push(
+            new_ir1(
+                irop, size,
+                val
+            )
+        );
+    }
 }
 
-static void simple_alu2(int opcode, int size, int irop)
+static void simple_alu2(int opcode, int size, int irop, const char* fallback)
 {
-    struct ir* right = pop(size);
-    struct ir* left = pop(size);
+    if (size > (2*EM_wordsize))
+    {
+        if (!fallback)
+            fatal("treebuilder: can't do opcode %s with size %d", em_mnem[opcode - sp_fmnem], size);
+        push(
+            new_wordir(size)
+        );
+        helper_function(fallback);
+    }
+    else
+    {
+        struct ir* right = pop(size);
+        struct ir* left = pop(size);
 
-    push(
-        new_ir2(
-            irop, size,
-            left, right
-        )
-    );
+        push(
+            new_ir2(
+                irop, size,
+                left, right
+            )
+        );
+    }
 }
 
 static struct ir* extract_block_refs(struct basicblock* bb)
@@ -675,39 +746,43 @@ static void insn_ivalue(int opcode, arith value)
 {
     switch (opcode)
     {
-        case op_adi: simple_alu2(opcode, value, IR_ADD); break;
-        case op_sbi: simple_alu2(opcode, value, IR_SUB); break;
-        case op_mli: simple_alu2(opcode, value, IR_MUL); break;
-        case op_dvi: simple_alu2(opcode, value, IR_DIV); break;
-        case op_rmi: simple_alu2(opcode, value, IR_MOD); break;
-        case op_sli: simple_alu2(opcode, value, IR_ASL); break;
-        case op_sri: simple_alu2(opcode, value, IR_ASR); break;
-        case op_ngi: simple_alu1(opcode, value, IR_NEG); break;
+        case op_adi: simple_alu2(opcode, value, IR_ADD, NULL); break;
+        case op_sbi: simple_alu2(opcode, value, IR_SUB, NULL); break;
+        case op_mli: simple_alu2(opcode, value, IR_MUL, NULL); break;
+        case op_dvi: simple_alu2(opcode, value, IR_DIV, NULL); break;
+        case op_rmi: simple_alu2(opcode, value, IR_MOD, NULL); break;
+        case op_sli: simple_alu2(opcode, value, IR_ASL, NULL); break;
+        case op_sri: simple_alu2(opcode, value, IR_ASR, NULL); break;
+        case op_ngi: simple_alu1(opcode, value, IR_NEG, NULL); break;
 
-        case op_adu: simple_alu2(opcode, value, IR_ADD); break;
-        case op_sbu: simple_alu2(opcode, value, IR_SUB); break;
-        case op_mlu: simple_alu2(opcode, value, IR_MUL); break;
-        case op_slu: simple_alu2(opcode, value, IR_LSL); break;
-        case op_sru: simple_alu2(opcode, value, IR_LSR); break;
-        case op_rmu: simple_alu2(opcode, value, IR_MODU); break;
-        case op_dvu: simple_alu2(opcode, value, IR_DIVU); break;
+        case op_adu: simple_alu2(opcode, value, IR_ADD, NULL); break;
+        case op_sbu: simple_alu2(opcode, value, IR_SUB, NULL); break;
+        case op_mlu: simple_alu2(opcode, value, IR_MUL, NULL); break;
+        case op_slu: simple_alu2(opcode, value, IR_LSL, NULL); break;
+        case op_sru: simple_alu2(opcode, value, IR_LSR, NULL); break;
+        case op_rmu: simple_alu2(opcode, value, IR_MODU, NULL); break;
+        case op_dvu: simple_alu2(opcode, value, IR_DIVU, NULL); break;
 
-        case op_and: simple_alu2(opcode, value, IR_AND); break;
-        case op_ior: simple_alu2(opcode, value, IR_OR); break;
-        case op_xor: simple_alu2(opcode, value, IR_EOR); break;
-        case op_com: simple_alu1(opcode, value, IR_NOT); break;
+        case op_and: simple_alu2(opcode, value, IR_AND, ".and"); break;
+        case op_ior: simple_alu2(opcode, value, IR_OR, ".ior"); break;
+        case op_xor: simple_alu2(opcode, value, IR_EOR, NULL); break;
+        case op_com: simple_alu1(opcode, value, IR_NOT, ".com"); break;
 
-        case op_adf: simple_alu2(opcode, value, IR_ADDF); break;
-        case op_sbf: simple_alu2(opcode, value, IR_SUBF); break;
-        case op_mlf: simple_alu2(opcode, value, IR_MULF); break;
-        case op_dvf: simple_alu2(opcode, value, IR_DIVF); break;
-        case op_ngf: simple_alu1(opcode, value, IR_NEGF); break;
+        case op_adf: simple_alu2(opcode, value, IR_ADDF, NULL); break;
+        case op_sbf: simple_alu2(opcode, value, IR_SUBF, NULL); break;
+        case op_mlf: simple_alu2(opcode, value, IR_MULF, NULL); break;
+        case op_dvf: simple_alu2(opcode, value, IR_DIVF, NULL); break;
+        case op_ngf: simple_alu1(opcode, value, IR_NEGF, NULL); break;
 
         case op_cmu: /* fall through */
         case op_cms: push(tristate_compare(value, IR_COMPAREUI)); break;
         case op_cmi: push(tristate_compare(value, IR_COMPARESI)); break;
         case op_cmf: push(tristate_compare(value, IR_COMPAREF)); break;
 
+        case op_rck: helper_function(".rck"); break;
+        case op_set: push(new_wordir(value)); helper_function(".set"); break;
+        case op_inn: push(new_wordir(value)); helper_function(".inn"); break;
+
         case op_lol:
             push(
                 load(
@@ -841,7 +916,7 @@ static void insn_ivalue(int opcode, arith value)
                 )
             );
             break;
-                
+
         case op_loc:
             push(
                 new_wordir(value)
@@ -853,17 +928,17 @@ static void insn_ivalue(int opcode, arith value)
             struct ir* ptr = pop(EM_pointersize);
             int offset = 0;
 
-            /* FIXME: this is awful; need a better way of dealing with
-             * non-standard EM sizes. */
             if (value > (EM_wordsize*2))
+            {
+                /* We're going to need to do multiple stores; fix the address
+                 * so it'll go into a register and we can do maths on it. */
                 appendir(ptr);
+            }
 
             while (value > 0)
             {
-                int s;
-                if (value > (EM_wordsize*2))
-                    s = EM_wordsize*2;
-                else
+                int s = EM_wordsize*2;
+                if (value < s)
                     s = value;
 
                 push(
@@ -912,24 +987,25 @@ static void insn_ivalue(int opcode, arith value)
             struct ir* ptr = pop(EM_pointersize);
             int offset = 0;
 
-            /* FIXME: this is awful; need a better way of dealing with
-             * non-standard EM sizes. */
-            if (value > (EM_wordsize*2))
+            if (value > peek(0))
+            {
+                /* We're going to need to do multiple stores; fix the address
+                 * so it'll go into a register and we can do maths on it. */
                 appendir(ptr);
+            }
 
             while (value > 0)
             {
-                int s;
-                if (value > (EM_wordsize*2))
-                    s = EM_wordsize*2;
-                else
+                struct ir* v = pop(peek(0));
+                int s = v->size;
+                if (value < s)
                     s = value;
 
                 appendir(
                     store(
                         s,
                         ptr, offset,
-                        pop(s)
+                        v
                     )
                 );
 
@@ -1007,7 +1083,7 @@ static void insn_ivalue(int opcode, arith value)
             struct ir* right = pop(EM_pointersize);
             struct ir* left = pop(EM_pointersize);
 
-            struct ir* delta = 
+            struct ir* delta =
                 new_ir2(
                     IR_SUB, EM_pointersize,
                     left, right
@@ -1019,13 +1095,25 @@ static void insn_ivalue(int opcode, arith value)
             push(delta);
             break;
         }
-            
+
         case op_dup:
         {
-            struct ir* v = pop(value);
-            appendir(v);
-            push(v);
-            push(v);
+            sequence_point();
+            if ((value == (EM_wordsize*2)) && (peek(0) == EM_wordsize) && (peek(1) == EM_wordsize))
+            {
+                struct ir* v1 = pop(EM_wordsize);
+                struct ir* v2 = pop(EM_wordsize);
+                push(v2);
+                push(v1);
+                push(v2);
+                push(v1);
+            }
+            else
+            {
+                struct ir* v = pop(value);
+                push(v);
+                push(v);
+            }
             break;
         }
 
@@ -1038,6 +1126,18 @@ static void insn_ivalue(int opcode, arith value)
             break;
         }
 
+        case op_zer:
+        {
+            if (value <= EM_wordsize)
+                push(new_constir(value, 0));
+            else
+            {
+                push(new_wordir(value));
+                helper_function(".zer");
+            }
+            break;
+        }
+
         case op_asp:
         {
             switch (value)
@@ -1055,19 +1155,19 @@ static void insn_ivalue(int opcode, arith value)
                 default:
                     while ((value > 0) && (stackptr > 0))
                     {
-                        struct ir* ir = pop(stack[stackptr-1]->size);
-                        value -= ir->size;
+                        int s = peek(0);
+                        if (s > value)
+                            s = value;
+                        pop(s);
+                        value -= s;
                     }
 
-                    if (value != 0)
-                    {
-                        appendir(
-                            new_ir1(
-                                IR_STACKADJUST, EM_pointersize,
-                                new_wordir(value)
-                            )
-                        );
-                    }
+                    appendir(
+                        new_ir1(
+                            IR_STACKADJUST, EM_pointersize,
+                            new_wordir(value)
+                        )
+                    );
                     break;
             }
             break;
@@ -1120,7 +1220,7 @@ static void insn_ivalue(int opcode, arith value)
             );
             break;
         }
-                    
+
         case op_lfr:
         {
             push(
@@ -1251,11 +1351,11 @@ static void insn_ivalue(int opcode, arith value)
                     new_labelir((value == 4) ? ".fef4" : ".fef8")
                 )
             );
-                    
+
             /* exit, leaving an int and then a float (or double) on the stack. */
             break;
         }
-            
+
         case op_fif:
         {
             /* fif is implemented by calling a helper function which then mutates
@@ -1271,11 +1371,11 @@ static void insn_ivalue(int opcode, arith value)
                     new_labelir((value == 4) ? ".fif4" : ".fif8")
                 )
             );
-                    
+
             /* exit, leaving two floats (or doubles) on the stack. */
             break;
         }
-            
+
         case op_lor:
         {
             switch (value)
@@ -1292,7 +1392,7 @@ static void insn_ivalue(int opcode, arith value)
                         )
                     );
                     break;
-                        
+
                 case 1:
                     push(
                         appendir(
@@ -1443,18 +1543,6 @@ static void insn_ivalue(int opcode, arith value)
             break;
         }
 
-        /* FIXME: These instructions are really complex and barely used
-         * (Modula-2 bitset support, I believe). Leave them until leter. */
-        case op_inn:
-        {
-            push(
-                new_wordir(value)
-            );
-
-            helper_function(".inn");
-            break;
-        }
-
         case op_lin:
         {
             /* Set line number --- ignore. */
@@ -1497,6 +1585,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             break;
 
         case op_ste:
+            sequence_point();
             appendir(
                 new_ir2(
                     IR_STORE, EM_wordsize,
@@ -1507,6 +1596,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             break;
 
         case op_sde:
+            sequence_point();
             appendir(
                 new_ir2(
                     IR_STORE, EM_wordsize*2,
@@ -1517,6 +1607,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             break;
 
         case op_zre:
+            sequence_point();
             appendir(
                 new_ir2(
                     IR_STORE, EM_wordsize,
@@ -1525,8 +1616,9 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
                 )
             );
             break;
-                
+
         case op_ine:
+            sequence_point();
             appendir(
                 new_ir2(
                     IR_STORE, EM_wordsize,
@@ -1544,6 +1636,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             break;
 
         case op_dee:
+            sequence_point();
             appendir(
                 new_ir2(
                     IR_STORE, EM_wordsize,
@@ -1612,7 +1705,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             /* Set filename --- ignore. */
             break;
         }
-                    
+
         default:
             fatal("treebuilder: unknown lvalue instruction '%s'",
                 em_mnem[opcode - sp_fmnem]);
@@ -1645,7 +1738,7 @@ static void generate_tree(struct basicblock* bb)
                 break;
 
             case PARAM_LVALUE:
-                tracef('E', "label=%s offset=%d\n", 
+                tracef('E', "label=%s offset=%d\n",
                     em->u.lvalue.label, em->u.lvalue.offset);
                 insn_lvalue(em->opcode, em->u.lvalue.label, em->u.lvalue.offset);
                 break;
diff --git a/mach/proto/ncg/codegen.c b/mach/proto/ncg/codegen.c
index 15d99d393..95a3c012d 100644
--- a/mach/proto/ncg/codegen.c
+++ b/mach/proto/ncg/codegen.c
@@ -22,12 +22,12 @@ static char rcsid[] = "$Id$";
  * Author: Hans van Staveren
  */
 
-#define ALLOW_NEXTEM	/* code generator is allowed new try of NEXTEM
-			   in exceptional cases */
+#define ALLOW_NEXTEM /* code generator is allowed new try of NEXTEM \
+            in exceptional cases */
 
 byte startupcode[] = { DO_NEXTEM };
 
-byte *nextem();
+byte* nextem();
 unsigned costcalc();
 unsigned docoerc();
 unsigned stackupto();
@@ -38,885 +38,1046 @@ string ad2str();
 #define DEBUG(string)
 #else
 #include <stdio.h>
-#define DEBUG(string) {if(Debug) fprintf(stderr,"%-*d%s\n",4*level,level,string);}
+#define DEBUG(string)                                              \
+	{                                                              \
+		if (Debug)                                                 \
+			fprintf(stderr, "%-*d%s\n", 4 * level, level, string); \
+	}
 #endif
 
-#define BROKE() {assert(origcp!=startupcode || !paniced);DEBUG("BROKE");totalcost=INFINITY;goto doreturn;}
-#define CHKCOST() {if (totalcost>=costlimit) BROKE();}
+#define BROKE()                                    \
+	{                                              \
+		assert(origcp != startupcode || !paniced); \
+		DEBUG("BROKE");                            \
+		totalcost = INFINITY;                      \
+		goto doreturn;                             \
+	}
+#define CHKCOST()                   \
+	{                               \
+		if (totalcost >= costlimit) \
+			BROKE();                \
+	}
 
 #ifdef TABLEDEBUG
 int tablelines[MAXTDBUG];
 int ntableline;
-int set_fd,set_size;
-short *set_val;
-char *set_flag;
+int set_fd, set_size;
+short* set_val;
+char* set_flag;
 #endif
 
-unsigned codegen(codep,ply,toplevel,costlimit,forced) byte *codep; unsigned costlimit; {
+unsigned codegen(byte* codep, int ply, int toplevel, unsigned costlimit, int forced)
+{
 #ifndef NDEBUG
-	byte *origcp=codep;
-	static int level=0;
+	byte* origcp = codep;
+	static int level = 0;
 #endif
 	unsigned totalcost = 0;
-	int inscoerc=0;
-	int procarg[MAXPROCARG+1];
+	int inscoerc = 0;
+	int procarg[MAXPROCARG + 1] = {};
 #ifdef ALLOW_NEXTEM
 	static int paniced;
-	char *savebp = 0;
+	char* savebp = 0;
 #endif
 	state_t state;
-#define SAVEST	savestatus(&state)
-#define RESTST	restorestatus(&state)
-#define FREEST	/* nothing */
+#define SAVEST savestatus(&state)
+#define RESTST restorestatus(&state)
+#define FREEST /* nothing */
 #ifdef TABLEDEBUG
-	extern char *tablename;
+	extern char* tablename;
 #endif
 
 #ifndef NDEBUG
 	assert(costlimit <= INFINITY);
 	level++;
 	DEBUG("Entering codegen");
-	if (Debug > 1) fprintf(stderr, "toplevel = %d\n", toplevel);
+	if (Debug > 1)
+		fprintf(stderr, "toplevel = %d\n", toplevel);
 #endif
-	for (;;) {
-	switch( (*codep++)&037 ) {
-    default:
-	assert(FALSE);
-	/* NOTREACHED */
+	for (;;)
+	{
+		switch ((*codep++) & 037)
+		{
+			default:
+				assert(FALSE);
+/* NOTREACHED */
 #ifdef TABLEDEBUG
-    case DO_DLINE: {
-	int n;
+			case DO_DLINE:
+			{
+				int n;
 
-	getint(n,codep);
-	tablelines[ntableline++] = n;
-	if (ntableline>=MAXTDBUG)
-		ntableline -= MAXTDBUG;
-	if (set_fd)
-		set_val[n>>4] &= ~(1<<(n&017));
+				getint(n, codep);
+				tablelines[ntableline++] = n;
+				if (ntableline >= MAXTDBUG)
+					ntableline -= MAXTDBUG;
+				if (set_fd)
+					set_val[n >> 4] &= ~(1 << (n & 017));
 #ifndef NDEBUG
-	if (Debug)
-		fprintf(stderr,"code from \"%s\", line %d\n",tablename,n);
+				if (Debug)
+					fprintf(stderr, "code from \"%s\", line %d\n", tablename, n);
 #endif
-	break;
-    }
+				break;
+			}
 #endif
-    case DO_NEXTEM: {
-	byte *bp;
-	int n;
-	unsigned mindistance,dist;
-	register i;
-	int cindex;
-	int npos,pos[MAXRULE];
-	unsigned mincost,t;
+			case DO_NEXTEM:
+			{
+				byte* bp;
+				int n;
+				unsigned mindistance, dist;
+				register i;
+				int cindex;
+				int npos, pos[MAXRULE];
+				unsigned mincost, t;
 
-	DEBUG("NEXTEM");
-	tokpatlen = 0;
-	nallreg=0;
-	if (toplevel) {
-		garbage_collect();
-		totalcost=0;
-	} else {
-		if (--ply <= 0)
-			goto doreturn;
-	}
-	if (stackheight>MAXFSTACK-7) {
+				DEBUG("NEXTEM");
+				tokpatlen = 0;
+				nallreg = 0;
+				if (toplevel)
+				{
+					garbage_collect();
+					totalcost = 0;
+				}
+				else
+				{
+					if (--ply <= 0)
+						goto doreturn;
+				}
+				if (stackheight > MAXFSTACK - 7)
+				{
 #ifndef NDEBUG
-		if (Debug)
-			fprintf(stderr,"Fakestack overflow threatens(%d), action ...\n",stackheight);
+					if (Debug)
+						fprintf(stderr, "Fakestack overflow threatens(%d), action ...\n", stackheight);
 #endif
-		totalcost += stackupto(&fakestack[6],ply,toplevel);
-	}
+					totalcost += stackupto(&fakestack[6], ply, toplevel);
+				}
 #ifndef ALLOW_NEXTEM
-	bp = nextem(toplevel);
+				bp = nextem(toplevel);
 #else
-	if (toplevel) paniced=0;
-	savebp = nextem(toplevel);
-    panic:
-	if (toplevel) totalcost = 0;
-	bp = savebp;
+				if (toplevel)
+					paniced = 0;
+				savebp = nextem(toplevel);
+			panic:
+				if (toplevel)
+					totalcost = 0;
+				bp = savebp;
 #endif
-	if (bp == 0) {
-		/*
+				if (bp == 0)
+				{
+					/*
 		 * No pattern found, can be pseudo or error
 		 * in table.
 		 */
-		if (toplevel) {
-			codep--;
-			DEBUG("pseudo");
-			dopseudo();
-		} else
-			goto doreturn;
-	} else {
-#ifndef NDEBUG
-		chkregs();
-#endif
-		if (! toplevel) {
-			ply -= emp-saveemp+1;
-			if (ply <= 0) ply = 1;
-		}
-		n = *bp++;
-		if (n==0) {	/* "procedure" */
-			int j, nargs;
-			getint(i,bp);
-			getint(nargs,bp);
-			assert(nargs <= MAXPROCARG);
-			for (j = 0; j < nargs; j++) {
-				getint(procarg[j],bp);
-			}
-			bp= &pattern[i];
-			n = *bp++;
-			DEBUG("PROC_CALL");
-		}
-		assert(n>0 && n<=MAXRULE);
-		if (n>1) {
-			mindistance = MAXINT; npos=0;
-			for(i=0;i<n;i++) {
-				getint(cindex,bp);
-				dist=distance(cindex);
-#ifndef NDEBUG
-if (Debug)
-	fprintf(stderr,"distance of pos %d is %u\n",i,dist);
-#endif
-				if (dist<=mindistance
-#ifdef ALLOW_NEXTEM
-				    || paniced
-#endif
-				   ) {
-					if (dist<mindistance) {
-						if(dist==0)
-							goto gotit;
-						npos=0;
-						mindistance = dist;
+					if (toplevel)
+					{
+						codep--;
+						DEBUG("pseudo");
+						dopseudo();
 					}
-#ifdef ALLOW_NEXTEM
-					if (dist < MAXINT)
-#endif
-					pos[npos++] = cindex;
+					else
+						goto doreturn;
 				}
-			}
-			assert(mindistance<MAXINT);
-			if (npos>1) {
-				/*
+				else
+				{
+#ifndef NDEBUG
+					chkregs();
+#endif
+					if (!toplevel)
+					{
+						ply -= emp - saveemp + 1;
+						if (ply <= 0)
+							ply = 1;
+					}
+					n = *bp++;
+					if (n == 0)
+					{ /* "procedure" */
+						int j, nargs;
+						getint(i, bp);
+						getint(nargs, bp);
+						assert(nargs <= MAXPROCARG);
+						for (j = 0; j < nargs; j++)
+						{
+							getint(procarg[j], bp);
+						}
+						bp = &pattern[i];
+						n = *bp++;
+						DEBUG("PROC_CALL");
+					}
+					assert(n > 0 && n <= MAXRULE);
+					if (n > 1)
+					{
+						mindistance = MAXINT;
+						npos = 0;
+						for (i = 0; i < n; i++)
+						{
+							getint(cindex, bp);
+							dist = distance(cindex);
+#ifndef NDEBUG
+							if (Debug)
+								fprintf(stderr, "distance of pos %d is %u\n", i, dist);
+#endif
+							if (dist <= mindistance
+#ifdef ALLOW_NEXTEM
+							    || paniced
+#endif
+							    )
+							{
+								if (dist < mindistance)
+								{
+									if (dist == 0)
+										goto gotit;
+									npos = 0;
+									mindistance = dist;
+								}
+#ifdef ALLOW_NEXTEM
+								if (dist < MAXINT)
+#endif
+									pos[npos++] = cindex;
+							}
+						}
+						assert(mindistance < MAXINT);
+						if (npos > 1)
+						{
+							/*
 				 * More than 1 tokenpattern is a candidate.
 				 * Decision has to be made by lookahead.
 				 */
-				SAVEST;
-				mincost = costlimit-totalcost+1;
-				assert(mincost <= INFINITY);
-				for(i=0;i<npos;i++) {
-					t=codegen(&coderules[pos[i]],ply,FALSE,
-					    costlimit<MAXINT?mincost:MAXINT,0);
+							SAVEST;
+							mincost = costlimit - totalcost + 1;
+							assert(mincost <= INFINITY);
+							for (i = 0; i < npos; i++)
+							{
+								t = codegen(&coderules[pos[i]], ply, FALSE,
+								    costlimit < MAXINT ? mincost : MAXINT, 0);
 #ifndef NDEBUG
-if (Debug)
-	fprintf(stderr,"mincost %u,cost %u,pos %d\n",mincost,t,i);
+								if (Debug)
+									fprintf(stderr, "mincost %u,cost %u,pos %d\n", mincost, t, i);
 #endif
-					if (t<mincost) {
-						mincost = t;
-						cindex = pos[i];
+								if (t < mincost)
+								{
+									mincost = t;
+									cindex = pos[i];
+								}
+								RESTST;
+							}
+							FREEST;
+							if (totalcost + mincost > costlimit)
+							{
+								BROKE();
+							}
+						}
+						else
+						{
+							cindex = pos[0];
+						}
+					}
+					else
+					{
+						getint(cindex, bp);
 					}
-					RESTST;
-				}
-				FREEST;
-				if (totalcost+mincost>costlimit) {
-					BROKE();
-				}
-			} else {
-				cindex = pos[0];
-			}
-		} else {
-			getint(cindex,bp);
-		}
 
-	gotit:
-		/*
+				gotit:
+					/*
 		 * Now cindex contains the code-index of the best candidate
 		 * so proceed to use it.
 		 */
-		codep = &coderules[cindex];
-	}
-	break;
-    }
-    case DO_COERC: {
-	DEBUG("COERC");
-	tokpatlen=1;
-	inscoerc=1;
-	break;
-    }
-    case DO_XXMATCH:
-	DEBUG("XXMATCH");
-    case DO_XMATCH: {
-	register i;
-	int temp;
-
-	DEBUG("XMATCH");
-	tokpatlen=(codep[-1]>>5)&07;
-	for (i=0;i<tokpatlen;i++)
-		getint(temp,codep);
-	break;	/* match already checked by distance() */
-    }
-    case DO_MATCH: {
-	register i;
-	int j;
-	unsigned mincost,t;
-	token_p tp;
-	int size,lsize;
-	int tokexp[MAXPATLEN];
-	int nregneeded;
-	token_p regtp[MAXCREG];
-	c3_p regcp[MAXCREG];
-	rl_p regls[MAXCREG];
-	c3_p cp,findcoerc();
-#ifdef MAXSPLIT
-	int sret;
-#endif
-	int stackpad = 0;
-	struct perm *tup,*ntup,*besttup,*tuples();
-
-	DEBUG("MATCH");
-	tokpatlen=(codep[-1]>>5)&07;
-	for(i=0;i<tokpatlen;i++)
-		getint(tokexp[i],codep);
-	tokexp[i] = 0;
-	tp = &fakestack[stackheight-1];
-	i=0;
-	while (i<tokpatlen && tp>=fakestack) {
-		size=tsize(tp);
-		while (i<tokpatlen && (lsize=ssize(tokexp[i]))<=size) {
-			size -= lsize;
-			i++;
-		}
-		if (i<tokpatlen && size!=0) {
-			totalcost += stackupto(tp,ply,toplevel);
-			CHKCOST();
-			break;
-		}
-		tp--;
-	}
-	tp = &fakestack[stackheight-1];
-	i=0;
-	while (i<tokpatlen && tp >= fakestack) {
-		size = tsize(tp);
-		lsize= ssize(tokexp[i]);
-		if (size != lsize) {    /* find coercion */
-#ifdef MAXSPLIT
-			sret = split(tp,&tokexp[i],ply,toplevel);
-			if (sret==0) {
-#endif /* MAXSPLIT */
-				totalcost += stackupto(tp,ply,toplevel);
-				CHKCOST();
-				break;
-#ifdef MAXSPLIT
-			}
-			i += sret;
-#endif /* MAXSPLIT */
-		} else
-			i += 1;
-		tp--;
-	}
-    nextmatch:
-	tp = &fakestack[stackheight-1];
-	i=0; nregneeded = 0;
-	while (i<tokpatlen && tp>=fakestack) {
-		if (!match(tp,&machsets[tokexp[i]],0)) {
-			cp = findcoerc(tp, &machsets[tokexp[i]]);
-#ifndef NDEBUG
-if (Debug>1) fprintf(stderr,"findcoerc returns 0x%x at position %d\n",(unsigned)cp,i);
-#endif
-			if (cp==0) {
-				for (j=0;j<nregneeded;j++)
-					regtp[j] -= (tp-fakestack+1);
-				totalcost += stackupto(tp,ply,toplevel);
-				CHKCOST();
-				break;
-			} else {
-				if (cp->c3_prop<0) {
-					totalcost+=docoerc(tp,cp,ply,toplevel,0);
-					CHKCOST();
-				} else {
-#ifndef NDEBUG
-if(Debug>1) fprintf(stderr,"Register of type %d needed, remembering...\n",cp->c3_prop);
-#endif
-					assert(nregneeded<MAXCREG);
-					regtp[nregneeded] = tp;
-					regcp[nregneeded] = cp;
-					regls[nregneeded] = curreglist;
-					nregneeded++;
+					codep = &coderules[cindex];
 				}
+				break;
 			}
-		}
-		i++; tp--;
-	}
-	if (tokpatlen>stackheight) {
-#ifndef NDEBUG
-if(Debug>1) fprintf(stderr,"Pattern too long, %d with only %d items on stack\n",
-		tokpatlen,stackheight);
+			case DO_COERC:
+			{
+				DEBUG("COERC");
+				tokpatlen = 1;
+				inscoerc = 1;
+				break;
+			}
+			case DO_XXMATCH:
+				DEBUG("XXMATCH");
+			case DO_XMATCH:
+			{
+				register i;
+				int temp;
+
+				DEBUG("XMATCH");
+				tokpatlen = (codep[-1] >> 5) & 07;
+				for (i = 0; i < tokpatlen; i++)
+					getint(temp, codep);
+				break; /* match already checked by distance() */
+			}
+			case DO_MATCH:
+			{
+				register i;
+				int j;
+				unsigned mincost, t;
+				token_p tp;
+				int size, lsize;
+				int tokexp[MAXPATLEN];
+				int nregneeded;
+				token_p regtp[MAXCREG];
+				c3_p regcp[MAXCREG];
+				rl_p regls[MAXCREG];
+				c3_p cp, findcoerc();
+#ifdef MAXSPLIT
+				int sret;
 #endif
-		stackpad = tokpatlen-stackheight;
-		for (j=stackheight-1;j>=0;j--)
-			fakestack[j+stackpad] = fakestack[j];
-		for (j=0;j<stackpad;j++)
-			fakestack[j].t_token=0;
-		stackheight += stackpad;
-		for (j=0;j<nregneeded;j++)
-			regtp[j] += stackpad;
-		for (tp = &fakestack[stackpad-1];i<tokpatlen && tp>=fakestack;i++,tp--) {
-			cp = findcoerc((token_p) 0, &machsets[tokexp[i]]);
-			if (cp==0) {
-				for (j=0;j<nregneeded;j++)
-					myfree((string) (regls[j]));
+				int stackpad = 0;
+				struct perm *tup, *ntup, *besttup, *tuples();
+
+				DEBUG("MATCH");
+				tokpatlen = (codep[-1] >> 5) & 07;
+				for (i = 0; i < tokpatlen; i++)
+					getint(tokexp[i], codep);
+				tp = &fakestack[stackheight - 1];
+				i = 0;
+				while (i < tokpatlen && tp >= fakestack)
+				{
+					size = tsize(tp);
+					while (i < tokpatlen && (lsize = ssize(tokexp[i])) <= size)
+					{
+						size -= lsize;
+						i++;
+					}
+					if (i < tokpatlen && size != 0)
+					{
+						totalcost += stackupto(tp, ply, toplevel);
+						CHKCOST();
+						break;
+					}
+					tp--;
+				}
+				tp = &fakestack[stackheight - 1];
+				i = 0;
+				while (i < tokpatlen && tp >= fakestack)
+				{
+					size = tsize(tp);
+					lsize = ssize(tokexp[i]);
+					if (size != lsize)
+					{ /* find coercion */
+#ifdef MAXSPLIT
+						sret = split(tp, &tokexp[i], ply, toplevel);
+						if (sret == 0)
+						{
+#endif /* MAXSPLIT */
+							totalcost += stackupto(tp, ply, toplevel);
+							CHKCOST();
+							break;
+#ifdef MAXSPLIT
+						}
+						i += sret;
+#endif /* MAXSPLIT */
+					}
+					else
+						i += 1;
+					tp--;
+				}
+			nextmatch:
+				tp = &fakestack[stackheight - 1];
+				i = 0;
+				nregneeded = 0;
+				while (i < tokpatlen && tp >= fakestack)
+				{
+					if (!match(tp, &machsets[tokexp[i]], 0))
+					{
+						cp = findcoerc(tp, &machsets[tokexp[i]]);
+#ifndef NDEBUG
+						if (Debug > 1)
+							fprintf(stderr, "findcoerc returns 0x%x at position %d\n", (unsigned)cp, i);
+#endif
+						if (cp == 0)
+						{
+							for (j = 0; j < nregneeded; j++)
+								regtp[j] -= (tp - fakestack + 1);
+							totalcost += stackupto(tp, ply, toplevel);
+							CHKCOST();
+							break;
+						}
+						else
+						{
+							if (cp->c3_prop < 0)
+							{
+								totalcost += docoerc(tp, cp, ply, toplevel, 0);
+								CHKCOST();
+							}
+							else
+							{
+#ifndef NDEBUG
+								if (Debug > 1)
+									fprintf(stderr, "Register of type %d needed, remembering...\n", cp->c3_prop);
+#endif
+								assert(nregneeded < MAXCREG);
+								regtp[nregneeded] = tp;
+								regcp[nregneeded] = cp;
+								regls[nregneeded] = curreglist;
+								nregneeded++;
+							}
+						}
+					}
+					i++;
+					tp--;
+				}
+				if (tokpatlen > stackheight)
+				{
+#ifndef NDEBUG
+					if (Debug > 1)
+						fprintf(stderr, "Pattern too long, %d with only %d items on stack\n",
+						    tokpatlen, stackheight);
+#endif
+					stackpad = tokpatlen - stackheight;
+					for (j = stackheight - 1; j >= 0; j--)
+						fakestack[j + stackpad] = fakestack[j];
+					for (j = 0; j < stackpad; j++)
+						fakestack[j].t_token = 0;
+					stackheight += stackpad;
+					for (j = 0; j < nregneeded; j++)
+						regtp[j] += stackpad;
+					for (tp = &fakestack[stackpad - 1]; i < tokpatlen && tp >= fakestack; i++, tp--)
+					{
+						cp = findcoerc((token_p)0, &machsets[tokexp[i]]);
+						if (cp == 0)
+						{
+							for (j = 0; j < nregneeded; j++)
+								myfree((string)(regls[j]));
 #ifndef ALLOW_NEXTEM
-				assert(!toplevel);
-				BROKE();
+							assert(!toplevel);
+							BROKE();
 #else
-				assert(!(toplevel&&paniced));
-				if (paniced) goto normalfailed;
-				totalcost = INFINITY;
-				for (i=0;i<stackheight-stackpad;i++)
-					fakestack[i] = fakestack[i+stackpad];
-				stackheight -= stackpad;
-				goto doreturn;
+							assert(!(toplevel && paniced));
+							if (paniced)
+								goto normalfailed;
+							totalcost = INFINITY;
+							for (i = 0; i < stackheight - stackpad; i++)
+								fakestack[i] = fakestack[i + stackpad];
+							stackheight -= stackpad;
+							goto doreturn;
 #endif
-			}
-			if (cp->c3_prop<0) {
-				totalcost+=docoerc(tp,cp,ply,toplevel,0);
-				CHKCOST();
-			} else {
-				assert(nregneeded<MAXCREG);
-				regtp[nregneeded] = tp;
-				regcp[nregneeded] = cp;
-				regls[nregneeded] = curreglist;
-				nregneeded++;
-			}
-		}
-	} else
-		stackpad=0;
-	assert(i==tokpatlen);
-	if (nregneeded==0)
-		break;
-	SAVEST;
-	mincost=costlimit-totalcost+1;
-	tup = tuples(regls,nregneeded);
-	besttup=0;
-	for (; tup != 0; tup = ntup) {
+						}
+						if (cp->c3_prop < 0)
+						{
+							totalcost += docoerc(tp, cp, ply, toplevel, 0);
+							CHKCOST();
+						}
+						else
+						{
+							assert(nregneeded < MAXCREG);
+							regtp[nregneeded] = tp;
+							regcp[nregneeded] = cp;
+							regls[nregneeded] = curreglist;
+							nregneeded++;
+						}
+					}
+				}
+				else
+					stackpad = 0;
+				assert(i == tokpatlen);
+				if (nregneeded == 0)
+					break;
+				SAVEST;
+				mincost = costlimit - totalcost + 1;
+				tup = tuples(regls, nregneeded);
+				besttup = 0;
+				for (; tup != 0; tup = ntup)
+				{
 #ifndef NDEBUG
-if(Debug>1) { fprintf(stderr,"Next tuple %d,%d,%d,%d\n",
-			tup->p_rar[0],
-			tup->p_rar[1],
-			tup->p_rar[2],
-			tup->p_rar[3]);
-		fprintf(stderr, "totalcost = %u, costlimit = %u, mincost = %u\n",
-			totalcost, costlimit, mincost);
-	}
+					if (Debug > 1)
+					{
+						fprintf(stderr, "Next tuple %d,%d,%d,%d\n",
+						    tup->p_rar[0],
+						    tup->p_rar[1],
+						    tup->p_rar[2],
+						    tup->p_rar[3]);
+						fprintf(stderr, "totalcost = %u, costlimit = %u, mincost = %u\n",
+						    totalcost, costlimit, mincost);
+					}
 #endif
-		ntup = tup->p_next;
-		for (i=0,t=0;i<nregneeded && t<mincost; i++)
-			t += docoerc(regtp[i],regcp[i],ply,FALSE,tup->p_rar[i]);
+					ntup = tup->p_next;
+					for (i = 0, t = 0; i < nregneeded && t < mincost; i++)
+						t += docoerc(regtp[i], regcp[i], ply, FALSE, tup->p_rar[i]);
 #ifndef NDEBUG
-if (Debug > 1) fprintf(stderr, "cost after coercions: %u\n", t);
+					if (Debug > 1)
+						fprintf(stderr, "cost after coercions: %u\n", t);
 #endif
-		if ( t<mincost && tokpatlen<=stackheight ) {
+					if (t < mincost && tokpatlen <= stackheight)
+					{
 #ifndef NDEBUG
-			if (Debug>2)
-				fprintf(stderr,"Continuing match after coercions\n");
+						if (Debug > 2)
+							fprintf(stderr, "Continuing match after coercions\n");
 #endif
-			t += codegen(codep,ply,FALSE,mincost<MAXINT?mincost-t:MAXINT,0);
-		}
-		if ( t<mincost && tokpatlen<=stackheight ) {
-			mincost = t;
-			besttup = tup;
-		} else
-			myfree((string) tup);
-		RESTST;
-	}
-	FREEST;
-	for (i=0;i<nregneeded;i++)
-		myfree((string)(regls[i]));
-	if (totalcost+mincost>costlimit) {
-		if (besttup)
-			myfree((string)besttup);
-normalfailed:	if (stackpad!=tokpatlen) {
-			if (stackpad) {
-				for (i=0;i<stackheight-stackpad;i++)
-					fakestack[i] = fakestack[i+stackpad];
-				stackheight -= stackpad;
-				if (costlimit<MAXINT)
+						t += codegen(codep, ply, FALSE, mincost < MAXINT ? mincost - t : MAXINT, 0);
+					}
+					if (t < mincost && tokpatlen <= stackheight)
+					{
+						mincost = t;
+						besttup = tup;
+					}
+					else
+						myfree((string)tup);
+					RESTST;
+				}
+				FREEST;
+				for (i = 0; i < nregneeded; i++)
+					myfree((string)(regls[i]));
+				if (totalcost + mincost > costlimit)
+				{
+					if (besttup)
+						myfree((string)besttup);
+				normalfailed:
+					if (stackpad != tokpatlen)
+					{
+						if (stackpad)
+						{
+							for (i = 0; i < stackheight - stackpad; i++)
+								fakestack[i] = fakestack[i + stackpad];
+							stackheight -= stackpad;
+							if (costlimit < MAXINT)
+								BROKE();
+							totalcost += stackupto(&fakestack[stackheight - 1], ply, toplevel);
+						}
+						else
+							totalcost += stackupto(fakestack, ply, toplevel);
+						CHKCOST();
+						goto nextmatch;
+					}
+					totalcost += mincost;
+					for (i = 0; i < stackheight - stackpad; i++)
+						fakestack[i] = fakestack[i + stackpad];
+					stackheight -= stackpad;
 					BROKE();
-				totalcost += stackupto(&fakestack[stackheight-1],ply,toplevel);
-			} else
-				totalcost += stackupto(fakestack,ply,toplevel);
-			CHKCOST();
-			goto nextmatch;
-		}
-		totalcost += mincost;
-		for (i=0;i<stackheight-stackpad;i++)
-			fakestack[i] = fakestack[i+stackpad];
-		stackheight -= stackpad;
-                BROKE();
-	}
-	for (i=0;i<nregneeded;i++)
-		totalcost += docoerc(regtp[i],regcp[i],ply,toplevel,besttup->p_rar[i]);
-	assert(totalcost <= costlimit);
-	myfree((string)besttup);
-	break;
-    }
-    case DO_TOSTACK:
-    case DO_REMOVE: {
-	int texpno,nodeno;
-	token_p tp;
-	struct reginfo *rp;
-	int doremove = (codep[-1] & 037) == DO_REMOVE;
-	extern int allsetno;
+				}
+				for (i = 0; i < nregneeded; i++)
+					totalcost += docoerc(regtp[i], regcp[i], ply, toplevel, besttup->p_rar[i]);
+				assert(totalcost <= costlimit);
+				myfree((string)besttup);
+				break;
+			}
+			case DO_TOSTACK:
+			case DO_REMOVE:
+			{
+				int texpno, nodeno;
+				token_p tp;
+				struct reginfo* rp;
+				int doremove = (codep[-1] & 037) == DO_REMOVE;
+				extern int allsetno;
 
-	DEBUG(doremove ? "REMOVE" : "TOSTACK");
-	if (codep[-1]&32) {
-		getint(texpno,codep);
-		getint(nodeno,codep);
-	} else {
-		getint(texpno,codep);
-		nodeno=0;
-	}
-	if (texpno == allsetno) {
-		totalcost += stackupto(&fakestack[stackheight-tokpatlen-1],ply,toplevel);
-		CHKCOST();
-		if (doremove) for (rp=machregs;rp<machregs+NREGS;rp++)
-			rp->r_contents.t_token=0;
-		break;
-	}
-	for (tp= &fakestack[stackheight-tokpatlen-1];tp>=&fakestack[0];tp--)
-		if (match(tp,&machsets[texpno],nodeno)) {
-			/* investigate possible coercion to register */
-			totalcost += stackupto(tp,ply,toplevel);
-			CHKCOST();
-			break;
-		}
-	if (doremove) for (rp=machregs;rp<machregs+NREGS;rp++) {
-		if (rp->r_contents.t_token != 0 &&
-		    match(&rp->r_contents,&machsets[texpno],nodeno)) {
+				DEBUG(doremove ? "REMOVE" : "TOSTACK");
+				if (codep[-1] & 32)
+				{
+					getint(texpno, codep);
+					getint(nodeno, codep);
+				}
+				else
+				{
+					getint(texpno, codep);
+					nodeno = 0;
+				}
+				if (texpno == allsetno)
+				{
+					totalcost += stackupto(&fakestack[stackheight - tokpatlen - 1], ply, toplevel);
+					CHKCOST();
+					if (doremove)
+						for (rp = machregs; rp < machregs + NREGS; rp++)
+							rp->r_contents.t_token = 0;
+					break;
+				}
+				for (tp = &fakestack[stackheight - tokpatlen - 1]; tp >= &fakestack[0]; tp--)
+					if (match(tp, &machsets[texpno], nodeno))
+					{
+						/* investigate possible coercion to register */
+						totalcost += stackupto(tp, ply, toplevel);
+						CHKCOST();
+						break;
+					}
+				if (doremove)
+					for (rp = machregs; rp < machregs + NREGS; rp++)
+					{
+						if (rp->r_contents.t_token != 0 && match(&rp->r_contents, &machsets[texpno], nodeno))
+						{
 #ifndef NDEBUG
-			if (Debug > 1) fprintf(stderr, "killing reg %ld (%s)\n", (long)(rp-machregs), rp->r_repr ? codestrings[rp->r_repr] : "cc");
+							if (Debug > 1)
+								fprintf(stderr, "killing reg %ld (%s)\n", (long)(rp - machregs), rp->r_repr ? codestrings[rp->r_repr] : "cc");
 #endif
-			rp->r_contents.t_token=0;
-		}
-	}
-	break;
-    }
-    case DO_KILLREG:
-    case DO_RREMOVE: {	/* register remove */
-	register i;
-	int nodeno;
-	token_p tp;
-	tkdef_p tdp;
-	result_t result;
-	int dokill = (codep[-1] & 037) == DO_KILLREG;
+							rp->r_contents.t_token = 0;
+						}
+					}
+				break;
+			}
+			case DO_KILLREG:
+			case DO_RREMOVE:
+			{ /* register remove */
+				register i;
+				int nodeno;
+				token_p tp;
+				tkdef_p tdp;
+				result_t result;
+				int dokill = (codep[-1] & 037) == DO_KILLREG;
 
-	DEBUG(dokill ? "KILLREG" : "RREMOVE");
-	getint(nodeno,codep);
-	compute(&enodes[nodeno], &result);
-	if (result.e_typ!=EV_REG)
-		break;
-	if ( in_stack(result.e_v.e_reg) ) BROKE() ; /* Check aside-stack */
-	if (dokill) {
-		/* kill register, and kill condition codes if they are set to
+				DEBUG(dokill ? "KILLREG" : "RREMOVE");
+				getint(nodeno, codep);
+				compute(&enodes[nodeno], &result);
+				if (result.e_typ != EV_REG)
+					break;
+				if (in_stack(result.e_v.e_reg))
+					BROKE(); /* Check aside-stack */
+				if (dokill)
+				{
+					/* kill register, and kill condition codes if they are set to
 		   this register
 		*/
-		machregs[result.e_v.e_reg].r_contents.t_token = 0;
-		if (machregs[0].r_contents.t_token == -1 &&
-		    machregs[0].r_contents.t_att[0].ar == result.e_v.e_reg) {
-			machregs[0].r_contents.t_token = 0;	
-		}
-	}
-	for (tp= &fakestack[stackheight-tokpatlen-1];tp>=&fakestack[0];tp--)
-		if (tp->t_token==-1) {
-			if(tp->t_att[0].ar==result.e_v.e_reg)
-				goto gotone;
-		} else {
-			tdp = &tokens[tp->t_token];
-			for(i=0;i<TOKENSIZE;i++)
-				if (tdp->t_type[i]==EV_REG &&
-				    tp->t_att[i].ar==result.e_v.e_reg)
-					goto gotone;
-		}
-	break;
-    gotone:
-	/* investigate possible coercion to register */
-	totalcost += stackupto(tp,ply,toplevel);
-	CHKCOST();
-	break;
-    }
-    case DO_DEALLOCATE: {
-	register i;
-	tkdef_p tdp;
-	int tinstno;
-	token_t token;
-
-	DEBUG("DEALLOCATE");
-	getint(tinstno,codep);
-	instance(tinstno,&token);
-	if (token.t_token==-1)
-		chrefcount(token.t_att[0].ar,-1,TRUE);
-	else {
-		tdp= &tokens[token.t_token];
-		for (i=0;i<TOKENSIZE;i++)
-			if (tdp->t_type[i]==EV_REG)
-				chrefcount(token.t_att[i].ar,-1,TRUE);
-	}
-	break;
-    }
-    case DO_REALLOCATE: {
-	struct reginfo *rp;
-
-	DEBUG("REALLOCATE");
-	for(rp=machregs+1;rp<machregs+NREGS;rp++)
-		if(rp->r_tcount) {
-			rp->r_refcount -= rp->r_tcount;
-			rp->r_tcount = 0;
-		}
-	break;
-    }
-    case DO_ALLOCATE: {
-	register i;
-	int j;
-	int tinstno;
-	int npos,npos2,pos[NREGS],pos2[NREGS];
-	unsigned mincost,t;
-	struct reginfo *rp,**rpp;
-	token_t token,token2;
-	int propno;
-	int exactmatch;
-	int decision;
-
-	if (codep[-1]&32) {
-		getint(propno,codep);
-		getint(tinstno,codep);
-		DEBUG("ALLOCATE,INIT");
-	} else {
-		getint(propno,codep);
-		tinstno=0;
-		DEBUG("ALLOCATE,EMPTY");
-	}
-	instance(tinstno,&token);
-	if (!forced) {
-		do {
-			npos=exactmatch=0;
-			for(rpp=reglist[propno];rp= *rpp; rpp++)
-				if (getrefcount((int)(rp-machregs), FALSE)==0) {
-					pos[npos++] = rp-machregs;
-					if (eqtoken(&rp->r_contents,&token))
-						pos2[exactmatch++] = rp-machregs;
+					machregs[result.e_v.e_reg].r_contents.t_token = 0;
+					if (machregs[0].r_contents.t_token == -1 && machregs[0].r_contents.t_att[0].ar == result.e_v.e_reg)
+					{
+						machregs[0].r_contents.t_token = 0;
+					}
 				}
-			/*
+				for (tp = &fakestack[stackheight - tokpatlen - 1]; tp >= &fakestack[0]; tp--)
+					if (tp->t_token == -1)
+					{
+						if (tp->t_att[0].ar == result.e_v.e_reg)
+							goto gotone;
+					}
+					else
+					{
+						tdp = &tokens[tp->t_token];
+						for (i = 0; i < TOKENSIZE; i++)
+							if (tdp->t_type[i] == EV_REG && tp->t_att[i].ar == result.e_v.e_reg)
+								goto gotone;
+					}
+				break;
+			gotone:
+				/* investigate possible coercion to register */
+				totalcost += stackupto(tp, ply, toplevel);
+				CHKCOST();
+				break;
+			}
+			case DO_DEALLOCATE:
+			{
+				register i;
+				tkdef_p tdp;
+				int tinstno;
+				token_t token;
+
+				DEBUG("DEALLOCATE");
+				getint(tinstno, codep);
+				instance(tinstno, &token);
+				if (token.t_token == -1)
+					chrefcount(token.t_att[0].ar, -1, TRUE);
+				else
+				{
+					tdp = &tokens[token.t_token];
+					for (i = 0; i < TOKENSIZE; i++)
+						if (tdp->t_type[i] == EV_REG)
+							chrefcount(token.t_att[i].ar, -1, TRUE);
+				}
+				break;
+			}
+			case DO_REALLOCATE:
+			{
+				struct reginfo* rp;
+
+				DEBUG("REALLOCATE");
+				for (rp = machregs + 1; rp < machregs + NREGS; rp++)
+					if (rp->r_tcount)
+					{
+						rp->r_refcount -= rp->r_tcount;
+						rp->r_tcount = 0;
+					}
+				break;
+			}
+			case DO_ALLOCATE:
+			{
+				register i;
+				int j;
+				int tinstno;
+				int npos, npos2, pos[NREGS], pos2[NREGS];
+				unsigned mincost, t;
+				struct reginfo *rp, **rpp;
+				token_t token, token2;
+				int propno;
+				int exactmatch;
+				int decision;
+
+				if (codep[-1] & 32)
+				{
+					getint(propno, codep);
+					getint(tinstno, codep);
+					DEBUG("ALLOCATE,INIT");
+				}
+				else
+				{
+					getint(propno, codep);
+					tinstno = 0;
+					DEBUG("ALLOCATE,EMPTY");
+				}
+				instance(tinstno, &token);
+				if (!forced)
+				{
+					do
+					{
+						npos = exactmatch = 0;
+						for (rpp = reglist[propno]; rp = *rpp; rpp++)
+							if (getrefcount((int)(rp - machregs), FALSE) == 0)
+							{
+								pos[npos++] = rp - machregs;
+								if (eqtoken(&rp->r_contents, &token))
+									pos2[exactmatch++] = rp - machregs;
+							}
+						/*
 			 * Now pos[] contains all free registers with desired
 			 * property. If none then some stacking has to take place.
 			 */
-			if (npos==0) {
-  				if (stackheight<=tokpatlen) {
-  					if (!toplevel) {
-  						BROKE();
- 					} else {
- 						if (paniced)
- 							fatal("No regs available");
- 						totalcost += stackupto( &fakestack[0],ply,toplevel);
- 						goto panic;
- 					}
-  				}
-  				totalcost += stackupto( &fakestack[0],ply,toplevel);
-  				CHKCOST();
-			}
-		} while (npos==0);
+						if (npos == 0)
+						{
+							if (stackheight <= tokpatlen)
+							{
+								if (!toplevel)
+								{
+									BROKE();
+								}
+								else
+								{
+									if (paniced)
+										fatal("No regs available");
+									totalcost += stackupto(&fakestack[0], ply, toplevel);
+									goto panic;
+								}
+							}
+							totalcost += stackupto(&fakestack[0], ply, toplevel);
+							CHKCOST();
+						}
+					} while (npos == 0);
 
-		if (!exactmatch && tinstno!=0) {
-			/*
+					if (!exactmatch && tinstno != 0)
+					{
+						/*
 			 * No exact match, but we were looking for a particular
 			 * token. Now try to find registers of which no
 			 * known contents is available (the others might still
 			 * be useful).
 			 */
-			for (i=0;i<npos;i++)
-				if (machregs[pos[i]].r_contents.t_token == 0) {
-					pos2[exactmatch++] = pos[i];
-				}
-		}
+						for (i = 0; i < npos; i++)
+							if (machregs[pos[i]].r_contents.t_token == 0)
+							{
+								pos2[exactmatch++] = pos[i];
+							}
+					}
 
-		if (!exactmatch) {
-			npos2=npos;
-			for(i=0;i<npos;i++)
-				pos2[i]=pos[i];
-		} else {
-			/*
+					if (!exactmatch)
+					{
+						npos2 = npos;
+						for (i = 0; i < npos; i++)
+							pos2[i] = pos[i];
+					}
+					else
+					{
+						/*
 			 * Now we are reducing the number of possible registers.
 			 * We take only one equally likely register out of every
 			 * equivalence class as given by set of properties.
 			 */
-			npos2=0;
-			for(i=0;i<exactmatch;i++) {
-				pos2[npos2++] = pos2[i];
-				for(j=0;j<npos2-1;j++)
-					if (eqregclass(pos2[j],pos2[i])) {
-						npos2--;
-						break;
+						npos2 = 0;
+						for (i = 0; i < exactmatch; i++)
+						{
+							pos2[npos2++] = pos2[i];
+							for (j = 0; j < npos2 - 1; j++)
+								if (eqregclass(pos2[j], pos2[i]))
+								{
+									npos2--;
+									break;
+								}
+						}
 					}
-			}
-		}
-		/*
+					/*
 		 * Now pos2[] contains all possibilities to try, if more than
 		 * one, lookahead is necessary.
 		 */
-		token2.t_token= -1;
-		for (i=1;i<TOKENSIZE;i++)
-			token2.t_att[i].aw=0;
-		decision=pos2[0];
-		if (npos2!=1) {
-			SAVEST;
-			mincost=costlimit-totalcost+1;
-			for(j=0;j<npos2;j++) {
-				chrefcount(pos2[j],1,FALSE);
-				token2.t_att[0].ar=pos2[j];
-				allreg[nallreg++] = pos2[j];
+					token2.t_token = -1;
+					for (i = 1; i < TOKENSIZE; i++)
+						token2.t_att[i].aw = 0;
+					decision = pos2[0];
+					if (npos2 != 1)
+					{
+						SAVEST;
+						mincost = costlimit - totalcost + 1;
+						for (j = 0; j < npos2; j++)
+						{
+							chrefcount(pos2[j], 1, FALSE);
+							token2.t_att[0].ar = pos2[j];
+							allreg[nallreg++] = pos2[j];
+							if (token.t_token != 0)
+								t = move(&token, &token2, ply, FALSE, mincost);
+							else
+							{
+								t = 0;
+								erasereg(pos2[j]);
+							}
+							if (t < mincost)
+								t += codegen(codep, ply, FALSE, mincost < MAXINT ? mincost - t : MAXINT, 0);
+							if (t < mincost)
+							{
+								mincost = t;
+								decision = pos2[j];
+							}
+							RESTST;
+						}
+						FREEST;
+						if (totalcost + mincost > costlimit)
+							BROKE();
+					}
+				}
+				else
+				{
+					decision = forced;
+					if (getrefcount(decision, FALSE) != 0)
+						BROKE();
+					token2.t_token = -1;
+				}
+				chrefcount(decision, 1, FALSE);
+				token2.t_att[0].ar = decision;
 				if (token.t_token != 0)
-					t=move(&token,&token2,ply,FALSE,mincost);
-				else {
-					t = 0;
-					erasereg(pos2[j]);
+				{
+					totalcost += move(&token, &token2, ply, toplevel, MAXINT);
+					CHKCOST();
 				}
-				if (t<mincost)
-					t += codegen(codep,ply,FALSE,mincost<MAXINT?mincost-t:MAXINT,0);
-				if (t<mincost) {
-					mincost=t;
-					decision=pos2[j];
-				}
-				RESTST;
+				else
+					erasereg(decision);
+				allreg[nallreg++] = decision;
+				break;
 			}
-			FREEST;
-			if (totalcost+mincost>costlimit)
-				BROKE();
-		}
-	} else {
-		decision = forced;
-		if (getrefcount(decision, FALSE)!=0)
-			BROKE();
-		token2.t_token = -1;
-	}
-	chrefcount(decision,1,FALSE);
-	token2.t_att[0].ar=decision;
-	if (token.t_token != 0) {
-		totalcost+=move(&token,&token2,ply,toplevel,MAXINT);
-		CHKCOST();
-	} else
-		erasereg(decision);
-	allreg[nallreg++]=decision;
-	break;
-    }
-    case DO_INSTR: {
-	register i;
-	int n;
-	int tinstno;
-	token_t token;
-	int stringno;
+			case DO_INSTR:
+			{
+				register i;
+				int n;
+				int tinstno;
+				token_t token;
+				int stringno;
 
-    	DEBUG("INSTR");
-	n=((codep[-1]>>5)&07);
-	getint(stringno,codep);
-	if (toplevel) {
-		swtxt();
-		if (stringno>10000) {
-			assert(stringno < 100001 + MAXPROCARG);
-			genstr(procarg[stringno-10001]);
-		} else
-			genstr(stringno);
-	}
-	for(i=0;i<n;i++) {
-		getint(tinstno,codep);
-		instance(tinstno,&token);
-		if (toplevel)
-			prtoken(&token,i==0 ? ' ' : ',');
-		if (token.t_token>0)
-			totalcost += tokens[token.t_token].t_cost.ct_space;
-	}
-	if (toplevel)
-		gennl();
-	CHKCOST();
-	break;		
-    }
-    case DO_MOVE: {
-	int tinstno;
-	token_t token,token2;
+				DEBUG("INSTR");
+				n = ((codep[-1] >> 5) & 07);
+				getint(stringno, codep);
+				if (toplevel)
+				{
+					swtxt();
+					if (stringno > 10000)
+					{
+						assert(stringno < 10001 + MAXPROCARG);
+						genstr(procarg[stringno - 10001]);
+					}
+					else
+						genstr(stringno);
+				}
+				for (i = 0; i < n; i++)
+				{
+					getint(tinstno, codep);
+					instance(tinstno, &token);
+					if (toplevel)
+						prtoken(&token, i == 0 ? ' ' : ',');
+					if (token.t_token > 0)
+						totalcost += tokens[token.t_token].t_cost.ct_space;
+				}
+				if (toplevel)
+					gennl();
+				CHKCOST();
+				break;
+			}
+			case DO_MOVE:
+			{
+				int tinstno;
+				token_t token, token2;
 
-	DEBUG("MOVE");
-	getint(tinstno,codep);
-	instance(tinstno,&token);
-	getint(tinstno,codep);
-	instance(tinstno,&token2);
-	totalcost += move(&token,&token2,ply,toplevel,costlimit-totalcost+1);
-	CHKCOST();
-	break;
-    }
-    case DO_TEST: {
-	int tinstno;
-	token_t token;
+				DEBUG("MOVE");
+				getint(tinstno, codep);
+				instance(tinstno, &token);
+				getint(tinstno, codep);
+				instance(tinstno, &token2);
+				totalcost += move(&token, &token2, ply, toplevel, costlimit - totalcost + 1);
+				CHKCOST();
+				break;
+			}
+			case DO_TEST:
+			{
+				int tinstno;
+				token_t token;
 
-	DEBUG("TEST");
-	getint(tinstno,codep);
-	instance(tinstno,&token);
-	totalcost += test(&token,ply,toplevel,costlimit-totalcost+1);
-	CHKCOST();
-	break;
-    }
-    case DO_SETCC: {
-	int tinstno;
-	token_t token;
+				DEBUG("TEST");
+				getint(tinstno, codep);
+				instance(tinstno, &token);
+				totalcost += test(&token, ply, toplevel, costlimit - totalcost + 1);
+				CHKCOST();
+				break;
+			}
+			case DO_SETCC:
+			{
+				int tinstno;
+				token_t token;
 
-    	DEBUG("SETCC");
-	getint(tinstno,codep);
-	instance(tinstno,&token);
-	setcc(&token);
-	break;
-    }
-    case DO_ERASE: {
-	int nodeno;
-	result_t result;
+				DEBUG("SETCC");
+				getint(tinstno, codep);
+				instance(tinstno, &token);
+				setcc(&token);
+				break;
+			}
+			case DO_ERASE:
+			{
+				int nodeno;
+				result_t result;
 
-	DEBUG("ERASE");
-	getint(nodeno,codep);
-	compute(&enodes[nodeno], &result);
-	assert(result.e_typ!=EV_INT && result.e_typ!=EV_ADDR);
-	if (result.e_typ==EV_REG)
-	{
-		int regno = result.e_v.e_reg;
-		erasereg(regno);
-	}
-	break;
-    }
-    case DO_TOKREPLACE: {
-	register i;
-	int tinstno;
-	int repllen;
-	token_t reptoken[MAXREPLLEN];
+				DEBUG("ERASE");
+				getint(nodeno, codep);
+				compute(&enodes[nodeno], &result);
+				assert(result.e_typ != EV_INT && result.e_typ != EV_ADDR);
+				if (result.e_typ == EV_REG)
+				{
+					int regno = result.e_v.e_reg;
+					erasereg(regno);
+				}
+				break;
+			}
+			case DO_TOKREPLACE:
+			{
+				register i;
+				int tinstno;
+				int repllen;
+				token_t reptoken[MAXREPLLEN];
 
-	DEBUG("TOKREPLACE");
-	assert(stackheight>=tokpatlen);
-	repllen=(codep[-1]>>5)&07;
+				DEBUG("TOKREPLACE");
+				assert(stackheight >= tokpatlen);
+				repllen = (codep[-1] >> 5) & 07;
 #ifndef NDEBUG
-	if (Debug>2)
-		fprintf(stderr,"Stackheight=%d, tokpatlen=%d, repllen=%d %s\n",
-			stackheight,tokpatlen,repllen,inscoerc ? "(inscoerc)":"");
+				if (Debug > 2)
+					fprintf(stderr, "Stackheight=%d, tokpatlen=%d, repllen=%d %s\n",
+					    stackheight, tokpatlen, repllen, inscoerc ? "(inscoerc)" : "");
 #endif
-	for(i=0;i<repllen;i++) {
-		getint(tinstno,codep);
-		instance(tinstno,&reptoken[i]);
-		tref(&reptoken[i],1);
-	}
-	for(i=0;i<tokpatlen;i++) {
-		if (!inscoerc)
-			tref(&fakestack[stackheight-1],-1);
-		stackheight--;
-	}
-	for (i=0;i<repllen;i++) {
-		assert(stackheight<MAXFSTACK);
-		fakestack[stackheight++] = reptoken[i];
-	}
-	for(i=0;i<nallreg;i++)
-		chrefcount(allreg[i],-1,FALSE);
-	break;
-    }
-    case DO_EMREPLACE: {
-	register i;
-	int j;
-	int nodeno;
-	result_t result[MAXEMREPLLEN];
-	int emrepllen,eminstr;
+				for (i = 0; i < repllen; i++)
+				{
+					getint(tinstno, codep);
+					instance(tinstno, &reptoken[i]);
+					tref(&reptoken[i], 1);
+				}
+				for (i = 0; i < tokpatlen; i++)
+				{
+					if (!inscoerc)
+						tref(&fakestack[stackheight - 1], -1);
+					stackheight--;
+				}
+				for (i = 0; i < repllen; i++)
+				{
+					assert(stackheight < MAXFSTACK);
+					fakestack[stackheight++] = reptoken[i];
+				}
+				for (i = 0; i < nallreg; i++)
+					chrefcount(allreg[i], -1, FALSE);
+				break;
+			}
+			case DO_EMREPLACE:
+			{
+				register i;
+				int j;
+				int nodeno;
+				result_t result[MAXEMREPLLEN];
+				int emrepllen, eminstr;
 
-	DEBUG("EMREPLACE");
-	emrepllen=(codep[-1]>>5)&07;
-	j=emp-emlines;
-	if (emrepllen>j) {
-		assert(nemlines+emrepllen-j<MAXEMLINES);
-		for (i=nemlines;i>=0;i--)
-			emlines[i+emrepllen-j] = emlines[i];
-		nemlines += emrepllen-j;
-		emp += emrepllen-j;
-	}
-	emp -= emrepllen;
-	for (i=0;i<emrepllen;i++) {
-		getint(eminstr,codep);
-		getint(nodeno,codep);
-		emp[i].em_instr = eminstr;
-		compute(&enodes[nodeno], &result[i]);
-	}
-	for (i=0;i<emrepllen;i++) {
-		switch(result[i].e_typ) {
-		default:
-			assert(FALSE);
-		case 0:
-			emp[i].em_optyp = OPNO;
-			emp[i].em_soper = 0;
-			break;
-		case EV_INT:
-			emp[i].em_optyp = OPINT;
-			emp[i].em_soper = tostring(result[i].e_v.e_con);
-			emp[i].em_u.em_ioper = result[i].e_v.e_con;
-			break;
-		case EV_ADDR:
-			emp[i].em_optyp = OPSYMBOL;
-			emp[i].em_soper = ad2str(result[i].e_v.e_addr);
-			break;
-		}
-	}
-	if (!toplevel) {
-		ply += emrepllen;
+				DEBUG("EMREPLACE");
+				emrepllen = (codep[-1] >> 5) & 07;
+				j = emp - emlines;
+				if (emrepllen > j)
+				{
+					assert(nemlines + emrepllen - j < MAXEMLINES);
+					for (i = nemlines; i >= 0; i--)
+						emlines[i + emrepllen - j] = emlines[i];
+					nemlines += emrepllen - j;
+					emp += emrepllen - j;
+				}
+				emp -= emrepllen;
+				for (i = 0; i < emrepllen; i++)
+				{
+					getint(eminstr, codep);
+					getint(nodeno, codep);
+					emp[i].em_instr = eminstr;
+					compute(&enodes[nodeno], &result[i]);
+				}
+				for (i = 0; i < emrepllen; i++)
+				{
+					switch (result[i].e_typ)
+					{
+						default:
+							assert(FALSE);
+						case 0:
+							emp[i].em_optyp = OPNO;
+							emp[i].em_soper = 0;
+							break;
+						case EV_INT:
+							emp[i].em_optyp = OPINT;
+							emp[i].em_soper = tostring(result[i].e_v.e_con);
+							emp[i].em_u.em_ioper = result[i].e_v.e_con;
+							break;
+						case EV_ADDR:
+							emp[i].em_optyp = OPSYMBOL;
+							emp[i].em_soper = ad2str(result[i].e_v.e_addr);
+							break;
+					}
+				}
+				if (!toplevel)
+				{
+					ply += emrepllen;
 #ifndef NDEBUG
-		if (Debug > 4) 
-			fprintf(stderr, "ply becomes %d\n", ply);
+					if (Debug > 4)
+						fprintf(stderr, "ply becomes %d\n", ply);
 #endif
-	}
-	break;
-    }
-    case DO_COST: {
-	cost_t cost;
+				}
+				break;
+			}
+			case DO_COST:
+			{
+				cost_t cost;
 
-	DEBUG("COST");
-	getint(cost.ct_space,codep);
-	getint(cost.ct_time,codep);
-	totalcost += costcalc(cost);
-	CHKCOST();
-	break;
-    }
+				DEBUG("COST");
+				getint(cost.ct_space, codep);
+				getint(cost.ct_time, codep);
+				totalcost += costcalc(cost);
+				CHKCOST();
+				break;
+			}
 #ifdef REGVARS
-    case DO_PRETURN: {
-	if (toplevel) {
-		swtxt();
-		regreturn();	/* in mach.c */
-	}
-	break;
-    }
+			case DO_PRETURN:
+			{
+				if (toplevel)
+				{
+					swtxt();
+					regreturn(); /* in mach.c */
+				}
+				break;
+			}
 #endif
-    case DO_RETURN:
-	DEBUG("RETURN");
-	assert(origcp!=startupcode);
+			case DO_RETURN:
+				DEBUG("RETURN");
+				assert(origcp != startupcode);
 #ifndef NDEBUG
-	level--;
+				level--;
 #endif
-	return(totalcost);
+				return (totalcost);
 #ifdef USE_TES
-    case DO_LABDEF: {
-	int index;
+			case DO_LABDEF:
+			{
+				int index;
 
-	DEBUG("LABDEF");
-	getint(index,codep);
-	if (toplevel) {
-		swtxt();
-		printlabel(index);
-	}
+				DEBUG("LABDEF");
+				getint(index, codep);
+				if (toplevel)
+				{
+					swtxt();
+					printlabel(index);
+				}
 
-	break;
-    }
+				break;
+			}
 #endif
+		}
 	}
-	}
-    doreturn:
+doreturn:
 #ifdef ALLOW_NEXTEM
-	if (toplevel && totalcost == INFINITY && ! paniced) {
+	if (toplevel && totalcost == INFINITY && !paniced)
+	{
 		DEBUG("PANIC!");
-		totalcost += stackupto(&fakestack[stackheight-1], ply, toplevel);
+		totalcost += stackupto(&fakestack[stackheight - 1], ply, toplevel);
 #ifndef NDEBUG
 		if (Debug > 2)
 			fprintf(stderr, "Stackheight = %d\n", stackheight);
@@ -929,18 +1090,21 @@ normalfailed:	if (stackpad!=tokpatlen) {
 #ifndef NDEBUG
 	level--;
 #endif
-	return(totalcost);
+	return (totalcost);
 }
 
-readcodebytes() {
+readcodebytes()
+{
 #ifndef CODEINC
 	register fd;
 	extern int ncodebytes;
 
-	if ((fd=open("code",0))<0) {
+	if ((fd = open("code", 0)) < 0)
+	{
 		error("Can't open code");
 	}
-	if (read(fd,coderules,ncodebytes)!=ncodebytes) {
+	if (read(fd, coderules, ncodebytes) != ncodebytes)
+	{
 		error("Short read from code");
 	}
 	close(fd);
@@ -948,30 +1112,34 @@ readcodebytes() {
 }
 
 #ifdef TABLEDEBUG
-initlset(f) char *f; {
-	extern char *myalloc();
+initlset(f) char* f;
+{
+	extern char* myalloc();
 
 	set_flag = f;
-	if ((set_fd=open(f+1,2))<0)
-		error("Can't open %s rw",f+1);
-	read(set_fd,&set_size,sizeof(int));
-	set_val=( short *) myalloc(set_size);
-	read(set_fd,set_val,set_size);
+	if ((set_fd = open(f + 1, 2)) < 0)
+		error("Can't open %s rw", f + 1);
+	read(set_fd, &set_size, sizeof(int));
+	set_val = (short*)myalloc(set_size);
+	read(set_fd, set_val, set_size);
 }
 
-termlset() {
+termlset()
+{
 
-	if (set_fd) {
-		lseek(set_fd,(long) sizeof(int),0);
-		write(set_fd,set_val,set_size);
+	if (set_fd)
+	{
+		lseek(set_fd, (long)sizeof(int), 0);
+		write(set_fd, set_val, set_size);
 		close(set_fd);
-		if (set_flag[0]=='u') {
+		if (set_flag[0] == 'u')
+		{
 			register i;
-			
-			fprintf(stderr,"Unused code rules:\n\n");
-			for(i=0;i<8*set_size;i++)
-				if(set_val[i>>4]&(1<<(i&017)))
-					fprintf(stderr,"\"%s\", line %d\n",tablename,i);
+
+			fprintf(stderr, "Unused code rules:\n\n");
+			for (i = 0; i < 8 * set_size; i++)
+				if (set_val[i >> 4] & (1 << (i & 017)))
+					fprintf(stderr, "\"%s\", line %d\n", tablename, i);
 		}
 	}
 }
diff --git a/mach/proto/ncg/salloc.c b/mach/proto/ncg/salloc.c
index e110d75ad..7ce1287bb 100644
--- a/mach/proto/ncg/salloc.c
+++ b/mach/proto/ncg/salloc.c
@@ -37,7 +37,7 @@ void chkstr();
 string myalloc(size) {
 	register string p;
 
-	p = (string) malloc((unsigned)size);
+	p = (string) calloc((unsigned)size, 1);
 	if (p==0)
 		fatal("Out of memory");
 	return(p);
diff --git a/mach/z80/int/em22 b/mach/z80/int/em22
index 8591c7bfc..d30597a0e 100644
--- a/mach/z80/int/em22
+++ b/mach/z80/int/em22
@@ -25,17 +25,17 @@ name asld
 	mapflag -s* SIZE_FLAG=-s*
 	mapflag -ansi C_LIB={EM}/{LIB}ac
 	args {SIZE_FLAG} \
-		({RTS}:.ocm.b={EM}/{RT}cc) \
+		({RTS}:.ocm.bas={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.c={EM}/{RT}cc) \
 		({RTS}{ANSI?}:.cansi={EM}/{RT}ac) \
 		({RTS}:.mod={EM}/{RT}m2) \
 		({RTS}:.p={EM}/{RT}pc) \
 		-o > < \
 		(.p:{TAIL}={EM}/{LIB}pc) \
-		(.b:{TAIL}={EM}/{LIB}bc) \
+		(.bas:{TAIL}={EM}/{LIB}bc) \
 		(.ocm:{TAIL}={EM}/{LIB}ocm) \
 		(.mod:{TAIL}={EM}/{LIB}m2) \
-		(.ocm.b:{TAIL}={OLD_C_LIB}) \
+		(.ocm.bas:{TAIL}={OLD_C_LIB}) \
 		(.c:{TAIL}={C_LIB}) \
 		(.b.c.ocm.mod.p.e:{TAIL}={EM}/{LIB}mon) \
 		({RTS}{ANSI?}:.cansi={EM}/lib/em22/end_em)
diff --git a/man/powerpc_as.6 b/man/powerpc_as.6
new file mode 100644
index 000000000..8198d6bce
--- /dev/null
+++ b/man/powerpc_as.6
@@ -0,0 +1,33 @@
+.TH POWERPC_AS 1
+.ad
+.SH NAME
+powerpc_as \- assembler for PowerPC
+
+.SH SYNOPSIS
+as [options] argument ...
+
+.SH DESCRIPTION
+This assembler is made with the general framework
+described in \fIuni_ass\fP(6).
+
+.SH SYNTAX
+Most 32-bit integer and floating point instructions are supported, but not many
+short form instructions. Instructions which take 16-bit operands can additionally
+use the following special functions:
+
+.IP hi16[value], ha16[value]
+Returns the high half of the value of the expression; if the value is not absolute,
+also generates the appropriate fixup. Use of either of these \fImust\fR be followed,
+in the next instruction, by the corresponding use of \fBlo16[]\fR. Use \fBhi16[]\fR
+if the low half is going to interpret its payload as an unsigned value, and
+\fBha16[]\fR if it will be interpreted as a signed value (so that the high half can
+be adjusted to match).
+
+.IP lo16[]
+Returns the low half of the value of the expression. No fixup is generated. Use of
+\fBlo16[]\fR must come in the instruction immediately after a use of \fBhi16[]\fR or
+\fBha16[]\fR.
+
+.SH "SEE ALSO"
+uni_ass(6),
+ack(1)
diff --git a/modules/src/object/build.lua b/modules/src/object/build.lua
index c30c7e54a..6a8bea04e 100644
--- a/modules/src/object/build.lua
+++ b/modules/src/object/build.lua
@@ -1,6 +1,7 @@
 clibrary {
 	name = "lib",
 	srcs = { "./*.c" },
+	hdrs = { "./object.h" },
 	deps = {
 		"modules+headers",
 		"h+local",
diff --git a/modules/src/object/obj.h b/modules/src/object/obj.h
index 8f7fd8d32..9000b32ce 100644
--- a/modules/src/object/obj.h
+++ b/modules/src/object/obj.h
@@ -6,6 +6,8 @@
 #include <local.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
 #include <out.h>
 #include <ranlib.h>
 #include <arch.h>
diff --git a/modules/src/object/object.h b/modules/src/object/object.h
index 68a5ea99f..d6c218a2a 100644
--- a/modules/src/object/object.h
+++ b/modules/src/object/object.h
@@ -4,42 +4,46 @@
  * See the copyright notice in the ACK home directory, in the file "Copyright".
  */
 
-#include <ansi.h>
-
 #ifndef __OBJECT_INCLUDED__
 #define __OBJECT_INCLUDED__
 
-_PROTOTYPE(int wr_open, (char *f));
-_PROTOTYPE(void wr_close, (void));
-_PROTOTYPE(void wr_ohead, (struct outhead *h));
-_PROTOTYPE(void wr_sect, (struct outsect *s, unsigned int c));
-_PROTOTYPE(void wr_outsect, (int sectno));
-_PROTOTYPE(void wr_emit, (char *b, long c));
-_PROTOTYPE(void wr_putc, (int c));
-_PROTOTYPE(void wr_relo, (struct outrelo *r, unsigned int c));
-_PROTOTYPE(void wr_name, (struct outname *n, unsigned int c));
-_PROTOTYPE(void wr_string, (char *s, long c));
-_PROTOTYPE(void wr_arhdr, (int fd, struct ar_hdr *a));
-_PROTOTYPE(void wr_ranlib, (int fd, struct ranlib *r, long cnt));
-_PROTOTYPE(void wr_int2, (int fd, int i));
-_PROTOTYPE(void wr_long, (int fd, long l));
-_PROTOTYPE(void wr_bytes, (int fd, char *buf, long l));
-_PROTOTYPE(int rd_open, (char *f));
-_PROTOTYPE(int rd_fdopen, (int f));
-_PROTOTYPE(void rd_close, (void));
-_PROTOTYPE(void rd_ohead, (struct outhead *h));
-_PROTOTYPE(void rd_sect, (struct outsect *s, unsigned int c));
-_PROTOTYPE(void rd_outsect, (int sectno));
-_PROTOTYPE(void rd_emit, (char *b, long c));
-_PROTOTYPE(void rd_relo, (struct outrelo *r, unsigned int c));
-_PROTOTYPE(void rd_rew_relo, (struct outhead *head));
-_PROTOTYPE(void rd_name, (struct outname *n, unsigned int c));
-_PROTOTYPE(void rd_string, (char *s, long c));
-_PROTOTYPE(int rd_arhdr, (int fd, struct ar_hdr *a));
-_PROTOTYPE(void rd_ranlib, (int fd, struct ranlib *r, long cnt));
-_PROTOTYPE(int rd_int2, (int fd));
-_PROTOTYPE(long rd_long, (int fd));
-_PROTOTYPE(void rd_bytes, (int fd, char *buf, long l));
-_PROTOTYPE(int rd_fd, (void));
+struct ar_hdr;
+struct outhead;
+struct outrelo;
+struct outsect;
+struct ranlib;
+
+int wr_open(char *f);
+void wr_close(void);
+void wr_ohead(struct outhead *h);
+void wr_sect(struct outsect *s, unsigned int c);
+void wr_outsect(int sectno);
+void wr_emit(char *b, long c);
+void wr_putc(int c);
+void wr_relo(struct outrelo *r, unsigned int c);
+void wr_name(struct outname *n, unsigned int c);
+void wr_string(char *s, long c);
+void wr_arhdr(int fd, struct ar_hdr *a);
+void wr_ranlib(int fd, struct ranlib *r, long cnt);
+void wr_int2(int fd, int i);
+void wr_long(int fd, long l);
+void wr_bytes(int fd, char *buf, long l);
+int rd_open(char *f);
+int rd_fdopen(int f);
+void rd_close(void);
+void rd_ohead(struct outhead *h);
+void rd_sect(struct outsect *s, unsigned int c);
+void rd_outsect(int sectno);
+void rd_emit(char *b, long c);
+void rd_relo(struct outrelo *r, unsigned int c);
+void rd_rew_relo(struct outhead *head);
+void rd_name(struct outname *n, unsigned int c);
+void rd_string(char *s, long c);
+int rd_arhdr(int fd, struct ar_hdr *a);
+void rd_ranlib(int fd, struct ranlib *r, long cnt);
+int rd_int2(int fd);
+long rd_long(int fd);
+void rd_bytes(int fd, char *buf, long l);
+int rd_fd(void);
 
 #endif /* __OBJECT_INCLUDED__ */
diff --git a/plat/build.lua b/plat/build.lua
index 85ba61bc9..dc0821f26 100644
--- a/plat/build.lua
+++ b/plat/build.lua
@@ -15,6 +15,8 @@ definerule("ackfile",
 			name = e.name,
 			srcs = e.srcs,
 			deps = {
+				"lang/b/compiler+pkg",
+				"lang/basic/src+pkg",
 				"lang/cem/cemcom.ansi+pkg",
 				"lang/cem/cpp.ansi+pkg",
 				"lang/m2/comp+pkg",
@@ -100,10 +102,12 @@ definerule("build_plat_libs",
 		return installable {
 			name = e.name,
 			map = {
+				"lang/b/lib+pkg_"..e.plat,
 				"lang/basic/lib+pkg_"..e.plat,
 				"lang/cem/libcc.ansi+pkg_"..e.plat,
 				"lang/m2/libm2+pkg_"..e.plat,
 				"lang/pc/libpc+pkg_"..e.plat,
+				"lang/b/lib+pkg_"..e.plat,
 				["$(PLATIND)/"..e.plat.."/libem.a"] = "mach/"..e.arch.."/libem+lib_"..e.plat,
 				["$(PLATIND)/"..e.plat.."/libend.a"] = "mach/"..e.arch.."/libend+lib_"..e.plat,
 			}
diff --git a/plat/cpm/descr b/plat/cpm/descr
index 2d626295a..d084f89ea 100644
--- a/plat/cpm/descr
+++ b/plat/cpm/descr
@@ -60,17 +60,19 @@ name led
 	mapflag -i SEPID=-b1:0
 	mapflag -fp FLOATS={EM}/{ILIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/linux/libsys/execve.c b/plat/linux/libsys/execve.c
new file mode 100644
index 000000000..d8f37b1cf
--- /dev/null
+++ b/plat/linux/libsys/execve.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "libsys.h"
+
+int execve(const char *path, char *const argv[], char *const envp[])
+{
+	return _syscall(__NR_execve, (quad) path, (quad) argv, (quad) envp);
+}
diff --git a/plat/linux/libsys/sbrk.c b/plat/linux/libsys/sbrk.c
index 7aeeecb86..f790a17cb 100644
--- a/plat/linux/libsys/sbrk.c
+++ b/plat/linux/libsys/sbrk.c
@@ -26,7 +26,6 @@ void* sbrk(int increment)
 {
 	char* old;
 	char* new;
-	char* actual;
 	
 	if (!current)
 		current = (char*) _syscall(__NR_brk, 0, 0, 0);
@@ -35,15 +34,21 @@ void* sbrk(int increment)
 		return current;
 		
 	old = current;
+
 	new = old + increment;
 
-	actual = (char*) _syscall(__NR_brk, (quad) new, 0, 0);
-	if (actual < new)
-	{
-		errno = ENOMEM;
-		return OUT_OF_MEMORY;
-	}
+	if ((increment > 0) && (new <= old))
+		goto out_of_memory;
+	else if ((increment < 0) && (new >= old))
+		goto out_of_memory;
+
+	if (brk(new) < 0)
+		goto out_of_memory;
 		
-	current = actual;
 	return old;
+
+out_of_memory:
+	errno = ENOMEM;
+	return OUT_OF_MEMORY;
 }
+
diff --git a/plat/linux/libsys/sigprocmask.c b/plat/linux/libsys/sigprocmask.c
new file mode 100644
index 000000000..ad1b339c2
--- /dev/null
+++ b/plat/linux/libsys/sigprocmask.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "libsys.h"
+
+int sigprocmask(int flags, const sigset_t *new, sigset_t *old)
+{
+	return _syscall(__NR_sigprocmask, flags, (quad) new, (quad) old);
+}
diff --git a/plat/linux386/build-tools.lua b/plat/linux386/build-tools.lua
index d711f85fd..31b8a7388 100644
--- a/plat/linux386/build-tools.lua
+++ b/plat/linux386/build-tools.lua
@@ -16,6 +16,7 @@ return installable {
 		["$(PLATDEP)/linux386/as"] = "+as",
 		["$(PLATDEP)/linux386/ncg"] = "+ncg",
 		["$(PLATIND)/descr/linux386"] = "./descr",
+		"util/amisc+aelflod-pkg",
 		"util/opt+pkg",
 	}
 }
diff --git a/plat/linux386/descr b/plat/linux386/descr
index 611e96e44..1888e4182 100644
--- a/plat/linux386/descr
+++ b/plat/linux386/descr
@@ -56,17 +56,19 @@ name led
 	mapflag -l* LNAME={PLATFORMDIR}/lib*
 	mapflag -fp FLOATS={EM}/{LIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/linux386/include/unistd.h b/plat/linux386/include/unistd.h
index 35dc8dde7..8c8637c09 100644
--- a/plat/linux386/include/unistd.h
+++ b/plat/linux386/include/unistd.h
@@ -56,7 +56,6 @@ extern int write(int fd, void* buffer, size_t count);
 extern off_t lseek(int fildes, off_t offset, int whence);
 extern int fcntl(int fd, int op, ...);
 extern int unlink(const char* path);
-extern int remove(const char* path);
 
 /* Special variables */
 
@@ -69,6 +68,7 @@ extern pid_t getpid(void);
 extern int brk(void* ptr);
 extern void* sbrk(int increment);
 extern int isatty(int d);
+extern int execve(const char *path, char *const argv[], char *const envp[]);
 
 /* Signal handling */
 
@@ -116,8 +116,16 @@ typedef int sig_atomic_t;
 
 #define _NSIG           32      /* Biggest signal number + 1
                                    (not including real-time signals).  */
+
+/* sigprocmask */
+#define SIG_BLOCK       0
+#define SIG_UNBLOCK     1
+#define SIG_SETMASK     2
+typedef unsigned long sigset_t;
+
 typedef void (*sighandler_t)(int);
 extern sighandler_t signal(int signum, sighandler_t handler);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
 extern int raise(int signum);
 
 
diff --git a/plat/linux386/tests/build.lua b/plat/linux386/tests/build.lua
new file mode 100644
index 000000000..afd12fdce
--- /dev/null
+++ b/plat/linux386/tests/build.lua
@@ -0,0 +1,7 @@
+include("tests/plat/build.lua")
+
+plat_testsuite {
+    name = "tests",
+    plat = "linux386",
+    method = "qemu-i386"
+}
diff --git a/plat/linux68k/build-tools.lua b/plat/linux68k/build-tools.lua
index 944e57f47..03d659a15 100644
--- a/plat/linux68k/build-tools.lua
+++ b/plat/linux68k/build-tools.lua
@@ -16,6 +16,7 @@ return installable {
 		["$(PLATDEP)/linux68k/as"] = "+as",
 		["$(PLATDEP)/linux68k/ncg"] = "+ncg",
 		["$(PLATIND)/descr/linux68k"] = "./descr",
+		"util/amisc+aelflod-pkg",
 		"util/opt+pkg",
 	}
 }
diff --git a/plat/linux68k/descr b/plat/linux68k/descr
index 9347ad2b2..1e3b6a5bd 100644
--- a/plat/linux68k/descr
+++ b/plat/linux68k/descr
@@ -56,17 +56,19 @@ name led
 	mapflag -l* LNAME={PLATFORMDIR}/lib*
 	mapflag -fp FLOATS={EM}/{LIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/linux68k/include/unistd.h b/plat/linux68k/include/unistd.h
index 307192f77..927a20459 100644
--- a/plat/linux68k/include/unistd.h
+++ b/plat/linux68k/include/unistd.h
@@ -55,6 +55,7 @@ extern int read(int fd, void* buffer, size_t count);
 extern int write(int fd, void* buffer, size_t count);
 extern off_t lseek(int fildes, off_t offset, int whence);
 extern int fcntl(int fd, int op, ...);
+extern int unlink(const char* path);
 
 /* Special variables */
 
@@ -67,6 +68,7 @@ extern pid_t getpid(void);
 extern int brk(void* ptr);
 extern void* sbrk(int increment);
 extern int isatty(int d);
+extern int execve(const char *path, char *const argv[], char *const envp[]);
 
 /* Signal handling */
 
@@ -114,8 +116,16 @@ typedef int sig_atomic_t;
 
 #define _NSIG           32      /* Biggest signal number + 1
                                    (not including real-time signals).  */
+
+/* sigprocmask */
+#define SIG_BLOCK       0
+#define SIG_UNBLOCK     1
+#define SIG_SETMASK     2
+typedef unsigned long sigset_t;
+
 typedef void (*sighandler_t)(int);
 extern sighandler_t signal(int signum, sighandler_t handler);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
 extern int raise(int signum);
 
 
diff --git a/plat/linuxppc/build-tools.lua b/plat/linuxppc/build-tools.lua
index ce1a163d8..e48524cc9 100644
--- a/plat/linuxppc/build-tools.lua
+++ b/plat/linuxppc/build-tools.lua
@@ -28,6 +28,7 @@ return installable {
 		["$(PLATDEP)/linuxppc/mcg"] = "+mcg",
 		["$(PLATDEP)/linuxppc/top"] = "+top",
 		["$(PLATIND)/descr/linuxppc"] = "./descr",
+		"util/amisc+aelflod-pkg",
 		"util/opt+pkg",
 	}
 }
diff --git a/plat/linuxppc/descr b/plat/linuxppc/descr
index 12bece6e9..ced1de4b1 100644
--- a/plat/linuxppc/descr
+++ b/plat/linuxppc/descr
@@ -62,17 +62,19 @@ name led
 	mapflag -l* LNAME={PLATFORMDIR}/lib*
 	mapflag -fp FLOATS={EM}/{LIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/linuxppc/include/unistd.h b/plat/linuxppc/include/unistd.h
index 307192f77..f57705365 100644
--- a/plat/linuxppc/include/unistd.h
+++ b/plat/linuxppc/include/unistd.h
@@ -55,6 +55,7 @@ extern int read(int fd, void* buffer, size_t count);
 extern int write(int fd, void* buffer, size_t count);
 extern off_t lseek(int fildes, off_t offset, int whence);
 extern int fcntl(int fd, int op, ...);
+extern int unlink(const char* path);
 
 /* Special variables */
 
@@ -67,6 +68,7 @@ extern pid_t getpid(void);
 extern int brk(void* ptr);
 extern void* sbrk(int increment);
 extern int isatty(int d);
+extern int execve(const char *path, char *const argv[], char *const envp[]);
 
 /* Signal handling */
 
@@ -114,8 +116,34 @@ typedef int sig_atomic_t;
 
 #define _NSIG           32      /* Biggest signal number + 1
                                    (not including real-time signals).  */
+
+/* sigprocmask */
+#define SIG_BLOCK       0
+#define SIG_UNBLOCK     1
+#define SIG_SETMASK     2
+typedef unsigned long sigset_t;
+
+/* sa_flags */
+#define SA_NODEFER      0x40000000UL
+#define SA_RESETHAND    0x80000000UL
+
+struct __siginfo;
+struct sigaction {
+	union {
+		void (*__sa_handler)(int);
+		void (*__sa_sigaction)(int, struct __siginfo *, void *);
+	} __sigaction_u;
+	sigset_t sa_mask;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+};
+#define sa_handler __sigaction_u.__sa_handler
+#define sa_sigaction __sigaction_u.__sa_sigaction
+
 typedef void (*sighandler_t)(int);
+extern int sigaction(int, const struct sigaction *, struct sigaction *);
 extern sighandler_t signal(int signum, sighandler_t handler);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
 extern int raise(int signum);
 
 
diff --git a/plat/linuxppc/libsys/build.lua b/plat/linuxppc/libsys/build.lua
index e74f3f416..f7b16b378 100644
--- a/plat/linuxppc/libsys/build.lua
+++ b/plat/linuxppc/libsys/build.lua
@@ -1,16 +1,36 @@
 acklibrary {
-    name = "lib",
-    srcs = {
-        "./*.s",
-        "plat/linux/libsys/*.c",
-        "plat/linux/libsys/*.s",
-    },
+	name = "lib",
+	srcs = {
+		"./_syscall.s",
+		"./sigaction.s",
+		"./signal.c",
+		"./trap.s",
+		"plat/linux/libsys/_exit.c",
+		"plat/linux/libsys/_hol0.s",
+		"plat/linux/libsys/close.c",
+		"plat/linux/libsys/creat.c",
+		"plat/linux/libsys/errno.s",
+		"plat/linux/libsys/execve.c",
+		"plat/linux/libsys/getpid.c",
+		"plat/linux/libsys/gettimeofday.c",
+		"plat/linux/libsys/ioctl.c",
+		"plat/linux/libsys/isatty.c",
+		"plat/linux/libsys/kill.c",
+		"plat/linux/libsys/lseek.c",
+		"plat/linux/libsys/open.c",
+		"plat/linux/libsys/read.c",
+		"plat/linux/libsys/sbrk.c",
+		-- omit signal.c
+		"plat/linux/libsys/sigprocmask.c",
+		"plat/linux/libsys/unlink.c",
+		"plat/linux/libsys/write.c",
+	},
 	deps = {
 		"lang/cem/libcc.ansi/headers+headers",
 		"plat/linuxppc/include+headers",
 	},
-    vars = {
-        plat = "linuxppc"
-    }
+	vars = {
+		plat = "linuxppc"
+	}
 }
 
diff --git a/plat/linuxppc/libsys/sigaction.s b/plat/linuxppc/libsys/sigaction.s
new file mode 100644
index 000000000..0509c8e72
--- /dev/null
+++ b/plat/linuxppc/libsys/sigaction.s
@@ -0,0 +1,156 @@
+#define __NR_sigaction		67
+#define SIG_BLOCK		0
+#define SIG_SETMASK		2
+#define MAXSIG			32
+
+/* offsets into our stack frame */
+#define mynew	16	/* new sigaction */
+#define mynset	32	/* new signal set */
+#define myoset	36	/* old signal set */
+#define mysave	40
+#define mysize	56
+
+.sect .text; .sect .rodata; .sect .data; .sect .bss
+
+/*
+ * Linux calls signal handlers with arguments in registers, but the
+ * ACK expects arguments on the stack.  This sigaction() uses a
+ * "bridge" to move the arguments.
+ */
+.sect .text
+.define _sigaction
+_sigaction:
+	mflr	r0
+	subi	r1, r1, mysize
+	stw	r31, mysave+8(r1)
+	stw	r30, mysave+4(r1)
+	stw	r29, mysave(r1)
+	stw	r0, mysave+12(r1)
+	li	r3, 0
+	stw	r3, mynset(r1)	   	! mynset = 0
+	lwz	r29, mysize(r1)		! r29 = signal number
+	lwz	r30, mysize+4(r1)	! r30 = new action
+	lwz	r31, mysize+8(r1)	! r31 = old action
+	/*
+	 * If the new action is non-NULL, the signal number is in
+	 * range 1 to MAXSIG, and the new handler is not SIG_DFL 0
+	 * or SIG_IGN 1, then we interpose our bridge.
+	 */
+	cmpwi	cr0, r30, 0
+	subi	r7, r29, 1		! r7 = index in handlers
+	cmplwi	cr7, r7, MAXSIG		! unsigned comparison
+	beq	cr0, kernel
+	bge	cr7, kernel
+	lwz	r3, 0(r30)		! r3 = new handler
+	clrrwi.	r3, r3, 1
+	beq	cr0, kernel
+	/*
+	 * Block the signal while we build the bridge.  Prevents a
+	 * race if a signal arrives after we change the bridge but
+	 * before we change the action in the kernel.
+	 */
+	li	r4, 1
+	slw	r4, r4, r7
+	stw	r4, mynset(r1)		! mynmask = 1 << (signal - 1)
+	li	r3, SIG_BLOCK
+	la	r4, mynset(r1)
+	la	r5, myoset(r1)
+	stw	r3, 0(r1)
+	stw	r4, 4(r1)
+	stw	r5, 8(r1)
+	bl	_sigprocmask
+	/*
+	 * Point our bridge to the new signal handler.  Then copy the
+	 * new sigaction but point it to our bridge.
+	 */
+	lis	r6, hi16[handlers]
+	ori	r6, r6, lo16[handlers]
+	subi	r7, r29, 1
+	slwi	r7, r7, 2
+	lwz	r3, 0(r30)		! r3 = new handler
+	stwx	r3, r6, r7		! put it in array of handlers
+	lis	r3, hi16[bridge]
+	ori	r3, r3, lo16[bridge]
+	lwz	r4, 4(r30)
+	lwz	r5, 8(r30)
+	lwz	r6, 12(r30)
+	stw	r3, mynew(r1)		! sa_handler or sa_sigaction
+	stw	r4, mynew+4(r1)		! sa_mask
+	stw	r5, mynew+8(r1)		! sa_flags
+	stw	r6, mynew+12(r1)	! sa_restorer
+	la	r30, mynew(r1)
+kernel:
+	li	r3, __NR_sigaction
+	stw	r3, 0(r1)
+	stw	r29, 4(r1)
+	stw	r30, 8(r1)
+	stw	r31, 12(r1)
+	bl	__syscall
+	/*
+	 * If we blocked the signal, then restore the old signal mask.
+	 */
+	lwz	r3, mynset(r1)
+	cmpwi	cr0, r3, 0
+	beq	cr0, fixold
+	li	r3, SIG_SETMASK
+	la	r4, myoset(r1)
+	li	r5, 0
+	stw	r3, 0(r1)
+	stw	r4, 4(r1)
+	stw	r5, 8(r1)
+	bl	_sigprocmask
+	/*
+	 * If the old sigaction is non-NULL and points to our bridge,
+	 * then point it to the signal handler.
+	 */
+fixold:
+	cmpwi	cr0, r31, 0
+	beq	cr0, leave
+	lis	r3, hi16[bridge]
+	ori	r3, r3, lo16[bridge]
+	lwz	r4, 0(r31)
+	cmpw	cr0, r3, r4
+	bne	cr0, leave
+	lis	r6, hi16[handlers]
+	ori	r6, r6, lo16[handlers]
+	subi	r7, r29, 1
+	slwi	r7, r7, 2
+	lwzx	r3, r6, r7	! get it from array of handlers
+	stw	r3, 0(r31)	! put it in old sigaction
+leave:
+	lwz	r0, mysave+12(r1)
+	lwz	r29, mysave(r1)
+	lwz	r30, mysave+4(r1)
+	lwz	r31, mysave+8(r1)
+	addi	r1, r1, mysize
+	mtlr	r0
+	blr			! return from sigaction
+
+/*
+ * Linux calls bridge(signum) or bridge(signum, info, context) with
+ * arguments in registers r3, r4, r5.
+ */
+bridge:
+	mflr	r0
+	subi	r1, r1, 16
+	stw	r0, 12(r1)
+	stw	r3, 0(r1)	! signal number
+	stw	r4, 4(r1)	! info
+	stw	r5, 8(r1)	! context
+
+	lis	r6, hi16[handlers]
+	ori	r6, r6, lo16[handlers]
+	subi	r7, r3, 1
+	slwi	r7, r7, 2
+	lwzx	r6, r6, r7
+	mtctr	r6
+	bctrl			! call our signal handler
+
+	lwz	r0, 12(r1)
+	addi	r1, r1, 16
+	mtlr	r0
+	blr			! return from bridge
+
+.sect .bss
+handlers:
+	.space 4 * MAXSIG	! array of signal handlers
diff --git a/plat/linuxppc/libsys/signal.c b/plat/linuxppc/libsys/signal.c
new file mode 100644
index 000000000..0ed1918e1
--- /dev/null
+++ b/plat/linuxppc/libsys/signal.c
@@ -0,0 +1,19 @@
+#include <signal.h>
+
+/*
+ * Uses our bridge in sigaction.s when calling the signal handler.
+ * Mimics Linux __NR_signal by using SA_NODEFER | SA_RESETHAND.
+ */
+sighandler_t signal(int signum, sighandler_t handler) {
+	struct sigaction new, old;
+	int i;
+
+	new.sa_handler = handler;
+	new.sa_mask = 0; /* empty set */
+	new.sa_flags = SA_NODEFER | SA_RESETHAND;
+
+	i = sigaction(signum, &new, &old);
+	if (i < 0)
+		return SIG_ERR;
+	return old.sa_handler;
+}
diff --git a/plat/linuxppc/libsys/trap.s b/plat/linuxppc/libsys/trap.s
index 09d3b0b21..93c5189a4 100644
--- a/plat/linuxppc/libsys/trap.s
+++ b/plat/linuxppc/libsys/trap.s
@@ -52,43 +52,50 @@ EUNIMPL = 63		! unimplemented em-instruction called
 .trap_ecase:
 	addi r3, r0, ECASE
 	b .trap
-	
+
 .define .trap_earray
 .trap_earray:
 	addi r3, r0, EARRAY
 	b .trap
-	
+
+.define .trap_erange
+.trap_erange:
+	addi r3, r0, ERANGE
+	b .trap
+
+.define .trp
 .define .trap
+.trp:
 .trap:
 	cmpi cr0, 0, r3, 15      ! traps >15 can't be ignored
 	bc IFTRUE, LT, 1f
-	
+
 	addi r4, r0, 1
 	rlwnm r4, r4, r3, 0, 31  ! calculate trap bit
 	li32 r5, .ignmask
 	lwz r5, 0(r5)            ! load ignore mask
 	and. r4, r4, r5          ! compare
 	bclr IFFALSE, EQ, 0      ! return if non-zero
-	
+
 1:
 	li32 r4, .trppc
 	lwz r5, 0(r4)            ! load user trap routine
 	or. r5, r5, r5           ! test
 	bc IFTRUE, EQ, fatal     ! if no user trap routine, bail out
-	
+
 	addi r0, r0, 0
 	stw r0, 0(r4)            ! reset trap routine
-	
+
 	mfspr r0, lr
 	stwu r0, -4(sp)          ! save old lr
-	
+
 	stwu r3, -4(sp)
 	mtspr ctr, r5
 	bcctrl ALWAYS, 0, 0      ! call trap routine
-	
+
 	lwz r0, 4(sp)            ! load old lr again
 	addi sp, sp, 8           ! retract over stack usage
-	bclr ALWAYS, 0, 0        ! return 
+	bclr ALWAYS, 0, 0        ! return
 
 fatal:
 	addi r3, r0, 1
@@ -96,7 +103,7 @@ fatal:
 	addi r5, r0, 6
 	addi r0, r0, 4           ! write()
 	sc 0
-	
+
 	addi r0, r0, 1           ! exit()
 	sc 0
 
diff --git a/plat/linuxppc/tests/build.lua b/plat/linuxppc/tests/build.lua
new file mode 100644
index 000000000..7601ab0be
--- /dev/null
+++ b/plat/linuxppc/tests/build.lua
@@ -0,0 +1,7 @@
+include("tests/plat/build.lua")
+
+plat_testsuite {
+    name = "tests",
+    plat = "linuxppc",
+    method = "qemu-ppc"
+}
diff --git a/plat/osx/cvmach/build.lua b/plat/osx/cvmach/build.lua
new file mode 100644
index 000000000..8076546c1
--- /dev/null
+++ b/plat/osx/cvmach/build.lua
@@ -0,0 +1,15 @@
+cprogram {
+	name = "cvmach",
+	srcs = { "./cvmach.c" },
+	deps = {
+		"h+emheaders",
+		"modules/src/object+lib",
+	}
+}
+
+installable {
+	name = "pkg",
+	map = {
+		["$(PLATDEP)/cvmach"] = "+cvmach",
+	}
+}
diff --git a/plat/osx/cvmach/cvmach.6 b/plat/osx/cvmach/cvmach.6
new file mode 100644
index 000000000..30d4aa2d7
--- /dev/null
+++ b/plat/osx/cvmach/cvmach.6
@@ -0,0 +1,96 @@
+.Dd December 2, 2016
+.Dt CVMACH 6
+.Os
+.Sh NAME
+.Nm cvmach
+.Nd convert an executable file from ack.out to Mach-o
+.Sh SYNOPSIS
+.Cm ~em/lib/ack/cvmach
+.Fl m Ns Ar number
+.Oo
+.Ar infile
+.Op Ar outfile
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+utility converts an executable file from
+.Xr ack.out 5
+format to Mach-object format.
+It can produce Mach-o executables for Mac OS X.
+If the
+.Ar infile
+or
+.Ar outfile
+are not given, then
+.Nm
+reads from standard input or writes to standard output.
+.Pp
+The option is required:
+.Bl -tag -width Ds
+.It Fl m Ns Ar number
+Sets the CPU type in the Mach header.
+This must be
+.Fl m Ns Cm 7
+for Intel i386 or
+.Fl m Ns Cm 18
+for PowerPC.
+.Nm
+doesn't know how to make Mach-o files for other CPU types.
+.El
+.Pp
+The input file must have four segments:
+TEXT, ROM, DATA and BSS, in that order.
+.Nm
+converts them into four Mach sections in two Mach segments.
+TEXT and ROM go in the RX segment (Read and eXecute).
+DATA and BSS go in the RW segment (Read and Write).
+.Nm
+sets the page protection so programs can't write the RX segment,
+and can't execute the RW segment.
+The program will begin execution at the beginning of TEXT.
+.Pp
+.Nm
+also converts the symbol table.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It text segment must have base 0x%lx, not 0x%lx
+TEXT must begin immediately after the Mach header and load commands.
+The message gives the correct
+.Ar base .
+Relinking the program with
+.Cm em_led Fl b Ns 0: Ns Ar base
+would fix it.
+.It the %s segment must follow the %s segment.
+TEXT and ROM must be continuous in memory, because
+.Nm
+maps them in the same Mach segment.
+Likewise, DATA and BSS must be contiguous.
+There may be a small gap between TEXT and ROM, or between DATA and
+BSS, only if the gap is necessary to align ROM or BSS.
+.It the data and rom segments are too close.
+DATA and ROM must not share a page in memory, because
+.Nm
+maps them in different Mach segments, with different page protections.
+The page size for i386 and PowerPC is 4096 or 0x1000 bytes.
+For example, if ROM ends at address 0x2bed,
+then DATA may not begin at 0x2bf0, because
+.Nm
+can't put the page from 0x2000 to 0x2fff in both Mach segments.
+Relinking the program with
+.Cm em_led Fl a Ns 2:4096
+would fix it.
+.It the bss space contains initialized data.
+BSS must not contain initialized data, because
+.Nm
+converts it to a zero-fill section.
+.El
+.Sh CAVEATS
+Mac OS X 10.4 for PowerPC does not protect pages against execution.
+All mapped pages are executable, whether or not the execute bit is set
+in the page protection.
+.Nm
+can't prevent the execution of the RW segment.
+.Sh BUGS
+The symbol conversion preserves the name and value of each symbol, but
+may lose other information, such as the symbol type.
diff --git a/plat/osx/cvmach/cvmach.c b/plat/osx/cvmach/cvmach.c
new file mode 100644
index 000000000..5f8315ddd
--- /dev/null
+++ b/plat/osx/cvmach/cvmach.c
@@ -0,0 +1,665 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+
+/*
+ * cvmach.c - convert ack.out to Mach-o
+ *
+ * Mostly pinched from aelflod (util/amisc/aelflod.c), which pinched
+ * from the ARM cv (mach/arm/cv/cv.c), which pinched from the m68k2 cv
+ * (mach/m68k2/cv/cv.c).  The code to read ack.out format using
+ * libobject is pinched from the Xenix i386 cv (mach/i386/cv/cv.c).
+ */
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <out.h>
+#include <object.h>
+
+/* Header and section table of ack.out */
+struct outhead	outhead;
+struct outsect	outsect[S_MAX];
+uint32_t ack_off_char;		/* Offset of string table in ack.out */
+
+int bigendian;			/* Emit big-endian Mach-o? */
+int cpu_type;
+uint32_t entry;			/* Virtual address of entry point */
+uint32_t sz_thread_command;
+
+char *outputfile = NULL;	/* Name of output file, or NULL */
+char *program;			/* Name of current program: argv[0] */
+FILE *output;			/* Output stream */
+#define writef(a, b, c)	fwrite((a), (b), (c), output)
+
+/* Segment numbers in ack.out */
+enum {
+	TEXT = 0,
+	ROM,
+	DATA,
+	BSS,
+	NUM_SEGMENTS
+};
+
+/* Constants from Mach headers */
+#define MH_MAGIC			0xfeedface
+#define MH_EXECUTE			2
+#define LC_SEGMENT			1
+#define LC_SYMTAB			2
+#define LC_UNIXTHREAD			5
+
+#define CPU_TYPE_X86			7
+#define CPU_SUBTYPE_X86_ALL		3
+#define x86_THREAD_STATE32		1
+#define x86_THREAD_STATE32_COUNT	16
+
+#define CPU_TYPE_POWERPC		18
+#define CPU_SUBTYPE_POWERPC_ALL		0
+#define PPC_THREAD_STATE		1
+#define PPC_THREAD_STATE_COUNT		40
+
+#define VM_PROT_NONE			0x0
+#define VM_PROT_READ			0x1
+#define VM_PROT_WRITE			0x2
+#define VM_PROT_EXECUTE			0x4
+
+/* sizes of Mach structs */
+#define SZ_MACH_HEADER			28
+#define SZ_SEGMENT_COMMAND		56
+#define SZ_SECTION_HEADER		68
+#define SZ_SYMTAB_COMMAND		24
+#define SZ_THREAD_COMMAND_BF_STATE	16
+#define SZ_NLIST			12
+
+/* the page size for x86 and PowerPC */
+#define CV_PGSZ				4096
+/* u modulo page size */
+#define pg_mod(u) ((u) & (CV_PGSZ - 1))
+/* u rounded down to whole pages */
+#define pg_trunc(u) ((u) & ~(CV_PGSZ - 1))
+/* u rounded up to whole pages */
+#define pg_round(u) pg_trunc((u) + (CV_PGSZ - 1))
+
+const char zero_pg[CV_PGSZ] = { 0 };
+
+/*
+ * machseg[0]: __PAGEZERO with address 0, size CV_PGSZ
+ * machseg[1]: __TEXT for ack TEXT, ROM
+ * machseg[2]: __DATA for ack DATA, BSS
+ */
+struct {
+	const char	*ms_name;
+	uint32_t	 ms_vmaddr;
+	uint32_t	 ms_vmsize;
+	uint32_t	 ms_fileoff;
+	uint32_t	 ms_filesize;
+	uint32_t	 ms_prot;
+	uint32_t	 ms_nsects;
+} machseg[3] = {
+	"__PAGEZERO", 0, CV_PGSZ, 0, 0, VM_PROT_NONE, 0,
+	"__TEXT", 0, 0, 0, 0, VM_PROT_READ | VM_PROT_EXECUTE, 2,
+	"__DATA", 0, 0, 0, 0, VM_PROT_READ | VM_PROT_WRITE, 2,
+};
+
+
+static void
+usage(void)
+{
+	fprintf(stderr, "Usage: %s -m<num> <inputfile> <outputfile>\n",
+	    program);
+	exit(1);
+}
+
+/* Produce an error message and exit. */
+static void
+fatal(const char* s, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s: ",program) ;
+
+	va_start(ap, s);
+	vfprintf(stderr, s, ap);
+	va_end(ap);
+
+	fprintf(stderr, "\n");
+
+	if (outputfile)
+		unlink(outputfile);
+	exit(1);
+}
+
+void
+rd_fatal(void)
+{
+	fatal("read error");
+}
+
+/* Returns n such that 2**n == a. */
+static uint32_t
+log2u(uint32_t a)
+{
+	uint32_t n = 0;
+	while (a) {
+		a >>= 1;
+		n++;
+	}
+	return n - 1;
+}
+
+/* Writes a byte. */
+static void
+emit8(uint8_t value)
+{
+	writef(&value, 1, 1);
+}
+
+/* Writes out a 16-bit value in the appropriate endianness. */
+static void
+emit16(uint16_t value)
+{
+	unsigned char buffer[2];
+
+	if (bigendian)
+	{
+		buffer[0] = (value >> 8) & 0xFF;
+		buffer[1] = (value >> 0) & 0xFF;
+	}
+	else
+	{
+		buffer[1] = (value >> 8) & 0xFF;
+		buffer[0] = (value >> 0) & 0xFF;
+	}
+
+	writef(buffer, 1, sizeof(buffer));
+}
+
+/* Writes out a 32-bit value in the appropriate endianness. */
+static void
+emit32(uint32_t value)
+{
+	unsigned char buffer[4];
+
+	if (bigendian)
+	{
+		buffer[0] = (value >> 24) & 0xFF;
+		buffer[1] = (value >> 16) & 0xFF;
+		buffer[2] = (value >>  8) & 0xFF;
+		buffer[3] = (value >>  0) & 0xFF;
+	}
+	else
+	{
+		buffer[3] = (value >> 24) & 0xFF;
+		buffer[2] = (value >> 16) & 0xFF;
+		buffer[1] = (value >>  8) & 0xFF;
+		buffer[0] = (value >>  0) & 0xFF;
+	}
+
+	writef(buffer, 1, sizeof(buffer));
+}
+
+/* Copies the contents of a section from the input stream
+ * to the output stream. */
+static void
+emit_section(int section_nr)
+{
+	struct outsect *section = &outsect[section_nr];
+	size_t blocksize;
+	uint32_t n = section->os_flen;
+	char buffer[BUFSIZ];
+
+	rd_outsect(section_nr);
+	while (n > 0)
+	{
+		blocksize = (n > BUFSIZ) ? BUFSIZ : n;
+		rd_emit(buffer, (long)blocksize);
+		writef(buffer, 1, blocksize);
+		n -= blocksize;
+	}
+
+	/* Zero fill any remaining space. */
+	n = section->os_size - section->os_flen;
+	while (n > 0)
+	{
+		blocksize = (n > sizeof(zero_pg)) ? sizeof(zero_pg) : n;
+		writef(zero_pg, 1, blocksize);
+		n -= blocksize;
+	}
+}
+
+static void
+emit_lc_segment(int i)
+{
+	uint32_t sz;
+	int flags, maxprot;
+	char namebuf[16];
+
+	if (i == 0) {
+		/* special values for __PAGEZERO */
+		maxprot = VM_PROT_NONE;
+		flags = 4; /* SG_NORELOC */
+	} else {
+		maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+		flags = 0;
+	}
+
+	/*
+	 * The size of this command includes the size of its section
+	 * headers, see emit_section_header().
+	 */
+	sz = SZ_SEGMENT_COMMAND + machseg[i].ms_nsects * SZ_SECTION_HEADER;
+
+	/* Use strncpy() to pad namebuf with '\0' bytes. */
+	strncpy(namebuf, machseg[i].ms_name, sizeof(namebuf));
+
+	emit32(LC_SEGMENT);		/* command */
+	emit32(sz);			/* size of command */
+	writef(namebuf, 1, sizeof(namebuf));
+	emit32(machseg[i].ms_vmaddr);	/* vm address */
+	emit32(machseg[i].ms_vmsize);	/* vm size */
+	emit32(machseg[i].ms_fileoff);	/* file offset */
+	emit32(machseg[i].ms_filesize);	/* file size */
+	emit32(maxprot);		/* max protection */
+	emit32(machseg[i].ms_prot);	/* initial protection */
+	emit32(machseg[i].ms_nsects);	/* number of Mach sections */
+	emit32(flags);			/* flags */
+}
+
+static void
+emit_section_header(int ms, const char *name, int os)
+{
+	uint32_t fileoff, flags;
+	char namebuf[16];
+
+	switch (os) {
+	case TEXT:
+		/* S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS */
+		flags = 0x80000400;
+		break;
+	case BSS:
+		flags = 0x1; /* S_ZEROFILL */
+		break;
+	default:
+		flags = 0x0; /* S_REGULAR */
+		break;
+	}
+
+	if (os == BSS)
+		fileoff = 0;
+	else
+		fileoff = machseg[ms].ms_fileoff +
+		    (outsect[os].os_base - machseg[ms].ms_vmaddr);
+
+	/* name of Mach section */
+	strncpy(namebuf, name, sizeof(namebuf));
+	writef(namebuf, 1, sizeof(namebuf));
+	/* name of Mach segment */
+	strncpy(namebuf, machseg[ms].ms_name, sizeof(namebuf));
+	writef(namebuf, 1, sizeof(namebuf));
+	emit32(outsect[os].os_base);	/* vm address */
+	emit32(outsect[os].os_size);	/* vm size */
+	emit32(fileoff);		/* file offset */
+	emit32(log2u(outsect[os].os_lign)); /* alignment */
+	emit32(0);			/* offset of relocations */
+	emit32(0);			/* number of relocations */
+	emit32(flags);			/* flags */
+	emit32(0);			/* reserved */
+	emit32(0);			/* reserved */
+}
+
+static void
+emit_lc_symtab(void)
+{
+	uint32_t off1, off2;
+
+	/* Symbol table will be at next page after machseg[2]. */
+	off1 = pg_round(machseg[2].ms_fileoff + machseg[2].ms_filesize);
+	/* String table will be after symbol table. */
+	off2 = off1 + 12 * outhead.oh_nname;
+
+	emit32(LC_SYMTAB);		/* command */
+	emit32(SZ_SYMTAB_COMMAND);	/* size of command */
+	emit32(off1);			/* offset of symbol table */
+	emit32(outhead.oh_nname);	/* number of symbols */
+	emit32(off2);			/* offset of string table */
+	emit32(1 + outhead.oh_nchar);	/* size of string table */
+}
+
+static void
+emit_lc_unixthread(void)
+{
+	int i, ireg, ts, ts_count;
+
+	/*
+	 * The thread state has ts_count registers.  The ireg'th
+	 * register holds the entry point.  We can set other registers
+	 * to zero.  At execution time, the kernel will allocate a
+	 * stack and set the stack pointer.
+	 */
+	switch (cpu_type) {
+	case CPU_TYPE_X86:
+		ireg = 10;	/* eip */
+		ts = x86_THREAD_STATE32;
+		ts_count = x86_THREAD_STATE32_COUNT;
+		break;
+	case CPU_TYPE_POWERPC:
+		ireg = 0;	/* srr0 */
+		ts = PPC_THREAD_STATE;
+		ts_count = PPC_THREAD_STATE_COUNT;
+		break;
+	}
+
+	emit32(LC_UNIXTHREAD);		/* command */
+	emit32(sz_thread_command);	/* size of command */
+	emit32(ts);			/* thread state */
+	emit32(ts_count);		/* thread state count */
+	for (i = 0; i < ts_count; i++) {
+		if (i == ireg)
+			emit32(entry);
+		else
+			emit32(0);
+	}
+}
+
+static void
+emit_symbol(struct outname *np)
+{
+	uint32_t soff;
+	uint8_t type;
+	uint8_t sect;
+	uint16_t desc;
+
+	if (np->on_type & S_STB) {
+		/* stab for debugger */
+		type = np->on_type >> 8;
+		desc = np->on_desc;
+	} else {
+		desc = 0;
+
+		switch (np->on_type & S_TYP) {
+		case S_UND:
+			type = 0x0; /* N_UNDF */
+			break;
+		case S_ABS:
+			type = 0x2; /* N_ABS */
+			break;
+		default:
+			type = 0xe; /* N_SECT */
+			break;
+		}
+
+		if (np->on_type & S_EXT)
+			type |= 0x1; /* N_EXT */
+	}
+
+	switch (np->on_type & S_TYP) {
+	case S_MIN + TEXT:
+		sect = 1;
+		break;
+	case S_MIN + ROM:
+		sect = 2;
+		break;
+	case S_MIN + DATA:
+		sect = 3;
+		break;
+	case S_MIN + BSS:
+	case S_MIN + NUM_SEGMENTS:
+		sect = 4;
+		break;
+	default:
+		sect = 0; /* NO_SECT */
+		break;
+	}
+
+	/*
+	 * To find the symbol's name, ack.out uses an offset from the
+	 * beginning of the file, but Mach-o uses an offset into the
+	 * string table.  Both formats use offset 0 for a symbol with
+	 * no name.  We will prepend a '\0' at offset 0, so every
+	 * named symbol needs + 1.
+	 */
+	if (np->on_foff)
+		soff = np->on_foff - ack_off_char + 1;
+	else
+		soff = 0;
+
+	emit32(soff);
+	emit8(type);
+	emit8(sect);
+	emit16(desc);
+	emit32(np->on_valu);
+}
+
+static void
+emit_symtab(void)
+{
+	struct outname *names, *np;
+	int i;
+	char *chars;
+
+	/* Using calloc(a, b) to check if a * b would overflow. */
+	names = calloc(outhead.oh_nname, sizeof(struct outname));
+	if (!names)
+		fatal("out of memory");
+	chars = malloc(outhead.oh_nchar);
+	if (!names || !chars)
+		fatal("out of memory");
+	rd_name(names, outhead.oh_nname);
+	rd_string(chars, outhead.oh_nchar);
+
+	ack_off_char = OFF_CHAR(outhead);
+
+	/* Emit each symbol entry. */
+	for (i = 0, np = names; i < outhead.oh_nname; i++, np++)
+		emit_symbol(np);
+
+	/*
+	 * Emit the string table.  The first character of a Mach-o
+	 * string table must be '\0', so we prepend a '\0'.
+	 */
+	emit8(0);
+	writef(chars, 1, outhead.oh_nchar);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	uint32_t end, pad[3], sz, sz_load_cmds;
+	int cpu_subtype, fd, mflag = 0;
+
+	/* General housecleaning and setup. */
+	output = stdout;
+	program = argv[0];
+
+	/* Read in and process any flags. */
+	while ((argc > 1) && (argv[1][0] == '-')) {
+		switch (argv[1][1]) {
+		case 'm': /* machine cpu type */
+			mflag = 1;
+			cpu_type = atoi(&argv[1][2]);
+			break;
+		case 'h': /* help */
+		default:
+			usage();
+		}
+
+		argv++;
+		argc--;
+	}
+
+	if (!mflag)
+		usage();
+
+	/* Check cpu type. */
+	switch (cpu_type) {
+	case CPU_TYPE_X86:
+		bigendian = 0;
+		cpu_subtype = CPU_SUBTYPE_X86_ALL;
+		sz_thread_command = 4 * x86_THREAD_STATE32_COUNT;
+		break;
+	case CPU_TYPE_POWERPC:
+		bigendian = 1;
+		cpu_subtype = CPU_SUBTYPE_POWERPC_ALL;
+		sz_thread_command = 4 * PPC_THREAD_STATE_COUNT;
+		break;
+	default:
+		/* Can't emit LC_UNIXTHREAD for unknown cpu. */
+		fatal("unknown cpu type -m%d", cpu_type);
+	}
+	sz_thread_command += SZ_THREAD_COMMAND_BF_STATE;
+
+	/* Process the rest of the arguments. */
+	switch (argc) {
+	case 1: /* No parameters --- read from stdin, write to stdout. */
+		rd_fdopen(0);
+		break;
+
+	case 3: /* Both input and output files specified. */
+		/* Use mode 0777 to allow executing the output file. */
+		fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0777);
+		if (fd < 0)
+			fatal("unable to open output file.");
+		output = fdopen(fd, "w");
+		if (!output)
+			fatal("unable to open output file.");
+		outputfile = argv[2];
+		/* FALLTHROUGH */
+
+	case 2: /* Input file specified. */
+		if (! rd_open(argv[1]))
+			fatal("unable to open input file.");
+		break;
+
+	default:
+		usage();
+	}
+
+	rd_ohead(&outhead);
+	if (BADMAGIC(outhead))
+		fatal("Not an ack object file.");
+	if (outhead.oh_flags & HF_LINK)
+		fatal("Contains unresolved references.");
+	if (outhead.oh_nrelo > 0)
+		fprintf(stderr, "Warning: relocation information present.");
+	if (outhead.oh_nsect != NUM_SEGMENTS &&
+	    outhead.oh_nsect != NUM_SEGMENTS + 1 ) {
+		fatal("Input file must have %d sections, not %ld\n",
+		    NUM_SEGMENTS, (long)outhead.oh_nsect);
+	}
+
+	rd_sect(outsect, outhead.oh_nsect);
+
+	/*
+	 * machseg[1] will start at a page boundary and include the
+	 * Mach header and load commands before ack TEXT and ROM.
+	 *
+	 * Find our entry point (immediately after the load commands)
+	 * and check that TEXT begins there.
+	 */
+	machseg[1].ms_vmaddr = pg_trunc(outsect[TEXT].os_base);
+	sz_load_cmds = 3 * SZ_SEGMENT_COMMAND + 4 * SZ_SECTION_HEADER +
+	    SZ_SYMTAB_COMMAND + sz_thread_command;
+	entry = machseg[1].ms_vmaddr + SZ_MACH_HEADER + sz_load_cmds;
+	if (entry != outsect[TEXT].os_base) {
+		fatal("text segment must have base 0x%lx, not 0x%lx"
+		    "\n\t(suggest em_led -b0:0x%lx)",
+		    (unsigned long)entry,
+		    (unsigned long)outsect[TEXT].os_base,
+		    (unsigned long)entry);
+	}
+
+	/* Pad for alignment between TEXT and ROM. */
+	sz = outsect[ROM].os_base - outsect[TEXT].os_base;
+	pad[0] = sz - outsect[TEXT].os_size;
+	if (sz < outsect[TEXT].os_size || pad[0] >= outsect[ROM].os_lign)
+		fatal("the rom segment must follow the text segment.");
+
+	/*
+	 * Pad between ROM and DATA such that we can map machseg[2] at
+	 * a page boundary with DATA at its correct base address.
+	 *
+	 * For example, if ROM ends at 0x2bed and DATA begins at
+	 * 0x3000, then we pad to the page boundary.  If ROM ends at
+	 * 0x2bed and DATA begins at 0x3bf0, then pad = 3 and we map
+	 * the page twice, at both 0x2000 and 0x3000.
+	 */
+	end = outsect[ROM].os_base + outsect[ROM].os_size;
+	pad[1] = pg_mod(outsect[DATA].os_base - end);
+
+	sz = end - machseg[1].ms_vmaddr;
+	machseg[1].ms_vmsize = machseg[1].ms_filesize = sz;
+	machseg[2].ms_vmaddr = pg_trunc(outsect[DATA].os_base);
+	machseg[2].ms_fileoff = pg_trunc(sz + pad[1]);
+	if (machseg[2].ms_vmaddr < end &&
+	    machseg[2].ms_vmaddr >= machseg[1].ms_vmaddr)
+		fatal("the data and rom segments are too close."
+		    "\n\t(suggest em_led -a2:%d)", (int)CV_PGSZ);
+
+	if (outsect[BSS].os_flen != 0)
+		fatal("the bss space contains initialized data.");
+	sz = outsect[BSS].os_base - outsect[DATA].os_base;
+	if (sz < outsect[DATA].os_size ||
+	    sz - outsect[DATA].os_size >= outsect[BSS].os_lign)
+		fatal("the bss segment must follow the data segment.");
+
+	end = outsect[DATA].os_base + outsect[DATA].os_size;
+	machseg[2].ms_filesize = end - machseg[2].ms_vmaddr;
+	end = outsect[BSS].os_base + outsect[BSS].os_size;
+	machseg[2].ms_vmsize = end - machseg[2].ms_vmaddr;
+
+	if (outhead.oh_nsect == NUM_SEGMENTS + 1) {
+		if (outsect[NUM_SEGMENTS].os_base !=
+		    outsect[BSS].os_base + outsect[BSS].os_size)
+			fatal("end segment must follow bss");
+		if (outsect[NUM_SEGMENTS].os_size != 0)
+			fatal("end segment must be empty");
+	}
+
+	/*
+	 * Pad to page boundary between BSS and symbol table.
+	 *
+	 * Also, some versions of Mac OS X refuse to load any
+	 * executable smaller than 4096 bytes (1 page).
+	 */
+	pad[2] = pg_mod(-(uint32_t)machseg[2].ms_filesize);
+
+	/* Emit the Mach header. */
+	emit32(MH_MAGIC);	/* magic */
+	emit32(cpu_type);	/* cpu type */
+	emit32(cpu_subtype);	/* cpu subtype */
+	emit32(MH_EXECUTE);	/* file type */
+	emit32(5);		/* number of load commands */
+	emit32(sz_load_cmds);	/* size of load commands */
+	emit32(0);		/* flags */
+
+	emit_lc_segment(0);
+	emit_lc_segment(1);
+	emit_section_header(1, "__text", TEXT);
+	emit_section_header(1, "__rom", ROM);
+	emit_lc_segment(2);
+	emit_section_header(2, "__data", DATA);
+	emit_section_header(2, "__bss", BSS);
+	emit_lc_symtab();
+	emit_lc_unixthread();
+
+	/* Emit non-empty sections. */
+	emit_section(TEXT);
+	writef(zero_pg, 1, pad[0]);
+	emit_section(ROM);
+	writef(zero_pg, 1, pad[1]);
+	emit_section(DATA);
+
+	writef(zero_pg, 1, pad[2]);
+	emit_symtab();
+
+	if (ferror(output))
+		fatal("write error");
+
+	return 0;
+}
diff --git a/plat/osx/include/ack/config.h b/plat/osx/include/ack/config.h
new file mode 100644
index 000000000..9f58a3941
--- /dev/null
+++ b/plat/osx/include/ack/config.h
@@ -0,0 +1,14 @@
+/* $Source$
+ * $State$
+ * $Revision$
+ */
+
+#ifndef _ACK_CONFIG_H
+#define _ACK_CONFIG_H
+
+/* We're providing a time() system call rather than wanting a wrapper around
+ * gettimeofday() in the libc. */
+
+/* #define ACKCONF_TIME_IS_A_SYSCALL */
+
+#endif
diff --git a/plat/osx/include/build.lua b/plat/osx/include/build.lua
new file mode 100644
index 000000000..ff7c87a4d
--- /dev/null
+++ b/plat/osx/include/build.lua
@@ -0,0 +1,26 @@
+include("plat/build.lua")
+
+headermap = {}
+packagemap = {}
+
+local function addheader(h)
+	headermap[h] = "plat/osx/include/"..h
+	packagemap["$(PLATIND)/osx/include/"..h] = "plat/osx/include/"..h
+end
+
+addheader("ack/config.h")
+addheader("sys/dirent.h")
+addheader("sys/mman.h")
+addheader("sys/stat.h")
+addheader("sys/types.h")
+addheader("unistd.h")
+
+acklibrary {
+	name = "headers",
+	hdrs = headermap
+}
+
+installable {
+	name = "pkg",
+	map = packagemap
+}
diff --git a/plat/osx/include/sys/dirent.h b/plat/osx/include/sys/dirent.h
new file mode 100644
index 000000000..073c84588
--- /dev/null
+++ b/plat/osx/include/sys/dirent.h
@@ -0,0 +1,17 @@
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+
+#include <sys/types.h>
+
+struct dirent {
+	ino_t		d_ino;
+	unsigned short	d_reclen;
+	unsigned char	d_type;
+	unsigned char	d_namlen;
+#define MAXNAMLEN 255
+	char		d_name[MAXNAMLEN + 1];
+};
+
+int getdirentries(int, char *, int, long *);
+
+#endif
diff --git a/plat/osx/include/sys/mman.h b/plat/osx/include/sys/mman.h
new file mode 100644
index 000000000..5a844c4b6
--- /dev/null
+++ b/plat/osx/include/sys/mman.h
@@ -0,0 +1,20 @@
+#ifndef _SYS_MMAN_H
+#define _SYS_MMAN_H
+
+#include <sys/types.h>
+
+#define MAP_FAILED ((void *)-1)
+
+#define PROT_NONE	0x00
+#define PROT_READ	0x01
+#define PROT_WRITE	0x02
+#define PROT_EXEC	0x04
+
+#define MAP_PRIVATE	0x0002
+#define MAP_FIXED	0x0010
+#define MAP_ANON	0x1000
+
+void *mmap(void *, size_t, int, int, int, off_t);
+int mprotect(void *, size_t, int);
+
+#endif
diff --git a/plat/osx/include/sys/stat.h b/plat/osx/include/sys/stat.h
new file mode 100644
index 000000000..6cb24902f
--- /dev/null
+++ b/plat/osx/include/sys/stat.h
@@ -0,0 +1,49 @@
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <sys/types.h>
+#include <sys/time.h> /* for timespec */
+
+struct stat {
+	dev_t		st_dev;
+	ino_t		st_ino;
+	mode_t		st_mode;
+	nlink_t		st_nlink;
+	uid_t		st_uid;
+	gid_t		st_gid;
+	dev_t		st_rdev;
+	struct timespec	st_atim;
+	struct timespec	st_mtim;
+	struct timespec	st_ctim;
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+#define st_ctime st_ctim.tv_sec
+	/*
+	 * XXX - We don't have 64-bit integers, so we only expose the
+	 * lower 32 bits of 64-bit fields.  We insert dummy fields for
+	 * the higher 32 bits.
+	 */
+#if defined(__i386)
+	off_t		st_size;
+	off_t		_st_size_hi;
+	blkcnt_t	st_blocks;
+	blkcnt_t	_st_blkcnt_hi;
+#elif defined(__powerpc)
+	off_t		_st_size_hi;
+	off_t		st_size;
+	blkcnt_t	_st_blkcnt_hi;
+	blkcnt_t	st_blkcnt;
+#else
+#error unknown arch
+#endif
+	blksize_t	st_blksize;
+	unsigned int	st_flags;
+	unsigned int	st_gen;
+	unsigned int	_st_spare[5];
+};
+
+int fstat(int, struct stat *);
+int lstat(const char *, struct stat *);
+int stat(const char *, struct stat *);
+
+#endif
diff --git a/plat/osx/include/sys/types.h b/plat/osx/include/sys/types.h
new file mode 100644
index 000000000..b4561b7b3
--- /dev/null
+++ b/plat/osx/include/sys/types.h
@@ -0,0 +1,17 @@
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <stddef.h> /* for off_t, ptrdiff_t, size_t */
+
+typedef int			blkcnt_t; /* XXX should have 64 bits */
+typedef int			blksize_t;
+typedef int			dev_t;
+typedef unsigned int		gid_t;
+typedef unsigned int		ino_t;
+typedef unsigned short		mode_t;
+typedef unsigned short		nlink_t;
+typedef int			pid_t;
+typedef ptrdiff_t		ssize_t;
+typedef unsigned int		uid_t;
+
+#endif
diff --git a/plat/osx/include/unistd.h b/plat/osx/include/unistd.h
new file mode 100644
index 000000000..bafa2a6c4
--- /dev/null
+++ b/plat/osx/include/unistd.h
@@ -0,0 +1,137 @@
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <sys/types.h>
+
+/*
+ * XXX - The following parts belong in other header files,
+ * but those headers are including us!
+ */
+
+/* XXX - begin sys/ioctl.h */
+
+#define TIOCGETD	0x4004741a
+
+int ioctl(int, unsigned long, ...);
+
+/* XXX - end sys/ioctl.h */
+
+/* XXX - begin sys/time.h */
+
+/* Don't conflict with time_t from <time.h> */
+typedef long _libsys_time_t;
+typedef int suseconds_t;
+
+struct timespec {
+	_libsys_time_t tv_sec;
+	long tv_nsec;
+};
+
+struct timeval {
+	_libsys_time_t tv_sec;
+	suseconds_t tv_usec;
+};
+
+struct timezone {
+	int tz_minuteswest;
+	int tz_dsttime;
+};
+
+int gettimeofday(struct timeval *, struct timezone *);
+
+/* XXX - end sys/time.h */
+
+/* XXX - begin fcntl.h */
+
+/* flags for open() */
+#define O_RDONLY	0x0000
+#define O_WRONLY	0x0001
+#define O_RDWR		0x0002
+#define O_NONBLOCK	0x0004
+#define O_APPEND	0x0008
+#define O_CREAT		0x0200
+#define O_TRUNC		0x0400
+#define O_EXCL		0x0800
+
+int creat(const char *, mode_t);
+int open(const char *, int, ...);
+
+/* XXX - end fcntl.h */
+
+/* XXX - begin signal.h */
+
+#define SIGHUP		1
+#define SIGINT		2
+#define SIGQUIT		3
+#define SIGILL		4
+#define SIGTRAP		5
+#define SIGABRT		6
+#define SIGEMT		7
+#define SIGFPE		8
+#define SIGKILL		9
+#define SIGBUS		10
+#define SIGSEGV		11
+#define SIGSYS		12
+#define SIGPIPE		13
+#define SIGALRM		14
+#define SIGTERM		15
+#define SIGURG		16
+#define SIGSTOP		17
+#define SIGTSTP		18
+#define SIGCONT		19
+#define SIGCHLD		20
+#define SIGTTIN		21
+#define SIGTTOU		22
+#define SIGIO		23
+#define SIGXCPU		24
+#define SIGXFSZ		25
+#define SIGVTALRM	26
+#define SIGPROF		27
+#define SIGWINCH	28
+#define SIGINFO		29
+#define SIGUSR1		30
+#define SIGUSR2		31
+#define _NSIG		32
+
+/* sa_flags */
+#define SA_RESTART	0x0002
+
+typedef void (*sig_t)(int);
+#define SIG_DFL ((sig_t)0)
+#define SIG_IGN ((sig_t)1)
+#define SIG_ERR ((sig_t)-1)
+
+typedef unsigned int sigset_t;
+
+struct __siginfo;
+
+struct sigaction {
+	union {
+		void (*__sa_handler)(int);
+		void (*__sa_sigaction)(int, struct __siginfo *, void *);
+	} __sigaction_u;
+	sigset_t sa_mask;
+	int sa_flags;
+};
+#define sa_handler __sigaction_u.__sa_handler
+#define sa_sigaction __sigaction_u.__sa_sigaction
+
+int kill(pid_t, int);
+int sigaction(int, const struct sigaction *, struct sigaction *);
+sig_t signal(int, sig_t);
+
+int raise(int); /* in libc */
+
+/* XXX - end signal.h */
+
+void _exit(int);
+int brk(void *);
+int close(int);
+pid_t getpid(void);
+int isatty(int);
+off_t lseek(int, off_t, int);
+ssize_t read(int, void *, size_t);
+void *sbrk(int);
+ssize_t write(int, const void *, size_t);
+
+#endif
diff --git a/plat/osx/libsys/brk.c b/plat/osx/libsys/brk.c
new file mode 100644
index 000000000..9b58ca1d8
--- /dev/null
+++ b/plat/osx/libsys/brk.c
@@ -0,0 +1,86 @@
+/*
+ * This emulates brk() and sbrk() using mmap() and mprotect().
+ *
+ * We reserve exactly SEGMENTSZ bytes of address space by calling
+ * mmap() with PROT_NONE.  Then we allocate pages in our segment by
+ * calling mprotect() with PROT_READ|PROT_WRITE.
+ *
+ * This emulation can't resize its segment.  If SEGMENTSZ is too big,
+ * then programs might run out of address space for other mappings.
+ */
+#include <sys/mman.h>
+#include <errno.h>
+#include <unistd.h>
+
+/*
+ * PAGESZ must be correct for this system!
+ * SEGMENTSZ must be a multiple of PAGESZ.
+ */
+#define PAGESZ 0x1000		/* page size for i386, powerpc */
+#define SEGMENTSZ 0x20000000
+
+static char *segment;
+static char *cbreak;		/* current break */
+
+static void brk_init(void)
+{
+	/*
+	 * Try exactly once to reserve our segment.  If we fail, then
+	 * segment == MAP_FAILED and we never try again.
+	 */
+	if (segment == NULL) {
+		segment = mmap(NULL, SEGMENTSZ, PROT_NONE,
+		    MAP_PRIVATE|MAP_ANON, -1, 0);
+		cbreak = segment;
+	}
+}
+
+static int brk1(char *nbreak)
+{
+	size_t sz;
+	char *new, *old;
+
+	sz = (segment == MAP_FAILED) ? 0 : SEGMENTSZ;
+	if (nbreak < segment || nbreak > segment + sz) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	/* Round up to page size. */
+	old = (char *)(((size_t)cbreak + (PAGESZ-1)) & ~(PAGESZ-1));
+	new = (char *)(((size_t)nbreak + (PAGESZ-1)) & ~(PAGESZ-1));
+
+	if (new > old) {
+		/* Allocate pages by unprotecting them. */
+		if (mprotect(old, new - old, PROT_READ|PROT_WRITE) < 0) {
+			errno = ENOMEM;
+			return -1;
+		}
+	} else if (new < old) {
+		/*
+		 * Free pages by using MAP_FIXED to replace the
+		 * mapping.  Ignore errors.
+		 */
+		mmap(new, old - new, PROT_NONE,
+		    MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0);
+	}
+	cbreak = nbreak;
+	return 0;
+}
+
+int brk(void *addr)
+{
+	brk_init();
+	return brk1(addr);
+}
+
+void *sbrk(int incr)
+{
+	char *base;
+
+	brk_init();
+	base = cbreak;
+	if (brk1(base + incr) < 0)
+		return (void*)-1;
+	return base;
+}
diff --git a/plat/osx/libsys/creat.c b/plat/osx/libsys/creat.c
new file mode 100644
index 000000000..3a350e357
--- /dev/null
+++ b/plat/osx/libsys/creat.c
@@ -0,0 +1,6 @@
+#include <fcntl.h>
+
+int creat(const char *path, mode_t mode)
+{
+	return open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);
+}
diff --git a/plat/osx/libsys/isatty.c b/plat/osx/libsys/isatty.c
new file mode 100644
index 000000000..1da6509df
--- /dev/null
+++ b/plat/osx/libsys/isatty.c
@@ -0,0 +1,7 @@
+#include <sys/ioctl.h>
+
+int isatty(int fd)
+{
+	int line_disc;
+	return 0 <= ioctl(fd, TIOCGETD, &line_disc);
+}
diff --git a/plat/osx/libsys/signal.c b/plat/osx/libsys/signal.c
new file mode 100644
index 000000000..0c1e12624
--- /dev/null
+++ b/plat/osx/libsys/signal.c
@@ -0,0 +1,16 @@
+#include <signal.h>
+
+sig_t signal(int sig, sig_t func)
+{
+	struct sigaction newsa, oldsa;
+	int i;
+
+	newsa.sa_handler = func;
+	newsa.sa_mask = 0; /* empty set */
+	newsa.sa_flags = SA_RESTART;
+
+	i = sigaction(sig, &newsa, &oldsa);
+	if (i < 0)
+		return SIG_ERR;
+	return oldsa.sa_handler;
+}
diff --git a/plat/osx386/README b/plat/osx386/README
new file mode 100644
index 000000000..8c34134ff
--- /dev/null
+++ b/plat/osx386/README
@@ -0,0 +1,25 @@
+The osx386 platform
+===================
+
+    ack -mosx386 ...
+
+This platform produces Mach-o executables for Intel Mac OS X.  These
+are 32-bit executables using our i386 code generator.
+
+See ../osxppc/README, because our osx386 platform has many of the same
+limitations and bugs as our osxppc platform.
+
+
+Bugs
+----
+
+Some programs can't read the tty after using job control to suspend
+and resume the program (with ^Z and "fg" in bash).  The read(2) system
+call fails with EINTR.  In ACK's stdio (in libc), the error is sticky,
+so all reads fail.  In Apple's stdio, the error is not sticky, and
+only the next read fails.  The EINTR seems to happen only on Intel Mac
+OS X, and not on other platforms.
+
+
+George Koehler <xkernigh@netscape.net>
+2016-12-03
diff --git a/plat/osx386/boot.s b/plat/osx386/boot.s
new file mode 100644
index 000000000..932a716e9
--- /dev/null
+++ b/plat/osx386/boot.s
@@ -0,0 +1,69 @@
+! plat/osx386/boot.s
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+.sect .text
+
+begtext:
+	! This code is placed at the entry point of the Mach-o
+	! executable and is the first thing that runs.
+	!
+	! On entry, the stack looks like this:
+	!
+	! sp+..            NULL
+	! sp+8+(4*argc)   env (X quads)
+	! sp+4+(4*argc)   NULL
+	! sp+4            argv (argc quads)
+	! sp              argc
+	!
+	! The ACK actually expects:
+	!
+	! sp+8            argc
+	! sp+4            argv
+	! sp              env
+
+	mov eax, (esp)    ! eax = argc
+	lea ebx, 4(esp)   ! ebx = argv
+	lea ecx, (esp)(eax*4)
+	add ecx, 12       ! environ
+
+	push ecx         ! environ
+	push ebx         ! argc
+	push eax         ! argv
+	push eax         ! dummy, representing the return argument
+	xor ebp, ebp
+
+	jmp __m_a_i_n
+
+	! This provides an emergency exit routine used by EM.
+
+.define EXIT
+.extern EXIT
+EXIT:
+	push 1
+	jmp __exit
+
+.sect .rom
+begrom:
+
+.sect .data
+begdata:
+
+! Some magic data. All EM systems need these.
+
+.sect .bss
+begbss:
+.define hol0
+.comm hol0, 8                ! line number and filename (for debugging)
+
+.define _errno
+.comm _errno, 4              ! Posix errno storage
+
+.define .trppc, .ignmask
+.comm .trppc, 4              ! ptr to user trap handler
+.comm .ignmask, 4            ! user trap ignore mask
diff --git a/plat/osx386/build-pkg.lua b/plat/osx386/build-pkg.lua
new file mode 100644
index 000000000..6dfe1561c
--- /dev/null
+++ b/plat/osx386/build-pkg.lua
@@ -0,0 +1,24 @@
+include("plat/build.lua")
+
+ackfile {
+	name = "boot",
+	srcs = { "./boot.s" },
+	vars = { plat = "osx386" }
+}
+
+build_plat_libs {
+	name = "libs",
+	arch = "i386",
+	plat = "osx386",
+}
+
+installable {
+	name = "pkg",
+	map = {
+		"+tools",
+		"+libs",
+		"plat/osx/include+pkg",
+		["$(PLATIND)/osx386/boot.o"] = "+boot",
+		["$(PLATIND)/osx386/libsys.a"] = "./libsys+lib",
+	}
+}
diff --git a/plat/osx386/build-tools.lua b/plat/osx386/build-tools.lua
new file mode 100644
index 000000000..a1a9a8e2b
--- /dev/null
+++ b/plat/osx386/build-tools.lua
@@ -0,0 +1,22 @@
+include("plat/build.lua")
+
+build_as {
+	name = "as",
+	arch = "i386",
+}
+
+build_ncg {
+	name = "ncg",
+	arch = "i386",
+}
+
+return installable {
+	name = "tools",
+	map = {
+		["$(PLATDEP)/osx386/as"] = "+as",
+		["$(PLATDEP)/osx386/ncg"] = "+ncg",
+		["$(PLATIND)/descr/osx386"] = "./descr",
+		"plat/osx/cvmach+pkg",
+		"util/opt+pkg",
+	}
+}
diff --git a/plat/osx386/descr b/plat/osx386/descr
new file mode 100644
index 000000000..afe46c588
--- /dev/null
+++ b/plat/osx386/descr
@@ -0,0 +1,81 @@
+# plat/osx386/descr
+
+var w=4
+var wa=4
+var p={w}
+var pa={w}
+var s=2
+var sa={s}
+var l={w}
+var la={w}
+var f={w}
+var fa={w}
+var d=8
+var da={d}
+var x=8
+var xa={x}
+var ARCH=i386
+var PLATFORM=osx386
+var PLATFORMDIR={EM}/share/ack/{PLATFORM}
+var CPP_F=-D__unix
+var ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x123c
+var C_LIB={PLATFORMDIR}/libc-ansi.a
+# bitfields reversed for compatibility with (g)cc.
+var CC_ALIGN=-Vr
+var OLD_C_LIB={C_LIB}
+var MACHOPT_F=-m10
+var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
+
+# Override the setting in fe so that files compiled for osx386 can see
+# the platform-specific headers.
+
+var C_INCLUDES=-I{EM}/share/ack/osx/include -I{EM}/share/ack/include/ansi
+
+name be
+	from .m.g
+	to .s
+	program {EM}/lib/ack/{PLATFORM}/ncg
+	mapflag -gdb GF=-gdb
+	args {GF?} <
+	stdout
+	need .e
+end
+name as
+	from .s.so
+	to .o
+	program {EM}/lib/ack/{PLATFORM}/as
+	args - -o > <
+	prep cond
+end
+name led
+	from .o.a
+	to .out
+	program {EM}/lib/ack/em_led
+	mapflag -l* LNAME={PLATFORMDIR}/lib*
+	mapflag -fp FLOATS={EM}/{LIB}fp
+	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
+	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
+		({RTS}:.ocm.bas.b.c={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
+		({RTS}:.p={PLATFORMDIR}/pascal.o) \
+		-o > < \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
+		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
+		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		{FLOATS?} \
+		(.e:{TAIL}={PLATFORMDIR}/libem.a \
+		           {PLATFORMDIR}/libsys.a \
+		           {PLATFORMDIR}/libend.a)
+	linker
+end
+name cv
+	from .out
+	to .exe
+	program {EM}/lib/ack/cvmach
+	args -m7 < >
+	outfile osx386.exe
+end
diff --git a/plat/osx386/include/build.lua b/plat/osx386/include/build.lua
new file mode 100644
index 000000000..c2a1050c2
--- /dev/null
+++ b/plat/osx386/include/build.lua
@@ -0,0 +1,4 @@
+installable {
+	name = "pkg",
+	map = { "plat/osx/include+pkg" }
+}
diff --git a/plat/osx386/libsys/_exit.s b/plat/osx386/libsys/_exit.s
new file mode 100644
index 000000000..80d30134b
--- /dev/null
+++ b/plat/osx386/libsys/_exit.s
@@ -0,0 +1,5 @@
+.sect .text
+.define __exit
+__exit:
+	mov eax, 1
+	int 0x80
diff --git a/plat/osx386/libsys/build.lua b/plat/osx386/libsys/build.lua
new file mode 100644
index 000000000..23e491f7a
--- /dev/null
+++ b/plat/osx386/libsys/build.lua
@@ -0,0 +1,35 @@
+acklibrary {
+	name = "lib",
+	srcs = {
+		"./_exit.s",
+		"./close.s",
+		"./fstat.s",
+		"./getdirentries.s",
+		"./getpid.s",
+		"./gettimeofday.s",
+		"./ioctl.s",
+		"./kill.s",
+		"./lseek.s",
+		"./lstat.s",
+		"./mmap.s",
+		"./mprotect.s",
+		"./open.s",
+		"./read.s",
+		"./set_errno.s",
+		"./sigaction.s",
+		"./stat.s",
+		"./write.s",
+		"plat/linux/libsys/errno.s",
+		"plat/osx/libsys/brk.c",
+		"plat/osx/libsys/creat.c",
+		"plat/osx/libsys/isatty.c",
+		"plat/osx/libsys/signal.c",
+	},
+	deps = {
+		"lang/cem/libcc.ansi/headers+headers",
+		"plat/osx386/include+pkg",
+	},
+	vars = {
+		plat = "osx386"
+	}
+}
diff --git a/plat/osx386/libsys/close.s b/plat/osx386/libsys/close.s
new file mode 100644
index 000000000..295b90ad1
--- /dev/null
+++ b/plat/osx386/libsys/close.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _close
+_close:
+	mov eax, 6
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/fstat.s b/plat/osx386/libsys/fstat.s
new file mode 100644
index 000000000..1b49ae0b7
--- /dev/null
+++ b/plat/osx386/libsys/fstat.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _fstat
+_fstat:
+	mov eax, 189
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/getdirentries.s b/plat/osx386/libsys/getdirentries.s
new file mode 100644
index 000000000..9c59c627c
--- /dev/null
+++ b/plat/osx386/libsys/getdirentries.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _getdirentries
+_getdirentries:
+	mov eax, 196
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/getpid.s b/plat/osx386/libsys/getpid.s
new file mode 100644
index 000000000..150791bb4
--- /dev/null
+++ b/plat/osx386/libsys/getpid.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _getpid
+_getpid:
+	mov eax, 20
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/gettimeofday.s b/plat/osx386/libsys/gettimeofday.s
new file mode 100644
index 000000000..43aff5fa9
--- /dev/null
+++ b/plat/osx386/libsys/gettimeofday.s
@@ -0,0 +1,18 @@
+! The system call checks the timeval pointer but doesn't store the
+! time there.  If the pointer wasn't NULL, then the system call
+! returns the time in a pair of registers.
+
+.sect .text
+.define _gettimeofday
+_gettimeofday:
+	mov eax, 116
+	int 0x80
+	jb .set_errno
+	mov ebx, 4(esp)		! timeval pointer
+	test ebx, ebx
+	je 1f
+	mov 0(ebx), eax		! seconds
+	mov 4(ebx), edx		! microseconds
+1:
+	mov eax, 0		! return 0
+	ret
diff --git a/plat/osx386/libsys/ioctl.s b/plat/osx386/libsys/ioctl.s
new file mode 100644
index 000000000..5b13e2cfb
--- /dev/null
+++ b/plat/osx386/libsys/ioctl.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _ioctl
+_ioctl:
+	mov eax, 54
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/kill.s b/plat/osx386/libsys/kill.s
new file mode 100644
index 000000000..8fdce95fd
--- /dev/null
+++ b/plat/osx386/libsys/kill.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _kill
+_kill:
+	mov eax, 37
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/lseek.s b/plat/osx386/libsys/lseek.s
new file mode 100644
index 000000000..22543b2eb
--- /dev/null
+++ b/plat/osx386/libsys/lseek.s
@@ -0,0 +1,17 @@
+.sect .text
+.define _lseek
+_lseek:
+	! ack passes 4-byte off_t, but system call takes 8-byte off_t
+	mov eax, esp
+	push 12(eax)		! whence
+	push 0			! offset (high long)
+	push 8(eax)		! offset (low long)
+	push 4(eax)		! fd
+	call 1f
+	add esp, 16
+	ret
+1:
+	mov eax, 199
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/lstat.s b/plat/osx386/libsys/lstat.s
new file mode 100644
index 000000000..a492cc3cb
--- /dev/null
+++ b/plat/osx386/libsys/lstat.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _lstat
+_lstat:
+	mov eax, 190
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/mmap.s b/plat/osx386/libsys/mmap.s
new file mode 100644
index 000000000..e39ea777a
--- /dev/null
+++ b/plat/osx386/libsys/mmap.s
@@ -0,0 +1,20 @@
+.sect .text
+.define _mmap
+_mmap:
+	! ack passes 4-byte off_t, but system call takes 8-byte off_t
+	mov eax, esp
+	push 0			! offset (high long)
+	push 24(eax)		! offset (low long)
+	push 20(eax)		! fd
+	push 16(eax)		! flags
+	push 12(eax)		! protection
+	push 8(eax)		! length
+	push 4(eax)		! address
+	call 1f
+	add esp, 28
+	ret
+1:
+	mov eax, 197
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/mprotect.s b/plat/osx386/libsys/mprotect.s
new file mode 100644
index 000000000..641173a16
--- /dev/null
+++ b/plat/osx386/libsys/mprotect.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _mprotect
+_mprotect:
+	mov eax, 74
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/open.s b/plat/osx386/libsys/open.s
new file mode 100644
index 000000000..154c00506
--- /dev/null
+++ b/plat/osx386/libsys/open.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _open
+_open:
+	mov eax, 5
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/read.s b/plat/osx386/libsys/read.s
new file mode 100644
index 000000000..ccd3f8162
--- /dev/null
+++ b/plat/osx386/libsys/read.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _read
+_read:
+	mov eax, 3
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/set_errno.s b/plat/osx386/libsys/set_errno.s
new file mode 100644
index 000000000..ff0823483
--- /dev/null
+++ b/plat/osx386/libsys/set_errno.s
@@ -0,0 +1,6 @@
+.sect .text
+.define .set_errno
+.set_errno:
+	mov (_errno), eax
+	mov eax, -1
+	ret
diff --git a/plat/osx386/libsys/sigaction.s b/plat/osx386/libsys/sigaction.s
new file mode 100644
index 000000000..2909cbe02
--- /dev/null
+++ b/plat/osx386/libsys/sigaction.s
@@ -0,0 +1,59 @@
+! OS X, unlike FreeBSD, requires us to provide our own signal
+! trampoline.  We must change the new action from a struct sigaction
+! to a bigger struct that includes the trampoline.
+
+.sect .text
+.define _sigaction
+_sigaction:
+	mov eax, esp
+	mov ebx, 8(esp)		! ebx = ptr to new action
+	cmp ebx, 0
+	je 1f
+	! push bigger struct
+	push 8(ebx)		! sa_flags
+	push 4(ebx)		! sa_mask
+	push trampoline		! sa_tramp
+	push 0(ebx)		! sa_handler
+	mov ebx, esp
+	jmp 2f
+1:
+	sub esp, 16
+2:
+	push 12(eax)		! ptr to old action
+	push ebx		! ptr to bigger struct
+	push 4(eax)		! sig
+	call 3f
+	add esp, 28
+	ret
+3:
+	mov eax, 46
+	int 0x80
+	jb .set_errno
+	ret
+
+trampoline:
+	! 4(esp) = handler
+	! 8(esp) = info style
+	! 12(esp) = sig
+	! 16(esp) = info
+	! 20(esp) = context
+
+	! Call handler(sig, info, context)
+	mov eax, esp
+	push 20(eax)
+	push 16(eax)
+	push 12(eax)
+	call 4(eax)
+	add esp, 12
+
+	! Return from trampoline.
+	mov eax, esp
+	push 8(eax)		! info style
+	push 20(eax)		! context
+	sub esp, 4
+	mov eax, 184		! sigreturn
+	int 0x80
+
+	! Only if sigreturn() fails:
+	mov eax, 1		! exit
+	int 0x80
diff --git a/plat/osx386/libsys/stat.s b/plat/osx386/libsys/stat.s
new file mode 100644
index 000000000..858d84db0
--- /dev/null
+++ b/plat/osx386/libsys/stat.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _stat
+_stat:
+	mov eax, 188
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osx386/libsys/write.s b/plat/osx386/libsys/write.s
new file mode 100644
index 000000000..a32d4d78a
--- /dev/null
+++ b/plat/osx386/libsys/write.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _write
+_write:
+	mov eax, 4
+	int 0x80
+	jb .set_errno
+	ret
diff --git a/plat/osxppc/README b/plat/osxppc/README
new file mode 100644
index 000000000..dd9a4d49c
--- /dev/null
+++ b/plat/osxppc/README
@@ -0,0 +1,110 @@
+The osxppc platform
+===================
+
+    ack -mosxppc ...
+
+This platform produces Mach-o executables for PowerPC Mac OS X.  You
+can run them from the command line in the Terminal.
+
+You *can't* link to libraries from other compilers.  These static
+executables don't use the dynamic linker.  They don't load Apple's
+libraries, so they can't call Carbon or Cocoa.
+
+The executables use BSD system calls to interact with your Mac.  Our
+libsys provides only a few system calls, enough to run a few demo
+programs, but not much else.  Check the header files in ../osx/include
+for the available system calls.
+
+
+Bugs
+----
+
+ACK didn't run on Mac OS X when this platform was added.  The only way
+to run ack -mosxppc was as a cross compiler from another operating
+system.
+
+ACK doesn't have 64-bit integers, but Mac OS X uses 64-bit integers in
+its system calls.  Our libsys converts between 32-bit and 64-bit
+integers by setting the high bits to zero, or discarding the high
+bits.  This affects lseek() and stat().  They report the wrong values
+for file sizes and offsets beyond 4 gigabytes.
+
+Our PowerPC code generator is new and probably has bugs.  Its stack
+layout and calling conventions are not compatible with other
+compilers.  It passes all function arguments on the stack, which is
+slower than passing them in registers.
+
+
+Example
+-------
+Compile something:
+
+    ack -mosxppc -O6 -o paranoia examples/paranoia.c
+
+The executable has a symbol table.  If you have Apple's Xcode, try
+
+    nm -g paranoia      # to list the global symbols
+    otool -hl paranoia  # to check the Mach header and load commands
+    gdb paranoia        # to debug it
+
+Within gdb, commands like "gdb main" and "gdb '.ret'" can disassemble
+functions.  Backtraces don't work, because our stack layout is not the
+same as Apple's.
+
+
+Other hints
+-----------
+
+PowerPC Macs became obsolete after Apple's transition to Intel.  Mac
+OS X 10.5 Leopard was the last version to run on PowerPC.  The older
+Mac OS X 10.4 Tiger was the last version to include Classic for
+running Mac OS 9 programs.  Our ack -mosxppc began to produce
+executables in 2016, about 7 years after Apple released Mac OS X 10.6
+Snow Leopard for Intel only.
+
+Apple's Xcode included tools like gcc and gdb.  It also had manual
+pages for some system calls, like getdirentries(2).  Some system calls
+are like FreeBSD, some are unique to OS X.  If you want to learn how
+to call write(2) or sigaction(2), then a manual page from another BSD
+or Linux might be enough.
+
+Xcode 2.5 was the last version to run on Tiger.  The "Xcode 2.5
+Developer Tools" were a 902.9 MB download from Apple.  As of 2016, the
+download required an Apple ID and was available at:
+
+    https://developer.apple.com/download/more/
+
+Older versions of Xcode came with Mac OS X.  If your version of OS X
+came with your Mac, /Applications/Installers might contain an Xcode
+installer.  If you upgraded OS X, your install DVD might have Xcode.
+
+The source code at https://opensource.apple.com/ might reveal more
+about system calls.  For 10.4.11.ppc, the kernel is in xnu-792.24.17,
+and Libc is in Libc-391.2.10.  These files might help:
+
+    xnu*/bsd/kern/syscalls.master
+      master list of BSD system calls
+    xnu*/osfmk/kern/syscall_sw.c
+      master list of Mach traps
+    xnu*/bsd/kern/mach_loader.c
+      details about loading Mach-o executables
+    xnu*/bsd/dev/ppc/unix_signal.c
+      details about sending signals to processes
+    xnu*/bsd/sys/*.h
+      headers that Xcode installs as /usr/include/sys/*.h
+    xnu*/bsd/man/man2/*.2
+      manual pages that Xcode installs as /usr/share/man/man2/*.2
+    Libc*/ppc/sys/SYS.h
+    Libc*/ppc/sys/*.s
+      assembly code (in gas syntax) for making system calls
+
+The 10.4.11.ppc sources are wrong for Intel; use 10.4.11.x86 or 10.5
+or newer.  10.5 moved SYS.h to xnu*/libsyscall/custom/SYS.h
+
+The kernel maps a common page into every process, and Apple's Libc
+uses the common page to speed up system calls like gettimeofday(2).
+Our libsys does not use the common page.
+
+
+George Koehler <xkernigh@netscape.net>
+2016-12-03
diff --git a/plat/osxppc/boot.s b/plat/osxppc/boot.s
new file mode 100644
index 000000000..e96198eb4
--- /dev/null
+++ b/plat/osxppc/boot.s
@@ -0,0 +1,60 @@
+! boot.s for osxppc
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+.sect .text
+
+begtext:
+	! This code is placed at the entry point of the Mach-o
+	! executable and is the first thing that runs.
+	!
+	! On entry, the stack looks like this:
+	!
+	! sp+...          NULL
+	! sp+8+(4*argc)   env (X quads)
+	! sp+4+(4*argc)   NULL
+	! sp+4            argv (argc quads)
+	! sp              argc
+	!
+	! The ACK actually expects:
+	!
+	! sp+8            argc
+	! sp+4            ptr to argv
+	! sp              ptr to env
+
+	lwz r3, 0(sp)            ! r3 = argc
+	addi r4, sp, 4           ! r4 = argv
+	rlwinm r5, r3, 32-2, 2, 31 ! shift left 2 bits
+	add r5, r5, r4
+	addi r5, r5, 8           ! r5 = env
+
+	stwu r5, -4(sp)
+	stwu r4, -4(sp)
+	stwu r3, -4(sp)
+
+	b __m_a_i_n
+
+.sect .rom
+begrom:
+
+.sect .data
+begdata:
+
+! Some magic data. All EM systems need these.
+
+.sect .bss
+begbss:
+.define hol0
+.comm hol0, 8                ! line number and filename (for debugging)
+
+.define _errno
+.comm _errno, 4              ! Posix errno storage
+
+.define .trppc, .ignmask
+.comm .trppc, 4              ! ptr to user trap handler
+.comm .ignmask, 4            ! user trap ignore mask
diff --git a/plat/osxppc/build-pkg.lua b/plat/osxppc/build-pkg.lua
new file mode 100644
index 000000000..c94ad6ef0
--- /dev/null
+++ b/plat/osxppc/build-pkg.lua
@@ -0,0 +1,24 @@
+include("plat/build.lua")
+
+ackfile {
+	name = "boot",
+	srcs = { "./boot.s" },
+	vars = { plat = "osxppc" }
+}
+
+build_plat_libs {
+	name = "libs",
+	arch = "powerpc",
+	plat = "osxppc",
+}
+
+installable {
+	name = "pkg",
+	map = {
+		"+tools",
+		"+libs",
+		"plat/osx/include+pkg",
+		["$(PLATIND)/osxppc/boot.o"] = "+boot",
+		["$(PLATIND)/osxppc/libsys.a"] = "./libsys+lib",
+	}
+}
diff --git a/plat/osxppc/build-tools.lua b/plat/osxppc/build-tools.lua
new file mode 100644
index 000000000..eddeea85a
--- /dev/null
+++ b/plat/osxppc/build-tools.lua
@@ -0,0 +1,28 @@
+include("plat/build.lua")
+
+build_as {
+	name = "as",
+	arch = "powerpc",
+}
+
+build_ncg {
+	name = "ncg",
+	arch = "powerpc",
+}
+
+build_top {
+	name = "top",
+	arch = "powerpc",
+}
+
+return installable {
+	name = "tools",
+	map = {
+		["$(PLATDEP)/osxppc/as"] = "+as",
+		["$(PLATDEP)/osxppc/ncg"] = "+ncg",
+		["$(PLATDEP)/osxppc/top"] = "+top",
+		["$(PLATIND)/descr/osxppc"] = "./descr",
+		"plat/osx/cvmach+pkg",
+		"util/opt+pkg",
+	}
+}
diff --git a/plat/osxppc/descr b/plat/osxppc/descr
new file mode 100644
index 000000000..5f416c44c
--- /dev/null
+++ b/plat/osxppc/descr
@@ -0,0 +1,86 @@
+# plat/osxppc/descr
+
+var w=4
+var wa=4
+var p={w}
+var pa={w}
+var s=2
+var sa={s}
+var l={w}
+var la={w}
+var f={w}
+var fa={w}
+var d=8
+var da={d}
+var x=8
+var xa={x}
+var ARCH=powerpc
+var PLATFORM=osxppc
+var PLATFORMDIR={EM}/share/ack/{PLATFORM}
+var CPP_F=-D__unix
+var ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x129c
+var MACHOPT_F=-m3
+var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
+
+# Override the setting in fe so that files compiled for osxppc can see
+# the platform-specific headers.
+
+var C_INCLUDES=-I{EM}/share/ack/osx/include -I{EM}/share/ack/include/ansi
+
+name be
+	from .m.g
+	to .s
+	program {EM}/lib/ack/{PLATFORM}/ncg
+	mapflag -gdb GF=-gdb
+	args {GF?} <
+	stdout
+	need .e
+end
+name asopt
+	from .s
+	to .so
+	program {EM}/lib/ack/{PLATFORM}/top
+	args
+	optimizer
+	stdin
+	stdout
+end
+name as
+	from .s.so
+	to .o
+	program {EM}/lib/ack/{PLATFORM}/as
+	args - -o > <
+	prep cond
+end
+name led
+	from .o.a
+	to .out
+	program {EM}/lib/ack/em_led
+	mapflag -l* LNAME={PLATFORMDIR}/lib*
+	mapflag -fp FLOATS={EM}/{LIB}fp
+	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
+	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
+		({RTS}:.ocm.bas.b.c={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
+		({RTS}:.p={PLATFORMDIR}/pascal.o) \
+		-o > < \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
+		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
+		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		{FLOATS?} \
+		(.e:{TAIL}={PLATFORMDIR}/libem.a \
+		           {PLATFORMDIR}/libsys.a \
+		           {PLATFORMDIR}/libend.a)
+	linker
+end
+name cv
+	from .out
+	to .exe
+	program {EM}/lib/ack/cvmach
+	args -m18 < >
+	outfile osxppc.exe
+end
diff --git a/plat/osxppc/include/build.lua b/plat/osxppc/include/build.lua
new file mode 100644
index 000000000..0fe204ece
--- /dev/null
+++ b/plat/osxppc/include/build.lua
@@ -0,0 +1,4 @@
+installable {
+	name = "pkg",
+	map = { "plat/osx/include+pkg" }
+}
\ No newline at end of file
diff --git a/plat/osxppc/libsys/_exit.s b/plat/osxppc/libsys/_exit.s
new file mode 100644
index 000000000..6ffe502d5
--- /dev/null
+++ b/plat/osxppc/libsys/_exit.s
@@ -0,0 +1,6 @@
+.sect .text
+.define __exit
+__exit:
+	addi r0, r0, 1		! _exit
+	lwz r3, 0(sp)		! status
+	sc 0
diff --git a/plat/osxppc/libsys/build.lua b/plat/osxppc/libsys/build.lua
new file mode 100644
index 000000000..072730b7a
--- /dev/null
+++ b/plat/osxppc/libsys/build.lua
@@ -0,0 +1,35 @@
+acklibrary {
+	name = "lib",
+	srcs = {
+		"./_exit.s",
+		"./close.s",
+		"./fstat.s",
+		"./getdirentries.s",
+		"./getpid.s",
+		"./gettimeofday.s",
+		"./ioctl.s",
+		"./kill.s",
+		"./lseek.s",
+		"./lstat.s",
+		"./mmap.s",
+		"./mprotect.s",
+		"./open.s",
+		"./read.s",
+		"./set_errno.s",
+		"./sigaction.s",
+		"./stat.s",
+		"./write.s",
+		"plat/linuxppc/libsys/trap.s",
+		"plat/osx/libsys/brk.c",
+		"plat/osx/libsys/creat.c",
+		"plat/osx/libsys/isatty.c",
+		"plat/osx/libsys/signal.c",
+	},
+	deps = {
+		"lang/cem/libcc.ansi/headers+headers",
+		"plat/osxppc/include+pkg",
+	},
+	vars = {
+		plat = "osxppc"
+	}
+}
diff --git a/plat/osxppc/libsys/close.s b/plat/osxppc/libsys/close.s
new file mode 100644
index 000000000..a799b5e9d
--- /dev/null
+++ b/plat/osxppc/libsys/close.s
@@ -0,0 +1,8 @@
+.sect .text
+.define _close
+_close:
+	addi r0, r0, 6		! close
+	lwz r3, 0(sp)		! fd
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/fstat.s b/plat/osxppc/libsys/fstat.s
new file mode 100644
index 000000000..d641cbd91
--- /dev/null
+++ b/plat/osxppc/libsys/fstat.s
@@ -0,0 +1,9 @@
+.sect .text
+.define _fstat
+_fstat:
+	addi r0, r0, 189	! fstat
+	lwz r3, 0(sp)		! fd
+	lwz r4, 4(sp)		! stat pointer
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/getdirentries.s b/plat/osxppc/libsys/getdirentries.s
new file mode 100644
index 000000000..d038c5977
--- /dev/null
+++ b/plat/osxppc/libsys/getdirentries.s
@@ -0,0 +1,11 @@
+.sect .text
+.define _getdirentries
+_getdirentries:
+	addi r0, r0, 196	! getdirentries
+	lwz r3, 0(sp)		! fd
+	lwz r4, 4(sp)		! buffer
+	lwz r5, 8(sp)		! buffer size
+	lwz r6, 12(sp)		! base pointer
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/getpid.s b/plat/osxppc/libsys/getpid.s
new file mode 100644
index 000000000..36525cf43
--- /dev/null
+++ b/plat/osxppc/libsys/getpid.s
@@ -0,0 +1,7 @@
+.sect .text
+.define _getpid
+_getpid:
+	addi r0, r0, 20		! getpid
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/gettimeofday.s b/plat/osxppc/libsys/gettimeofday.s
new file mode 100644
index 000000000..178d17fdd
--- /dev/null
+++ b/plat/osxppc/libsys/gettimeofday.s
@@ -0,0 +1,19 @@
+! The system call checks the timeval pointer but doesn't store the
+! time there.  If the pointer wasn't NULL, then the system call
+! returns the time in a pair of registers.
+
+.sect .text
+.define _gettimeofday
+_gettimeofday:
+	addi r0, r0, 116	! gettimeofday
+	lwz r3, 0(sp)		! timeval pointer
+	lwz r4, 4(sp)		! timezone pointer
+	or. r5, r3, r3
+	sc 0
+	b .set_errno
+	bc 12, 2, 1f		! beq 1f
+	stw r3, 0(r5)		! seconds
+	stw r4, 4(r5)		! microseconds
+1:
+	addi r3, r0, 0		! return 0
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/ioctl.s b/plat/osxppc/libsys/ioctl.s
new file mode 100644
index 000000000..685ba8499
--- /dev/null
+++ b/plat/osxppc/libsys/ioctl.s
@@ -0,0 +1,10 @@
+.sect .text
+.define _ioctl
+_ioctl:
+	addi r0, r0, 54		! ioctl
+	lwz r3, 0(sp)		! fd
+	lwz r4, 4(sp)		! command
+	lwz r5, 8(sp)		! argument pointer
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/kill.s b/plat/osxppc/libsys/kill.s
new file mode 100644
index 000000000..4c7d5566f
--- /dev/null
+++ b/plat/osxppc/libsys/kill.s
@@ -0,0 +1,9 @@
+.sect .text
+.define _kill
+_kill:
+	addi r0, r0, 37		! kill
+	lwz r3, 0(sp)		! pid
+	lwz r4, 4(sp)		! signal
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/lseek.s b/plat/osxppc/libsys/lseek.s
new file mode 100644
index 000000000..129b08a8d
--- /dev/null
+++ b/plat/osxppc/libsys/lseek.s
@@ -0,0 +1,13 @@
+.sect .text
+.define _lseek
+_lseek:
+	addi r0, r0, 199	! lseek
+	lwz r3, 0(sp)		! fd
+	! ack passes 4-byte off_t, but system call takes 8-byte off_t
+	addi r4, r0, 0		! offset (high word)
+	lwz r5, 4(sp)		! offset (low word)
+	lwz r6, 8(sp)		! whence
+	sc 0
+	b .set_errno
+	or r3, r4, r4		! return offset (low word)
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/lstat.s b/plat/osxppc/libsys/lstat.s
new file mode 100644
index 000000000..24d7c44ab
--- /dev/null
+++ b/plat/osxppc/libsys/lstat.s
@@ -0,0 +1,9 @@
+.sect .text
+.define _lstat
+_lstat:
+	addi r0, r0, 190	! lstat
+	lwz r3, 0(sp)		! path
+	lwz r4, 4(sp)		! stat pointer
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/mmap.s b/plat/osxppc/libsys/mmap.s
new file mode 100644
index 000000000..f2ec5e28b
--- /dev/null
+++ b/plat/osxppc/libsys/mmap.s
@@ -0,0 +1,15 @@
+.sect .text
+.define _mmap
+_mmap:
+	addi r0, r0, 197	! mmap
+	lwz r3, 0(sp)		! address
+	lwz r4, 4(sp)		! length
+	lwz r5, 8(sp)		! protection
+	lwz r6, 12(sp)		! flags
+	lwz r7, 16(sp)		! fd
+	! ack passes 4-byte off_t, but system call takes 8-byte off_t
+	addi r8, r0, 0		! offset (high word)
+	lwz r9, 20(sp)		! offset (low word)
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/mprotect.s b/plat/osxppc/libsys/mprotect.s
new file mode 100644
index 000000000..fbea70251
--- /dev/null
+++ b/plat/osxppc/libsys/mprotect.s
@@ -0,0 +1,10 @@
+.sect .text
+.define _mprotect
+_mprotect:
+	addi r0, r0, 74		! mprotect
+	lwz r3, 0(sp)		! address
+	lwz r4, 4(sp)		! length
+	lwz r5, 8(sp)		! protection
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/open.s b/plat/osxppc/libsys/open.s
new file mode 100644
index 000000000..1d066c7ad
--- /dev/null
+++ b/plat/osxppc/libsys/open.s
@@ -0,0 +1,10 @@
+.sect .text
+.define _open
+_open:
+	addi r0, r0, 5		! open
+	lwz r3, 0(sp)		! path
+	lwz r4, 4(sp)		! flags
+	lwz r5, 8(sp)		! mode
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/read.s b/plat/osxppc/libsys/read.s
new file mode 100644
index 000000000..849da5932
--- /dev/null
+++ b/plat/osxppc/libsys/read.s
@@ -0,0 +1,10 @@
+.sect .text
+.define _read
+_read:
+	addi r0, r0, 3		! read
+	lwz r3, 0(sp)		! fd
+	lwz r4, 4(sp)		! buffer
+	lwz r5, 8(sp)		! buffer size
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/set_errno.s b/plat/osxppc/libsys/set_errno.s
new file mode 100644
index 000000000..e406865a6
--- /dev/null
+++ b/plat/osxppc/libsys/set_errno.s
@@ -0,0 +1,7 @@
+.sect .text
+.define .set_errno
+.set_errno:
+	li32 r10, _errno
+	stw r3, 0(r10)		! set errno
+	addi r3, r0, -1		! return -1
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/sigaction.s b/plat/osxppc/libsys/sigaction.s
new file mode 100644
index 000000000..f330c88a5
--- /dev/null
+++ b/plat/osxppc/libsys/sigaction.s
@@ -0,0 +1,59 @@
+#define IFTRUE 12
+#define ALWAYS 20
+#define EQ 2
+
+! OS X, unlike FreeBSD, requires us to provide our own signal
+! trampoline.  We must change the new action from a struct sigaction
+! to a bigger struct that includes the trampoline.
+
+.sect .text
+.define _sigaction
+_sigaction:
+	addi r0, r0, 46		! sigaction
+	lwz r3, 0(sp)		! sig
+	lwz r4, 4(sp)		! ptr to new action
+	lwz r5, 8(sp)		! ptr to old action
+	or. r6, r4, r4
+	bc IFTRUE, EQ, 1f	! skip if new action is NULL
+
+	! We may use the "red zone" from -224(sp) to 0(sp).
+	addi r4, sp, -16	! r4 = bigger struct
+	lwz r7, 0(r6)
+	stw r7, 0(r4)		! sa_handler
+	li32 r7, trampoline
+	stw r7, 4(r4)		! sa_tramp
+	lwz r7, 4(r6)
+	stw r7, 8(r4)		! sa_mask
+	lwz r7, 8(r6)
+	stw r7, 12(r4)		! sa_flags
+1:
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
+
+trampoline:
+	! r3 = handler
+	! r4 = info style
+	! r5 = sig
+	! r6 = info
+	! r7 = context
+	or r31, r4, r4		! ack preserves r30, r31
+	or r30, r7, r7
+
+	! Call handler(sig, info, context).
+	mtspr ctr, r3
+	stwu r7, -4(sp)		! ack expects arguments on stack
+	stwu r6, -4(sp)
+	stwu r5, -4(sp)
+	bcctrl ALWAYS, 0, 0
+
+	! Return from trampoline.
+	addi r0, r0, 184	! sigreturn
+	or r3, r30, r30		! context
+	or r4, r31, r31		! info style
+	sc 0
+	ori r0, r0, 0		! nop
+
+	! Only if sigreturn() fails:
+	addi r0, r0, 1		! exit
+	sc 0
diff --git a/plat/osxppc/libsys/stat.s b/plat/osxppc/libsys/stat.s
new file mode 100644
index 000000000..ab8422cda
--- /dev/null
+++ b/plat/osxppc/libsys/stat.s
@@ -0,0 +1,9 @@
+.sect .text
+.define _stat
+_stat:
+	addi r0, r0, 188	! stat
+	lwz r3, 0(sp)		! path
+	lwz r4, 4(sp)		! stat pointer
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/osxppc/libsys/write.s b/plat/osxppc/libsys/write.s
new file mode 100644
index 000000000..48f59cd72
--- /dev/null
+++ b/plat/osxppc/libsys/write.s
@@ -0,0 +1,10 @@
+.sect .text
+.define _write
+_write:
+	addi r0, r0, 4		! write
+	lwz r3, 0(sp)		! fd
+	lwz r4, 4(sp)		! buffer
+	lwz r5, 8(sp)		! buffer size
+	sc 0
+	b .set_errno
+	bclr 20, 0, 0
diff --git a/plat/pc86/README b/plat/pc86/README
index 689c70844..dcbe0ba27 100644
--- a/plat/pc86/README
+++ b/plat/pc86/README
@@ -23,6 +23,9 @@ are stubs required to make the demo apps link. File descriptors 0, 1 and 2
 represent the console. All reads block. There's enough TTY emulation to allow
 \n conversion and local echo (but it can't be turned off).
 
+Console output is echoed to the serial port (without any setup). This is used
+by qemu for running tests.
+
 
 Example command line
 ====================
diff --git a/plat/pc86/boot.s b/plat/pc86/boot.s
index 534809697..51b288e75 100644
--- a/plat/pc86/boot.s
+++ b/plat/pc86/boot.s
@@ -23,7 +23,7 @@
 ! If you ever need to change the boot code, this needs adjusting. I recommend
 ! a hex editor.
 
-PADDING = 0xB7
+PADDING = 0xB3
 
 ! Some definitions.
 
@@ -271,9 +271,12 @@ finished:
 	
 	! Push standard parameters onto the stack and go.
 	
-	push envp               ! envp
-	push argv               ! argv
-	push 1                  ! argc
+	mov ax, envp
+	push ax
+	mov ax, argv
+	push ax
+	mov ax, 1
+	push ax
 	call __m_a_i_n
 	! fall through into the exit routine.
 	
diff --git a/plat/pc86/descr b/plat/pc86/descr
index d8cb006e6..9b54410ff 100644
--- a/plat/pc86/descr
+++ b/plat/pc86/descr
@@ -20,7 +20,7 @@ var ARCH=i86
 var PLATFORM=pc86
 var PLATFORMDIR={EM}/share/ack/{PLATFORM}
 var CPP_F=-D__unix
-var ALIGN=-a0:1 -a1:1 -a2:1 -a3:1
+var ALIGN=-a0:2 -a1:2 -a2:2 -a3:2
 var MACHOPT_F=-m8
 var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
 
@@ -52,17 +52,19 @@ name led
 	mapflag -i SEPID=-b1:0
 	mapflag -fp FLOATS={EM}/{ILIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/pc86/include/unistd.h b/plat/pc86/include/unistd.h
index ea4f51c0f..174c43ad0 100644
--- a/plat/pc86/include/unistd.h
+++ b/plat/pc86/include/unistd.h
@@ -37,6 +37,7 @@ extern char** environ;
 
 extern void _exit(int);
 extern pid_t getpid(void);
+extern int brk(void* addr);
 extern void* sbrk(int increment);
 extern int isatty(int d);
 extern off_t lseek(int fildes, off_t offset, int whence);
diff --git a/plat/pc86/libsys/_sys_rawwrite.s b/plat/pc86/libsys/_sys_rawwrite.s
index 75f75aae1..ae477c6d2 100644
--- a/plat/pc86/libsys/_sys_rawwrite.s
+++ b/plat/pc86/libsys/_sys_rawwrite.s
@@ -21,9 +21,18 @@ __sys_rawwrite:
 	push bp
 	mov bp, sp
 
+	! Write to the BIOS console.
+
 	movb al, 4(bp)
 	movb ah, 0x0E
 	mov bx, 0x0007
 	int 0x10
+
+	! Also write to the serial port (used by the test suite).
+
+	movb ah, 0x01
+	xor dx, dx
+	int 0x14
+
 	jmp .cret
 	
\ No newline at end of file
diff --git a/plat/pc86/libsys/brk.c b/plat/pc86/libsys/brk.c
index 952a9c747..293703234 100644
--- a/plat/pc86/libsys/brk.c
+++ b/plat/pc86/libsys/brk.c
@@ -22,7 +22,10 @@ int brk(void* newend)
 	
 	if ((p > (&dummy - STACK_BUFFER)) ||
 	    (p < _end))	
+	{
+		errno = ENOMEM;
 		return -1;
+	}
 		
 	current = p;
 	return 0;
@@ -31,13 +34,26 @@ int brk(void* newend)
 void* sbrk(int increment)
 {
 	char* old;
-	
+	char* new;
+
 	if (increment == 0)
 		return current;
 		
 	old = current;
-	if (brk(old + increment) < 0)
-		return OUT_OF_MEMORY;
+
+	new = old + increment;
+
+	if ((increment > 0) && (new <= old))
+		goto out_of_memory;
+	else if ((increment < 0) && (new >= old))
+		goto out_of_memory;
+
+	if (brk(new) < 0)
+		goto out_of_memory;
 		
 	return old;
+
+out_of_memory:
+	errno = ENOMEM;
+	return OUT_OF_MEMORY;
 }
diff --git a/plat/pc86/tests/build.lua b/plat/pc86/tests/build.lua
new file mode 100644
index 000000000..fe871e450
--- /dev/null
+++ b/plat/pc86/tests/build.lua
@@ -0,0 +1,7 @@
+include("tests/plat/build.lua")
+
+plat_testsuite {
+    name = "tests",
+    plat = "pc86",
+    method = "qemu-system-i386"
+}
diff --git a/plat/qemuppc/boot.s b/plat/qemuppc/boot.s
index 2dd9a4c5c..ac3227dc9 100644
--- a/plat/qemuppc/boot.s
+++ b/plat/qemuppc/boot.s
@@ -13,22 +13,14 @@
 .sect .text
 
 begtext:
-	! This code is placed at the beginning of the ELF executable and is the
-	! first thing that runs.
+	! This code is the first thing that runs.  The booloader
+	! passes the Open Firmware pointer in r5.
 	!
-	! On entry, the stack looks like this:
+	! We keep the bootloader's stack.  The ACK expects:
 	!
-	! sp+...          NULL
-	! sp+8+(4*argc)   env (X quads)
-	! sp+4+(4*argc)   NULL
-	! sp+4            argv (argc quads)
+	! sp+8            environment pointer
+	! sp+4            argv as a pointer
 	! sp              argc
-	!
-	! The ACK actually expects:
-	!
-	! sp+8            argc
-	! sp+4            ptr to argv
-	! sp              ptr to env
 
 	li32 r3, __openfirmware_ptr
 	stw r5, 0(r3)
@@ -47,15 +39,23 @@ begtext:
 	! falls through
 
 .define __exit
-.extern __exit
 .define EXIT
-.extern EXIT
 __exit:
 EXIT:
-	b EXIT
+	! Halt the CPU.  This code halts the default G3 emulation of
+	! qemu-system-ppc.  It's wrong for some other CPU models.
+#define hid0 0x3f0
+#define mfmsr(r) [[31<<26]|[[r]<<21]|0x0a6]
+#define mtmsr(r) [[31<<26]|[[r]<<21]|0x124]
+	mfspr r3, hid0
+	oris r3, r3, 0x00e0		! set DOZE, NAP, SLEEP
+	mtspr hid0, r3			!   in hid0
+	.data4 mfmsr(3)
+	oris r3, r3, 0x0004		! set POW
+	.data4 mtmsr(3)			!   in msr
+	b EXIT		! If we failed to halt, then spin.
 
 .define _openfirmware_call
-.extern _openfirmware_call
 _openfirmware_call:
 	lwz r3, 0(sp)
 	li32 r4, __openfirmware_ptr
@@ -66,15 +66,10 @@ _openfirmware_call:
 ! Define symbols at the beginning of our various segments, so that we can find
 ! them. (Except .text, which has already been done.)
 
-.sect .data;       begdata:
 .sect .rom;        begrom:
+.sect .data;       begdata:
 .sect .bss;        begbss:
 
-! Some magic data. All EM systems need these.
-
-.define _errno
-.comm _errno, 4              ! Posix errno storage
-
 ! The argv and env arrays.
 
 .sect .rom
@@ -82,6 +77,12 @@ argv: .data4 exename, 0
 envp: .data4 0
 exename: .asciz 'qemuppc.img'
 
+! Some magic data. All EM systems need these.
+
+.sect .bss
+.define _errno
+.comm _errno, 4              ! Posix errno storage
+
 .define .trppc, .ignmask
 .comm .trppc, 4              ! ptr to user trap handler
 .comm .ignmask, 4            ! user trap ignore mask 
diff --git a/plat/qemuppc/descr b/plat/qemuppc/descr
index c0bc1eab0..f5191b249 100644
--- a/plat/qemuppc/descr
+++ b/plat/qemuppc/descr
@@ -62,17 +62,19 @@ name led
 	mapflag -l* LNAME={PLATFORMDIR}/lib*
 	mapflag -fp FLOATS={EM}/{LIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/qemuppc/libsys/brk.c b/plat/qemuppc/libsys/brk.c
index 118bda3cf..7d49fa960 100644
--- a/plat/qemuppc/libsys/brk.c
+++ b/plat/qemuppc/libsys/brk.c
@@ -34,13 +34,26 @@ int brk(void* newend)
 void* sbrk(int increment)
 {
 	char* old;
+	char* new;
 	
 	if (increment == 0)
 		return current;
 		
 	old = current;
-	if (brk(old + increment) < 0)
-		return OUT_OF_MEMORY;
+
+	new = old + increment;
+
+	if ((increment > 0) && (new <= old))
+		goto out_of_memory;
+	else if ((increment < 0) && (new >= old))
+		goto out_of_memory;
+
+	if (brk(new) < 0)
+		goto out_of_memory;
 		
 	return old;
+
+out_of_memory:
+	errno = ENOMEM;
+	return OUT_OF_MEMORY;
 }
diff --git a/plat/qemuppc/libsys/trap.s b/plat/qemuppc/libsys/trap.s
index f05b907d0..e00c4d561 100644
--- a/plat/qemuppc/libsys/trap.s
+++ b/plat/qemuppc/libsys/trap.s
@@ -49,21 +49,17 @@ EUNIMPL = 63		! unimplemented em-instruction called
 .define .trap_ecase
 .trap_ecase:
 	b .trp
-	
+
 .define .trap_earray
 .trap_earray:
 	b .trp
 
+.define .trap_erange
+.trap_erange:
+	b .trap
+
 .define .trp
 .define .trap
 .trp:
 .trap:
 	b .trp					! spin forever
-
-.define .sig
-.sig:
-	lwz r3, 0(sp)
-	li32 r4, .trppc
-	stw r3, 0(r4)
-	bclr ALWAYS, 0, 0		! return
-	
\ No newline at end of file
diff --git a/plat/qemuppc/tests/brk_c.c b/plat/qemuppc/tests/brk_c.c
deleted file mode 100644
index aa0f7ef99..000000000
--- a/plat/qemuppc/tests/brk_c.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include "test.h"
-
-int main(int argc, const char* argv[])
-{
-    void* p;
-
-    ASSERT(-1 == (intptr_t)brk((void*)0xffffffff));
-    ASSERT(ENOMEM == errno);
-
-    p = sbrk(0);
-    ASSERT(p == sbrk(0));
-    ASSERT(p == sbrk(8));
-    ASSERT(p != sbrk(0));
-    ASSERT(p != sbrk(-8));
-    ASSERT(p == sbrk(0));
-
-    /* We assume the test environment has less than 2GB of RAM. */
-    ASSERT(-1 == (intptr_t)sbrk(INT_MAX));
-    ASSERT(-1 == (intptr_t)sbrk(INT_MIN));
-
-    finished();
-}
-
diff --git a/plat/qemuppc/tests/build.lua b/plat/qemuppc/tests/build.lua
index f0c2993c4..6581d93ef 100644
--- a/plat/qemuppc/tests/build.lua
+++ b/plat/qemuppc/tests/build.lua
@@ -1,49 +1,7 @@
-include("plat/build.lua")
+include("tests/plat/build.lua")
 
-local qemu = "qemu-system-ppc"
-local tests = {}
-
-if os.execute("which "..qemu.." > /dev/null") ~= 0 then
-	print("warning: skipping tests which require ", qemu)
-else
-	local testcases = filenamesof("./*.c", "./*.s", "./*.e", "./*.p")
-
-	for _, f in ipairs(testcases) do
-		local fs = replace(basename(f), "%..$", "")
-		local _, _, lang = fs:find("_(.)$")
-		if not lang then
-			lang = "e"
-		end
-
-		local bin = ackprogram {
-			name = fs.."_bin",
-			srcs = { f },
-			deps = { "plat/qemuppc/tests/lib+lib" },
-			vars = {
-				plat = "qemuppc",
-				lang = lang,
-				ackcflags = "-O0"
-			}
-		}
-
-		tests[#tests+1] = normalrule {
-			name = fs,
-			outleaves = { "stamp" },
-			ins = {
-				bin,
-				"./testdriver.sh"
-			},
-			commands = {
-				"%{ins[2]} "..qemu.." %{ins[1]} 5",
-				"touch %{outs}"
-			}
-		}
-	end
-end
-
-normalrule {
-	name = "tests",
-	outleaves = { "stamp" },
-	ins = tests,
-	commands = { "touch %{outs}" }
-}
\ No newline at end of file
+plat_testsuite {
+    name = "tests",
+    plat = "qemuppc",
+    method = "qemu-system-ppc"
+}
diff --git a/plat/qemuppc/tests/lib/build.lua b/plat/qemuppc/tests/lib/build.lua
deleted file mode 100644
index cb6b5cbea..000000000
--- a/plat/qemuppc/tests/lib/build.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-include("plat/build.lua")
-
-acklibrary {
-	name = "lib",
-	srcs = { "./test.c" },
-	hdrs = { "./test.h" },
-	vars = { plat = "qemuppc" }
-}
diff --git a/plat/qemuppc/tests/testdriver.sh b/plat/qemuppc/tests/testdriver.sh
deleted file mode 100755
index 3424e9626..000000000
--- a/plat/qemuppc/tests/testdriver.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-qemu=$1
-img=$2
-timeout=$3
-
-pipe=/tmp/$$.testdriver.pipe
-mknod $pipe p
-trap "rm -f $pipe" EXIT
-
-result=/tmp/$$.testdriver.result
-trap "rm -f $result" EXIT
-
-pidfile=/tmp/$$.testdriver.pid
-trap "rm -f $pidfile" EXIT
-
-( $qemu -nographic -kernel $img 2>&1 & echo $! > $pidfile ) \
-    | tee $result \
-    | ( timeout $timeout grep -l -q @@FINISHED ; echo ) \
-    | ( read dummy && kill $(cat $pidfile) )
-
-( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
-exit 0
\ No newline at end of file
diff --git a/plat/rpi/descr b/plat/rpi/descr
index 6daff9606..43d3256a3 100644
--- a/plat/rpi/descr
+++ b/plat/rpi/descr
@@ -51,17 +51,19 @@ name led
 	mapflag -i SEPID=-b1:0
 	mapflag -fp FLOATS={EM}/{ILIB}fp
 	args {ALIGN} {SEPID?} \
+		({RTS}:.b=-u _i_main) \
 	    (.e:{HEAD}={PLATFORMDIR}/boot.o) \
-		({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+		({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
 		({RTS}:.mod={PLATFORMDIR}/modula2.o) \
 		({RTS}:.p={PLATFORMDIR}/pascal.o) \
 		-o > < \
 		(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
-		(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+		(.b:{TAIL}={PLATFORMDIR}/libb.a) \
+		(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
 		(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
 		(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
-		(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+		(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
 		{FLOATS?} \
 		(.e:{TAIL}={PLATFORMDIR}/libem.a \
 		           {PLATFORMDIR}/libsys.a \
diff --git a/plat/qemuppc/tests/_dummy.c b/tests/plat/_dummy_e.c
similarity index 100%
rename from plat/qemuppc/tests/_dummy.c
rename to tests/plat/_dummy_e.c
diff --git a/tests/plat/b/control_b.b b/tests/plat/b/control_b.b
new file mode 100644
index 000000000..a31b9d380
--- /dev/null
+++ b/tests/plat/b/control_b.b
@@ -0,0 +1,107 @@
+#
+zero 0;
+one 1;
+
+if_t()
+{
+	extrn zero, one;
+	auto fails, successes;
+
+	successes = 0;
+
+	if (zero)
+		fail(__LINE__);
+
+	if (zero)
+		fail(__LINE__);
+	else
+		successes++;
+
+	if (one)
+		successes++;
+
+	if (one)
+		successes++;
+	else
+		fail(__LINE__);
+
+	if (successes != 3)
+		fail(__LINE__);
+}
+
+while_t()
+{
+	extrn zero, one;
+	auto successes, count;
+	
+	successes = 3;
+	count = 0;
+	while (count)
+	{
+		successes++;
+		count--;
+	}
+	if (successes != 3)
+		fail(__LINE__);
+
+	while (zero)
+		fail(__LINE__);
+
+	while (one)
+	{
+		break;
+		fail(__LINE__);
+	}
+}
+
+sdata(n)
+{
+	switch (n)
+	{
+		case 0: return(0);
+		case 1: return(1);
+		case 100: return(100);
+		default: return(-1);
+	}
+}
+
+switch_t()
+{
+	extrn zero;
+	auto successes;
+
+	if (!(sdata(-1) == -1)) fail(__LINE__);
+	if (!(sdata(0) == 0)) fail(__LINE__);
+	if (!(sdata(1) == 1)) fail(__LINE__);
+	if (!(sdata(2) == -1)) fail(__LINE__);
+	if (!(sdata(100) == 100)) fail(__LINE__);
+	if (!(sdata(200) == -1)) fail(__LINE__);
+
+	successes = 0;
+	switch (zero)
+	{
+		case 0: /* fall through */
+		case 1: successes++; break;
+	}
+	if (successes != 1)
+		fail(__LINE__);
+}
+
+goto_t()
+{
+	goto n;
+	fail(__LINE__);
+	n:;
+}
+
+main()
+{
+	if_t();
+	switch_t();
+	goto_t();
+	while_t();
+
+	finished();
+	return(0);
+}
+
diff --git a/tests/plat/b/incdec_b.b b/tests/plat/b/incdec_b.b
new file mode 100644
index 000000000..4edf5f6bf
--- /dev/null
+++ b/tests/plat/b/incdec_b.b
@@ -0,0 +1,82 @@
+#
+/* External variables to defeat constant folding. */
+zero 0;
+one 1;
+
+i 0;
+
+ext_t()
+{
+    extrn zero, one, i;
+
+	i = zero;
+	if (!(i++ == 0)) fail(__LINE__);
+
+	i = one;
+	if (!(i-- == 1)) fail(__LINE__);
+	if (!(i == 0)) fail(__LINE__);
+
+	i = zero;
+	if (!(++i == 1)) fail(__LINE__);
+	if (!(i == 1)) fail(__LINE__);
+
+	i = one;
+	if (!(--i == 0)) fail(__LINE__);
+	if (!(i == 0)) fail(__LINE__);
+}
+
+int_t()
+{
+    extrn zero, one;
+	auto i;
+
+	i = zero;
+	if (!(i++ == 0)) fail(__LINE__);
+
+	i = one;
+	if (!(i-- == 1)) fail(__LINE__);
+	if (!(i == 0)) fail(__LINE__);
+
+	i = zero;
+	if (!(++i == 1)) fail(__LINE__);
+	if (!(i == 1)) fail(__LINE__);
+
+	i = one;
+	if (!(--i == 0)) fail(__LINE__);
+	if (!(i == 0)) fail(__LINE__);
+}
+
+star_t()
+{
+    extrn zero, one, i;
+    auto p;
+
+    p = &i;
+
+	i = zero;
+    if (!((*p)++ == 0)) fail(__LINE__);
+
+	i = one;
+    if (!((*p)-- == 1)) fail(__LINE__);
+	if (!(i == 0)) fail(__LINE__);
+
+	i = zero;
+    if (!(++(*p) == 1)) fail(__LINE__);
+	if (!(i == 1)) fail(__LINE__);
+
+	i = one;
+    if (!(--(*p) == 0)) fail(__LINE__);
+	if (!(i == 0)) fail(__LINE__);
+}
+
+main()
+{
+    ext_t();
+    int_t();
+    star_t();
+
+	finished();
+	return(0);
+}
+
+
diff --git a/tests/plat/b/operators_b.b b/tests/plat/b/operators_b.b
new file mode 100644
index 000000000..5baa674b1
--- /dev/null
+++ b/tests/plat/b/operators_b.b
@@ -0,0 +1,69 @@
+#
+minusone -1;
+zero 0;
+one 1;
+two 2;
+
+main()
+{
+	extrn minusone, zero, one, two;
+	auto i, j;
+
+	if (!(zero == 0)) fail(__LINE__);
+	if (!(one == 1)) fail(__LINE__);
+	if (!(-one == -1)) fail(__LINE__);
+	if (!(!one == 0)) fail(__LINE__);
+	if (!(!zero == 1)) fail(__LINE__);
+	if (!(~zero == -1)) fail(__LINE__);
+	if (!(~minusone == 0)) fail(__LINE__);
+
+	if (!(zero == zero)) fail(__LINE__);
+	if (!(zero != one))  fail(__LINE__);
+	if (!(zero <  one))  fail(__LINE__);
+	if (!(zero <= one))  fail(__LINE__);
+	if (!(zero <= zero)) fail(__LINE__);
+	if (!(one >  zero))  fail(__LINE__);
+	if (!(one >= zero))  fail(__LINE__);
+	if (!(one >= one))   fail(__LINE__);
+
+	if (!((two + two) == 4)) fail(__LINE__);
+	if (!((two - two) == 0)) fail(__LINE__);
+	if (!((two * two) == 4)) fail(__LINE__);
+	if (!((two / two) == 1)) fail(__LINE__);
+	if (!((two % two) == 0)) fail(__LINE__);
+
+	if (!((one << 1) == 2)) fail(__LINE__);
+	if (!((two >> 1) == 1)) fail(__LINE__);
+
+	if (!((two & 1) == 0)) fail(__LINE__);
+	if (!((two | 1) == 3)) fail(__LINE__);
+	if (!((two ^ 2) == 0)) fail(__LINE__);
+
+	i = 2; i =+ two; if (!(i == 4)) fail(__LINE__);
+	i = 2; i =- two; if (!(i == 0)) fail(__LINE__);
+	i = 2; i =* two; if (!(i == 4)) fail(__LINE__);
+	i = 2; i =/ two; if (!(i == 1)) fail(__LINE__);
+	i = 2; i =% two; if (!(i == 0)) fail(__LINE__);
+
+	i = zero; i === zero; if (!i) fail(__LINE__);
+	i = zero; i =!= one;  if (!i) fail(__LINE__);
+	i = zero; i =<  one;  if (!i) fail(__LINE__);
+	i = zero; i =<= one;  if (!i) fail(__LINE__);
+	i = zero; i =<= zero; if (!i) fail(__LINE__);
+	i = one;  i =>  zero; if (!i) fail(__LINE__);
+	i = one;  i =>= zero; if (!i) fail(__LINE__);
+	i = one;  i =>= one;  if (!i) fail(__LINE__);
+
+	i = one; i =<< one; if (!(i == 2)) fail(__LINE__);
+	i = two; i =>> one; if (!(i == 1)) fail(__LINE__);
+
+	i = two; i =& 1; if (!(i == 0)) fail(__LINE__);
+	i = two; i =| 1; if (!(i == 3)) fail(__LINE__);
+	i = two; i =^ 2; if (!(i == 0)) fail(__LINE__);
+
+	if (!(one ? 1 : 0)) fail(__LINE__);
+	if (!(zero ? 0 : 1)) fail(__LINE__);
+
+	finished();
+	return(0);
+}
diff --git a/tests/plat/brk_c.c b/tests/plat/brk_c.c
new file mode 100644
index 000000000..434cec50b
--- /dev/null
+++ b/tests/plat/brk_c.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include "test.h"
+
+int main(int argc, const char* argv[])
+{
+    char* o;
+    char* p;
+
+    p = sbrk(0);
+    ASSERT(p == sbrk(0));
+    ASSERT(p == sbrk(8));
+    ASSERT(p != sbrk(0));
+    ASSERT(p != sbrk(-8));
+    ASSERT(p == sbrk(0));
+
+    errno = 0;
+    o = sbrk(INT_MAX);
+    if (o == (char*)-1)
+        ASSERT(ENOMEM == errno);
+    else
+    {
+        ASSERT(0 == errno);
+        p = sbrk(0);
+        ASSERT(p > o);
+        brk(o);
+    }
+
+    errno = 0;
+    o = sbrk(INT_MIN);
+    if (o == (char*)-1)
+        ASSERT(ENOMEM == errno);
+    else
+    {
+        ASSERT(0 == errno);
+        p = sbrk(0);
+        ASSERT(p < o);
+        brk(o);
+    }
+
+    finished();
+}
+
diff --git a/tests/plat/bugs/bug-22-inn_mod.mod b/tests/plat/bugs/bug-22-inn_mod.mod
new file mode 100644
index 000000000..53fe93568
--- /dev/null
+++ b/tests/plat/bugs/bug-22-inn_mod.mod
@@ -0,0 +1,22 @@
+MODULE test;
+FROM Test IMPORT fail, finished;
+
+TYPE charset = SET OF CHAR;
+
+PROCEDURE Space(c: CHAR): BOOLEAN;
+BEGIN
+  RETURN c IN charset{' ', 11C, 12C, 15C}
+END Space;
+
+BEGIN
+  IF Space('a') THEN
+    fail(1);
+  END;
+  IF NOT Space(' ') THEN
+    fail(2);
+  END;
+  IF NOT Space(12C) THEN
+    fail(3);
+  END;
+  finished;
+END test.
\ No newline at end of file
diff --git a/tests/plat/build.lua b/tests/plat/build.lua
new file mode 100644
index 000000000..b689ea5f6
--- /dev/null
+++ b/tests/plat/build.lua
@@ -0,0 +1,70 @@
+include("plat/build.lua")
+
+definerule("plat_testsuite",
+	{
+		plat = { type="string" },
+		method = { type="string" },
+	},
+	function(e)
+		-- Remember this is executed from the caller's directory; local
+		-- target names will resolve there.
+		local testfiles = filenamesof(
+			"tests/plat/*.c",
+			"tests/plat/*.e",
+			"tests/plat/*.p",
+			"tests/plat/b/*.b",
+			"tests/plat/bugs/*.mod"
+		)
+
+		acklibrary {
+			name = "lib",
+			srcs = {
+				"tests/plat/lib/test.c",
+				"tests/plat/lib/test_b.c",
+			},
+			hdrs = {
+				"tests/plat/lib/test.h",
+				"tests/plat/lib/Test.def"
+			},
+			vars = { plat = e.plat },
+		}
+
+		local tests = {}
+		for _, f in ipairs(testfiles) do
+			local fs = replace(basename(f), "%.[^.]+$", "")
+			local _, _, lang = fs:find("_([^_]+)$")
+			if not lang then
+				lang = "e"
+			end
+
+			local bin = ackprogram {
+				name = fs.."_bin",
+				srcs = { f },
+				deps = { "+lib" },
+				vars = {
+					plat = e.plat,
+					lang = lang,
+					ackcflags = "-O0 -Bmain"
+				}
+			}
+
+			tests[#tests+1] = normalrule {
+				name = fs,
+				outleaves = { e.plat.."-"..fs.."-testlog.txt" },
+				ins = {
+					bin,
+					"tests/plat/testdriver.sh",
+					"util/build+testrunner"
+				},
+				commands = {
+					"(%{ins[2]} "..e.method.." %{ins[1]} 5 %{ins[3]} || echo @@FAIL) > %{outs}",
+				}
+			}
+		end
+
+		return bundle {
+			name = e.name,
+			srcs = tests,
+		}
+	end
+)
diff --git a/plat/qemuppc/tests/calloc_c.c b/tests/plat/calloc_c.c
similarity index 100%
rename from plat/qemuppc/tests/calloc_c.c
rename to tests/plat/calloc_c.c
diff --git a/plat/qemuppc/tests/csa_e.c b/tests/plat/csa_e.c
similarity index 100%
rename from plat/qemuppc/tests/csa_e.c
rename to tests/plat/csa_e.c
diff --git a/plat/qemuppc/tests/csb_e.c b/tests/plat/csb_e.c
similarity index 100%
rename from plat/qemuppc/tests/csb_e.c
rename to tests/plat/csb_e.c
diff --git a/plat/qemuppc/tests/doublecmp_e.c b/tests/plat/doublecmp_e.c
similarity index 100%
rename from plat/qemuppc/tests/doublecmp_e.c
rename to tests/plat/doublecmp_e.c
diff --git a/plat/qemuppc/tests/from_d_to_si_e.c b/tests/plat/from_d_to_si_e.c
similarity index 67%
rename from plat/qemuppc/tests/from_d_to_si_e.c
rename to tests/plat/from_d_to_si_e.c
index 8c7e31c3e..7f51e6c5b 100644
--- a/plat/qemuppc/tests/from_d_to_si_e.c
+++ b/tests/plat/from_d_to_si_e.c
@@ -1,11 +1,12 @@
+#include <limits.h>
 #include "test.h"
 
 /* Constants in globals to defeat constant folding. */
 double one = 1.0;
 double zero = 0.0;
 double minusone = -1.0;
-double big = 2147483647.0;
-double minusbig = -2147483648.0;
+double big = (double)INT_MAX;
+double minusbig = (double)INT_MIN;
 
 /* Bypasses the CRT, so there's no stdio or BSS initialisation. */
 void _m_a_i_n(void)
@@ -13,8 +14,8 @@ void _m_a_i_n(void)
     ASSERT((int)zero == 0);
     ASSERT((int)one == 1);
     ASSERT((int)minusone == -1);
-    ASSERT((int)big == 2147483647);
-    ASSERT((int)minusbig == -2147483648);
+    ASSERT((int)big == INT_MAX);
+    ASSERT((int)minusbig == INT_MIN);
 
     finished();
 }
\ No newline at end of file
diff --git a/plat/qemuppc/tests/from_d_to_ui_e.c b/tests/plat/from_d_to_ui_e.c
similarity index 75%
rename from plat/qemuppc/tests/from_d_to_ui_e.c
rename to tests/plat/from_d_to_ui_e.c
index b16667502..811780b87 100644
--- a/plat/qemuppc/tests/from_d_to_ui_e.c
+++ b/tests/plat/from_d_to_ui_e.c
@@ -1,16 +1,17 @@
+#include <limits.h>
 #include "test.h"
 
 /* Constants in globals to defeat constant folding. */
 double one = 1.0;
 double zero = 0.0;
-double big = 4294967295.0;
+double big = (double)UINT_MAX;
 
 /* Bypasses the CRT, so there's no stdio or BSS initialisation. */
 void _m_a_i_n(void)
 {
     ASSERT((unsigned int)zero == 0);
     ASSERT((unsigned int)one == 1);
-    ASSERT((unsigned int)big == 4294967295);
+    ASSERT((unsigned int)big == UINT_MAX);
 
     finished();
 }
\ No newline at end of file
diff --git a/plat/qemuppc/tests/from_si_to_d_e.c b/tests/plat/from_si_to_d_e.c
similarity index 64%
rename from plat/qemuppc/tests/from_si_to_d_e.c
rename to tests/plat/from_si_to_d_e.c
index e81c2f7c2..b6c7a25ba 100644
--- a/plat/qemuppc/tests/from_si_to_d_e.c
+++ b/tests/plat/from_si_to_d_e.c
@@ -1,11 +1,12 @@
+#include <limits.h>
 #include "test.h"
 
 /* Constants in globals to defeat constant folding. */
 int one = 1;
 int zero = 0;
 int minusone = -1;
-int big = 0x7fffffff;
-int minusbig = -0x8000000;
+int big = INT_MAX;
+int minusbig = INT_MIN;
 
 /* Bypasses the CRT, so there's no stdio or BSS initialisation. */
 void _m_a_i_n(void)
@@ -13,8 +14,8 @@ void _m_a_i_n(void)
     ASSERT((double)zero == 0.0);
     ASSERT((double)one == 1.0);
     ASSERT((double)minusone == -1.0);
-    ASSERT((double)big == 2147483647.0);
-    /* ASSERT((double)minusbig == -2147483648.0); FIXME: fails for now */
+    ASSERT((double)big == (double)INT_MAX);
+    /* ASSERT((double)minusbig == (double)INT_MIN); FIXME: fails for now */
 
     finished();
 }
\ No newline at end of file
diff --git a/plat/qemuppc/tests/from_ui_to_d_e.c b/tests/plat/from_ui_to_d_e.c
similarity index 75%
rename from plat/qemuppc/tests/from_ui_to_d_e.c
rename to tests/plat/from_ui_to_d_e.c
index a3517b24c..b8e017c99 100644
--- a/plat/qemuppc/tests/from_ui_to_d_e.c
+++ b/tests/plat/from_ui_to_d_e.c
@@ -1,16 +1,17 @@
+#include <limits.h>
 #include "test.h"
 
 /* Constants in globals to defeat constant folding. */
 unsigned int one_u = 1;
 unsigned int zero_u = 0;
-unsigned int big_u = 0xffffffff;
+unsigned int big_u = UINT_MAX;
 
 /* Bypasses the CRT, so there's no stdio or BSS initialisation. */
 void _m_a_i_n(void)
 {
     ASSERT((double)zero_u == 0.0);
     ASSERT((double)one_u == 1.0);
-    ASSERT((double)big_u == 4294967295.0);
+    ASSERT((double)big_u == (double)UINT_MAX);
 
     finished();
 }
\ No newline at end of file
diff --git a/plat/qemuppc/tests/inn_e.e b/tests/plat/inn_e.e
similarity index 56%
rename from plat/qemuppc/tests/inn_e.e
rename to tests/plat/inn_e.e
index 4e53b35c5..a5aee02f5 100644
--- a/plat/qemuppc/tests/inn_e.e
+++ b/tests/plat/inn_e.e
@@ -1,5 +1,5 @@
 #
-    mes 2, 4, 4
+    mes 2, EM_WSIZE, EM_PSIZE
 
     exp $_m_a_i_n
     pro $_m_a_i_n, 0
@@ -7,7 +7,7 @@
     /* Test non-existent bit */
 
 .1
-    rom 0I1, 0I1, 0I1, 0I1
+    rom 0I4
     loe .1
     loc 1       /* bit number */
     inn 4
@@ -15,59 +15,60 @@
 
     loc __LINE__
     cal $fail
-    ass 4
+    ass EM_WSIZE
 1
 
     /* Test existent bit */
 
 .2
-    rom 2I1, 0I1, 0I1, 0I1
+    rom 16384
+.21
+    rom 14      /* to defeat constant folding */
+
     loe .2
-    loc 1       /* bit number */
-    inn 4
+    loe .21      /* bit number */
+    inn EM_WSIZE
     zne *2
 
     loc __LINE__
     cal $fail
-    ass 4
+    ass EM_WSIZE
 2
 
     /* Test non-existent high bit */
 
 .3
-    rom 0I1, 0I1, 0I1, 0I1
-    rom 0I1, 0I1, 0I1, 0I1
+    rom 0, 0
 .31
-    rom 33      /* to defeat constant folding */
+    rom 8       /* to defeat constant folding */
 
     lae .3
-    loi 8
+    loi EM_WSIZE*2
     loe .31     /* bit number */
-    inn 8
+    inn EM_WSIZE*2
     zeq *3
 
     loc __LINE__
     cal $fail
-    ass 4
+    ass EM_WSIZE
 3
 
     /* Test existent high bit */
 
 .4
-    rom 0I1, 0I1, 0I1, 0I1
-    rom 2I1, 0I1, 0I1, 0I1
+    rom 0, 2
 .41
-    rom 33      /* to defeat constant folding */
+    rom (EM_WSIZE*8)+1      /* to defeat constant folding */
 
     lae .4
-    loi 8
+    loi EM_WSIZE*2
     loe .41     /* bit number */
-    inn 8
+    inn EM_WSIZE*2
     zne *4
 
     loc __LINE__
     cal $fail
-    ass 4
+    ass EM_WSIZE
 4
 
     cal $finished
diff --git a/plat/qemuppc/tests/intadd_e.c b/tests/plat/intadd_e.c
similarity index 100%
rename from plat/qemuppc/tests/intadd_e.c
rename to tests/plat/intadd_e.c
diff --git a/plat/qemuppc/tests/intcmp_e.c b/tests/plat/intcmp_e.c
similarity index 100%
rename from plat/qemuppc/tests/intcmp_e.c
rename to tests/plat/intcmp_e.c
diff --git a/plat/qemuppc/tests/intdiv_e.c b/tests/plat/intdiv_e.c
similarity index 100%
rename from plat/qemuppc/tests/intdiv_e.c
rename to tests/plat/intdiv_e.c
diff --git a/plat/qemuppc/tests/intrem_e.c b/tests/plat/intrem_e.c
similarity index 100%
rename from plat/qemuppc/tests/intrem_e.c
rename to tests/plat/intrem_e.c
diff --git a/plat/qemuppc/tests/intshift_e.c b/tests/plat/intshift_e.c
similarity index 83%
rename from plat/qemuppc/tests/intshift_e.c
rename to tests/plat/intshift_e.c
index dd280142c..3cc6d52f9 100644
--- a/plat/qemuppc/tests/intshift_e.c
+++ b/tests/plat/intshift_e.c
@@ -1,3 +1,4 @@
+#include <limits.h>
 #include "test.h"
 
 /* Constants in globals to defeat constant folding. */
@@ -25,8 +26,8 @@ void _m_a_i_n(void)
 
     ASSERT(((unsigned int)one     >>(unsigned int)zero) == 1);
     ASSERT(((unsigned int)one     >>(unsigned int)one)  == 0);
-    ASSERT(((unsigned int)minusone>>(unsigned int)zero) == 0xffffffff);
-    ASSERT(((unsigned int)minusone>>(unsigned int)one)  == 0x7fffffff);
+    ASSERT(((unsigned int)minusone>>(unsigned int)zero) == UINT_MAX);
+    ASSERT(((unsigned int)minusone>>(unsigned int)one)  == (UINT_MAX>>1));
 
     ASSERT((one     <<0) == 1);
     ASSERT((one     <<1)  == 2);
@@ -45,8 +46,8 @@ void _m_a_i_n(void)
 
     ASSERT(((unsigned int)one     >>(unsigned int)0) == 1);
     ASSERT(((unsigned int)one     >>(unsigned int)1)  == 0);
-    ASSERT(((unsigned int)minusone>>(unsigned int)0) == 0xffffffff);
-    ASSERT(((unsigned int)minusone>>(unsigned int)1)  == 0x7fffffff);
+    ASSERT(((unsigned int)minusone>>(unsigned int)0) == UINT_MAX);
+    ASSERT(((unsigned int)minusone>>(unsigned int)1)  == (UINT_MAX>>1));
 
     finished();
 }
\ No newline at end of file
diff --git a/plat/qemuppc/tests/intsub_e.c b/tests/plat/intsub_e.c
similarity index 73%
rename from plat/qemuppc/tests/intsub_e.c
rename to tests/plat/intsub_e.c
index 72ba0ff08..d8f67d3a3 100644
--- a/plat/qemuppc/tests/intsub_e.c
+++ b/tests/plat/intsub_e.c
@@ -1,3 +1,4 @@
+#include <limits.h>
 #include "test.h"
 
 /* Constants in globals to defeat constant folding. */
@@ -19,13 +20,13 @@ void _m_a_i_n(void)
     ASSERT((1   - two) == -1);
 
     ASSERT(((unsigned int)two - (unsigned int)one) == 1);
-    ASSERT(((unsigned int)one - (unsigned int)two) == 0xffffffff);
+    ASSERT(((unsigned int)one - (unsigned int)two) == UINT_MAX);
 
     ASSERT(((unsigned int)two - (unsigned int)1) == 1);
-    ASSERT(((unsigned int)one - (unsigned int)2) == 0xffffffff);
+    ASSERT(((unsigned int)one - (unsigned int)2) == UINT_MAX);
 
     ASSERT(((unsigned int)2   - (unsigned int)one) == 1);
-    ASSERT(((unsigned int)1   - (unsigned int)two) == 0xffffffff);
+    ASSERT(((unsigned int)1   - (unsigned int)two) == UINT_MAX);
 
     finished();
 }
\ No newline at end of file
diff --git a/tests/plat/lib/Test.def b/tests/plat/lib/Test.def
new file mode 100644
index 000000000..cab31f2e8
--- /dev/null
+++ b/tests/plat/lib/Test.def
@@ -0,0 +1,6 @@
+(*$Foreign*)
+DEFINITION MODULE Test;
+  PROCEDURE finished();
+  PROCEDURE writehex(code: LONGINT);
+  PROCEDURE fail(code: LONGINT);
+END Test.
diff --git a/plat/qemuppc/tests/lib/test.c b/tests/plat/lib/test.c
similarity index 71%
rename from plat/qemuppc/tests/lib/test.c
rename to tests/plat/lib/test.c
index 33d72f3ce..426f9944a 100644
--- a/plat/qemuppc/tests/lib/test.c
+++ b/tests/plat/lib/test.c
@@ -6,6 +6,7 @@ void finished(void)
 {
     static const char s[] = "@@FINISHED\n";
     write(1, s, sizeof(s));
+    _exit(0);
 }
 
 void writehex(uint32_t code)
@@ -25,7 +26,10 @@ void writehex(uint32_t code)
 
 void fail(uint32_t code)
 {
-    write(1, "@@FAIL on line 0x", 7);
+    static const char fail_msg[] = "@@FAIL 0x";
+    static const char nl_msg[] = "\n";
+
+    write(1, fail_msg, sizeof(fail_msg)-1);
     writehex(code);
-    write(1, "\n", 1);
+    write(1, nl_msg, sizeof(nl_msg)-1);
 }
diff --git a/plat/qemuppc/tests/lib/test.h b/tests/plat/lib/test.h
similarity index 79%
rename from plat/qemuppc/tests/lib/test.h
rename to tests/plat/lib/test.h
index 96537a2cb..db16506f9 100644
--- a/plat/qemuppc/tests/lib/test.h
+++ b/tests/plat/lib/test.h
@@ -9,6 +9,6 @@ extern void writehex(uint32_t code);
 extern void fail(uint32_t code);
 
 #define ASSERT(condition) \
-    if (!(condition)) fail(__LINE__)
+    do { if (!(condition)) fail(__LINE__); } while(0)
 
 #endif
diff --git a/tests/plat/lib/test_b.c b/tests/plat/lib/test_b.c
new file mode 100644
index 000000000..b2173b4f3
--- /dev/null
+++ b/tests/plat/lib/test_b.c
@@ -0,0 +1,34 @@
+#include <stdint.h>
+#include "test.h"
+
+extern void patch_addresses(uintptr_t* module);
+extern uintptr_t* bmodule_main;
+
+static void i_writehex(intptr_t code)
+{
+	writehex(code);
+}
+
+static void i_fail(intptr_t code)
+{
+	fail(code);
+}
+
+uintptr_t b_finished = (uintptr_t)&finished;
+uintptr_t b_writehex = (uintptr_t)&i_writehex;
+uintptr_t b_fail = (uintptr_t)&i_fail;
+
+static uintptr_t* bmodule_test[] =
+{
+    &b_finished,
+    &b_writehex,
+    &b_fail,
+	0
+};
+
+void binit(void)
+{
+	patch_addresses(&bmodule_test);
+	patch_addresses(&bmodule_main);
+}
+
diff --git a/plat/qemuppc/tests/newdispose_p.p b/tests/plat/newdispose_p.p
similarity index 98%
rename from plat/qemuppc/tests/newdispose_p.p
rename to tests/plat/newdispose_p.p
index 36f09e99b..aa3be5a46 100644
--- a/plat/qemuppc/tests/newdispose_p.p
+++ b/tests/plat/newdispose_p.p
@@ -9,13 +9,13 @@ type
 var
     ptr1 : iptr;
     ptr2 : iptr;
-    
+
 procedure finished;
     extern;
 
 procedure fail(line: integer);
     extern;
-    
+
 #define ASSERT(cond) \
     if (not (cond)) then fail(__LINE__)
 
diff --git a/tests/plat/pascalsets_p.p b/tests/plat/pascalsets_p.p
new file mode 100644
index 000000000..b443b492d
--- /dev/null
+++ b/tests/plat/pascalsets_p.p
@@ -0,0 +1,37 @@
+#
+(*$U+ -- enables underscores in identifiers *)
+
+program pascalsets;
+
+type
+    charset = set of char;
+
+var
+    s : charset;
+    i : integer;
+
+procedure finished;
+    extern;
+
+procedure fail(line: integer);
+    extern;
+
+#define ASSERT(cond) \
+    if (not (cond)) then fail(__LINE__)
+
+begin
+    s := [];
+    for i := 0 to 255 do
+        s := s + [chr(i)];
+
+    i := 99; (* to defeat optimisation *)
+    ASSERT(chr(42) in s);
+    ASSERT(chr(142) in s);
+    ASSERT(chr(i) in s);
+    s := s - [chr(42)];
+    ASSERT(not(chr(42) in s));
+    ASSERT(chr(142) in s);
+    ASSERT(chr(i) in s);
+
+    finished
+end.
diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh
new file mode 100755
index 000000000..384c83b47
--- /dev/null
+++ b/tests/plat/testdriver.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+method=$1
+img=$2
+timeout=$3
+timeoutprog=$4
+
+set -e
+
+result=/tmp/$$.testdriver.result
+trap "rm -f $result" EXIT
+
+errcho() {
+    >&2 echo "$*"
+}
+
+get_test_output() {
+    case $method in
+        qemu-system-*)
+            if ! command -v $method >/dev/null 2>&1 ; then
+                errcho "Warning: $method not installed, skipping test"
+                echo "@@SKIPPED"
+                exit 0
+            fi
+
+            case $method in
+                qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;;
+                qemu-system-ppc)  img="-kernel $img" ;;
+            esac
+
+            $timeoutprog -t $timeout -- $method -nographic $img > $result 2>&1
+            ;;
+
+        qemu-*)
+            if ! command -v $method >/dev/null 2>&1 ; then
+                errcho "Warning: $method not installed, skipping test"
+                echo "@@SKIPPED"
+                exit 0
+            fi
+
+            $method $img > $result 2>&1
+            ;;
+
+        *)
+            errcho "Error: $method not known by testdriver"
+            exit 1
+            ;;
+    esac
+}
+
+get_test_output
+( grep -q '@@FAIL\|@@SKIPPED' $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
+exit 0
diff --git a/util/ack/ack.1.X b/util/ack/ack.1.X
index 689992ac7..8ea920586 100644
--- a/util/ack/ack.1.X
+++ b/util/ack/ack.1.X
@@ -1,20 +1,12 @@
-.\" $Id$
-.de SB
-.\" SuBheader
-.sp 1
-.PP
-.nr Sf \\n(.f
-.ft B
-\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
-.ft \\n(Sf
-.sp 1
-..
-.TH ACK 1 "$Revision$"
+.TH ACK 1 2017-01-18
 .ad
+.
 .SH NAME
 ack \- Amsterdam Compiler Kit
+.
 .SH SYNOPSIS
 \fBack\fP arguments
+.
 .SH DESCRIPTION
 This program transforms sources in several
 languages to load files for a variety of machines,
@@ -51,6 +43,8 @@ Pascal program.
 .IP .c
 C module.
 .IP .b
+B module.
+.IP .bas
 Basic program.
 .IP .ocm
 Occam program.
@@ -68,10 +62,8 @@ Optimized compact EM assembly code.
 Machine assembly language code.
 .IP .o
 Object file.
-.PP
-
+.
 .SH OPTIONS
-
 \fIAck\fP accepts the following flags:
 .IP \-m\fImachine\fP
 This flag tells \fIack\fP to generate a load file for \fImachine\fP.
@@ -100,8 +92,9 @@ Note: \fIack\fP refuses to overwrite argument \fI.e\fP files.
 .IP \-t
 Preserve all intermediate files.
 If two \fB\-t\fP are used,
-\fIack\fP also preserves core dumps and output of failed transformations.
-
+\fIack\fP also preserves output of failed transformations.
+.
+.sp 1
 .IP \-w
 Suppress all warning messages.
 .IP \-v
@@ -113,7 +106,8 @@ Tell the C-compiler to conform to "Kernighan & Ritchie" C.
 Tell \fIack\fP to use the ANSI C compiler instead of the old one.
 .IP \-fp
 Use the software floating point package, if present.
-
+.
+.sp 1
 .IP \-I\fIdir\fP
 \&\`#include\' files whose names do not begin with \`/\' are
 always sought first in the directory of the \fIfile\fP argument,
@@ -131,7 +125,8 @@ preprocessing.
 Don't generate line directives.
 .IP \-C
 Leave C-comments in.
-
+.
+.sp 1
 .IP \-p
 This flag tells both the Pascal and C front ends to include
 code enabling the user to do some monitoring/debugging.
@@ -139,7 +134,16 @@ Each time a routine is entered the routine \fBprocentry\fP
 is called and just before each return \fBprocexit\fP is called.
 These routines are supplied with one parameter, a pointer
 to a string containing the name of the routine.
-
+.
+.sp 1
+.IP \-B\fIname\fP
+Tells the B front end what the name of the module being compiled is, for use
+with separate compilation.
+Defaults to
+.I main
+if not specified. See the section below on compiling B.
+.
+.sp 1
 .IP \-O
 .IP \-O\fInum\fP
 .IP \-O\fIopt1,opt2,...\fP
@@ -228,7 +232,8 @@ for higher levels: as for \-O4.
 Disable the generation of code by the front ends to
 record line number and source file name at run-time.
 (This is the default for C and Fortran).
-
+.
+.sp 1
 .IP \-l\fIname\fP
 Tells \fIack\fP to insert a library module at this point.
 For example: the library \fImon\fP contains the
@@ -248,13 +253,14 @@ These flags tell \fIack\fP to include the libraries needed when
 a file with \fIsuffix\fP would be included in the arguments.
 .IP \-LIB
 This flag tells the peephole optimizer
-.RF em_opt 6
+em_opt(6)
 to add information about the visibility of the names used
 to each output module.
 This is needed by
 assembler/linkers when these modules are to be inserted
 in libraries.
-
+.
+.sp 1
 .IP \-{xxx}
 The string starting after \`{\' and terminated by a \`}\' is passed
 as an option string to the Pascal compiler and supersedes corresponding
@@ -282,7 +288,8 @@ the defaults per program.
 The changed options are recorded in the "e.out" header.
 These flags \-\- and \-+ are passed to the assembler for this purpose.
 So, \-\-t and \-+pfce invert the defaults.
-
+.
+.sp 1
 .IP \-R\fIprogram=xxx\fP
 Replace the \fIprogram\fP by the pathname \fIxxx\fP.
 The program names referred to later in this manual are allowed here.
@@ -309,6 +316,7 @@ Sparc, Vax, Intel 80386.
 .PP
 All arguments without a suffix or with an unrecognized suffix
 are passed to the loaders, as for flags.
+.
 .SH PREPROCESSOR
 All C source programs are run through the preprocessor
 before they are fed to the compiler proper.
@@ -329,13 +337,47 @@ EM_WSIZE:wordsize:EM_PSIZE:pointer size
 EM_SSIZE:size of shorts (C):EM_LSIZE:size of longs (C+Pascal)
 EM_FSIZE:size of floats (C):EM_DSIZE:size of doubles (C+Pascal)
 .TE
-.sp 1
+.PP
 The name of the \fImachine\fP or something like it when
 the machine name is numeric is also defined (as 1).
 As the ANSI C rules forbid this, in ANSI C, underscores are prepended to
 these names.
 .PP
 The default directories searched for include files differ for each machine.
+.
+.SH COMPILING B
+B programs have special needs when compiled with the ACK.
+B modules have to be
+initialised before use, to convert pointer addresses to word addresses; this is
+done automatically when compiling a single B source file to an executable, but
+must be done manually when using separate compilation.
+.PP
+To do this, compile your B modules with the \fI-B\fP option as usual, and then
+use the
+.B abmodules
+program to scan the object files and emit a C file which performs the
+initialisation.
+Then compile this as well into an object file, and link the
+whole lot together.
+The result will be a runnable executable.
+.PP
+Beware \(em referring to an uninitialised module will cause your program to
+crash!
+.PP
+The default initialiser in the B standard library looks for a module called
+\fBmain\fP.
+.PP
+For example:
+.nf
+.sp
+ack -c -mpc86 thismodule.b -Bthismodule
+ack -c -mpc86 thatmodule.b -Bthatmodule
+ack -c -mpc86 theothermodule.b -Btheothermodule
+abmodules -o binit.c thismodule.o thatmodule.o theothermodule.o
+ack -c -mpc86 binit.c
+ack -mpc86 -o pc86.exe thismodule.o thatmodule.o theothermodule.o binit.o
+.fi
+.
 .SH PROGRAMS
 \fIAck\fP uses one or more programs in each phase of the
 transformation.
@@ -354,7 +396,7 @@ input:name:output:description
 \&.f:f77:.c:Fortran-to-C front end
 \&.c:cem:.k:C front end [4,5,6]
 \&.p:pc:.k:Pascal front end [2,3,6]
-\&.b:abc:.k:Basic front end [6,8]
+\&.b:basic:.k:Basic front end [6,8]
 \&.ocm:ocm:.k:Occam front end [9]
 \&.mod:m2:.k:Modula-2 front end [11]
 \&.e:encode:.k:Compactify EM assembly language [1]
@@ -372,6 +414,7 @@ input:name:output:description
 \&.o:cv:a.out:Conversion from Ack object to machine object
 .TE
 .in -2
+.
 .SH "ENVIRONMENT VARIABLES"
 .IP ACKDIR
 If set, this environment variable overrides ack's idea of its home
@@ -382,13 +425,14 @@ machine it compiles for.
 .IP ACKFE
 If set, this environment variable tells ack where to get the front-end
 description file.
+.
 .SH "SEE ALSO"
-.PD 0
 em_opt(6), em_ass(6), em_cg(6), ack.out(5)
 .IP [1]
 A.S. Tanenbaum, Hans van Staveren, Ed Keizer and Johan
 Stevenson, \fIDescription of a machine architecture for use with
 block structured languages\fP, Informatica rapport IR-81.
+.PD 0
 .IP [2]
 K. Jensen and N. Wirth,
 \fIPASCAL, User manual and report\fP Springer Verlag.
@@ -413,12 +457,13 @@ Informatica rapport IR-99.
 .IP [11]
 C.J.H. Jacobs, \fIThe ACK Modula-2 Compiler\fP.
 .PD
+.
 .SH DIAGNOSTICS
-.PD
 The diagnostics are intended to be self\-explanatory.
+.
 .SH BUGS
 Not all warning messages are superseded by \fB\-w\fP.
-.br
+.PP
 Argument assembly files are not preprocessed when fed into the
 universal assembler/loader.
 .SH AUTHOR
diff --git a/util/ack/ack.h b/util/ack/ack.h
index 0877a8c0d..01eec8212 100644
--- a/util/ack/ack.h
+++ b/util/ack/ack.h
@@ -6,6 +6,8 @@
 #define RCS_ACK "$Id$"
 #endif
 
+#include <stdlib.h> /* size_t, free() */
+
 /****************************************************************************/
 /*                      User settable options                               */
 /****************************************************************************/
@@ -61,20 +63,29 @@ typedef struct {
 
 #define p_cont(elem) ((path *)l_content(elem))
 
-/* Return values of setpath() */
-enum f_path { F_OK, F_NOMATCH, F_NOPATH } ;
-
 /* Own routines */
-enum f_path getpath();
-enum f_path scan_end();
-extern void noodstop();
-extern char *getvar();
-extern char *keeps();
-extern char *basename();
-extern char *skipblank();
-extern char *firstblank();
-extern char *getcore();
-extern char *changecore();
+
+/* rmach.c */
+void setlist(char *);
+
+/* svars.c */
+void setsvar(char *, char *);
+void setpvar(char *, char *(*)(void));
+char *getvar(const char *);
+
+/* util.c */
+char *ack_basename(const char *);
+char *skipblank(char *);
+char *firstblank(char *);
+void fatal(const char *, ...);
+void vprint(const char *, ...);
+void fuerror(const char *, ...);
+void werror(const char *, ...);
+void quit(int);
+char *keeps(const char *);
+#define throws(str)  free(str)
+void *getcore(size_t);
+void *changecore(void *, size_t);
 #define freecore(area)  free(area)
 
 #define DEBUG	1	/* Allow debugging of Ack */
diff --git a/util/ack/build.lua b/util/ack/build.lua
index 4394484b4..cb9b66fd4 100644
--- a/util/ack/build.lua
+++ b/util/ack/build.lua
@@ -18,12 +18,28 @@ normalrule {
 cprogram {
 	name = "ack",
 	srcs = {
-		"./*.c",
+		"./data.c",
+		"./files.c",
+		"./grows.c",
+		"./list.c",
+		"./main.c",
+		"./rmach.c",
+		"./run.c",
+		"./scan.c",
+		"./svars.c",
+		"./trans.c",
+		"./util.c",
 		"+tables",
 	},
 	deps = {
 		"h+emheaders",
 		"h+local",
+		"./ack.h",
+		"./data.h",
+		"./dmach.h",
+		"./grows.h",
+		"./list.h",
+		"./trans.h",
 	}
 }
 
diff --git a/util/ack/data.h b/util/ack/data.h
index d6ae07855..ea845c4f7 100644
--- a/util/ack/data.h
+++ b/util/ack/data.h
@@ -48,4 +48,4 @@ EXTERN  path            in;             /* The current single input pathname */
 EXTERN  path            out;            /* The current output pathname */
 EXTERN  path            orig;           /* The original input path */
 EXTERN  char            *p_basename;    /* The current basename */
-EXTERN  char            *p_suffix;      /* The current input suffix */
+EXTERN  const char      *p_suffix;      /* The current input suffix */
diff --git a/util/ack/files.c b/util/ack/files.c
index f2dbc8ed2..e149b90f7 100644
--- a/util/ack/files.c
+++ b/util/ack/files.c
@@ -16,7 +16,7 @@
 static char rcs_id[] = "$Id$" ;
 #endif
 
-char *add_u(part,ptr) char *ptr ; {
+static char *add_u(int part, char *ptr) {
 	if ( part>=26 ) {
 		ptr=add_u(part/26-1,ptr) ;
 	}
@@ -24,7 +24,7 @@ char *add_u(part,ptr) char *ptr ; {
 	return ptr+1 ;
 }
 
-char *unique() {
+static char *unique(void) {
 	/* Get the next unique part of the internal filename */
 	static int u_next = 0 ;
 	static char buf[10] ;
@@ -36,7 +36,7 @@ char *unique() {
 	return buf ;
 }
 
-setfiles(phase) register trf *phase ; {
+int setfiles(trf *phase) {
 	/* Set the out structure according to the in structure,
 	   the transformation and some global data */
 	growstring pathname ;
@@ -94,18 +94,7 @@ setfiles(phase) register trf *phase ; {
 	return 1 ;
 }
 
-disc_files(phase) trf *phase ; {
-	path temp ;
-
-	if ( !phase->t_combine ) {
-		file_final(&in) ;
-	} else {
-		disc_inputs(phase) ;
-	}
-	temp=in ; in=out ; out=temp ;
-}
-
-file_final(file) path *file ; {
+static void file_final(path *file) {
 	if ( file->p_path ) {
 		if ( !file->p_keep && t_flag<=1 ) {
 			if ( unlink(file->p_path)!=0 ) {
@@ -119,7 +108,18 @@ file_final(file) path *file ; {
 	file->p_keep=NO ;
 }
 
-disc_inputs(phase) trf *phase ; {
+void disc_files(trf *phase) {
+	path temp ;
+
+	if ( !phase->t_combine ) {
+		file_final(&in) ;
+	} else {
+		disc_inputs(phase) ;
+	}
+	temp=in ; in=out ; out=temp ;
+}
+
+void disc_inputs(trf *phase) {
 	/* Remove all the input files of this phase */
 	/* Only for combiners */
 	register path *l_in ;
@@ -132,7 +132,7 @@ disc_inputs(phase) trf *phase ; {
 	l_clear(&phase->t_inputs) ;
 }
 
-rmfile(file) path *file ; {
+void rmfile(path *file) {
 	/* Remove a file, do not complain when is does not exist */
 	if ( file->p_path ) {
 		if ( t_flag<=1 ) unlink(file->p_path) ;
@@ -143,8 +143,7 @@ rmfile(file) path *file ; {
 	}
 }
 
-void
-rmtemps() {
+void rmtemps(void) {
 	/* Called in case of disaster, always remove the current output file!
 	*/
 	register list_elem *elem ;
@@ -159,7 +158,7 @@ rmtemps() {
 	}
 }
 
-add_input(file,phase) path *file ; trf *phase ; {
+void add_input(path *file, trf *phase) {
 	register path *store ;
 #ifdef DEBUG
 	if ( debug ) {
diff --git a/util/ack/grows.c b/util/ack/grows.c
index 81c3c002d..a74e27731 100644
--- a/util/ack/grows.c
+++ b/util/ack/grows.c
@@ -19,7 +19,7 @@ static char rcs_id[] = "$Id$" ;
 static char rcs_grows[] = RCS_GROWS ;
 #endif
 
-gr_add(id,c) register growstring *id ; char c ; {
+int gr_add(growstring *id, int c) {
 	if ( id->gr_size==id->gr_max) {
 		if ( id->gr_size==0 ) { /* The first time */
 			id->gr_max= 2*GR_MORE ;
@@ -32,8 +32,8 @@ gr_add(id,c) register growstring *id ; char c ; {
 	*(id->gr_string+id->gr_size++)= c ;
 }
 
-gr_cat(id,string) growstring *id ; char *string ; {
-	register char *ptr ;
+int gr_cat(growstring *id, const char *string) {
+	const char *ptr ;
 
 #ifdef DEBUG
 	if ( id->gr_size && *(id->gr_string+id->gr_size-1) ) {
@@ -50,8 +50,7 @@ gr_cat(id,string) growstring *id ; char *string ; {
 	}
 }
 
-void
-gr_throw(id) register growstring *id ; {
+void gr_throw(growstring *id) {
 	/* Throw the string away */
 	if ( id->gr_max==0 ) return ;
 	freecore(id->gr_string) ;
@@ -60,11 +59,11 @@ gr_throw(id) register growstring *id ; {
 	id->gr_size=0 ;
 }
 
-gr_init(id) growstring *id ; {
+void gr_init(growstring *id) {
 	id->gr_size=0 ; id->gr_max=0 ;
 }
 
-char *gr_final(id) growstring *id ; {
+char *gr_final(growstring *id) {
 	/* Throw away the bookkeeping, adjust the string to its final
 	   length and return a pointer to a string to be get rid of with
 	   throws
diff --git a/util/ack/grows.h b/util/ack/grows.h
index 9b9511049..04f95aa59 100644
--- a/util/ack/grows.h
+++ b/util/ack/grows.h
@@ -20,8 +20,8 @@ typedef struct {
 
 /* Routines used */
 
-extern  void    gr_throw() ;    /* To free the core */
-extern  int     gr_add() ;      /* To add one character */
-extern  int     gr_cat() ;      /* concatenate the contents and the string */
-extern  int     gr_init() ;     /* Initialize the bookkeeping */
-extern  char    *gr_final() ;   /* Transform to a stable storage string */
+void     gr_throw(growstring *) ;               /* To free the core */
+int      gr_add(growstring *, int) ;            /* To add one character */
+int      gr_cat(growstring *, const char *) ;   /* To append a string */
+void     gr_init(growstring *) ;        /* Initialize the bookkeeping */
+char    *gr_final(growstring *) ;       /* Move to a stable storage string */
diff --git a/util/ack/list.c b/util/ack/list.c
index 278f55580..5370e96cb 100644
--- a/util/ack/list.c
+++ b/util/ack/list.c
@@ -33,7 +33,7 @@ Routines:
 */
 
 
-l_add(header,string) list_head *header ; char *string ; {
+void l_add(list_head *header, char *string) {
 	register list_elem *new;
 
 	/* NOSTRICT */
@@ -49,7 +49,7 @@ l_add(header,string) list_head *header ; char *string ; {
 	header->ca_last= new ;
 }
 
-l_clear(header) list_head *header ; {
+void l_clear(list_head *header) {
 	register list_elem *old, *next;
 	for ( old=header->ca_first ; old ; old= next ) {
 		next= old->ca_next ;
@@ -59,7 +59,7 @@ l_clear(header) list_head *header ; {
 	header->ca_last = (list_elem *) 0 ;
 }
 
-l_throw(header) list_head *header ; {
+void l_throw(list_head *header) {
 	register list_elem *old, *next;
 	for ( old=header->ca_first ; old ; old= next ) {
 		throws(l_content(*old)) ;
diff --git a/util/ack/list.h b/util/ack/list.h
index 3e6d55170..f96d8ce15 100644
--- a/util/ack/list.h
+++ b/util/ack/list.h
@@ -29,3 +29,7 @@ typedef struct ca_elem list_elem ;         /* The decl. for elements */
 /* To be used for scanning lists, ptr is the running variable */
 #define scanlist(elem,ptr) \
 	for ( ptr= elem ; ptr; ptr= l_next(*ptr) )
+
+void l_add(list_head *, char *);
+void l_clear(list_head *);
+void l_throw(list_head *);
diff --git a/util/ack/main.c b/util/ack/main.c
index 99e27dceb..a57454d60 100644
--- a/util/ack/main.c
+++ b/util/ack/main.c
@@ -15,444 +15,569 @@
 #include <signal.h>
 
 #ifndef NORCSID
-static char rcs_id[] = "$Id$" ;
-static char rcs_ack[] = RCS_ACK ;
+static char rcs_id[] = "$Id$";
+static char rcs_ack[] = RCS_ACK;
 #endif
 
-static int sigs[] = { SIGINT, SIGHUP, SIGTERM, 0 } ;
+static int sigs[] = { SIGINT, SIGHUP, SIGTERM, 0 };
 static int arg_count;
 
-extern  char    *getenv();
+static char* srcvar(void);
+static char* getsuffix(void);
+static void varinit(void);
+static void vieuwargs(int, char**);
+static void firstarg(char*);
+static int process(char*);
+static int startrf(trf*);
+static void block(trf*);
+static int mayprep(void);
+static void scanneeds(void);
+static void setneeds(const char*, int);
+static void noodstop(int);
 
-void vieuwargs();
+int main(int argc, char** argv)
+{
+	register list_elem* elem;
+	register char* frontend;
+	register int* n_sig;
+	register trf* phase;
 
-main(argc,argv) char **argv ; {
-	register list_elem *elem ;
-	register char *frontend ;
-	register int *n_sig ;
-	register trf *phase ;
-
-	progname=argv[0];
+	progname = argv[0];
 	varinit();
-	vieuwargs(argc,argv);
-	if ( (frontend=getenv("ACKFE")) ) {
-		setlist(frontend) ;
-	} else {
+	vieuwargs(argc, argv);
+	if ((frontend = getenv("ACKFE")))
+	{
+		setlist(frontend);
+	}
+	else
+	{
 		setlist(FRONTENDS);
 	}
-	if ( callname ) {
-		if ( machine ) {
+	if (callname)
+	{
+		if (machine)
+		{
 			fuerror("can not produce code for both %s and %s",
-				callname,machine) ;
+			    callname, machine);
 		}
-		machine= callname ;
+		machine = callname;
 	}
-	if ( !machine && ! (machine=getenv("ACKM")) ) {
+	if (!machine && !(machine = getenv("ACKM")))
+	{
 #ifdef ACKM
-		machine= ACKM;          /* The default machine */
+		machine = ACKM; /* The default machine */
 #else
-		fuerror("No machine specified") ;
+		fuerror("No machine specified");
 #endif
 	}
 	setlist(machine);
 	/* Find the linker, needed for argument building */
-	scanlist(l_first(tr_list),elem) {
-		if ( t_cont(*elem)->t_linker ) {
-			linker= t_cont(*elem) ;
+	scanlist(l_first(tr_list), elem)
+	{
+		if (t_cont(*elem)->t_linker)
+		{
+			linker = t_cont(*elem);
 		}
 	}
 	transini();
 	scanneeds();
-	sprintf(template,TMPNAME,getpid()) ;
-	if ( n_error && !k_flag ) exit(n_error) ;
+	sprintf(template, TMPNAME, getpid());
+	if (n_error && !k_flag)
+		exit(n_error);
 
-	for ( n_sig=sigs ; *n_sig ; n_sig++ ) {
-		if ( signal(*n_sig,noodstop)==SIG_IGN ) {
-			signal(*n_sig,SIG_IGN) ;
+	for (n_sig = sigs; *n_sig; n_sig++)
+	{
+		if (signal(*n_sig, noodstop) == SIG_IGN)
+		{
+			signal(*n_sig, SIG_IGN);
 		}
 	}
 
-	scanlist ( l_first(arguments), elem ) {
+	scanlist(l_first(arguments), elem)
+	{
 		arg_count++;
 	}
 
-	scanlist ( l_first(arguments), elem ) {
-		if ( !process(l_content(*elem)) && !k_flag ) exit(1) ;
+	scanlist(l_first(arguments), elem)
+	{
+		if (!process(l_content(*elem)) && !k_flag)
+			exit(1);
 	}
-	orig.p_path= (char *)0 ;
-	if ( !rts ) rts="." ;
-	setsvar(keeps(RTS),rts) ;
-	if ( linker ) getmapflags(linker) ;
+	orig.p_path = (char*)0;
+	if (!rts)
+		rts = ".";
+	setsvar(keeps(RTS), rts);
+	if (linker)
+		getmapflags(linker);
 
-	scanlist(l_first(tr_list),elem) {
-		phase=t_cont(*elem) ;
-		if ( phase->t_combine && phase->t_do ) {
-			if ( phase->t_blocked ) {
+	scanlist(l_first(tr_list), elem)
+	{
+		phase = t_cont(*elem);
+		if (phase->t_combine && phase->t_do)
+		{
+			if (phase->t_blocked)
+			{
 #ifdef DEBUG
-				if ( debug ) {
+				if (debug)
+				{
 					vprint("phase %s is blocked\n",
-						phase->t_name) ;
+					    phase->t_name);
 				}
 #endif
-				disc_inputs(phase) ;
-				continue ;
+				disc_inputs(phase);
+				continue;
 			}
-			orig.p_keep=YES ;
-			orig.p_keeps=NO ;
-			orig.p_path=phase->t_origname ;
-			if ( p_basename ) throws(p_basename) ;
-			if ( orig.p_path ) {
-				p_basename= keeps(basename(orig.p_path)) ;
-			} else {
-				p_basename=0 ;
+			orig.p_keep = YES;
+			orig.p_keeps = NO;
+			orig.p_path = phase->t_origname;
+			if (p_basename)
+				throws(p_basename);
+			if (orig.p_path)
+			{
+				p_basename = keeps(ack_basename(orig.p_path));
 			}
-			if ( !startrf(phase) && !k_flag ) exit(1) ;
+			else
+			{
+				p_basename = 0;
+			}
+			if (!startrf(phase) && !k_flag)
+				exit(1);
 		}
 	}
 
-	if ( n_error ) exit(n_error) ;
+	if (n_error)
+		exit(n_error);
 
-	exit(0) ;
+	exit(0);
 }
 
-char *srcvar() {
-	return orig.p_path ;
+static char* srcvar(void)
+{
+	return orig.p_path;
 }
 
-char *getsuffix() {
-	return strrchr(orig.p_path, SUFCHAR) ;
+static char* getsuffix(void)
+{
+	return strrchr(orig.p_path, SUFCHAR);
 }
 
-varinit() {
+static void varinit(void)
+{
 	/* initialize the string variables */
-	register char *envstr ;
-	extern char *em_dir;
+	register char* envstr;
+	extern char* em_dir;
 
-	if ( envstr=getenv("ACKDIR") ) {
+	if (envstr = getenv("ACKDIR"))
+	{
 		em_dir = keeps(envstr);
 	}
-	setsvar(keeps(HOME),em_dir) ;
-	setpvar(keeps(SRC),srcvar)  ;
-	setpvar(keeps(SUFFIX),getsuffix) ;
+	setsvar(keeps(HOME), em_dir);
+	setpvar(keeps(SRC), srcvar);
+	setpvar(keeps(SUFFIX), getsuffix);
 }
 
 /************************* flag processing ***********************/
 
-void
-vieuwargs(argc,argv) char **argv ; {
-	register char *argp;
-	register int nextarg ;
-	register int eaten ;
-	int hide ;
+void vieuwargs(int argc, char** argv)
+{
+	register char* argp;
+	register int nextarg;
+	register int eaten;
+	int hide;
 
-	firstarg(argv[0]) ;
+	firstarg(argv[0]);
 
-	nextarg= 1 ;
+	nextarg = 1;
 
-	while ( nextarg<argc ) {
-		argp= argv[nextarg] ;
-		nextarg++ ;
-		if ( argp[0]!='-' || argp[1]=='l' ) {
+	while (nextarg < argc)
+	{
+		argp = argv[nextarg];
+		nextarg++;
+		if (argp[0] != '-' || argp[1] == 'l')
+		{
 			/* Not a flag, or a library */
-			l_add(&arguments,argp) ;
-			continue ;
+			l_add(&arguments, argp);
+			continue;
 		}
 
 		/* Flags */
-		hide=NO ; /* Do not hide this flags to the phases */
-		eaten=0 ; /* Did not 'eat' tail of flag yet */
-		switch ( argp[1] ) {
-	   case 'm':    if ( machine ) fuerror("Two machines?") ;
-			machine= &argp[2];
-			if (*machine == '\0') {
-				fuerror("-m needs machine name");
-			}
-			eaten=1 ;
-			break ;
-	   case 'o':    if ( nextarg>=argc ) {
-				fuerror("-o can't be the last flag") ;
-			}
-			if ( outfile ) fuerror("Two results?") ;
-			outfile= argv[nextarg++] ;
-			hide=YES ;
-			break ;
-	   case 'O':    Optlevel = atoi(&argp[2]);
-			if (! Optlevel) Optlevel = 1;
-			Optlist= &argp[2] ;
-			eaten=1 ;
-			break ;
-	   case 'v':    if ( argp[2] ) {
-				v_flag += atoi(&argp[2]) ;
-				eaten=1 ;
-			} else {
-	   			v_flag++ ;
-			}
+		hide = NO; /* Do not hide this flags to the phases */
+		eaten = 0; /* Did not 'eat' tail of flag yet */
+		switch (argp[1])
+		{
+			case 'm':
+				if (machine)
+					fuerror("Two machines?");
+				machine = &argp[2];
+				if (*machine == '\0')
+				{
+					fuerror("-m needs machine name");
+				}
+				eaten = 1;
+				break;
+			case 'o':
+				if (nextarg >= argc)
+				{
+					fuerror("-o can't be the last flag");
+				}
+				if (outfile)
+					fuerror("Two results?");
+				outfile = argv[nextarg++];
+				hide = YES;
+				break;
+			case 'O':
+				Optlevel = atoi(&argp[2]);
+				if (!Optlevel)
+					Optlevel = 1;
+				Optlist = &argp[2];
+				eaten = 1;
+				break;
+			case 'v':
+				if (argp[2])
+				{
+					v_flag += atoi(&argp[2]);
+					eaten = 1;
+				}
+				else
+				{
+					v_flag++;
+				}
 #ifdef DEBUG
-	   		if ( v_flag>=3 ) debug=v_flag-2 ;
+				if (v_flag >= 3)
+					debug = v_flag - 2;
 #endif
-			break ;
-	   case 'c':    if ( stopsuffix ) fuerror("Two -c flags") ;
-			stopsuffix= &argp[2]; eaten=1;
-			if ( *stopsuffix && *stopsuffix!=SUFCHAR ) {
-				fuerror("-c flag has invalid tail") ;
-			}
-			break ;
-	   case 'k':    k_flag++ ;
-			break ;
-	   case 't':    t_flag++ ;
-			break ;
-	   case 'R':    eaten=1;
-			break ;
-	   case 'r':    if ( argp[2]!=SUFCHAR ) {
-				error("-r must be followed by %c",SUFCHAR) ;
-			}
-			keeptail(&argp[2]); eaten=1 ;
-			break ;
-	   case '.':    if ( rts ) {
-	   			if ( strcmp(rts,&argp[1])!=0 )
-					fuerror("Two run-time systems?") ;
-			} else {
-				rts= &argp[1] ;
-				keephead(rts) ; keeptail(rts) ;
-			}
-			eaten=1 ;
-			break ;
-	   case  0 :    nill_flag++ ; eaten++ ;
-	   		hide=YES ;
-			break;
-	   case 'w':    w_flag++;
-			break ;
-	   default:     /* The flag is not recognized,
+				break;
+			case 'c':
+				if (stopsuffix)
+					fuerror("Two -c flags");
+				stopsuffix = &argp[2];
+				eaten = 1;
+				if (*stopsuffix && *stopsuffix != SUFCHAR)
+				{
+					fuerror("-c flag has invalid tail");
+				}
+				break;
+			case 'k':
+				k_flag++;
+				break;
+			case 't':
+				t_flag++;
+				break;
+			case 'R':
+				eaten = 1;
+				break;
+			case 'r':
+				if (argp[2] != SUFCHAR)
+				{
+					error("-r must be followed by %c", SUFCHAR);
+				}
+				l_add(&tail_list, &argp[2]);
+				eaten = 1;
+				break;
+			case '.':
+				if (rts)
+				{
+					if (strcmp(rts, &argp[1]) != 0)
+						fuerror("Two run-time systems?");
+				}
+				else
+				{
+					rts = &argp[1];
+					l_add(&head_list, rts);
+					l_add(&tail_list, rts);
+				}
+				eaten = 1;
+				break;
+			case 0:
+				nill_flag++;
+				eaten++;
+				hide = YES;
+				break;
+			case 'w':
+				w_flag++;
+				break;
+			default: /* The flag is not recognized,
 			   put it on the list for the sub-processes
 			*/
 #ifdef DEBUG
-			if ( debug ) {
-				vprint("Flag %s: phase dependent\n",argp) ;
-			}
+				if (debug)
+				{
+					vprint("Flag %s: phase dependent\n", argp);
+				}
 #endif
-			l_add(&flags,keeps(argp)) ;
-			eaten=1 ;
-			hide=YES ;
+				l_add(&flags, keeps(argp));
+				eaten = 1;
+				hide = YES;
 		}
-		if ( !hide ) {
-			register char *tokeep ;
-			tokeep=keeps(argp) ;
-			if ( argp[1]=='R' ) {
-				do_Rflag(tokeep); 
-			} else {
-				*tokeep |= NO_SCAN ;
+		if (!hide)
+		{
+			register char* tokeep;
+			tokeep = keeps(argp);
+			if (argp[1] == 'R')
+			{
+				l_add(&R_list, tokeep);
 			}
-			l_add(&flags,tokeep) ;
+			else
+			{
+				*tokeep |= NO_SCAN;
+			}
+			l_add(&flags, tokeep);
 		}
-		if ( argp[2] && !eaten ) {
-			werror("Unexpected characters at end of %s",argp) ;
+		if (argp[2] && !eaten)
+		{
+			werror("Unexpected characters at end of %s", argp);
 		}
 	}
-	return ;
+	return;
 }
 
-firstarg(argp) register char *argp ; {
-	register char *name ;
+static void firstarg(char* argp)
+{
+	register char* name;
 
-	name=strrchr(argp,'/') ;
-	if ( name && *(name+1) ) {
-		name++ ;
-	} else {
-		name= argp ;
+	name = strrchr(argp, '/');
+	if (name && *(name + 1))
+	{
+		name++;
 	}
-	callname= name;
+	else
+	{
+		name = argp;
+	}
+	callname = name;
 }
 
 /************************* argument processing ***********************/
 
-process(arg) char *arg ; {
+static int process(char* arg)
+{
 	/* Process files & library arguments */
-	trf *phase ;
-	register trf *tmp ;
+	trf* phase;
+	register trf* tmp;
 
 #ifdef DEBUG
-	if ( debug ) vprint("Processing %s\n",arg) ;
+	if (debug)
+		vprint("Processing %s\n", arg);
 #endif
-	p_suffix= strrchr(arg,SUFCHAR) ;
-	orig.p_keep= YES ;      /* Don't throw away the original ! */
-	orig.p_keeps= NO;
-	orig.p_path= arg ;
-	if ( arg[0]=='-' || !p_suffix ) {
-		if ( linker ) add_input(&orig,linker) ;
-		return 1 ;
+	p_suffix = strrchr(arg, SUFCHAR);
+	orig.p_keep = YES; /* Don't throw away the original ! */
+	orig.p_keeps = NO;
+	orig.p_path = arg;
+	if (arg[0] == '-' || !p_suffix)
+	{
+		if (linker)
+			add_input(&orig, linker);
+		return 1;
 	}
-	if ( p_basename ) throws(p_basename) ;
-	p_basename= keeps(basename(arg)) ;
+	if (p_basename)
+		throws(p_basename);
+	p_basename = keeps(ack_basename(arg));
 	/* Try to find a path through the transformations */
-	switch( getpath(&phase) ) {
-	case F_NOPATH :
-		error("Cannot produce the desired file from %s",arg) ;
-		if ( linker ) add_input(&orig,linker) ;
-		return 1 ;
-	case F_NOMATCH :
-		if ( stopsuffix ) werror("Unknown suffix in %s",arg) ;
-		if ( linker ) add_input(&orig,linker) ;
-		return 1 ;
-	case F_OK :
-		break ;
+	switch (getpath(&phase))
+	{
+		case F_NOPATH:
+			error("Cannot produce the desired file from %s", arg);
+			if (linker)
+				add_input(&orig, linker);
+			return 1;
+		case F_NOMATCH:
+			if (stopsuffix)
+				werror("Unknown suffix in %s", arg);
+			if (linker)
+				add_input(&orig, linker);
+			return 1;
+		case F_OK:
+			break;
 	}
-	if ( !phase ) return 1 ;
-	for ( tmp=phase ; tmp ; tmp=tmp->t_next )
-	if ( !tmp->t_visited ) {
-		/* The flags are set up once.
+	if (!phase)
+		return 1;
+	for (tmp = phase; tmp; tmp = tmp->t_next)
+		if (!tmp->t_visited)
+		{
+			/* The flags are set up once.
 		   At the first time each phase is in a list.
 		   The program name and flags may already be touched
 		   by vieuwargs.
 		*/
-		tmp->t_visited=YES ;
-		if ( tmp->t_priority<0 )
-			werror("Using phase %s (negative priority)",
-				tmp->t_name) ;
-		if ( !rts && tmp->t_rts ) rts= tmp->t_rts ;
-		if ( tmp->t_needed ) {
-			add_head(tmp->t_needed) ;
-			add_tail(tmp->t_needed) ;
+			tmp->t_visited = YES;
+			if (tmp->t_priority < 0)
+				werror("Using phase %s (negative priority)",
+				    tmp->t_name);
+			if (!rts && tmp->t_rts)
+				rts = tmp->t_rts;
+			if (tmp->t_needed)
+			{
+				add_head(tmp->t_needed);
+				add_tail(tmp->t_needed);
+			}
 		}
+	if (phase->t_combine)
+	{
+		add_input(&orig, phase);
+		return 1;
 	}
-	if ( phase->t_combine ) {
-		add_input(&orig,phase) ;
-		return 1 ;
-	}
-	in= orig ;
-	if ( !nill_flag && arg_count > 1 ) {
-		printf("%s\n",arg) ;
-	}
-	return startrf(phase) ;
+	in = orig;
+	return startrf(phase);
 }
 
-int startrf(first) trf *first ; {
+static int startrf(trf* first)
+{
 	/* Start the transformations at the indicated phase */
-	register trf *phase ;
+	register trf* phase;
 
-	phase=first ;
-	for(;;) {
+	phase = first;
+	for (;;)
+	{
 		int do_preprocess = 0;
 		int only_prep = 0;
 
-		switch ( phase->t_prep ) {
+		switch (phase->t_prep)
+		{
 			/* BEWARE, sign extension */
-		case NO :    break ;
-		default :    if ( !mayprep() ) break ;
-		case YES:    do_preprocess = 1;
-			     break;
+			case NO:
+				break;
+			default:
+				if (!mayprep())
+					break;
+			case YES:
+				do_preprocess = 1;
+				break;
 		}
-		if ( cpp_trafo && stopsuffix &&
-		     strcmp(cpp_trafo->t_out,stopsuffix)==0 ) {
+		if (cpp_trafo && stopsuffix && strcmp(cpp_trafo->t_out, stopsuffix) == 0)
+		{
 			/* user explicitly asked for preprocessing */
 			do_preprocess = 1;
 			only_prep = 1;
 		}
 
-		if (do_preprocess && !transform(cpp_trafo) ) {
-				   n_error++ ;
+		if (do_preprocess && !transform(cpp_trafo))
+		{
+			n_error++;
 #ifdef DEBUG
-				   vprint("Pre-processor failed\n") ;
+			vprint("Pre-processor failed\n");
 #endif
-				   return 0 ;
+			return 0;
 		}
-		if ( only_prep ) {
-			break ;
+		if (only_prep)
+		{
+			break;
 		}
-		if ( !transform(phase) ) {
-			n_error++ ;
-			block(phase->t_next) ;
+		if (!transform(phase))
+		{
+			n_error++;
+			block(phase->t_next);
 #ifdef DEBUG
-			if ( debug ) {
-				if ( !orig.p_path ) {
+			if (debug)
+			{
+				if (!orig.p_path)
+				{
 					vprint("phase %s failed\n",
-						phase->t_name ) ;
-				} else {
+					    phase->t_name);
+				}
+				else
+				{
 					vprint("phase %s for %s failed\n",
-					        phase->t_name,orig.p_path) ;
+					    phase->t_name, orig.p_path);
 				}
 			}
 #endif
-			return 0 ;
+			return 0;
 		}
-		first=NO ;
-		phase=phase->t_next ;
-		if ( !phase ) {
+		first = NO;
+		phase = phase->t_next;
+		if (!phase)
+		{
 #ifdef DEBUG
-if ( debug ) vprint("Transformation sequence complete for %s\n",
-				orig.p_path) ;
+			if (debug)
+				vprint("Transformation sequence complete for %s\n",
+				    orig.p_path);
 #endif
 			/* No more work on this file */
-			if ( !in.p_keep ) {
-				fatal("attempt to discard the result file") ;
+			if (!in.p_keep)
+			{
+				fatal("attempt to discard the result file");
 			}
-			if ( in.p_keeps ) throws(in.p_path) ;
-			in.p_keep=NO ; in.p_keeps=NO ; in.p_path= (char *) 0 ;
-			return 1 ;
+			if (in.p_keeps)
+				throws(in.p_path);
+			in.p_keep = NO;
+			in.p_keeps = NO;
+			in.p_path = (char*)0;
+			return 1;
 		}
-		if ( phase->t_combine ) {
-			add_input(&in,phase) ;
-			break ;
+		if (phase->t_combine)
+		{
+			add_input(&in, phase);
+			break;
 		}
 	}
-	return 1 ;
+	return 1;
 }
 
-block(first) trf *first ; {
+static void block(trf* first)
+{
 	/* One of the input files of this phase could not be produced,
 	   block all combiners taking their input from this one.
 	*/
-	register trf *phase ;
-	for ( phase=first ; phase ; phase=phase->t_next ) {
-		if ( phase->t_combine ) phase->t_blocked=YES ;
+	register trf* phase;
+	for (phase = first; phase; phase = phase->t_next)
+	{
+		if (phase->t_combine)
+			phase->t_blocked = YES;
 	}
 }
-mayprep() {
-	int file ;
-	char fc ;
-	file=open(in.p_path,0);
-	if ( file<0 ) return 0 ;
-	if ( read(file,&fc,1)!=1 ) fc=0 ;
-	close(file) ;
-	return fc=='#' ;
+
+static int mayprep(void)
+{
+	int file;
+	char fc;
+	file = open(in.p_path, 0);
+	if (file < 0)
+		return 0;
+	if (read(file, &fc, 1) != 1)
+		fc = 0;
+	close(file);
+	return fc == '#';
 }
 
-keephead(suffix) char *suffix ; {
-	l_add(&head_list, suffix) ;
+static void scanneeds(void)
+{
+	register list_elem* elem;
+	scanlist(l_first(head_list), elem) { setneeds(l_content(*elem), 0); }
+	l_clear(&head_list);
+	scanlist(l_first(tail_list), elem) { setneeds(l_content(*elem), 1); }
+	l_clear(&tail_list);
 }
 
-keeptail(suffix) char *suffix ; {
-	l_add(&tail_list, suffix) ;
-}
+static void setneeds(const char* suffix, int tail)
+{
+	trf* phase;
 
-scanneeds() {
-	register list_elem *elem ;
-	scanlist(l_first(head_list), elem) { setneeds(l_content(*elem),0) ; }
-	l_clear(&head_list) ;
-	scanlist(l_first(tail_list), elem) { setneeds(l_content(*elem),1) ; }
-	l_clear(&tail_list) ;
-}
-
-setneeds(suffix,tail) char *suffix ; {
-	trf *phase ;
-
-	p_suffix= suffix ;
-	switch ( getpath(&phase) ) {
-	case F_OK :
-		for ( ; phase ; phase= phase->t_next ) {
-			if ( phase->t_needed ) {
-				if ( tail )
-					add_tail(phase->t_needed) ;
-				else
-					add_head(phase->t_needed) ;
+	p_suffix = suffix;
+	switch (getpath(&phase))
+	{
+		case F_OK:
+			for (; phase; phase = phase->t_next)
+			{
+				if (phase->t_needed)
+				{
+					if (tail)
+						add_tail(phase->t_needed);
+					else
+						add_head(phase->t_needed);
+				}
 			}
-		}
-		break ;
-	case F_NOMATCH :
-		werror("\"%s\": unrecognized suffix",suffix) ;
-		break ;
-	case F_NOPATH :
-		werror("sorry, cannot produce the desired file(s) from %s files",
-			suffix) ;
-		break ;
+			break;
+		case F_NOMATCH:
+			werror("\"%s\": unrecognized suffix", suffix);
+			break;
+		case F_NOPATH:
+			werror("sorry, cannot produce the desired file(s) from %s files",
+			    suffix);
+			break;
 	}
 }
+
+static void noodstop(int sig)
+{
+	quit(-3);
+}
diff --git a/util/ack/rmach.c b/util/ack/rmach.c
index 1e33e8713..13f904a38 100644
--- a/util/ack/rmach.c
+++ b/util/ack/rmach.c
@@ -47,19 +47,17 @@ static char rcs_dmach[] = RCS_DMACH ;
 #define CALL	"callname"
 #define END     "end"
 
-extern growstring scanb();
-extern growstring scanvars();
+static void intrf(void) ;
+static void open_in(char *) ;
+static void close_in(void) ;
+static int getinchar(void) ;
+static int getln(void) ;
 
-int getln() ;
-int getinchar() ;
 static char *ty_name ;
 static char *bol ;
-
-void open_in();
-
 static char *inname ;
 
-setlist(name) char *name ; {
+void setlist(char *name) {
 	/* Name is sought in the internal tables,
 	   if not present, the a file of that name is sought
 	   in first the current and then the EM Lib directory
@@ -92,9 +90,7 @@ setlist(name) char *name ; {
 #endif
 }
 
-static int inoptlist(nm)
-	char *nm ;
-{
+static int inoptlist(char *nm) {
 	register char *p=Optlist ;
 
 	while ( p && *p ) {
@@ -107,9 +103,9 @@ static int inoptlist(nm)
 	return 0;
 }
 
-intrf() {
+static void intrf(void) {
+	/* Read in trf (transformation) */
 	register trf *new ;
-	growstring bline ;
 	int twice ;
 	int name_seen=0 ;
 
@@ -130,20 +126,14 @@ intrf() {
 		} else
 		if ( strcmp(ty_name,PROG)==0 ) {
 			if ( new->t_prog ) twice=YES ;
-			bline= scanb(bol);                /* Scan for \ */
-                      new->t_prog= gr_final(&bline);
+			new->t_prog= keeps(bol);
 		} else
 		if ( strcmp(ty_name,MAPF)==0 ) {
-			/* First read the mapflags line
-				and scan for backslashes */
-			bline= scanb(bol) ;
-			l_add(&new->t_mapf,gr_final(&bline)) ;
+			l_add(&new->t_mapf,keeps(bol)) ;
 		} else
 		if ( strcmp(ty_name,ARGS)==0 ) {
 			if ( new->t_argd ) twice=YES ;
-			bline= scanb(bol) ;
-			new->t_argd= keeps(gr_start(bline)) ;
-			gr_throw(&bline) ;
+			new->t_argd= keeps(bol) ;
 		} else
 		if ( strcmp(ty_name,STD_IN)==0 ) {
 			if ( new->t_stdin ) twice=YES ;
@@ -234,14 +224,15 @@ intrf() {
 				rts, new->t_rts) ;
 		}
 		rts= new->t_rts ;
-		keephead(rts) ; keeptail(rts) ;
+		l_add(&head_list, rts) ;
+		l_add(&tail_list, rts) ;
 	}
 #ifdef DEBUG
 	if ( debug>=3 ) {
 		register list_elem *elem ;
 		vprint("%s: from %s to %s '%s'\n",
 			new->t_name,new->t_in ? new->t_in : "(null)",new->t_out,new->t_prog) ;
-		vprint("\targs: ") ; prns(new->t_argd) ;
+		vprint("\targs: %s",new->t_argd) ;
 		scanlist( l_first(new->t_mapf), elem ) {
 			vprint("\t%s\n",l_content(*elem)) ;
 		}
@@ -264,8 +255,7 @@ static  FILE            *infile ;
 static  char            *inptr ;
 char			*em_dir = EM_DIR;
 
-void
-open_in(name) register char *name ; {
+static void open_in(char *name) {
 	register dmach *cmac ;
 
 	gr_init(&rline) ;
@@ -298,12 +288,12 @@ open_in(name) register char *name ; {
 	}
 }
 
-close_in() {
+static void close_in(void) {
 	if ( !incore ) fclose(infile) ;
 	gr_throw(&rline) ;
 }
 
-char *readline() {
+static char *readline(void) {
 	/* Get a line from the input,
 	   return 0 if at end,
 	   The line is stored in a volatile buffer,
@@ -355,7 +345,7 @@ char *readline() {
 	}
 }
 
-int getinchar() {
+static int getinchar(void) {
 	register int token ;
 
 	if ( incore ) {
@@ -369,7 +359,7 @@ int getinchar() {
 	return token ;
 }
 
-int getln() {
+static int getln(void) {
 	register char *c_ptr ;
 
 	do {
diff --git a/util/ack/run.c b/util/ack/run.c
index 8d0481a58..32cb59fe5 100644
--- a/util/ack/run.c
+++ b/util/ack/run.c
@@ -5,6 +5,7 @@
  */
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include "ack.h"
 #include "list.h"
@@ -19,19 +20,18 @@ static char rcs_id[] = "$Id$" ;
 
 #define ARG_MORE  40            /* The size of args chunks to allocate */
 
-extern growstring scanvars();
+static int run_exec(trf *, const char *);
+static void x_arg(char *);
 
 static char      **arglist ;    /* The first argument */
 static unsigned  argcount ;     /* The current number of arguments */
 static unsigned  argmax;        /* The maximum number of arguments so far */
 
-int runphase(phase) register trf *phase ; {
+int runphase(trf *phase) {
 	register list_elem *elem ;
-      char *prog ; int result ;
-      growstring bline ;
+	char *prog ; int result ;
 
-      bline=scanvars(phase->t_prog) ;
-      prog=gr_final(&bline) ;
+	prog=phase->t_prog ;
 	if ( v_flag || debug ) {
 		if ( v_flag==1 && !debug ) {
 			vprint("%s",phase->t_name) ;
@@ -65,16 +65,19 @@ int runphase(phase) register trf *phase ; {
 		x_arg(l_content(*elem)) ;
 	}
 	x_arg( (char *)0 ) ;
-      result=run_exec(phase,prog) ;
-      throws(prog) ;
-      return result ;
+	result=run_exec(phase,prog) ;
+	return result ;
 }
 
-int run_exec(phase,prog) trf *phase ; char *prog ; {
+static int run_exec(trf *phase, const char *prog) {
 	int status, child, waitchild ;
 
-	do_flush();
-	while ( (child=fork())== -1 ) ;
+	fflush(stdout) ;
+	fflush(stderr) ;
+	child= fork() ;
+	if ( child== - 1) {
+		fatal("Cannot fork %s", prog) ;
+	}
 	if ( child ) {
 		/* The parent */
 		do {
@@ -84,8 +87,6 @@ int run_exec(phase,prog) trf *phase ; char *prog ; {
 			}
 		} while ( waitchild!=child) ;
 		if ( status ) {
-			if ( status&0200 && (status&0177)!=SIGQUIT &&
-				t_flag<=1 ) unlink("core") ;
 			switch ( status&0177 ) {
 			case 0 :
 				break ;
@@ -136,7 +137,7 @@ int run_exec(phase,prog) trf *phase ; char *prog ; {
 	/*NOTREACHED*/
 }
 
-x_arg(string) char *string ; {
+static void x_arg(char *string) {
 	/* Add one execute argument to the argument vector */
 	if ( argcount==argmax ) {
 		if ( argmax==0 ) {
diff --git a/util/ack/scan.c b/util/ack/scan.c
index d020e6a5b..3aaab8492 100644
--- a/util/ack/scan.c
+++ b/util/ack/scan.c
@@ -15,9 +15,14 @@
 static char rcs_id[] = "$Id$" ;
 #endif
 
-void try();
+static void start_scan(void);
+static void try(list_elem *, const char *);
+static void scan_found(void);
+static int satisfy(trf *, const char *);
+static enum f_path scan_end(trf **);
+static void find_cpp(void);
 
-enum f_path getpath(first) register trf **first ; {
+enum f_path getpath(trf **first) {
 	/* Try to find a transformation path */
 
 	start_scan();
@@ -49,7 +54,7 @@ static  int     suf_found;      /* Was the suffix at least recognized ? */
 
 /********************       The hard work          ********************/
 
-start_scan() {
+static void start_scan(void) {
 	register list_elem *scan ;
 
 	scanlist(l_first(tr_list),scan) {
@@ -63,8 +68,7 @@ start_scan() {
 	last_ocount= 0 ;
 }
 
-void
-try(f_scan,suffix) list_elem *f_scan; char *suffix; {
+static void try(list_elem *f_scan, const char *suffix) {
 	register list_elem *scan ;
 	register trf  *trafo ;
 	/* Try to find a transformation path starting at f_scan for a
@@ -134,7 +138,7 @@ try(f_scan,suffix) list_elem *f_scan; char *suffix; {
 	}
 }
 
-scan_found() {
+static void scan_found(void) {
 	register list_elem *scan;
 	int ncount, ocount, pcount ;
 
@@ -182,7 +186,7 @@ scan_found() {
 	}
 }
 
-int satisfy(trafo,suffix) register trf *trafo; char *suffix ; {
+static int satisfy(trf *trafo, const char *suffix) {
 	register char *f_char, *l_char ;
 	/* Check whether this transformation is present for
 	   the current machine and the parameter suffix is among
@@ -207,7 +211,7 @@ int satisfy(trafo,suffix) register trf *trafo; char *suffix ; {
 	return 0 ;
 }
 
-enum f_path scan_end(first) trf **first ; {    /* Finalization */
+static enum f_path scan_end(trf **first) {    /* Finalization */
 	/* Return value indicating whether a transformation was found */
 	/* Set the flags for the transformation up to, but not including,
 	   the combiner
@@ -248,7 +252,7 @@ enum f_path scan_end(first) trf **first ; {    /* Finalization */
 	return F_OK ;
 }
 
-find_cpp() {
+static void find_cpp(void) {
 	register list_elem *elem ;
 	scanlist( l_first(tr_list), elem ) {
 		if ( t_cont(*elem)->t_isprep ) {
diff --git a/util/ack/svars.c b/util/ack/svars.c
index 2d7e4b42c..e540e5d02 100644
--- a/util/ack/svars.c
+++ b/util/ack/svars.c
@@ -4,6 +4,7 @@
  *
  */
 
+#include <string.h>
 #include "ack.h"
 
 #ifndef NORCSID
@@ -44,9 +45,6 @@ static char rcs_id[] = "$Id$" ;
 
 */
 
-extern  char    *getcore();
-extern          fatal();
-
 struct vars {
 	char                            *v_name;
 	enum { routine, string }        v_type;
@@ -60,7 +58,7 @@ struct vars {
 
 static struct vars *v_first ;
 
-static struct vars *newvar(name) char *name; {
+static struct vars *newvar(char *name) {
 	register struct vars *new ;
 
 	for ( new=v_first ; new ; new= new->v_next ) {
@@ -72,36 +70,36 @@ static struct vars *newvar(name) char *name; {
 			return new ;
 		}
 	}
-	new= (struct vars *)getcore( (unsigned)sizeof (struct vars));
+	new= (struct vars *)getcore(sizeof (struct vars));
 	new->v_name= name ;
 	new->v_next= v_first ;
 	v_first= new ;
 	return new ;
 }
 
-setsvar(name,str) char *name, *str ; {
+void setsvar(char *name, char *str) {
 	register struct vars *new ;
 
 	new= newvar(name);
 #ifdef DEBUG
-	if ( debug>=2 ) vprint("%s=%s\n", name, str) ;
+	if ( debug>=2 ) vprint("%s=%s\n", new->v_name, str) ;
 #endif
 	new->v_type= string;
 	new->v_value.v_string= str;
 }
 
-setpvar(name,rout) char *name, *(*rout)() ; {
+void setpvar(char *name, char *(*rout)(void)) {
 	register struct vars *new ;
 
 	new= newvar(name);
 #ifdef DEBUG
-	if ( debug>=2 ) vprint("%s= (*%o)()\n",name,rout) ;
+	if ( debug>=2 ) vprint("%s= (*%o)()\n", new->v_name, rout) ;
 #endif
 	new->v_type= routine;
 	new->v_value.v_routine= rout;
 }
 
-char *getvar(name) char *name ; {
+char *getvar(const char *name) {
 	register struct vars *scan ;
 
 	for ( scan=v_first ; scan ; scan= scan->v_next ) {
diff --git a/util/ack/trans.c b/util/ack/trans.c
index 3cb2d7ea8..98a75a066 100644
--- a/util/ack/trans.c
+++ b/util/ack/trans.c
@@ -26,13 +26,17 @@ static int        touch_head= NO ;
 static growstring tail ;
 static int        touch_tail= NO ;
 
-char *headvar(),*tailvar() ;
+static char *headvar(void);
+static char *tailvar(void);
+static void set_Rflag(char *);
+static void condit(growstring *, list_head *, list_head *, char *);
+static int mapflag(list_head *, const char *);
+static int mapexpand(char *, const char *);
+static void getcallargs(trf *);
+static growstring without_bslash(const char *);
+static void getprogram(trf *);
 
-void condit();
-void doassign();
-void set_Rflag();
-
-int transform(phase) register trf *phase ; {
+int transform(trf *phase) {
 	int ok ;
 
 	if ( !setfiles(phase) ) {
@@ -40,17 +44,19 @@ int transform(phase) register trf *phase ; {
 		return 0 ;
 	}
 	getcallargs(phase) ;
+	getprogram(phase) ;
 	ok= runphase(phase) ;
 	if ( !ok ) rmfile(&out) ;
 	/* Free the space occupied by the arguments,
 	   except for the linker, since we are bound to exit soon
 	   and do not foresee further need of memory space */
-	if ( !phase->t_linker ) discardargs(phase) ;
+	if ( !phase->t_linker )
+		l_throw(&phase->t_args) ;
 	disc_files(phase) ;
 	return ok ;
 }
 
-getmapflags(phase) register trf *phase ; {
+void getmapflags(trf *phase) {
 	register path *l_in ;
 	register list_elem *elem ;
 	int scanned ;
@@ -75,8 +81,9 @@ getmapflags(phase) register trf *phase ; {
 		scanlist(l_first(phase->t_inputs),elem) {
 			l_in = p_cont(*elem) ;
 			if ( mapflag(&(phase->t_mapf),l_in->p_path) ) {
-				ptr= keeps(getvar(LIBVAR)) ;
-				clr_noscan(ptr) ;
+				growstring temp;
+				temp= without_bslash(getvar(LIBVAR)) ;
+				ptr= gr_final(&temp);
 #ifdef DEBUG
 				if ( debug >=4 ) {
 					vprint("phase %s, library %s(%s)\n",
@@ -110,16 +117,12 @@ getmapflags(phase) register trf *phase ; {
 }
 
 
-do_Rflag(argp) char *argp ; {
-	l_add(&R_list,argp) ;
-}
-
-char *headvar() {
+static char *headvar(void) {
 	if ( !touch_head) return "" ;
 	return gr_start(head) ;
 }
 
-add_head(str) char *str; {
+void add_head(const char *str) {
 	if ( !touch_head) {
 		gr_init(&head) ;
 		touch_head=YES ;
@@ -127,12 +130,12 @@ add_head(str) char *str; {
 	gr_cat(&head,str) ;
 }
 
-char *tailvar() {
+static char *tailvar(void) {
 	if ( !touch_tail ) return "" ;
 	return gr_start(tail) ;
 }
 
-add_tail(str) char *str ; {
+void add_tail(const char *str) {
 	if ( !touch_tail ) {
 		gr_init(&tail) ;
 		touch_tail=YES ;
@@ -141,7 +144,7 @@ add_tail(str) char *str ; {
 }
 
 
-transini() {
+void transini(void) {
 	register list_elem *elem ;
 	register trf *phase ;
 
@@ -157,8 +160,7 @@ transini() {
 	setpvar(keeps(TAIL),tailvar) ;
 }
 
-void
-set_Rflag(argp) register char *argp ; {
+static void set_Rflag(char *argp) {
 	register char *eos ;
 	register list_elem *prog ;
 	register int length ;
@@ -206,72 +208,47 @@ set_Rflag(argp) register char *argp ; {
 /*                                                                        */
 /**************************************************************************/
 
-growstring scanb(line) char *line ; {
-	/* Scan a line for backslashes, setting the NO_SCAN bit in characters
-	   preceded by a backslash.
-	*/
-	register char *in_c ;
-	register int  token ;
-	growstring result ;
-	enum { TEXT, ESCAPED } state = TEXT ;
-
-	gr_init(&result) ;
-	for ( in_c= line ; *in_c ; in_c++ ) {
-		token= *in_c&0377 ;
-		switch( state ) {
-		case TEXT :
-			if ( token==BSLASH ) {
-				state= ESCAPED ;
-			} else {
-				gr_add(&result,token) ;
-			}
-			break ;
-		case ESCAPED :
-			gr_add(&result,token|NO_SCAN) ;
-			state=TEXT ;
-			break ;
-		}
-	}
-	gr_add(&result,0) ;
-	if ( state!=TEXT ) werror("flag line ends with %c",BSLASH) ;
-	return result ;
-}
-
-growstring scanvars(line) char *line ; {
+static growstring scanvars(const char *line) {
 	/* Scan a line variable replacements started by S_VAR.
-	   Two sequences exist: S_VAR name E_VAR, S_VAR name A_VAR text E_VAR.
+	   Two sequences exist: S_VAR name C_VAR, S_VAR name A_VAR text C_VAR.
 	   neither name nor text may contain further replacements.
 	   In the first form an error message is issued if the name is not
 	   present in the variables, the second form produces text
 	   in that case.
-	   The sequence S_VAR S_VAR is transformed into S_VAR.
-	   This to allow later recognition in mapflags, where B_SLASH
-	   would be preventing any recognition.
 	*/
-	register char *in_c ;
-	register int  token ;
-	growstring result ;
-	growstring name ;
-	register char *tr ;
+	const char *in_c ;
+	int token, token_r ;
+	growstring result, name ;
+	char *tr ;
 	enum { TEXT, FIRST, NAME, SKIP, COPY } state = TEXT ;
+	int escaped = NO;
 
 	gr_init(&result) ; gr_init(&name) ;
 	for ( in_c= line ; *in_c ; in_c++ ) {
 		token= *in_c&0377 ;
+		token_r= (escaped ? 0 : token);
+
+		/* A backslash escapes the next character. */
+		if ( token_r==BSLASH ) {
+			if ( state==TEXT || state==COPY ) {
+				/* Keep BSLASH for later scans. */
+				gr_add(&result,token) ;
+			}
+			escaped= YES;
+			continue;
+		}
+		escaped= NO;
+
 		switch( state ) {
 		case TEXT :
-			if ( token==S_VAR ) {
+			if ( token_r==S_VAR ) {
 				state= FIRST ;
 			} else {
 				gr_add(&result,token) ;
 			}
 			break ;
 		case FIRST :
-			switch ( token ) {
-			case S_VAR :
-				state= TEXT ;
-				gr_add(&result,token) ;
-				break ;
+			switch ( token_r ) {
 			case A_VAR :
 			case C_VAR :
 				fatal("empty string variable name") ;
@@ -282,7 +259,7 @@ growstring scanvars(line) char *line ; {
 			}
 			break ;
 		case NAME:
-			switch ( token ) {
+			switch ( token_r ) {
 			case A_VAR :
 				gr_add(&name,0) ;
 				if ( tr=getvar(gr_start(name)) ) {
@@ -314,16 +291,17 @@ growstring scanvars(line) char *line ; {
 			}
 			break ;
 		case SKIP :
-			if ( token==C_VAR ) state= TEXT ;
+			if ( token_r==C_VAR ) state= TEXT ;
 			break ;
 		case COPY :
-			if ( token==C_VAR ) state= TEXT ; else {
+			if ( token_r==C_VAR ) state= TEXT ; else {
 				gr_add(&result,token) ;
 			}
 			break ;
 		}
 	}
 	gr_add(&result,0) ;
+	if ( escaped ) werror("flag line ends with %c",BSLASH) ;
 	if ( state!=TEXT ) {
 		werror("flag line misses %c",C_VAR) ;
 		gr_throw(&name) ;
@@ -331,74 +309,84 @@ growstring scanvars(line) char *line ; {
 	return result ;
 }
 
-growstring scanexpr(line) char *line ; {
+static growstring scanexpr(const char *line) {
 	/* Scan a line for conditional or flag expressions,
 	   dependent on the type. The format is
 	   S_EXPR suflist M_EXPR suflist T_EXPR tail C_EXPR
-	   the head and tail are passed to treat, together with the
+	   the head and tail are passed to condit(), together with the
 	   growstring for futher treatment.
 	   Nesting is not allowed.
 	*/
-	register char *in_c ;
-	char *heads ;
-	register int  token ;
-	growstring sufs, tailval ;
-	growstring result ;
+	const char *in_c, *heads ;
+	int token, token_r ;
+	growstring sufs, tailval, result ;
 	static list_head fsuff, lsuff ;
 	enum { TEXT, FDOT, FSUF, LDOT, LSUF, FTAIL } state = TEXT ;
+	int escaped = NO;
 
 	gr_init(&result) ; gr_init(&sufs) ; gr_init(&tailval) ;
 	for ( in_c= line ; *in_c ; in_c++ ) {
 		token= *in_c&0377 ;
+		token_r= (escaped ? 0 : token);
+
+		/* A backslash escapes the next character. */
+		if ( token_r==BSLASH ) {
+			if ( state==TEXT || state==FTAIL ) {
+				/* Keep BSLASH for later scans. */
+				gr_add(&result,token) ;
+			}
+			escaped= YES;
+			continue;
+		}
+		escaped= NO;
+
 		switch( state ) {
 		case TEXT :
-			if ( token==S_EXPR ) {
+			if ( token_r==S_EXPR ) {
 				state= FDOT ;
 				heads=in_c ;
 			} else gr_add(&result,token) ;
 			break ;
 		case FDOT :
-			if ( token==M_EXPR ) {
+			if ( token_r==M_EXPR ) {
 				state=LDOT ;
 				break ;
 			}
-			token &= ~NO_SCAN ;
 			if ( token!=SUFCHAR ) {
 				error("Missing %c in expression",SUFCHAR) ;
 			}
 			gr_add(&sufs,token) ; state=FSUF ;
 			break ;
 		case FSUF :
-			if ( token==M_EXPR || (token&~NO_SCAN)==SUFCHAR) {
+			if ( token_r==M_EXPR || token==SUFCHAR ) {
 				gr_add(&sufs,0) ;
 				l_add(&fsuff,gr_final(&sufs)) ;
 			}
-			if ( token==M_EXPR ) {
+			if ( token_r==M_EXPR ) {
 				state=LDOT ;
-			} else gr_add(&sufs,token&~NO_SCAN) ;
+			} else gr_add(&sufs,token) ;
 			break ;
 		case LDOT :
-			if ( token==T_EXPR ) {
+			if ( token_r==T_EXPR ) {
 				state=FTAIL ;
 				break ;
 			}
-			token &= ~NO_SCAN ;
 			if ( token!=SUFCHAR ) {
 				error("Missing %c in expression",SUFCHAR) ;
 			}
 			gr_add(&sufs,token) ; state=LSUF ;
 			break ;
 		case LSUF :
-			if ( token==T_EXPR || (token&~NO_SCAN)==SUFCHAR) {
+			if ( token_r==T_EXPR || token==SUFCHAR) {
 				gr_add(&sufs,0) ;
 				l_add(&lsuff,gr_final(&sufs)) ;
 			}
-			if ( token==T_EXPR ) {
+			if ( token_r==T_EXPR ) {
 				state=FTAIL ;
-			} else gr_add(&sufs,token&~NO_SCAN) ;
+			} else gr_add(&sufs,token) ;
 			break ;
 		case FTAIL :
-			if ( token==C_EXPR ) {
+			if ( token_r==C_EXPR ) {
 				/* Found one !! */
 				gr_add(&tailval,0) ;
 				condit(&result,&fsuff,&lsuff,gr_start(tailval)) ;
@@ -418,10 +406,8 @@ growstring scanexpr(line) char *line ; {
 	return result ;
 }
 
-void
-condit(line,fsuff,lsuff,tailval) growstring *line ;
-	list_head *fsuff, *lsuff;
-	char *tailval ;
+static void condit(growstring *line, list_head *fsuff, list_head *lsuff,
+		   char *tailval)
 {
 	register list_elem *first ;
 	register list_elem *last ;
@@ -446,7 +432,7 @@ condit(line,fsuff,lsuff,tailval) growstring *line ;
 #endif
 }
 
-int mapflag(maplist,cflag) list_head *maplist ; char *cflag ; {
+static int mapflag(list_head *maplist, const char *cflag) {
 	/* Expand a flag expression */
 	/* The flag "cflag" is checked for each of the mapflags.
 	   A mapflag entry has the form
@@ -468,12 +454,9 @@ int mapflag(maplist,cflag) list_head *maplist ; char *cflag ; {
 	return 0 ;
 }
 
-int mapexpand(mapentry,cflag)
-	char *mapentry, *cflag ;
-{
-	register char *star ;
-	register char *ptr ;
-	register char *space ;
+static int mapexpand(char *mapentry, const char *cflag) {
+	const char *star ;
+	char *ptr, *space ;
 	int length ;
 
 	star=strchr(mapentry,STAR) ;
@@ -510,10 +493,10 @@ int mapexpand(mapentry,cflag)
 	return 1 ;
 }
 
-void
-doassign(line,star,length) char *line, *star ; {
+void doassign(const char *line, const char *star, int length) {
 	growstring varval, name, temp ;
-	register char *ptr ;
+	const char *ptr ;
+	int escaped = NO ;
 
 	gr_init(&varval) ;
 	gr_init(&name) ;
@@ -528,12 +511,21 @@ doassign(line,star,length) char *line, *star ; {
 	}
 	temp= scanvars(ptr+1) ;
 	for ( ptr=gr_start(temp); *ptr; ptr++ ) switch ( *ptr ) {
+	case BSLASH :
+		escaped= YES ;
+		gr_add(&varval,*ptr) ;
+		break ;
 	case STAR :
-		if ( star ) {
-			while ( length-- ) gr_add(&varval,*star++|NO_SCAN) ;
+		if ( star && !escaped ) {
+			while ( length-- ) {
+				gr_add(&varval,BSLASH) ;
+				gr_add(&varval,*star++) ;
+			}
 			break ;
 		}
+		/* FALLTHROUGH */
 	default :
+		escaped= NO ;
 		gr_add(&varval,*ptr) ;
 		break ;
 	}
@@ -544,15 +536,16 @@ doassign(line,star,length) char *line, *star ; {
 
 #define ISBLANK(c) ( (c)==SPACE || (c)==TAB )
 
-unravel(line,action) char *line ; int (*action)() ; {
+static void unravel(const char *line, void (*action)(char *)) {
 	/* Unravel the line, get arguments a la shell */
 	/* each argument is handled to action */
 	/* The input string is left intact */
-	register char *in_c ;
-	register int  token ;
-	enum { BLANK, ARG } state = BLANK ;
+	const char *in_c ;
+	int token ;
+	enum { BLANK, ARG, ESCAPED } state = BLANK ;
 	growstring argum ;
 
+	/* Loop for each character of line, including final '\0' */
 	in_c=line ;
 	for (;;) {
 		token= *in_c&0377 ;
@@ -560,9 +553,13 @@ unravel(line,action) char *line ; int (*action)() ; {
 		case BLANK :
 			if ( token==0 ) break ;
 			if ( !ISBLANK(token) ) {
-				state= ARG ;
 				gr_init(&argum) ;
-				gr_add(&argum,token&~NO_SCAN) ;
+				gr_add(&argum,token) ;
+				if ( token == BSLASH ) {
+					state= ESCAPED ;
+				} else {
+					state= ARG ;
+				}
 			}
 			break ;
 		case ARG :
@@ -572,97 +569,106 @@ unravel(line,action) char *line ; int (*action)() ; {
 				gr_throw(&argum) ;
 				state=BLANK ;
 			} else {
-				gr_add(&argum,token&~NO_SCAN) ;
+				gr_add(&argum,token) ;
+				if ( token == BSLASH ) state= ESCAPED ;
 			}
 			break ;
+		case ESCAPED :
+			gr_add(&argum,token) ;
+			state= ARG ;
+			break ;
 		}
 		if ( token == 0 ) break ;
 		in_c++ ;
 	}
 }
 
-char *c_rep(string,place,rep) char *string, *place, *rep ; {
-	/* Produce a string in stable storage produced from 'string'
-	   with the character at place replaced by rep
-	*/
-	growstring name ;
-	register char *nc ;
-	register char *xc ;
-
-	gr_init(&name) ;
-	for ( nc=string ; *nc && nc<place ; nc++ ) {
-		gr_add(&name,*nc) ;
-	}
-#ifdef DEBUG
-	if ( *nc==0 ) fatal("Place is not in string") ;
-#endif
-	for ( xc=rep ; *xc ; xc++ ) gr_add(&name,*xc|NO_SCAN) ;
-	gr_add(&name,0) ;
-	gr_cat(&name,nc+1) ;
-	return gr_final(&name) ;
-}
-
 static list_head *curargs ;
 static list_head *comb_args ;
 
-void
-addargs(string) char *string ; {
-	register char *temp, *repc ;
-	register list_elem *elem ;
+static void addargs3(const char *prefix1, const char *prefix2,
+		     const char *string)
+{
+	/* Prepend prefix1 and prefix2 to string, then add it to
+	   curargs.  string is scanned to strip backslashes and
+	   substitute files for C_IN and C_OUT.  prefixes are not
+	   scanned.
+	*/
+	const char *in_c ;
+	int token ;
+	char *tr ;
+	list_elem *elem ;
+	growstring argum ;
+	int escaped = NO ;
 
-	repc=strchr(string,C_IN) ;
-	if ( repc ) {
-		/* INPUT FILE TOKEN seen, replace it and scan further */
-		if ( repc==string && string[1]==0 ) {
-			if ( in.p_path ) { /* All but combiner */
-				l_add(curargs,keeps(in.p_path)) ;
-			} else {
-				scanlist( l_first(*comb_args), elem ) {
-					l_add(curargs,
-					      keeps(p_cont(*elem)->p_path)) ;
+	gr_init(&argum);
+	for ( in_c= prefix1 ; *in_c ; in_c++ ) {
+		gr_add(&argum,*in_c) ;
+	}
+	for ( in_c= prefix2 ; *in_c ; in_c++ ) {
+		gr_add(&argum,*in_c) ;
+	}
+	for ( in_c= string ; *in_c ; in_c++ ) {
+		token= *in_c&0377 ;
+		if ( escaped ) {
+			/* Strip BSLASH, keep escaped character. */
+			gr_add(&argum,token) ;
+			escaped= NO ;
+			continue;
+		}
+		switch ( token ) {
+		case BSLASH:
+			escaped= YES ;
+			break;
+		case C_IN:  /* Input file */
+			if ( in.p_path ) { /* Not for the combiners */
+				for ( tr= in.p_path ; *tr; tr++ ) {
+					gr_add(&argum,*tr);
 				}
+			} else {           /* For the combiners */
+				gr_add(&argum,0);
+				tr= gr_final(&argum);
+				in_c++;
+				scanlist( l_first(*comb_args), elem ) {
+					char *p = p_cont(*elem)->p_path ;
+					addargs3(tr,p,in_c) ;
+				}
+				throws(tr);
+				return;
 			}
-			return ;
-		}
-		if ( in.p_path ) { /* Not for the combiners */
-			temp=c_rep(string,repc,in.p_path) ;
-			addargs(temp) ;
-			throws(temp) ;
-		} else {           /* For the combiners */
-			scanlist( l_first(*comb_args), elem ) {
-				temp=c_rep(string,repc,p_cont(*elem)->p_path);
-				addargs(temp) ;
-				throws(temp) ;
-			}
-		}
-		return ;
-	}
-	repc=strchr(string,C_OUT) ;
-	if ( repc ) {
-		/* replace the outfile token as with the infile token */
+			break;
+		case C_OUT: /* Output file */
 #ifdef DEBUG
-		if ( !out.p_path ) fatal("missing output filename") ;
+			if ( !out.p_path ) fatal("missing output filename") ;
 #endif
-		temp=c_rep(string,repc,out.p_path) ;
-		addargs(temp) ;
-		throws(temp) ;
-		return ;
+			for ( tr= out.p_path ; *tr ; tr++ ) {
+				gr_add(&argum,*tr) ;
+			}
+			break;
+		default:
+			gr_add(&argum,token) ;
+			break;
+		}
 	}
-	temp= keeps(string) ;
-	clr_noscan(temp) ;
-	l_add(curargs,temp) ;
+	gr_add(&argum,0) ;
+	tr= gr_final(&argum) ;
+	l_add(curargs,tr) ;
 }
 
-getcallargs(phase) register trf *phase ; {
+static void addargs(char *string) {
+	addargs3("", "", string) ;
+}
+
+static void getcallargs(trf *phase) {
 	growstring arg1, arg2 ;
 
 	arg1= scanvars(phase->t_argd) ;
 #ifdef DEBUG
-	if ( debug>=3 ) { vprint("\tvars: ") ; prns(gr_start(arg1)) ; }
+	if ( debug>=3 ) vprint("\tvars: %s", gr_start(arg1)) ;
 #endif
 	arg2= scanexpr(gr_start(arg1)) ;
 #ifdef DEBUG
-	if ( debug>=3 ) { vprint("\texpr: ") ; prns(gr_start(arg2)) ; }
+	if ( debug>=3 ) vprint("\texpr: %s", gr_start(arg2)) ;
 #endif
 	gr_throw(&arg1) ;
 	curargs= &phase->t_args ;
@@ -671,6 +677,39 @@ getcallargs(phase) register trf *phase ; {
 	gr_throw(&arg2) ;
 }
 
-discardargs(phase) register trf *phase ; {
-	l_throw(&phase->t_args) ;
+static growstring without_bslash(const char *string) {
+	/* Strip backslashes from a copy of the string. */
+	growstring result;
+	const char *in_c ;
+	int token ;
+	int escaped = NO ;
+
+	gr_init(&result) ;
+	for ( in_c= string ; *in_c ; in_c++ ) {
+		token= *in_c&0377 ;
+		if ( token==BSLASH && !escaped ) {
+			escaped= YES ;
+		} else {
+			gr_add(&result,token);
+			escaped= NO ;
+		}
+	}
+	gr_add(&result,0);
+	return result;
+}
+
+static void getprogram(trf *phase) {
+	growstring prog1, prog2 ;
+	const char *in_c ;
+	int token ;
+	int escaped = NO ;
+
+	/* Expand string variables in program name. */
+	prog1= scanvars(phase->t_prog) ;
+	throws(phase->t_prog) ;
+
+	/* Strip backslashes. */
+	prog2= without_bslash(gr_start(prog1));
+	gr_throw(&prog1);
+	phase->t_prog= gr_final(&prog2);
 }
diff --git a/util/ack/trans.h b/util/ack/trans.h
index 70be80832..54086a563 100644
--- a/util/ack/trans.h
+++ b/util/ack/trans.h
@@ -44,3 +44,26 @@ struct transform {
 } ;
 
 #define t_cont(elem) ((trf *)l_content(elem))
+
+/* files.c */
+int setfiles(trf *);
+void disc_files(trf *);
+void disc_inputs(trf *);
+void rmfile(path *);
+void rmtemps(void);
+void add_input(path *, trf *);
+
+/* run.c */
+int runphase(trf *);
+
+/* scan.c */
+enum f_path { F_OK, F_NOMATCH, F_NOPATH } ;
+enum f_path getpath(trf **);
+
+/* trans.c */
+int transform(trf *);
+void getmapflags(trf *);
+void add_head(const char *);
+void add_tail(const char *);
+void transini(void);
+void doassign(const char *, const char *, int);
diff --git a/util/ack/util.c b/util/ack/util.c
index 419f087e3..b3754f28e 100644
--- a/util/ack/util.c
+++ b/util/ack/util.c
@@ -32,15 +32,11 @@ extern  int     n_error;
 # define STDOUT stderr
 #endif
 
-void fuerror(const char* fmt, ...);
-void werror(const char* fmt, ...);
-
-char *basename(string) char *string ; {
+char *ack_basename(const char *string) {
 	static char retval[256] ;
-	char *last_dot, *last_start ;
-	register char *store;
-	register char *fetch ;
-	register int ctoken ;
+	const char *last_dot, *last_start, *fetch ;
+	char *store ;
+	int ctoken ;
 
 	last_dot= (char *)0 ;
 	last_start= string ;
@@ -50,9 +46,6 @@ char *basename(string) char *string ; {
 		case '/'     : last_start=fetch+1 ; break ;
 		case  0      : goto out ;
 		}
-		if ( !isascii(ctoken) || !isprint(ctoken) ) {
-			werror("non-ascii characters in argument %s",string) ;
-		}
 	}
 out:
 	if ( ! *last_start ) fuerror("empty filename \"%s\"",string) ;
@@ -65,21 +58,14 @@ out:
 	return retval ;
 }
 
-clr_noscan(str) char *str ; {
-	register char *ptr ;
-	for ( ptr=str ; *ptr ; ptr++ ) {
-		*ptr&= ~NO_SCAN ;
-	}
-}
-
-char *skipblank(str) char *str ; {
+char *skipblank(char *str) {
 	register char *ptr ;
 
 	for ( ptr=str ; *ptr==SPACE || *ptr==TAB ; ptr++ ) ;
 	return ptr ;
 }
 
-char *firstblank(str) char *str ; {
+char *firstblank(char *str) {
 	register char *ptr ;
 
 	for ( ptr=str ; *ptr && *ptr!=SPACE && *ptr!=TAB ; ptr++ ) ;
@@ -109,15 +95,6 @@ void vprint(const char* fmt, ...)
 	va_end(ap);
 }
 
-#ifdef DEBUG
-prns(s) register char *s ; {
-	for ( ; *s ; s++ ) {
-		putc((*s&0377)&~NO_SCAN,STDOUT) ;
-	}
-	putc('\n',STDOUT) ;
-}
-#endif
-
 /* VARARGS1 */
 void fuerror(const char *fmt, ...) {
 	/* Fatal user error */
@@ -153,48 +130,36 @@ void error(const char *fmt, ...) {
 	va_end(ap);
 }
 
-do_flush() {
-	fflush(stdout) ;
-	fflush(stderr) ;
-}
-
-void
-noodstop() {
-	quit(-3) ;
-}
-
-quit(code) {
+void quit(int code) {
 	rmtemps();
 	exit(code);
 }
+
 /******
 	char *keeps(string)
 		Keep the string in stable storage.
 	throws(string)
 		Remove the string stored by keep from stable storage.
+		throws() is now a macro in ack.h.
 ***********/
 
-char *keeps(str) char *str ; {
+char *keeps(const char *str) {
 	register char *result ;
 	result= getcore( (unsigned)(strlen(str)+1) ) ;
 	if ( !result ) fatal("Out of core") ;
 	return strcpy(result,str) ;
 }
 
-throws(str) char *str ; {
-	freecore(str) ;
-}
-
-char *getcore(size) unsigned size ; {
-	register char *retptr ;
+void *getcore(size_t size) {
+	void *retptr ;
 
 	retptr= calloc(1,size) ;
 	if ( !retptr ) fatal("Out of memory") ;
 	return retptr ;
 }
 
-char *changecore(ptr,size) char *ptr ; unsigned size ; {
-	register char *retptr ;
+void *changecore(void *ptr, size_t size) {
+	void *retptr ;
 
 	retptr= realloc(ptr,size) ;
 	if ( !retptr ) fatal("Out of memory") ;
diff --git a/util/amisc/abmodules.1 b/util/amisc/abmodules.1
new file mode 100644
index 000000000..1eb67d843
--- /dev/null
+++ b/util/amisc/abmodules.1
@@ -0,0 +1,25 @@
+.TH ABMODULES 1 2017-01-18
+.SH NAME
+abmodules  \-  find B modules
+.SH SYNOPSIS
+abmodules [ \-o outputfile.c ] [ file ... ]
+.SH DESCRIPTION
+.I abmodules
+finds B modules in a set of ack.out(5) format object files, and either lists
+them or generates a C file which initialises the modules.
+.PP
+This tool is used for multiple compilation of B programs; B modules must be
+initialised before use, and this tool generates the initialisation code for
+programs containing an abitrary number of modules.
+See em_b(6) for details.
+.PP
+Options are:
+.TP
+.B  \-o filename
+Write C source to
+.I filename
+containing a definition of a binit() function which will initalise all modules
+found.
+If not present, a simple list of module names is written to stdout instead.
+.SH SEE ALSO
+ack.out(5), em_b(6)
diff --git a/util/amisc/abmodules.c b/util/amisc/abmodules.c
new file mode 100644
index 000000000..e1190c207
--- /dev/null
+++ b/util/amisc/abmodules.c
@@ -0,0 +1,216 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "out.h"
+#include "arch.h"
+#include "ranlib.h"
+#include "object.h"
+#include "diagnostics.h"
+#include "stringlist.h"
+
+int	numsort_flg;
+int	sectsort_flg;
+int	undef_flg;
+int	revsort_flg = 1;
+int	globl_flg;
+int	nosort_flg;
+int	arch_flg;
+int	prep_flg;
+int	read_error;
+struct	outsect	sbuf;
+long	off;
+long	s_base[S_MAX];	/* for specially encoded bases */
+char	*filename;
+int	narg;
+
+extern int rd_unsigned2();
+
+static const char prefix[] = "_bmodule_";
+
+static struct stringlist modules;
+
+static void do_file(int fd)
+{
+	struct outhead hbuf;
+	struct	outname	*nbufp = NULL;
+	char		*cbufp;
+	long		fi_to_co;
+	long		n;
+	unsigned	readcount;
+	int		i,j;
+	int		compare();
+
+	read_error = 0;
+	rd_fdopen(fd);
+
+	rd_ohead(&hbuf);
+	if (BADMAGIC(hbuf))
+		return;
+
+	n = hbuf.oh_nname;
+	if (n == 0)
+		fatal("%s --- no name list", filename);
+
+	if (hbuf.oh_nchar == 0)
+		fatal("%s --- no names", filename);
+
+	if ((readcount = hbuf.oh_nchar) != hbuf.oh_nchar)
+		fatal("%s --- string area too big", filename);
+
+	cbufp = calloc(readcount, 1);
+	rd_string(cbufp, hbuf.oh_nchar);
+	if (read_error)
+		goto corrupt;
+
+	fi_to_co = (long) (cbufp - OFF_CHAR(hbuf));
+	while (--n >= 0)
+	{
+		struct outname nbuf;
+		struct stringfragment* f;
+
+		rd_name(&nbuf, 1);
+		if (read_error)
+			goto corrupt;
+
+		if (!(nbuf.on_type & S_EXT))
+			continue;
+		if ((nbuf.on_type & S_TYP) == S_UND)
+			continue;
+
+		if (nbuf.on_foff == 0)
+			nbuf.on_mptr = 0;
+		else
+			nbuf.on_mptr = (char *) (nbuf.on_foff + fi_to_co);
+
+		if (strlen(nbuf.on_mptr) <= sizeof(prefix))
+			continue;
+		if (memcmp(nbuf.on_mptr, prefix, sizeof(prefix)-1) != 0)
+			continue;
+
+		stringlist_add(&modules, strdup(nbuf.on_mptr + sizeof(prefix) - 1));
+	}
+
+	if (cbufp)
+		free(cbufp);
+
+	return;
+corrupt:
+	fatal("%s --- corrupt", filename);
+}
+
+static void process(int fd)
+{
+	uint16_t magic = rd_unsigned2(fd);
+	switch(magic) {
+		case O_MAGIC:
+			lseek(fd, 0L, 0);
+			do_file(fd);
+			break;
+
+		case ARMAG:
+		case AALMAG:
+		{
+			struct ar_hdr archive_header;
+			static char	buf[sizeof(archive_header.ar_name)+1];
+
+			while (rd_arhdr(fd, &archive_header))
+			{
+				long nextpos = lseek(fd, 0L, SEEK_CUR) + archive_header.ar_size;
+				if (nextpos & 1)
+					nextpos++;
+
+				strncpy(buf, archive_header.ar_name, sizeof(archive_header.ar_name));
+				filename = buf;
+				if (strcmp(filename, SYMDEF) != 0)
+					do_file(fd);
+				lseek(fd, nextpos, 0);
+			}
+			break;
+		}
+		
+		default:
+			fatal("file %s is of unknown format", filename);
+	}
+}
+
+int main(int argc, char* const argv[])
+{
+	int opt;
+	FILE* outputfp = NULL;
+
+	program_name = argv[0];
+	for (;;)
+	{
+		int opt = getopt(argc, argv, "o:");
+		if (opt == -1)
+			break;
+
+		switch (opt)
+		{
+			case 'o':
+				outputfp = fopen(optarg, "w");
+				if (!outputfp)
+					fatal("cannot open output file: %s", strerror(errno));
+				break;
+
+			default:
+				fatal("usage: abmodules [-o outputfile] [file...]");
+		}
+	}
+
+	for (;;)
+	{
+		int fd;
+
+		filename = argv[optind++];
+		if (!filename)
+			break;
+		if ((fd = open(filename, 0)) < 0)
+			fatal("cannot open %s: %s", filename, strerror(errno));
+		process(fd);
+		close(fd);
+	}
+
+	if (outputfp)
+	{
+		struct stringfragment* f;
+
+		fprintf(outputfp, "#include <stdint.h>\n");
+		fprintf(outputfp, "\n");
+
+		for (f = modules.first; f; f = f->next)
+			fprintf(outputfp, "extern uintptr_t bmodule_%s[];\n", f->data);
+
+		fprintf(outputfp, "\n");
+		fprintf(outputfp, "extern void patch_addresses(uintptr_t* module);\n");
+		fprintf(outputfp, "\n");
+		fprintf(outputfp, "void binit(void) {\n");
+		for (f = modules.first; f; f = f->next)
+			fprintf(outputfp, "\tpatch_addresses(bmodule_%s);\n", f->data);
+		fprintf(outputfp, "}\n");
+		fclose(outputfp);
+	}
+	else
+	{
+		struct stringfragment* f;
+
+		for (f = modules.first; f; f = f->next)
+			printf("%s\n", f->data);
+	}
+
+	exit(0);
+}
+
+void rd_fatal(void)
+{
+	fatal("read error on %s", filename);
+}
diff --git a/util/amisc/aelflod.1 b/util/amisc/aelflod.1
index 24001ba2d..e6af7ef2e 100644
--- a/util/amisc/aelflod.1
+++ b/util/amisc/aelflod.1
@@ -1,25 +1,59 @@
-.TH ASLOD 1 "$Revision$"
+.TH AELFLOD 1 2017-01-18
 .SH NAME
 aelflod \- ACK ELF loader
 .SH SYNOPSIS
-aelflod [-h] [-v] inputfile outputfile
+.B aelflod
+[\-a\fInumber\fP] [\-b] [\-h] [\-l] [\-m\fInumber\fP] [\-v]
+inputfile outputfile
 .SH DESCRIPTION
 .I aelflod
 converts an absolute ack.out file into a simple binary memory
-dump wrapped up in an ELF executable. It is suitable for producing
-executables for operating systems such as Linux.
-
+dump wrapped up in an ELF executable.
+It is suitable for producing executables for operating systems
+such as Linux.
+.PP
+.I aelflod
+accepts the following flags:
+.TP
+.BI \-a number
+Set the ABI in the ELF header to \fInumber\fP.
+The default value is \fI3\fP for Linux.
+.TP
+.B \-b
+Write a big-endian ELF file.
+.TP
+.B \-h
+Print a help message and exit.
+.TP
+.B \-l
+Write a little-endian ELF file.
+This is the default.
+.TP
+.BI \-m number
+Set the machine type in the ELF header to \fInumber\fP.
+The default value is \fI3\fP for Intel 386 (i386).
+Other values are \fI4\fP for Motorola 68000 (m68k)
+and \fI20\fP for PowerPC.
+.TP
+.B \-v
+Be verbose.
+.PP
 The input file must contain exactly four segments: TEXT, ROM,
 DATA and BSS, in that order, all occupying contiguous memory.
 The file must have all references resolved and be linked to a
-fixed address. The fixed address must be at least 0x54 bytes
-greater than a page boundary, in order to make room for the ELF
-header itself.
-
-aelflod will write out an ELF header followed by each segment, in
-order, ensuring that enough padding is inserted between each segment
-to keep the offsets correct. The created executable will contain just
-one rwx segment, and no sections.
-
+fixed address.
+The fixed address must be at least 0x54 bytes greater than a
+page boundary, in order to make room for the ELF header itself.
+.PP
+.I aelflod
+will write out an ELF header followed by each segment, in order,
+ensuring that enough padding is inserted between each segment
+to keep the offsets correct.
+The created executable will contain just one ELF segment mapped rwx.
+.PP
+If the input file has symbols, then
+.I aelflod
+will convert the symbol table to ELF.
+The output file has ELF section headers if and only if it has symbols.
 .SH "SEE ALSO"
 ack.out(5)
diff --git a/util/amisc/aelflod.c b/util/amisc/aelflod.c
index e3692ac01..dbaafc9b5 100644
--- a/util/amisc/aelflod.c
+++ b/util/amisc/aelflod.c
@@ -35,10 +35,15 @@ int elfabi = 3;                         /* abi = Linux */
 int elfmachine = 3;                     /* machine = EM_386 */
 
 /* Header and section table of an ack object file. */
- 
+
 struct outhead outhead;
 struct outsect outsect[S_MAX];
+struct outname* outname = NULL;
 char* stringarea;
+uint32_t ack_off_char;
+int nstab = 0;                          /* S_STB symbol count */
+int nsym = 0;                           /* other symbol count */
+int nlocal = 0;                         /* local symbols */
 
 char* outputfile = NULL;                /* Name of output file, or NULL */
 char* program;                          /* Name of current program: argv[0] */
@@ -49,23 +54,30 @@ FILE* output;                           /* Output stream */
 #define readf(a, b, c)	fread((a), (b), (int)(c), input)
 #define writef(a, b, c)	fwrite((a), (b), (int)(c), output)
 
-/* Header and program header table of an ELF object file. */
+/* Contents of an ELF object file. */
 
 #define ELF_HEADER_SIZE 0x34
 #define PROGRAM_HEADER_SIZE 0x20
 #define PROGRAM_HEADER_COUNT 1
-unsigned long codeoffset;
+#define SECTION_HEADER_SIZE 0x28
+#define STAB_SYMBOL_SIZE 12
+#define ELF_SYMBOL_SIZE 16
+
+uint32_t code_offset;       /* ELF segment */
+uint32_t stab_offset;       /* Debugger symbol table */
+uint32_t symtab_offset;     /* ELF symbol table */
+uint32_t strtab_offset;     /* String table */
+uint32_t shstrtab_offset;   /* Section header string table */
+uint32_t sh_offset;         /* ELF section headers */
+
+int sh_count = 0;           /* Number of ELF sections */
+int shstrtab_nr = 0;        /* Section number of .shstrtab */
+int shstrtab_size;
 
 const char elf_le_ident_string[] = {
 	0x7F, 'E', 'L', 'F'
 };
 
-/* Output file definitions and such */
-
-#define HDR_LENGTH	32
-
-char hdr[HDR_LENGTH] ;
-
 bool verbose = false;
 
 /* Segment numbers understood by aelflod. */
@@ -78,13 +90,33 @@ enum {
 	NUM_SEGMENTS
 };
 
-#define N_EXT	040
-#define N_UNDEF	00
-#define N_ABS	01
-#define N_TEXT	02
-#define N_DATA	03
-#define N_BSS	04
-#define N_FN	037
+/*
+ * ELF section numbers count up in the order that we write the ELF
+ * section headers.  If we have no debugger symbols, we will skip
+ * .stab and .stabstr, then subtract 2 from all later numbers.
+ */
+enum {
+	N_UNDEF = 0,
+	N_TEXT,
+	N_RODATA,
+	N_DATA,
+	N_BSS,
+	N_STAB,
+	N_STABSTR,
+	N_SYMTAB,
+	N_STRTAB,
+	N_SHSTRTAB,
+	NUM_ELF_SECTIONS,
+};
+const char shstrtab[] =
+	"\0.text\0.rodata\0.data\0.bss\0.stab\0.stabstr\0"
+	".symtab\0.strtab\0.shstrtab";
+	/* Compiler appends one more "\0". */
+const int sh_name[] = {
+	/* Index of each name in shstrtab: */
+	0, 1, 7, 15, 21, 26, 32,
+	41, 49, 57,
+};
 
 /* Produce an error message and exit. */
 
@@ -121,6 +153,80 @@ int follows(struct outsect* pa, struct outsect* pb)
 	return (pa->os_base >= align(pb->os_base+pb->os_size, pa->os_lign));
 }
 
+/* Convert a symbol's name index from ack.out to ELF. */
+
+uint32_t cvname(struct outname* n)
+{
+	if (n->on_foff) {
+		/* ack.out: offset from beginning of file
+		 * ELF: index in string table
+		 * the + 1 because we prepend a '\0' */
+		return n->on_foff - ack_off_char + 1;
+	} else
+		return 0;  /* no name */
+}
+
+/* Convert a symbol's type and binding from ack.out to ELF. */
+
+int cvinfo(struct outname* n)
+{
+	int bind, type;
+
+	switch (n->on_type & S_ETC) {
+		case S_SCT:
+			type = 3;  /* STT_SECTION */
+			break;
+		case S_FIL:
+		case S_MOD:
+			type = 4;  /* STT_FILE */
+			break;
+		default:
+			switch (n->on_type & S_TYP) {
+				case S_MIN + TEXT:
+					type = 2;  /* STT_FUNC */
+					break;
+				case S_MIN + ROM:
+				case S_MIN + DATA:
+				case S_MIN + BSS:
+				case S_MIN + NUM_SEGMENTS:
+					type = 1;  /* STT_OBJECT */
+					break;
+				default:
+					type = 0;  /* STT_NOTYPE */
+					break;
+			}
+			break;
+	}
+
+	if (n->on_type & S_EXT)
+		bind = 1;  /* STB_GLOBAL */
+	else
+		bind = 0;  /* STB_LOCAL */
+
+	return (bind << 4) | type;
+}
+
+/* Convert a symbol's section index from ack.out to ELF. */
+
+int cvsect(struct outname* n)
+{
+	switch (n->on_type & S_TYP) {
+		case S_ABS:
+			return 0xfff1;  /* SHN_ABS */
+		case S_MIN + TEXT:
+			return N_TEXT;
+		case S_MIN + ROM:
+			return N_RODATA;
+		case S_MIN + DATA:
+			return N_DATA;
+		case S_MIN + BSS:
+		case S_MIN + NUM_SEGMENTS:
+			return N_BSS;
+		default:
+			return N_UNDEF;
+	}
+}
+
 /* Writes a byte. */
 
 void emit8(unsigned char value)
@@ -220,6 +326,210 @@ void emitphdr(unsigned long address, unsigned long filesize,
 	fileoffset += filesize;
 }
 
+/* The next few functions write parts of the symbol table. */
+
+void emit_stab(void)
+{
+	struct outname* n;
+	int i;
+
+	for (i = 0; i < outhead.oh_nname; i++) {
+		n = &outname[i];
+		if (n->on_type & S_STB) {
+			emit32(cvname(n));          /* name index */
+			emit8(n->on_type >> 8);     /* type */
+			emit8(cvsect(n));           /* section */
+			emit16(n->on_desc);         /* desc */
+			emit32(n->on_valu);         /* value */
+		}
+	}
+}
+
+void emit_symtab(void)
+{
+	struct outname* n;
+	int i, pass;
+	bool global;
+
+	/* ELF .symtab must have local symbols before other symbols.
+	 * We emit locals in pass 0, globals in pass 1. */
+	for (pass = 0; pass < 2; pass++) {
+		for (i = 0; i < outhead.oh_nname; i++) {
+			n = &outname[i];
+
+			/* Don't emit .stab symbol in .symtab. */
+			if (n->on_type & S_STB)
+				continue;
+
+			global = (n->on_type & S_EXT);
+			if ((pass == 0 && !global) ||
+			    (pass == 1 && global)) {
+				emit32(cvname(n));    /* name index */
+				emit32(n->on_valu);   /* value */
+				emit32(0);            /* size = unknown */
+				emit8(cvinfo(n));     /* info */
+				emit8(0);             /* other */
+				emit16(cvsect(n));    /* section */
+			}
+		}
+	}
+}
+
+void emit_strtab(void)
+{
+	/* We prepend a '\0' because ELF uses offset 0 for symbols
+	 * without a name. */
+	emit8('\0');
+	writef(stringarea, outhead.oh_nchar, 1);
+}
+
+void emit_shstrtab(void)
+{
+	if (nstab) {
+		writef(shstrtab, sizeof(shstrtab), 1);
+	} else {
+		/* Skip .stab and .stabstr */
+		int i = sh_name[N_SYMTAB];
+		writef(shstrtab, sh_name[N_STAB], 1);
+		writef(shstrtab + i, sizeof(shstrtab) - i, 1);
+	}
+}
+
+/* Writes out an ELF section header. */
+
+void emit_sh(int i)
+{
+	uint32_t name, type, flags, addr, offset, size, link, info,
+		 addralign, entsize;
+
+	/* If no debugger symbols, skip .stab and .stabstr */
+	if (nstab == 0 && (i == N_STAB || i == N_STABSTR))
+		return;
+
+	name = sh_name[i];
+	if (nstab == 0 && i >= N_STAB)
+		name -= (sh_name[N_SYMTAB] - sh_name[N_STAB]);
+
+	switch (i) {
+		case N_TEXT:
+		case N_RODATA:
+		case N_DATA:
+		case N_STAB:
+			type = 1;  /* SHT_PROGBITS */
+			break;
+		case N_BSS:
+			type = 8;  /* SHT_NOBITS */
+			break;
+		case N_SYMTAB:
+			type = 2;  /* SHT_SYMTAB */
+			break;
+		case N_STABSTR:
+		case N_STRTAB:
+		case N_SHSTRTAB:
+			type = 3;  /* SHT_STRTAB */
+			break;
+		default:
+			type = 0;  /* SHT_NULL */
+			break;
+	}
+
+	switch (i) {
+		case N_TEXT:
+			flags = 4|2;  /* SHF_EXECINSTR|SHF_ALLOC */
+			addr = outsect[TEXT].os_base;
+			offset = code_offset;
+			size = outsect[TEXT].os_size;
+			addralign = outsect[TEXT].os_lign;
+			break;
+		case N_RODATA:
+			flags = 2;    /* SHF_ALLOC */
+			addr = outsect[ROM].os_base;
+			offset = code_offset + outsect[TEXT].os_size;
+			size = outsect[ROM].os_size;
+			addralign = outsect[ROM].os_lign;
+			break;
+		case N_DATA:
+			flags = 2|1;  /* SHF_ALLOC|SHF_WRITE */
+			addr = outsect[DATA].os_base;
+			offset = code_offset + outsect[TEXT].os_size +
+				outsect[ROM].os_size;
+			size = outsect[DATA].os_size;
+			addralign = outsect[DATA].os_lign;
+			break;
+		case N_BSS:
+			flags = 2|1;  /* SHF_ALLOC|SHF_WRITE */
+			addr = outsect[BSS].os_base;
+			offset = code_offset + outsect[TEXT].os_size +
+				outsect[ROM].os_size + outsect[DATA].os_size;
+			size = outsect[BSS].os_size;
+			addralign = outsect[BSS].os_lign;
+			break;
+		default:
+			flags = addr = offset = size = addralign = 0;
+			break;
+	}
+
+	entsize = 0;
+	switch (i) {
+		case N_STAB:
+			offset = stab_offset;
+			size = STAB_SYMBOL_SIZE * nstab;
+			entsize = STAB_SYMBOL_SIZE;
+			break;
+		case N_SYMTAB:
+			offset = symtab_offset;
+			size = ELF_SYMBOL_SIZE * nsym;
+			entsize = ELF_SYMBOL_SIZE;
+			break;
+		case N_STABSTR:
+		case N_STRTAB:
+			/* .stabstr, .strtab share the string area */
+			offset = strtab_offset;
+			/* the + 1 because we prepend a '\0' */
+			size = 1 + outhead.oh_nchar;
+			break;
+		case N_SHSTRTAB:
+			offset = shstrtab_offset;
+			size = shstrtab_size;
+			break;
+	}
+
+	/* Link .stab to .stabstr and .symtab to .strtab */
+	switch (i) {
+		case N_STAB:
+			link = N_STABSTR;
+			break;
+		case N_SYMTAB:
+			link = N_STRTAB;
+			if (nstab == 0)
+				link -= 2;
+			break;
+		default:
+			link = 0;
+			break;
+	}
+
+	switch (i) {
+		case N_SYMTAB:
+			info = nlocal;
+			break;
+		default:
+			info = 0;
+			break;
+	}
+
+	emit32(name);
+	emit32(type);
+	emit32(flags);
+	emit32(addr);
+	emit32(offset);
+	emit32(size);
+	emit32(link);
+	emit32(info);
+	emit32(addralign);
+	emit32(entsize);
+}
+
 /* Macros from modules/src/object/obj.h */
 #define Xchar(ch)	((ch) & 0377)
 #define uget2(c)	(Xchar((c)[0]) | ((unsigned) Xchar((c)[1]) << 8))
@@ -264,6 +574,60 @@ int rsect(FILE* f, struct outsect* sect)
 	return 1 ;
 }
 
+/*
+ * Read the ack.out symbol table and string area.  Count symbols.
+ * Seek back to the current file position.
+ */
+int rnames(FILE* f)
+{
+	long told;
+	int i;
+
+	/* If no symbols, then do nothing successfully. */
+	if (outhead.oh_nname == 0)
+		return 1;
+
+	/* Seek to the symbol table. */
+	told = ftell(f);
+	if (told == -1)
+		return 0;
+	ack_off_char = OFF_CHAR(outhead);  /* for cvname() */
+	if (fseek(f, OFF_NAME(outhead), SEEK_SET))
+		return 0;
+
+	/* Using calloc(a, b) to check if a * b would overflow. */
+	outname = calloc(outhead.oh_nname, sizeof(outname[0]));
+	if (outname == NULL)
+		fatal("out of memory.");
+	for (i = 0; i < outhead.oh_nname; i++) {
+		char buf[SZ_NAME], *c;
+		if (fread(buf, SZ_NAME, 1, f) != 1)
+			return 0;
+		c = buf;
+		outname[i].on_foff = get4(c); c += 4;
+		outname[i].on_type = uget2(c); c += 2;
+		outname[i].on_desc = uget2(c); c += 2;
+		outname[i].on_valu = get4(c);
+		if (outname[i].on_type & S_STB) {
+			nstab++;
+		} else {
+			nsym++;
+			if (!(outname[i].on_type & S_EXT))
+				nlocal++;
+		}
+	}
+
+	stringarea = malloc(outhead.oh_nchar);
+	if (stringarea == NULL)
+		fatal("out of memory.");
+	if (fread(stringarea, outhead.oh_nchar, 1, f) != 1)
+		return 0;
+
+	if (fseek(f, told, SEEK_SET))
+		return 0;
+	return 1;
+}
+
 int main(int argc, char* argv[])
 {
 	/* General housecleaning and setup. */
@@ -287,7 +651,7 @@ int main(int argc, char* argv[])
 				break;
 
 			case 'h':
-				fprintf(stderr, "%s: Syntax: aelflod [-a<number>] [-b] [-h] [-l]\n\t[-m<number>] <inputfile> <outputfile>\n",
+				fprintf(stderr, "%s: Syntax: aelflod [-a<number>] [-b] [-h] [-l]\n\t[-m<number>] [-v] <inputfile> <outputfile>\n",
 					program);
 				exit(0);
 
@@ -360,6 +724,11 @@ int main(int argc, char* argv[])
 		}
 	}
 
+	/* Read the symbol table, then seek back to the section data. */
+
+	if (!rnames(input))
+		fatal("failed to read symbol table.");
+
 	/* A few checks */
 
 	if (outsect[BSS].os_flen != 0)
@@ -387,8 +756,8 @@ int main(int argc, char* argv[])
 
 	/* Ensure the base address doesn't overlap the file header. */
 
-	codeoffset = outsect[TEXT].os_base & 0x1FFF;
-	if (codeoffset < (ELF_HEADER_SIZE + PROGRAM_HEADER_SIZE*PROGRAM_HEADER_COUNT))
+	code_offset = outsect[TEXT].os_base & 0x1FFF;
+	if (code_offset < (ELF_HEADER_SIZE + PROGRAM_HEADER_SIZE*PROGRAM_HEADER_COUNT))
 		fatal("base address too small --- overlaps ELF header");
 
 	/* Rationalise the memory sizes. */
@@ -398,6 +767,30 @@ int main(int argc, char* argv[])
 	outsect[DATA].os_size = outsect[BSS ].os_base - outsect[DATA].os_base;
 	outsect[BSS ].os_size = align(outsect[BSS].os_size, outsect[BSS].os_lign);
 
+	stab_offset = code_offset + outsect[TEXT].os_size +
+	    outsect[ROM].os_size + outsect[DATA].os_size;
+
+	/* If we have symbols, then calculate some offsets. */
+
+	if (outhead.oh_nname) {
+		sh_count = NUM_ELF_SECTIONS;
+		shstrtab_nr = N_SHSTRTAB;
+		shstrtab_size = sizeof(shstrtab);
+		if (nstab == 0) {
+			/* Skip .stab and .stabstr */
+			sh_count -= 2;
+			shstrtab_nr -= 2;
+			shstrtab_size -=
+			    (sh_name[N_SYMTAB] - sh_name[N_STAB]);
+		}
+
+		symtab_offset = stab_offset + STAB_SYMBOL_SIZE * nstab;
+		strtab_offset = symtab_offset + ELF_SYMBOL_SIZE * nsym;
+		/* the + 1 because we prepend a '\0' */
+		shstrtab_offset = strtab_offset + 1 + outhead.oh_nchar;
+		sh_offset = shstrtab_offset + shstrtab_size;
+	}
+
 	/* Write out the ELF file header. */
 	
 	writef(elf_le_ident_string, 4, 1);
@@ -414,33 +807,29 @@ int main(int argc, char* argv[])
 	emit32(1);                         /* ELF version again */
 	emit32(outsect[TEXT].os_base);     /* entry point */
 	emit32(ELF_HEADER_SIZE);           /* program header offset */
-	emit32(0);                         /* section header offset */
+	emit32(sh_offset);                 /* section header offset */
 	emit32(0);                         /* flags */
 	emit16(ELF_HEADER_SIZE);           /* elf header size */
 	emit16(PROGRAM_HEADER_SIZE);       /* program header entry size */
 	emit16(1);                         /* number of program header entries */
-	emit16(0x28);                      /* section header entry size */
-	emit16(0);                         /* number of section header entries */
-	emit16(0);                         /* section header string table index = SHN_UNDEF */
+	emit16(SECTION_HEADER_SIZE);       /* section header entry size */
+	emit16(sh_count);                  /* number of section header entries */
+	emit16(shstrtab_nr);               /* section header string table index  */
 	
 	/* Write out a single rwx section for the entire program. */
 	
 	{
-		unsigned long filelength = codeoffset +
-			outsect[TEXT].os_size +
-			outsect[ROM].os_size +
-			outsect[DATA].os_size;
-			
-		unsigned long memlength = filelength +
-			outsect[BSS].os_size;
-		
-		emitphdr(outsect[TEXT].os_base & ~0x1FFF, filelength, memlength,
-			0, 4|2|1);
+		uint32_t filelength = stab_offset;
+		uint32_t memlength = filelength + outsect[BSS].os_size;
+
+		emitphdr(outsect[TEXT].os_base & ~0x1FFF,
+			 filelength, memlength, 0, 4|2|1);
 	}
 
 	/* Write padding until the code start. */
-	
-	fseek(output, codeoffset, SEEK_SET);
+
+	if (fseek(output, code_offset, SEEK_SET))
+		fatal("output seek error");
 
 	/* Write out the actual data. */
 	
@@ -448,6 +837,19 @@ int main(int argc, char* argv[])
 	emits(&outsect[ROM]);
 	emits(&outsect[DATA]);
 
+	/* Write out the symbol table and section headers. */
+
+	if (outhead.oh_nname) {
+		int i;
+		if (nstab)
+			emit_stab();
+		emit_symtab();
+		emit_strtab();
+		emit_shstrtab();
+		for (i = 0; i < NUM_ELF_SECTIONS; i++)
+			emit_sh(i);
+	}
+
 	if (ferror(output))
 		fatal("output write error");
 	if (outputfile)
@@ -459,7 +861,7 @@ int main(int argc, char* argv[])
 	{
 		uint32_t ss = 0;
 		printf("        address  length\n");
-		printf(" ehdr : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base & ~0x1FFF, codeoffset);
+		printf(" ehdr : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base & ~0x1FFF, code_offset);
 		printf(" text : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base, outsect[TEXT].os_size);
 		printf(" rom  : %08"PRIx32" %08"PRIx32"\n", outsect[ROM].os_base, outsect[ROM].os_size);
 		printf(" data : %08"PRIx32" %08"PRIx32"\n", outsect[DATA].os_base, outsect[DATA].os_size);
diff --git a/util/amisc/anm.1 b/util/amisc/anm.1
index 48cdff814..a76be02cd 100644
--- a/util/amisc/anm.1
+++ b/util/amisc/anm.1
@@ -1,4 +1,4 @@
-.TH ANM 1 "$Revision$"
+.TH ANM 1 2017-01-18
 .SH NAME
 anm  \-  print name list
 .SH SYNOPSIS
@@ -7,7 +7,8 @@ anm [ \-gnoprus ] [ file ... ]
 .I Anm
 prints the name list (symbol table) of each ack.out(5) format object
 .I file
-in the argument list. If an argument is an aal(1) or arch(1) archive,
+in the argument list.
+If an argument is an aal(1) or arch(1) archive,
 a listing of each object file in the archive will be produced.
 If no
 .I file
@@ -18,32 +19,24 @@ are listed.
 Each symbol name is preceded by its value, a section indicator
 and a type indicator.
 A section indicator can be
-.SM
-.B U
+.SB U
 (undefined symbol),
-.SM
-.B A
+.SB A
 (absolute symbol),
-.SM
-.B C
+.SB C
 (common symbol), a section number (section related symbol),
 or
-.SM
-.B -
+.SB \-
 (other symbol).
 A type indicator can be
-.SM
-.B F
+.SB F
 (filename),
-.SM
-.B M
+.SB M
 (module name),
-.SM
-.B E
+.SB E
 (external (global) symbol),
 or
-.SM
-.B -
+.SB \-
 (local symbol).
 The output is sorted alphabetically.
 .PP
@@ -69,6 +62,5 @@ Print only undefined symbols.
 .TP
 .B  \-s
 Sort in section order.
-.sh FILES
 .SH SEE ALSO
 ack.out(5)
diff --git a/util/amisc/ashow.1 b/util/amisc/ashow.1
index 842c8ea35..1aaac2623 100644
--- a/util/amisc/ashow.1
+++ b/util/amisc/ashow.1
@@ -1,12 +1,12 @@
-.TH ASLOD 1 "$Revision$"
+.TH ASHOW 1 2017-01-18
 .SH NAME
 ashow \- make the contents of an ACK object file human readable
 .SH SYNOPSIS
 ashow inputfile inputfile...
 .SH DESCRIPTION
 .I ashow
-dumps the contents of an ack.out file in human-readable form. It shows
+dumps the contents of an ack.out file in human-readable form.
+It shows
 details of all symbols, relocation entries, sections, and other information.
-
 .SH "SEE ALSO"
 ack.out(5)
diff --git a/util/amisc/ashow.c b/util/amisc/ashow.c
index 498ae3980..ec85de30d 100644
--- a/util/amisc/ashow.c
+++ b/util/amisc/ashow.c
@@ -140,6 +140,9 @@ showrelo()
 	case RELOPPC:
 		printf("\tPowerPC 26-bit address\n");
 		break;
+	case RELOLIS:
+		printf("\tPowerPC lis instruction\n");
+		break;
 	case RELOVC4:
 		printf("\tVideoCore IV address in 32-bit instruction\n");
 		break;
diff --git a/util/amisc/asize.1 b/util/amisc/asize.1
index 89454dcaf..36a4d6ada 100644
--- a/util/amisc/asize.1
+++ b/util/amisc/asize.1
@@ -1,4 +1,4 @@
-.TH ASIZE 1 "$Revision$"
+.TH ASIZE 1 2017-01-18
 .SH NAME
 asize \- size of an object file
 .SH SYNOPSIS
diff --git a/util/amisc/aslod.1 b/util/amisc/aslod.1
index a786b13e6..5a1f857a0 100644
--- a/util/amisc/aslod.1
+++ b/util/amisc/aslod.1
@@ -1,20 +1,20 @@
-.TH ASLOD 1 "$Revision$"
+.TH ASLOD 1 2017-01-18
 .SH NAME
 aslod \- ACK simple loader
 .SH SYNOPSIS
-aslod [-h] [-v] inputfile outputfile
+.B aslod
+[\-h] [\-v] inputfile outputfile
 .SH DESCRIPTION
 .I aslod
-converts an absolute ack.out file into a simple binary memory
-dump. It is suitable for producing RAM images, executables for
+converts an absolute ack.out file into a simple binary memory dump.
+It is suitable for producing RAM images, executables for
 simple operating systems such as CP/M, DOS, etc.
-
+.PP
 The input file must contain exactly four segments: TEXT, ROM,
 DATA and BSS, in that order, all occupying contiguous memory.
 The file must have all references resolved and be linked to a
 fixed address. aslod will dump the segments, in order, such
 that the first byte of TEXT is at offset 0 in the file
 (regardless of where it is in memory).
-
 .SH "SEE ALSO"
 ack.out(5)
diff --git a/util/amisc/aslod.c b/util/amisc/aslod.c
index afc8f8c3e..72fbc8ce4 100644
--- a/util/amisc/aslod.c
+++ b/util/amisc/aslod.c
@@ -45,12 +45,6 @@ FILE* output;                           /* Output stream */
 #define readf(a, b, c)	fread((a), (b), (int)(c), input)
 #define writef(a, b, c)	fwrite((a), (b), (int)(c), output)
 
-/* Output file definitions and such */
-
-#define HDR_LENGTH	32
-
-char hdr[HDR_LENGTH] ;
-
 bool verbose = false;
 
 /* Segment numbers understood by aslod. */
@@ -63,14 +57,6 @@ enum {
 	NUM_SEGMENTS
 };
 
-#define N_EXT	040
-#define N_UNDEF	00
-#define N_ABS	01
-#define N_TEXT	02
-#define N_DATA	03
-#define N_BSS	04
-#define N_FN	037
-
 /* Produce an error message and exit. */
 
 void fatal(const char* s, ...)
diff --git a/util/amisc/astrip.1 b/util/amisc/astrip.1
index 2f83bf1ab..1a3fa5433 100644
--- a/util/amisc/astrip.1
+++ b/util/amisc/astrip.1
@@ -1,4 +1,4 @@
-.TH ASTRIP 1 "$Revision$"
+.TH ASTRIP 1 2017-01-18
 .SH NAME
 astrip  \-  remove symbols and relocation information
 .SH SYNOPSIS
@@ -11,6 +11,7 @@ ack.out(5) format object files.
 This is useful to save space after a program has been
 debugged.
 .SH FILES
-/tmp/s?	temporary file
+.IP /tmp/s? 16n
+temporary file
 .SH "SEE ALSO"
 ack.out(5)
diff --git a/util/amisc/build.lua b/util/amisc/build.lua
index d1b8a3356..22fa396cf 100644
--- a/util/amisc/build.lua
+++ b/util/amisc/build.lua
@@ -4,7 +4,10 @@ local function simpleprogram(name)
 		srcs = { "./"..name..".c" },
 		deps = {
 			"h+emheaders",
+			"modules/src/alloc+lib",
+			"modules/src/data+lib",
 			"modules/src/object+lib",
+			"modules/src/system+lib",
 		}
 	}
 
@@ -12,11 +15,12 @@ local function simpleprogram(name)
 		name = name.."-pkg",
 		map = {
 			["$(INSDIR)/bin/"..name] = "+"..name,
-			["$(PLATIND)/man/man1/"..name..".1"] = "./"..name..".1",
+			["$(INSDIR)/share/man/man1/"..name..".1"] = "./"..name..".1",
 		}
 	}
 end
 
+simpleprogram("abmodules")
 simpleprogram("aelflod")
 simpleprogram("anm")
 simpleprogram("ashow")
@@ -27,6 +31,7 @@ simpleprogram("astrip")
 installable {
 	name = "pkg",
 	map = {
+		"+abmodules-pkg",
 		"+aelflod-pkg",
 		"+anm-pkg",
 		"+ashow-pkg",
diff --git a/util/arch/aal.1 b/util/arch/aal.1
index 93b41191e..7f9af68ed 100644
--- a/util/arch/aal.1
+++ b/util/arch/aal.1
@@ -1,5 +1,4 @@
-.\" $Id$
-.TH AAL 1 "$Revision$"
+.TH AAL 1 2017-01-18
 .ad
 .SH NAME
 aal \- archive and library maintainer
@@ -18,10 +17,10 @@ only understands archives made with
 .PP
 .I Key
 is one character from the set
-.B qdrtx,
+.BR qdrtx ,
 optionally concatenated with
 one or more of
-.B vlc.
+.BR vlc .
 .I Afile
 is the archive file.
 The
@@ -82,9 +81,10 @@ The create option supresses the normal message that is produced when
 .I afile
 is created.
 .SH FILES
-/tmp/ar.* temporaries
+.IP /tmp/ar.* 16
+temporaries
 .SH "SEE ALSO"
-led(6), arch(5),
+led(6), arch(5)
 .SH BUGS
 If the same file is mentioned twice in an argument list,
 it may be put in the archive twice.
diff --git a/util/arch/build.lua b/util/arch/build.lua
index 54b05f981..160b9c21f 100644
--- a/util/arch/build.lua
+++ b/util/arch/build.lua
@@ -17,6 +17,6 @@ installable {
 	name = "pkg",
 	map = {
 		["$(INSDIR)/bin/aal"] = "+aal",
-		["$(PLATIND)/man/man1/aal.1"] = "./aal.1"
+		["$(INSDIR)/share/man/man1/aal.1"] = "./aal.1"
 	}
 }
diff --git a/util/build/build.lua b/util/build/build.lua
new file mode 100644
index 000000000..41bd0b6ad
--- /dev/null
+++ b/util/build/build.lua
@@ -0,0 +1,8 @@
+cprogram {
+	name = "testrunner",
+	srcs = { "./testrunner.c" },
+	deps = { 
+        "modules/src/data+lib"
+    }
+}
+
diff --git a/util/build/testrunner.c b/util/build/testrunner.c
new file mode 100644
index 000000000..fb2add562
--- /dev/null
+++ b/util/build/testrunner.c
@@ -0,0 +1,117 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include "diagnostics.h"
+
+static bool timed_out = false;
+static bool child_exited = false;
+static char* const* command = NULL;
+static int timeout = 0;
+static int pid = 0;
+
+static void parse_arguments(int argc, char* const argv[])
+{
+    program_name = argv[0];
+    for (;;)
+    {
+        int c = getopt(argc, argv, "t:");
+        if (c == -1)
+            break;
+
+        switch (c)
+        {
+            case 't':
+                timeout = atoi(optarg);
+                break;
+
+            default:
+                fatal("syntax: testrunner <timeout in secs> -- <command>\n");
+        }
+    }
+
+    command = &argv[optind];
+    if (!command[0])
+        fatal("you must supply a command");
+    if (timeout <= 0)
+        fatal("timeout missing or invalid");
+}
+
+static void sigalrm_cb(int sigraised)
+{
+    timed_out = true;
+    if (pid)
+        kill(pid, SIGKILL);
+}
+
+int main(int argc, char* const argv[])
+{
+    const int READ = 0;
+    const int WRITE = 1;
+
+    int fds[2];
+    FILE* childin;
+    int wstatus;
+    char buffer[4096];
+    char* p;
+
+    parse_arguments(argc, argv);
+
+    pipe(fds);
+    pid = fork();
+    if (pid == 0)
+    {
+        /* Child */
+        close(fds[READ]);
+        close(0);
+        dup2(fds[WRITE], 1);
+        dup2(fds[WRITE], 2);
+        execvp(command[0], command);
+        _exit(1);
+    }
+    else
+    {
+        /* Parent */
+        close(fds[WRITE]);
+        signal(SIGALRM, sigalrm_cb);
+        alarm(timeout);
+    }
+
+    childin = fdopen(fds[READ], "r");
+    if (!childin)
+        fatal("cannot open pipe");
+
+    while (!timed_out)
+    {
+        if (!fgets(buffer, sizeof(buffer), childin))
+            break;
+        fputs(buffer, stdout);
+
+        p = buffer;
+        while (isspace(*p))
+            p++;
+
+        if (strcmp(p, "@@FINISHED\n") == 0)
+            break;
+        if (strcmp(p, "@@FINISHED\r\n") == 0)
+            break;
+    }
+
+    /* Reached via EOF or seeing a @@FINISHED. */
+
+    alarm(0);
+
+    kill(pid, SIGKILL);
+    waitpid(pid, &wstatus, 0);
+    if (timed_out)
+    {
+        fprintf(stderr, "@@TIMEDOUT\n");
+        exit(1);
+    }
+    exit(WEXITSTATUS(wstatus));
+}
diff --git a/util/ego/descr/build.lua b/util/ego/descr/build.lua
index 034ffa3ce..e9a008cc5 100644
--- a/util/ego/descr/build.lua
+++ b/util/ego/descr/build.lua
@@ -22,6 +22,7 @@ end
 build_descr("i386")
 build_descr("i86")
 build_descr("m68020")
+build_descr("powerpc")
 
 installable {
 	name = "pkg",
diff --git a/util/ego/descr/powerpc.descr b/util/ego/descr/powerpc.descr
new file mode 100644
index 000000000..5138cc44b
--- /dev/null
+++ b/util/ego/descr/powerpc.descr
@@ -0,0 +1,118 @@
+wordsize: 4
+pointersize: 4
+%%RA
+general registers: 19
+address registers: 0
+floating point registers: 0
+use general as pointer: yes
+
+register score parameters:
+	local variable:
+		(2 cases)
+		pointer,general
+			(1 size)
+			default ->	(3,4)
+		general,general
+			(1 size)
+			default ->	(3,4)
+	address of local variable:
+		(2 cases)
+		pointer,general
+			(1 size)
+			default ->	(0,0)
+		general,general
+			(1 size)
+			default ->	(0,0)
+	constant:
+		(2 sizes)
+		fitbyte ->	(-1,-1)
+		default ->	(-1,-1)
+	double constant:
+		(1 size)
+		default ->	(-1,-1)
+	address of global variable:
+		(1 size)
+		default ->	(2,8)
+	address of procedure:
+		(1 size)
+		default ->	(-1,-1)
+
+opening cost parameters:
+	local variable:
+		(2 cases)
+		pointer
+			(1 size)
+			default ->	(3,4)
+		general
+			(1 size)
+			default ->	(3,4)
+	address of local variable:
+		(2 cases)
+		pointer
+			(1 size)
+			default ->	(1,4)
+		general
+			(1 size)
+			general ->	(1,4)
+	constant:
+		(2 sizes)
+		fitbyte ->	(1000,1000)
+		default ->	(1000,1000)
+	double constant:
+		(1 size)
+		default ->	(1000,1000)
+	address of global variable:
+		(1 size)
+		default ->	(2,8)
+	address of procedure:
+		(1 size)
+		default ->	(1000,1000)
+
+register save costs:
+	(21 cases)
+	0 -> (0,0)
+	1 -> (6,8)
+	2 -> (12,16)
+	3 -> (18,24)
+	4 -> (24,32)
+	5 -> (30,40)
+	6 -> (36,48)
+	7 -> (42,56)
+	8 -> (48,64)
+	9 -> (54,72)
+	10 -> (60,80)
+	11 -> (66,88)
+	12 -> (72,96)
+	13 -> (78,104)
+	14 -> (84,112)
+	15 -> (90,120)
+	16 -> (96,128)
+	17 -> (102,136)
+	18 -> (108,144)
+	19 -> (114,152)
+	0 -> (0,0)
+%%UD
+access costs of global variables:
+	(1 size)
+	default ->	(5,12)
+access costs of local variables:
+	(1 size)
+	default ->	(3,4)
+%%SR
+overflow harmful?:  no
+array bound harmful?:  yes
+reduce sli if shift count larger than:  0
+%%CS
+#include "em_mnem.h"
+first time then space:
+addressing modes: op_ads op_adp op_lof op_ldf op_loi op_dch op_lpb -1
+		  op_ads op_adp op_lof op_ldf op_loi op_dch op_lpb -1
+cheap operations: op_cii op_ciu op_cui op_cuu op_cmi op_cmu op_cmp -1 
+		  op_cii op_ciu op_cui op_cuu op_cmi op_cmu op_cmp -1
+lexical tresholds: 1 1
+indirection limit: 8
+do not eliminate sli if index on shiftcounts:	-1
+						-1
+forbidden operators: -1 -1
+%%SP
+global stack pollution allowed?: yes
diff --git a/util/led/ack.out.5 b/util/led/ack.out.5
index b49b0976b..c8b9fc8fa 100644
--- a/util/led/ack.out.5
+++ b/util/led/ack.out.5
@@ -1,4 +1,4 @@
-.TH "ACK.OUT" 5 "$Revision$"
+.TH "ACK.OUT" 5 2017-01-18
 .ad
 .SH NAME
 ack.out\ \-\ ACK-assembler and link editor output
@@ -14,7 +14,7 @@ further processed on another.
 .ta \w'#define x'u +\w'XXXXXXXX'u +\w'XXXXXXXXXXX'u
 .PP
 In the following discussion, some structures are defined using
-\fBlong\fR and \fBshort\fR as type indicators. 
+\fBlong\fR and \fBshort\fR as type indicators.
 It is assumed that the size of a short is 2 bytes (chars) and that the
 size of a long is 4 bytes.
 However, these types
@@ -55,7 +55,9 @@ struct outhead {
 };
 .fi
 .PP
+.nf
 #define HF_LINK	0x0004	/* unresolved references left */
+.fi
 .PP
 The fields of this structure have the following purpose:
 .nr x \w'oh_magic\ \ \ 'u
@@ -131,9 +133,10 @@ in tact.
 .br
 The next part of an object file contains the sections themselves.
 Usually, the LED program places the sections right behind one another in the
-target machine, taking the
-alignment requirements into account. However, the user is allowed to give
-the start addresses of each section. But if the user gave a start address for
+target machine, taking the alignment requirements into account.
+However, the user is allowed to give
+the start addresses of each section.
+But if the user gave a start address for
 say section 2, but not for section 3, section 3 will be put
 right behind section 2.
 .PP
@@ -158,12 +161,13 @@ struct outrelo {
 /*
  * relocation type bits
  */
-#define RELSZ	0x0fff      /* relocation length */
+#define RELSZ	0x0fff		/* relocation length */
 #define RELO1	0x01		/* 1 byte */
 #define RELO2	0x02		/* 2 bytes */
 #define RELO4	0x03		/* 4 bytes */
 #define RELOPPC	0x04		/* 26-bit PowerPC address */
-#define RELOVC4 0x06        /* VideoCore IV address in 32-bit insruction */
+#define RELOLIS	0x05		/* PowerPC lis */
+#define RELOVC4	0x06 /* VideoCore IV address in 32-bit insruction */
 #define RELPC	0x2000		/* pc relative */
 #define RELBR	0x4000		/* High order byte lowest address. */
 #define RELWR	0x8000		/* High order word lowest address. */
@@ -194,13 +198,16 @@ The fields of this structure have the following purpose:
 Contains several flags: One of RELO1, RELO2 and RELO4 is set, indicating the
 size of the relocatable datum, RELPC is set when the datum is
 relocated pc relative, RELBR and RELWR indicate byte and word order of
-the relocatable datum. RELBR and RELWR are needed here. It is not sufficient
+the relocatable datum.
+RELBR and RELWR are needed here.
+It is not sufficient
 to have flags for them in the header of the object file, because some
 machines (NS 32016) use several of the possible combinations in their
 instruction encoding.
 .IP or_sect \nxu
-Contains the section number of the referenc\fIing\fR section. This is a number
-that lies between S_MIN and S_MAX. The section indicated with number S_MIN
+Contains the section number of the referenc\fIing\fR section.
+This is a number that lies between S_MIN and S_MAX.
+The section indicated with number S_MIN
 is the first section in the sections-section, etc.
 .IP or_addr \nxu
 Contains the address of the relocatable datum, in the form of an
@@ -209,18 +216,33 @@ offset from the base of the section indicated in the \fIor_sect\fR field.
 Usually contains the index of the referenced symbol in the symbol table,
 starting at 0.
 In this case, the reference is to an undefined external symbol, a common
-symbol, or a section name. The relocatable datum then contains
+symbol, or a section name.
+The relocatable datum then contains
 an offset from the indicated symbol or the start of the indicated section.
 It may, however, also have the same value as
-the \fIoh_nname\fR field of the header. In this case the relocatable datum
+the \fIoh_nname\fR field of the header.
+In this case the relocatable datum
 is an absolute number, and the datum is relocated pc relative.
 The relocatable datum must then be relocated with respect to the
 base address of its section.
 .PP
+For RELOPPC and RELOVC4, the relocatable datum is a PowerPC or
+VideoCore IV instruction.
+The relocation depends on the instruction, and uses an offset encoded
+in the instruction.
+.PP
+RELOLIS assembles a PowerPC \fBlis\fR instruction.
+The relocatable datum is a 4-byte integer.
+The high bit is set for ha16 or clear for hi16.
+The next 5 bits are the register \fIRT\fR.
+The low 26 bits are a signed offset.
+The relocation replaces the datum with the PowerPC instruction
+\(oq\fBlis\fR\ \fIRT\fR,\ ha16[\fIsymbol\fR\ +\ \fIoffset\fR]\(cq.
+.PP
 .B The symbol table.
 .br
-This table contains definitions of symbols. It is referred to by
-outrelo-structures, and can be used by debuggers.
+This table contains definitions of symbols.
+It is referred to by outrelo-structures, and can be used by debuggers.
 Entries in this table have the following structure:
 .PP
 .nf
@@ -250,12 +272,13 @@ struct outname {
 .PP
 The members of this structure have the following purpose:
 .IP on_foff \nxu
-Contains the offset of the name from the beginning of the file. The name
-extends from the offset to the next null byte.
+Contains the offset of the name from the beginning of the file.
+The name extends from the offset to the next null byte.
 .IP on_type \nxu
 The S_TYP field of this member contains the section number of the symbol.
 Here, this number may be S_ABS for an absolute item, or S_UND, for an
-undefined item. The S_EXT flag is set in this member if the symbol is external.
+undefined item.
+The S_EXT flag is set in this member if the symbol is external.
 The S_ETC field has the following flags:
 S_SCT is set if the symbol represents a section name,
 S_COM is set if the symbol represents a common name,
@@ -265,15 +288,16 @@ and S_MOD is set if the symbol refers to an assembler source file item.
 .IP on_desc \nxu
 Currently not used.
 .IP on_valu \nxu
-Is not used if the symbol refers to an undefined item. For absolute items
+Is not used if the symbol refers to an undefined item.
+For absolute items
 it contains the value, for common names it contains the size, and
 for anything else it contains the offset from the beginning of the section.
 In a fully linked binary, the beginning of the section is added.
 .PP
 .B The string area.
 .br
-The last part of an object file contains the name list. This is just a
-sequence of null-terminated strings.
+The last part of an object file contains the name list.
+This is just a sequence of null-terminated strings.
 .PP
 The relocation information, the symbol table, and the name list do not
 have to be present, but then of course we do not have a relocatable
@@ -283,7 +307,6 @@ object file.
 .br
 The following miscellaneous defines might come in handy when reading
 object files:
-.fi
 .PP
 .nf
 /*
diff --git a/util/led/archive.c b/util/led/archive.c
index e36958d17..7e39e9fb7 100644
--- a/util/led/archive.c
+++ b/util/led/archive.c
@@ -6,8 +6,10 @@
 static char rcsid[] = "$Id$";
 #endif
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include "arch.h"
 #include "out.h"
 #include "ranlib.h"
diff --git a/util/led/const.h b/util/led/const.h
index 40ad395b5..d2d27f51a 100644
--- a/util/led/const.h
+++ b/util/led/const.h
@@ -4,8 +4,6 @@
  */
 /* $Id$ */
 
-typedef int		bool;
-
 #define FALSE		0
 #define TRUE		1
 
diff --git a/util/led/debug.h b/util/led/debug.h
index 0e493185d..715409d25 100644
--- a/util/led/debug.h
+++ b/util/led/debug.h
@@ -17,3 +17,5 @@ extern int DEB;
 
 extern int Verbose;
 #define verbose(s, a1, a2, a3, a4)	(Verbose && do_verbose(s, a1, a2, a3, a4))
+
+extern void fatal(char* format, ...);
diff --git a/util/led/error.c b/util/led/error.c
index e7f4fc6ec..61dc7983e 100644
--- a/util/led/error.c
+++ b/util/led/error.c
@@ -6,9 +6,11 @@
 static char rcsid[] = "$Id$";
 #endif
 
-#include <stdarg.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
 #include <out.h>
 #include "const.h"
 
@@ -73,7 +75,7 @@ do_verbose(char *format, ...)
 static void
 diag(char *tail, char *format, va_list ap)
 {
-	extern char	*progname, *archname, *modulname; 
+	extern char	*progname, *archname, *modulname;
 
 	fprintf(stderr, "%s: ", progname);
 	if (archname && modulname)
diff --git a/util/led/extract.c b/util/led/extract.c
index 5878d527d..48a2f16c6 100644
--- a/util/led/extract.c
+++ b/util/led/extract.c
@@ -6,8 +6,10 @@
 static char rcsid[] = "$Id$";
 #endif
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include "out.h"
 #include "const.h"
 #include "debug.h"
diff --git a/util/led/finish.c b/util/led/finish.c
index 2eace760b..439d4b364 100644
--- a/util/led/finish.c
+++ b/util/led/finish.c
@@ -6,6 +6,10 @@
 static char rcsid[] = "$Id$";
 #endif
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <out.h>
 #include "const.h"
 #include "defs.h"
diff --git a/util/led/led.6 b/util/led/led.6
index c89866efe..8e4b98e69 100644
--- a/util/led/led.6
+++ b/util/led/led.6
@@ -1,4 +1,4 @@
-.TH LED 6 "$Revision$"
+.TH LED 6 2017-01-18
 .ad
 .SH NAME
 led \- link editor
@@ -78,7 +78,7 @@ The previous remarks about
 and
 .I nnnn
 apply.
-.TP 
+.TP
 .B \-o
 The
 .I name
@@ -88,7 +88,7 @@ is used as the name of the
 .I led
 output file, instead of
 .BR a.out .
-.TP 
+.TP
 .B  \-r
 Generate relocation information in the output file
 so that it can be the subject of another
@@ -104,7 +104,8 @@ at load time. This flag disables the \fB\-r\fP flag.
 .TP
 .B \-n
 Usually, after linking, a value in the namelist represents an absolute
-address. Sometimes, particularly when using the \fB\-c\fR flag, it may be
+address.
+Sometimes, particularly when using the \fB\-c\fR flag, it may be
 useful to have as value the offset with respect to the beginning of the
 corresponding section. The \fB\-n\fR flag enables this.
 .TP
@@ -112,7 +113,7 @@ corresponding section. The \fB\-n\fR flag enables this.
 `Strip' the output, that is, remove the name table
 and relocation information to save space (but impair the
 usefulness of the debuggers).
-.TP 
+.TP
 .B  \-u
 Take the following argument as a symbol and enter
 it as undefined in the name table.
@@ -129,9 +130,12 @@ chose to link it (which unresolved reference it resolves).
 This option is useful in resolving 'multiply defined' problems.
 .SH FILES
 ~em/lib.bin/em_led
-a.out	output file
+.PD 0
+.IP a.out 24n
+output file
+.PD
 .SH "SEE ALSO"
-ack(1)
-arch(1)
-ack.out.h(5)
+ack(1),
+arch(1),
+ack.out.h(5),
 uni_ass(6)
diff --git a/util/led/main.c b/util/led/main.c
index b176514cb..c9a3895d2 100644
--- a/util/led/main.c
+++ b/util/led/main.c
@@ -12,7 +12,9 @@ static char rcsid[] = "$Id$";
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <out.h>
 #include "const.h"
 #include "debug.h"
@@ -31,15 +33,16 @@ int		Verbose = 0;
 
 static			initializations();
 static			first_pass();
-static long		number();
-static			setlign();
-static			setbase();
+static uint32_t		number(const char *);
+static void		setlign(int, uint32_t);
+static void		setbase(int, uint32_t);
 static struct outname	*makename();
 static			pass1();
 static			evaluate();
-static void norm_commons();
+static void		norm_commons();
 static			complete_sections();
-static void change_names();
+static void		change_names();
+static bool		setbit();
 static bool		tstbit();
 static			second_pass();
 static			pass2();
@@ -126,6 +129,8 @@ first_pass(argv)
 	register char		*argp;
 	int			sectno;
 	int			h;
+	extern int		atoi();
+	extern char		*strchr();
 	extern int		hash();
 	extern struct outname	*searchname();
 
@@ -166,7 +171,7 @@ first_pass(argv)
 		case 'c':
 			/*
 			 * Leave relocation information in the output, so that
-			 * a next pass can see where relocation was done. The 
+			 * a next pass can see where relocation was done. The
 			 * resulting output however is no longer relocatable.
 			 */
 			flagword &= ~RFLAG;
@@ -251,12 +256,11 @@ first_pass(argv)
  * else if it starts with 0, it's octal,
  * else it's decimal.
  */
-static long
-number(s)
-	register char	*s;
+static uint32_t
+number(const char *s)
 {
 	register int	digit;
-	register long	value = 0;
+	register uint32_t value = 0;
 	register int	radix = 10;
 
 	if (*s == '0') {
@@ -291,19 +295,17 @@ number(s)
  * not. Only one base may be given. The same applies for alignments.
  */
 static char	basemap[MAXSECT / WIDTH];
-static long	sect_base[MAXSECT];
+static uint32_t	sect_base[MAXSECT];
 static char	lignmap[MAXSECT / WIDTH];
-static long	sect_lign[MAXSECT];
+static uint32_t	sect_lign[MAXSECT];
 
 /*
 /*
  * Set the alignment of section `sectno' to `lign', if this doesn't
  * conflict with earlier alignment.
  */
-static
-setlign(sectno, lign)
-	register int	sectno;
-	register long	lign;
+static void
+setlign(int sectno, uint32_t lign)
 {
 	extern bool	setbit();
 
@@ -318,10 +320,8 @@ setlign(sectno, lign)
  * Set the base of section `sectno' to `base', if no other base has been
  * given yet.
  */
-static
-setbase(sectno, base)
-	register int	sectno;
-	register long	base;
+static void
+setbase(int sectno, uint32_t base)
 {
 	extern bool	setbit();
 
@@ -336,7 +336,7 @@ makename(string)
 {
 	static struct outname	namebuf;
 
-	namebuf.on_mptr = string;
+	namebuf.on_foff = string - core_position - mems[ALLOMODL].mem_base;
 	namebuf.on_type = S_UND + S_EXT;
 	namebuf.on_valu = (long)0;
 
@@ -459,8 +459,8 @@ struct orig	relorig[MAXSECT];
 static
 complete_sections()
 {
-	register long	base = 0;
-	register long	foff;
+	register uint32_t base = 0;
+	register uint32_t foff;
 	register struct outsect *sc;
 	register int	sectindex;
 
diff --git a/util/led/memory.c b/util/led/memory.c
index 6349c826a..df4ee99d9 100644
--- a/util/led/memory.c
+++ b/util/led/memory.c
@@ -22,6 +22,9 @@ static char rcsid[] = "$Id$";
  */
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <out.h>
 #include "const.h"
 #include "assert.h"
@@ -112,7 +115,7 @@ init_core()
 		incore = FALSE;	/* In core strategy failed. */
 		if (sbreak(AT_LEAST) == -1)
 			fatal("no core at all");
-		
+
 		base = BASE;
 		for (mem = mems; mem < &mems[NMEMS]; mem++) {
 			mem->mem_base = base;
@@ -198,15 +201,15 @@ compact(piece, incr, flag)
 		gain = (mem->mem_full + incr) >> SHIFT_COUNT;
 		if (incr < gain) incr = gain;
 	}
-	
+
 	/*
 	 * First, check that moving will result in enough space
 	 */
 	if (flag != FREEZE) {
 		gain = mem->mem_left;
 		for (mem = &mems[piece-1]; mem >= &mems[0]; mem--) {
-			/* 
-			 * Don't give it all away! 
+			/*
+			 * Don't give it all away!
 			 * If this does not give us enough, bad luck
 			 */
 			if (flag == FORCED)
@@ -224,8 +227,8 @@ compact(piece, incr, flag)
 		}
 		if (min == piece)
 		    for (mem = &mems[piece+1]; mem <= &mems[NMEMS - 1]; mem++) {
-			/* 
-			 * Don't give it all away! 
+			/*
+			 * Don't give it all away!
 			 * If this does not give us enough, bad luck
 			 */
 			if (flag == FORCED)
diff --git a/util/led/output.c b/util/led/output.c
index 0ee622e3a..835627631 100644
--- a/util/led/output.c
+++ b/util/led/output.c
@@ -6,6 +6,10 @@
 static char rcsid[] = "$Id$";
 #endif
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <out.h>
 #include "const.h"
 #include "memory.h"
@@ -60,7 +64,7 @@ generate_section_names()
 	extern struct outsect	outsect[];
 	extern char		*core_alloc();
 
-	size = (long)outhead.oh_nsect * sizeof(struct outname); 
+	size = (long)outhead.oh_nsect * sizeof(struct outname);
 	name = (struct outname *)core_alloc(ALLOGLOB, size);
 	if (name == (struct outname *)0)
 		return;
diff --git a/util/led/read.c b/util/led/read.c
index 95ec7dd6b..3ea15925c 100644
--- a/util/led/read.c
+++ b/util/led/read.c
@@ -6,6 +6,11 @@
 static char rcsid[] = "$Id$";
 #endif
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
 int	infile;	/* The current input file. */
 
 rd_fatal()
diff --git a/util/led/relocate.c b/util/led/relocate.c
index c72965e75..1b8960938 100644
--- a/util/led/relocate.c
+++ b/util/led/relocate.c
@@ -9,6 +9,7 @@ static char rcsid[] = "$Id$";
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <assert.h>
 #include "out.h"
 #include "const.h"
@@ -104,6 +105,30 @@ static uint32_t get_vc4_valu(char* addr)
 	assert(0 && "unrecognised VC4 instruction");
 }
 
+static bool is_powerpc_memory_op(uint32_t opcode)
+{
+	/* Tests for any PowerPC memory indirection instruction (or
+	 * addi) where the payload is a *signed* 16-bit value. */
+	switch ((opcode & 0xfc000000) >> 26)
+	{
+		case 14: /* addi */
+		case 34: /* lbz */
+		case 48: /* lfs */
+		case 50: /* lfd */
+		case 42: /* lha */
+		case 40: /* lhz */
+		case 32: /* lwz */
+		case 38: /* stb */
+		case 52: /* stfs */
+		case 54: /* stfd */
+		case 44: /* sth */
+		case 36: /* stw */
+			return true;
+	}
+
+	return false;
+}
+
 /* PowerPC fixups are complex as we need to patch up to the next two
  * instructions in one of several different ways, depending on what the
  * instructions area.
@@ -125,8 +150,32 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
 		/* addis / ori instruction pair */
 		return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
 	}
+	else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
+	         is_powerpc_memory_op(opcode2))
+	{
+		/* addis / memoryop instruction pair */
+		uint16_t hi = opcode1 & 0xffff;
+		uint16_t lo = opcode2 & 0xffff;
 
-	assert(0 && "unrecognised PowerPC instruction");
+		/* Undo the sign adjustment (see mach/powerpc/as/mach5.c). */
+
+		if (lo > 0x7fff)
+			hi--;
+
+		return ((hi << 16) | lo);
+	}
+
+	fatal("Don't know how to read from PowerPC fixup on instructions 0x%08lx+0x%08lx",
+		(unsigned long)opcode1, (unsigned long)opcode2);
+}
+
+/* RELOLIS stores a signed 26-bit offset in the low bits. */
+static uint32_t get_lis_valu(char *addr, uint16_t type)
+{
+	uint32_t valu = read4(addr, type) & 0x03ffffff;
+	if (valu & 0x02000000)
+		valu |= 0xfc000000; /* sign extension */
+	return valu;
 }
 
 /*
@@ -144,6 +193,8 @@ static uint32_t getvalu(char* addr, uint16_t type)
 		return read4(addr, type);
 	case RELOPPC:
 		return get_powerpc_valu(addr, type);
+	case RELOLIS:
+		return get_lis_valu(addr, type);
 	case RELOVC4:
 		return get_vc4_valu(addr);
 	default:
@@ -263,14 +314,58 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
 	else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
 	         ((opcode2 & 0xfc000000) == 0x60000000))
 	{
+		/* addis / ori instruction pair */
 		uint16_t hi = value >> 16;
 		uint16_t lo = value & 0xffff;
 
 		write4((opcode1 & 0xffff0000) | hi, addr+0, type);
 		write4((opcode2 & 0xffff0000) | lo, addr+4, type);
 	}
+	else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
+	         is_powerpc_memory_op(opcode2))
+	{
+		/* addis / memoryop instruction pair */
+		uint16_t hi = value >> 16;
+		uint16_t lo = value & 0xffff;
+
+		/* Apply the sign adjustment (see mach/powerpc/as/mach5.c). */
+
+		if (lo > 0x7fff)
+			hi++;
+
+		write4((opcode1 & 0xffff0000) | hi, addr+0, type);
+		write4((opcode2 & 0xffff0000) | lo, addr+4, type);
+	}
+
 	else
-		assert(0 && "unrecognised PowerPC instruction");
+		fatal("Don't know how to write a PowerPC fixup to instructions 0x%08lx+0x%08lx",
+			(unsigned long)opcode1, (unsigned long)opcode2);
+}
+
+/* Writes a PowerPC lis instruction. */
+static void put_lis_valu(char* addr, uint32_t value, uint16_t type)
+{
+	uint32_t opcode, reg;
+	uint16_t hi, lo;
+	bool ha16;
+
+	/* ha16 flag in high bit, register in next 5 bits */
+	opcode = read4(addr, type);
+	ha16 = opcode >> 31;
+	reg = (opcode >> 26) & 0x1f;
+
+	/*
+	 * Apply the sign adjustment if the ha16 flag is set and the
+	 * low half is a negative signed 16-bit integer.
+	 */
+	hi = value >> 16;
+	lo = value & 0xffff;
+	if (ha16 && lo > 0x7fff)
+		hi++;
+
+	/* Assemble lis reg, hi == addis reg, r0, hi. */
+	opcode = (15 << 26) | (reg << 21) | (0 << 16) | hi;
+	write4(opcode, addr, type);
 }
 
 /*
@@ -294,6 +389,9 @@ static putvalu(uint32_t valu, char* addr, uint16_t type)
 	case RELOPPC:
 		put_powerpc_valu(addr, valu, type);
 		break;
+	case RELOLIS:
+		put_lis_valu(addr, valu, type);
+		break;
 	case RELOVC4:
 		put_vc4_valu(addr, valu);
 		break;
@@ -339,7 +437,7 @@ addrelo(relo, names, valu_out)
 		extern int		hash();
 		extern struct outname	*searchname();
 		extern unsigned 	indexof();
-		extern struct outhead	outhead; 
+		extern struct outhead	outhead;
 
 		name = searchname(local->on_mptr, hash(local->on_mptr));
 		if (name == (struct outname *)0)
diff --git a/util/led/save.c b/util/led/save.c
index 3804413d9..952649633 100644
--- a/util/led/save.c
+++ b/util/led/save.c
@@ -10,8 +10,10 @@ static char rcsid[] = "$Id$";
  * If everything is kept in core, we must save some things for the second pass.
  */
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <string.h>
 #include "arch.h"
 #include "out.h"
diff --git a/util/led/scan.c b/util/led/scan.c
index a870f8e05..1740a14de 100644
--- a/util/led/scan.c
+++ b/util/led/scan.c
@@ -6,8 +6,10 @@
 static char rcsid[] = "$Id$";
 #endif
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #ifdef SYMDBUG
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/util/led/sym.c b/util/led/sym.c
index 2ec47b6b7..53f0f3440 100644
--- a/util/led/sym.c
+++ b/util/led/sym.c
@@ -10,8 +10,10 @@ static char rcsid[] = "$Id$";
  * Symbol table management.
  */
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include "out.h"
 #include "const.h"
 #include "memory.h"
@@ -49,7 +51,7 @@ init_symboltable()
  * in the hash table is followed. If the names match, a pointer to the outname
  * in this element of the list is returned. When a match cannot be found,
  * NIL is returned.
- */ 
+ */
 struct outname *
 searchname(string, hashval)
 	char			*string;
@@ -74,7 +76,7 @@ searchname(string, hashval)
 				debug("found %x, %x, %lx\n",
 					name->on_type, name->on_desc, name->on_valu, 0);
 				return name;
-			}	
+			}
 		symindex = sym->sy_next;
 	}
 	/* Not found. */
diff --git a/util/led/write.c b/util/led/write.c
index d77ea98ef..b916949ae 100644
--- a/util/led/write.c
+++ b/util/led/write.c
@@ -6,8 +6,10 @@
 static char rcsid[] = "$Id$";
 #endif
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <string.h>
 #include "out.h"
 #include "const.h"
@@ -75,7 +77,7 @@ end_write()
 	for (sectindex = 0; sectindex < outhead.oh_nsect; sectindex++)
 		wrt_name(sectname(sectindex), 1);
 }
-	
+
 wrt_emit(emit, sectindex, cnt)
 	char		*emit;
 	int		sectindex;
diff --git a/util/misc/build.lua b/util/misc/build.lua
index dd207bbbc..e8dfbca33 100644
--- a/util/misc/build.lua
+++ b/util/misc/build.lua
@@ -41,59 +41,7 @@ installable {
 		["$(PLATDEP)/em_encode"] = "+encode",
 		["$(PLATDEP)/em_decode"] = "+decode",
 		["$(INSDIR)/bin/esize"] = "+esize",
-		["$(PLATIND)/man/man1/esize.1"] = "./esize.1",
-		["$(PLATIND)/man/man6/em_decode.6"] = "./em_decode.6"
+		["$(INSDIR)/share/man/man1/esize.1"] = "./esize.1",
+		["$(INSDIR)/share/man/man6/em_decode.6"] = "./em_decode.6"
 	}
 }
-
---[[
-D := util/misc
-
-define build-misc-impl
-	$(call reset)
-	$(call cfile, $D/esize.c)
-	$(call cprogram, $(BINDIR)/esize)
-	$(call installto, $(INSDIR)/bin/esize)
-
-	$(call reset)
-	$(eval q := $D/esize.1)
-	$(call installto, $(INSDIR)/share/man/man1/esize.1)
-
-	$(call reset)
-	$(eval objdir := encode)
-	$(call cfile, $D/convert.c)
-	$(eval $q: $(INCDIR)/em_comp.h $(INCDIR)/em_codeEK.h)
-	$(call rawfile, $(LIBREAD_EMEV))
-	$(call rawfile, $(LIBEMK))
-	$(call rawfile, $(LIBEM_DATA))
-	$(call rawfile, $(LIBALLOC))
-	$(call rawfile, $(LIBPRINT))
-	$(call rawfile, $(LIBSTRING))
-	$(call rawfile, $(LIBSYSTEM))
-	$(call cprogram, $(BINDIR)/em_encode)
-	$(call installto, $(PLATDEP)/em_encode)
-	$(eval EM_ENCODE := $o)
-	$(eval ACK_CORE_TOOLS += $o)
-
-	$(call reset)
-	$(eval objdir := decode)
-	$(call cfile, $D/convert.c)
-	$(eval $q: $(INCDIR)/em_comp.h $(INCDIR)/em_codeEK.h)
-	$(call rawfile, $(LIBREAD_EMKV))
-	$(call rawfile, $(LIBEME))
-	$(call rawfile, $(LIBEM_DATA))
-	$(call rawfile, $(LIBALLOC))
-	$(call rawfile, $(LIBPRINT))
-	$(call rawfile, $(LIBSTRING))
-	$(call rawfile, $(LIBSYSTEM))
-	$(call cprogram, $(BINDIR)/em_decode)
-	$(call installto, $(PLATDEP)/em_decode)
-	$(eval EM_DECODE := $o)
-
-	$(call reset)
-	$(eval q := $D/em_decode.6)
-	$(call installto, $(INSDIR)/share/man/man6/em_decode.6)
-endef
-
-$(eval $(build-misc-impl))
---]]
diff --git a/util/misc/em_decode.6 b/util/misc/em_decode.6
index 92f7a084d..a21c939eb 100644
--- a/util/misc/em_decode.6
+++ b/util/misc/em_decode.6
@@ -1,8 +1,7 @@
-.\" $Id$
-.TH EM_DECODE 6 "$Revision$"
+.TH EM_DECODE 6 2017-01-18
 .ad
 .SH NAME
-em_decode,em_encode \- compact to readable EM and v.v.
+em_decode, em_encode \- compact to readable EM and v.v.
 .SH SYNOPSIS
 .B ~em/lib.bin/em_decode
 [ inputfile [ outputfile ] ]
diff --git a/util/misc/esize.1 b/util/misc/esize.1
index e62a17028..c05eb42f3 100644
--- a/util/misc/esize.1
+++ b/util/misc/esize.1
@@ -1,4 +1,4 @@
-.TH ESIZE I
+.TH ESIZE 1 2017-01-18
 .SH NAME
 esize \- print info from e.out header
 .SH SYNOPSIS
@@ -9,7 +9,8 @@ esize \- print info from e.out header
 prints information from the
 .I e.out
 headers of the indicated files, including flags, word and pointer sizes,
-text and data sizes, etc. All values are in decimal.
+text and data sizes, etc.
+All values are in decimal.
 .PP
 If no parameters are given, the header of
 .I e.out
diff --git a/util/opt/em_opt.6 b/util/opt/em_opt.6
index bdb6587d9..267bd9c69 100644
--- a/util/opt/em_opt.6
+++ b/util/opt/em_opt.6
@@ -1,11 +1,10 @@
-.\" $Id$
-.TH EM_OPT 6 "$Revision$"
+.TH EM_OPT 6 2017-01-18
 .ad
 .SH NAME
 em_opt \- EM peephole optimizer
 .SH SYNOPSIS
 .B ~em/lib.bin/em_opt
-[-Ln] [-m[l]<num>] [ argument ]
+[\-Ln] [\-m[l]<num>] [ argument ]
 .SH DESCRIPTION
 Em_opt reads a compact EM-program, argument or standard input,
 and produces another compact EM program on standard output
@@ -15,22 +14,22 @@ Some other functions are here that make this program mandatory
 before running a codegenerator,
 it may be left out when interpretation is wanted.
 Flags recognized are:
-.IP -L
+.IP \-L
 Make a library module.
 This means that the output will start with a message giving
 the names of all exported entities in this module.
-.IP -n
+.IP \-n
 Do not optimize.
 No peephole optimizations will be performed,
 other functions will be carried out.
-.IP -m<num>
+.IP \-m<num>
 Try to replace multiplies with constants by combinations of shifts and adds,
-but no more than <num> of them. Integer overflow detection is lost with this
-option.
-.IP -ml<num>
-Like -m<num>, but also for long multiplies.
+but no more than <num> of them.
+Integer overflow detection is lost with this option.
+.IP \-ml<num>
+Like \-m<num>, but also for long multiplies.
 .SH "FILES"
-/tmp/emopt??????, is used when the -L flag is given only.
+/tmp/emopt??????, is used when the \-L flag is given only.
 .SH "SEE ALSO"
 ack(1)
 .PD 0