diff --git a/src/acme.c b/src/acme.c
index 876336d..6018095 100644
--- a/src/acme.c
+++ b/src/acme.c
@@ -17,7 +17,7 @@
 
 #define RELEASE		"0.95.4"	// update before release (FIXME)
 #define CODENAME	"Fenchurch"	// update before release
-#define CHANGE_DATE	"3 Dec"	// update before release
+#define CHANGE_DATE	"4 Dec"	// update before release
 #define CHANGE_YEAR	"2014"		// update before release
 //#define HOME_PAGE	"http://home.pages.de/~mac_bacon/smorbrod/acme/"	// FIXME
 #define HOME_PAGE	"http://sourceforge.net/p/acme-crossass/"	// FIXME
@@ -562,7 +562,6 @@ int main(int argc, const char *argv[])
 	Mnemo_init();
 	Output_init(fill_value);
 	pseudoopcodes_init();	// setup keyword tree for pseudo opcodes
-	Section_init();
 	if (do_actual_work())
 		save_output_file();
 	return ACME_finalize(EXIT_SUCCESS);	// dump labels, if wanted
diff --git a/src/global.c b/src/global.c
index 8424b0f..f63eca4 100644
--- a/src/global.c
+++ b/src/global.c
@@ -37,6 +37,9 @@ const char	s_eor[]		= "eor";
 const char	s_error[]	= "error";
 const char	s_lsr[]		= "lsr";
 const char	s_scrxor[]	= "scrxor";
+char		s_untitled[]	= "<untitled>";	// FIXME - this is actually const
+const char	s_Zone[]	= "Zone";
+const char	s_subzone[]	= "subzone";
 // Exception messages during assembly
 const char	exception_cannot_open_input_file[] = "Cannot open input file.";
 const char	exception_missing_string[]	= "No string given.";
@@ -145,38 +148,6 @@ static void parse_pc_def(void)	// Now GotByte = "*"
 }
 
 
-// Parse pseudo opcodes. Has to be re-entrant.
-static void parse_pseudo_opcode(void)	// Now GotByte = "!"
-{
-	void		*node_body;
-	enum eos	(*fn)(void),
-			then	= SKIP_REMAINDER;	// prepare for errors
-
-	GetByte();	// read next byte
-	// on missing keyword, return (complaining will have been done)
-	if (Input_read_and_lower_keyword()) {
-
-// move this to pseudoopcodes.c:
-		// search for tree item
-		if ((Tree_easy_scan(pseudo_opcode_tree, &node_body, GlobalDynaBuf))
-		&& node_body) {
-			fn = (enum eos (*)(void)) node_body;
-			SKIPSPACE();
-			// call function
-			then = fn();
-		} else {
-			Throw_error("Unknown pseudo opcode.");
-		}
-	}
-	if (then == SKIP_REMAINDER)
-		Input_skip_remainder();
-	else if (then == ENSURE_EOS)
-		Input_ensure_EOS();
-	// the other two possibilities (PARSE_REMAINDER and AT_EOS_ANYWAY)
-	// will lead to the remainder of the line being parsed by the mainloop.
-}
-
-
 // Check and return whether first label of statement. Complain if not.
 static int first_label_of_statement(int *statement_flags)
 {
@@ -292,7 +263,7 @@ void Parse_until_eob_or_eof(void)
 					parse_forward_anon_def(&statement_flags);
 				break;
 			case PSEUDO_OPCODE_PREFIX:
-				parse_pseudo_opcode();
+				pseudoopcode_parse();
 				break;
 			case '*':
 				parse_pc_def();
diff --git a/src/global.h b/src/global.h
index 6309d90..3ead1ff 100644
--- a/src/global.h
+++ b/src/global.h
@@ -32,7 +32,11 @@ extern const char	s_eor[];
 extern const char	s_error[];
 extern const char	s_lsr[];
 extern const char	s_scrxor[];
-// Error messages during assembly
+extern char		s_untitled[];
+extern const char	s_Zone[];
+#define s_zone	(s_subzone + 3)	// Yes, I know I'm sick
+extern const char	s_subzone[];
+// error messages during assembly
 extern const char	exception_cannot_open_input_file[];
 extern const char	exception_missing_string[];
 extern const char	exception_no_left_brace[];
@@ -42,7 +46,7 @@ extern const char	exception_no_right_brace[];
 extern const char	exception_number_out_of_range[];
 extern const char	exception_pc_undefined[];
 extern const char	exception_syntax[];
-// Byte flags table
+// byte flags table
 extern const char	Byte_flags[];
 #define BYTEFLAGS(c)	(Byte_flags[(unsigned char) c])
 #define STARTS_KEYWORD	(1u << 7)	// Byte is allowed to start a keyword
@@ -55,7 +59,7 @@ extern const char	Byte_flags[];
 
 
 // structures
-// different ways to handle end-of-statement:
+// different ways to handle end-of-statement: (FIXME - after grouping all pseudo opcodes, move to pseudoopcodes.c)
 enum eos {
 	SKIP_REMAINDER,		// skip remainder of line - (after errors)
 	ENSURE_EOS,		// make sure there's nothing left in statement
@@ -68,7 +72,7 @@ extern int	warn_on_indented_labels;	// warn if indented label is encountered
 extern int	warn_on_old_for;	// warn if "!for" with old syntax is found
 extern int	warn_on_type_mismatch;	// use type-checking system
 extern char	GotByte;	// Last byte read (processed)
-// Global counters
+// global counters
 extern int	pass_undefined_count;	// "NeedValue" type errors in current pass
 extern int	pass_real_errors;	// Errors yet
 extern signed long	max_errors;	// errors before giving up
@@ -104,7 +108,7 @@ do {				\
 
 // Prototypes
 
-// Allocate memory and die if not available
+// allocate memory and die if not available
 extern void *safe_malloc(size_t);
 // Parse block, beginning with next byte.
 // End reason (either CHAR_EOB or CHAR_EOF) can be found in GotByte afterwards
@@ -132,7 +136,7 @@ extern void Throw_error(const char *);
 // assembly. Example: "!fill" without a parameter - the program counter cannot
 // be set correctly in this case, so proceeding would be of no use at all.
 extern void Throw_serious_error(const char *);
-// Handle bugs
+// handle bugs
 extern void Bug_found(const char *, int);
 
 
diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c
index 8a2a896..dd3fb05 100644
--- a/src/pseudoopcodes.c
+++ b/src/pseudoopcodes.c
@@ -13,6 +13,7 @@
 #include "input.h"
 #include "global.h"
 #include "output.h"
+#include "section.h"
 #include "tree.h"
 #include "typesystem.h"
 #include "pseudoopcodes.h"
@@ -251,6 +252,51 @@ static enum eos po_skip(void)	// now GotByte = illegal char
 }
 */
 
+// switch to new zone ("!zone" or "!zn"). has to be re-entrant.
+static enum eos po_zone(void)
+{
+	struct section	entry_values;	// buffer for outer zone
+	char		*new_title;
+	int		allocated;
+
+	// remember everything about current structure
+	entry_values = *Section_now;
+	// set default values in case there is no valid title
+	new_title = s_untitled;
+	allocated = FALSE;
+	// Check whether a zone title is given. If yes and it can be read,
+	// get copy, remember pointer and remember to free it later on.
+	if (BYTEFLAGS(GotByte) & CONTS_KEYWORD) {
+		// Because we know of one character for sure,
+		// there's no need to check the return value.
+		Input_read_keyword();
+		new_title = DynaBuf_get_copy(GlobalDynaBuf);
+		allocated = TRUE;
+	}
+	// setup new section
+	// section type is "subzone", just in case a block follows
+	Section_new_zone(Section_now, "Subzone", new_title, allocated);
+	if (Parse_optional_block()) {
+		// Block has been parsed, so it was a SUBzone.
+		Section_finalize(Section_now);	// end inner zone
+		*Section_now = entry_values;	// restore entry values
+	} else {
+		// no block found, so it's a normal zone change
+		Section_finalize(&entry_values);	// end outer zone
+		Section_now->type = s_Zone;	// change type to "Zone"
+	}
+	return ENSURE_EOS;
+}
+
+// "!subzone" or "!sz" pseudo opcode (now obsolete)
+static enum eos po_subzone(void)
+{
+	Throw_error("\"!subzone {}\" is obsolete; use \"!zone {}\" instead.");
+	// call "!zone" instead
+	return po_zone();
+}
+
+
 // constants
 #define USERMSG_DYNABUF_INITIALSIZE	80
 
@@ -364,6 +410,10 @@ static struct ronode	pseudo_opcodes[]	= {
 	PREDEFNODE("addr",	po_addr),
 	PREDEFNODE("address",	po_addr),
 //	PREDEFNODE("skip",	po_skip),
+	PREDEFNODE(s_zone,	po_zone),
+	PREDEFNODE("zn",	po_zone),
+	PREDEFNODE(s_subzone,	po_subzone),
+	PREDEFNODE("sz",	po_subzone),
 //	PREDEFNODE("debug",	po_debug),
 //	PREDEFNODE("info",	po_info),
 	PREDEFNODE("warn",	po_warn),
@@ -379,3 +429,33 @@ void pseudoopcodes_init(void)
 	user_message = DynaBuf_create(USERMSG_DYNABUF_INITIALSIZE);
 	Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
 }
+
+
+// parse a pseudo opcode. has to be re-entrant.
+void pseudoopcode_parse(void)	// Now GotByte = "!"
+{
+	void		*node_body;
+	enum eos	(*fn)(void),
+			then	= SKIP_REMAINDER;	// prepare for errors
+
+	GetByte();	// read next byte
+	// on missing keyword, return (complaining will have been done)
+	if (Input_read_and_lower_keyword()) {
+		// search for tree item
+		if ((Tree_easy_scan(pseudo_opcode_tree, &node_body, GlobalDynaBuf))
+		&& node_body) {
+			fn = (enum eos (*)(void)) node_body;
+			SKIPSPACE();
+			// call function
+			then = fn();
+		} else {
+			Throw_error("Unknown pseudo opcode.");
+		}
+	}
+	if (then == SKIP_REMAINDER)
+		Input_skip_remainder();
+	else if (then == ENSURE_EOS)
+		Input_ensure_EOS();
+	// the other two possibilities (PARSE_REMAINDER and AT_EOS_ANYWAY)
+	// will lead to the remainder of the line being parsed by the mainloop.
+}
diff --git a/src/pseudoopcodes.h b/src/pseudoopcodes.h
index cadda56..bf9c349 100644
--- a/src/pseudoopcodes.h
+++ b/src/pseudoopcodes.h
@@ -15,6 +15,8 @@ extern struct ronode	*pseudo_opcode_tree;	// tree to hold pseudo opcodes
 extern void notreallypo_setpc(void);
 // register pseudo opcodes
 extern void pseudoopcodes_init(void);
+// parse pseudo opcode. has to be re-entrant.
+extern void pseudoopcode_parse(void);
 
 
 #endif
diff --git a/src/section.c b/src/section.c
index c3074fc..081e777 100644
--- a/src/section.c
+++ b/src/section.c
@@ -12,13 +12,6 @@
 #include "section.h"
 
 
-// Constants
-static const char	type_zone[]	= "Zone";
-static const char	s_subzone[]	= "subzone";
-#define s_zone	(s_subzone + 3)	// Yes, I know I'm sick
-static char		untitled[]	= "<untitled>";
-// ...is actually constant, but flagging it "const" results in heap of warnings
-
 // fake section structure (for error msgs before any real section is in use)
 static struct section	initial_section	= {
 	0,		// zone value
@@ -53,68 +46,9 @@ void Section_finalize(struct section *section)
 		free(section->title);
 }
 
-// Switch to new zone ("!zone" or "!zn"). Has to be re-entrant.
-static enum eos PO_zone(void)
-{
-	struct section	entry_values;	// buffer for outer zone
-	char		*new_title;
-	int		allocated;
-
-	// remember everything about current structure
-	entry_values = *Section_now;
-	// set default values in case there is no valid title
-	new_title = untitled;
-	allocated = FALSE;
-	// Check whether a zone title is given. If yes and it can be read,
-	// get copy, remember pointer and remember to free it later on.
-	if (BYTEFLAGS(GotByte) & CONTS_KEYWORD) {
-		// Because we know of one character for sure,
-		// there's no need to check the return value.
-		Input_read_keyword();
-		new_title = DynaBuf_get_copy(GlobalDynaBuf);
-		allocated = TRUE;
-	}
-	// setup new section
-	// section type is "subzone", just in case a block follows
-	Section_new_zone(Section_now, "Subzone", new_title, allocated);
-	if (Parse_optional_block()) {
-		// Block has been parsed, so it was a SUBzone.
-		Section_finalize(Section_now);	// end inner zone
-		*Section_now = entry_values;	// restore entry values
-	} else {
-		// no block found, so it's a normal zone change
-		Section_finalize(&entry_values);	// end outer zone
-		Section_now->type = type_zone;	// change type to "zone"
-	}
-	return ENSURE_EOS;
-}
-
-// "!subzone" or "!sz" pseudo opcode (now obsolete)
-static enum eos PO_subzone(void)
-{
-	Throw_error("\"!subzone {}\" is obsolete; use \"!zone {}\" instead.");
-	// call "!zone" instead
-	return PO_zone();
-}
-
-// predefined stuff
-static struct ronode	pseudo_opcodes[]	= {
-	PREDEFNODE(s_zone,	PO_zone),
-	PREDEFNODE("zn",	PO_zone),
-	PREDEFNODE(s_subzone,	PO_subzone),
-	PREDEFLAST("sz",	PO_subzone),
-	//    ^^^^ this marks the last element
-};
-
-// register pseudo opcodes
-void Section_init(void)
-{
-	Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
-}
-
 // Setup outermost section
 void Section_passinit(void)
 {
 	zone_max = ZONE_GLOBAL;	// will be incremented by next line
-	Section_new_zone(&outer_section, type_zone, untitled, FALSE);
+	Section_new_zone(&outer_section, s_Zone, s_untitled, FALSE);
 }
diff --git a/src/section.h b/src/section.h
index 5234afd..bd0b1bc 100644
--- a/src/section.h
+++ b/src/section.h
@@ -33,8 +33,6 @@ extern struct section	*Section_now;
 
 // Write given info into given zone structure and activate it
 extern void Section_new_zone(struct section *section, const char *type, char *title, int allocated);
-// register pseudo opcodes
-extern void Section_init(void);
 // Setup outermost section
 extern void Section_passinit(void);
 // Tidy up: If necessary, release section title.