diff --git a/src/snc/analysis.c b/src/snc/analysis.c
index 34cf14611108eb4cc9a5b425141dd60a3c4f1cb6..7c41527c3ad3a5403df6393448a8741084be7a73 100644
--- a/src/snc/analysis.c
+++ b/src/snc/analysis.c
@@ -25,7 +25,6 @@ in the file LICENSE that is included with this distribution.
 
 static const int impossible = 0;
 
-static void analyse_funcdefs(Expr *prog);
 static void analyse_definitions(Program *p);
 static void analyse_option(Options *options, Expr *defn);
 static void analyse_state_option(StateOptions *options, Expr *defn);
@@ -78,7 +77,6 @@ Program *analyse_program(Expr *prog, Options options)
 	report("created symbol table, channel list, and syncq list\n");
 #endif
 
-	analyse_funcdefs(p->prog);
 	analyse_definitions(p);
 	p->num_ss = connect_states(p->sym_table, prog);
 	connect_variables(p->sym_table, prog);
@@ -89,103 +87,72 @@ Program *analyse_program(Expr *prog, Options options)
 	return p;
 }
 
-static void analyse_funcdefs(Expr *prog)
+static void analyse_funcdef(Expr *defn)
 {
-	Expr *f;
+	Expr *d = defn->funcdef_decl;
+	Var *var = d->extra.e_decl;
+	struct function_type *fun_type;
+	Expr *p;
+	Token t;
 
-	assert(prog->type == D_PROG);
-	foreach(f, prog->prog_funcdefs)
+	assert(defn->type == D_FUNCDEF);
+	fun_type = &var->type->val.function;
+	if (var->type->tag != T_FUNCTION)
 	{
-		Expr *d = f->funcdef_decl;
-		Var *var = d->extra.e_decl;
-		struct function_type *fun_type = &var->type->val.function;
-		Expr *p;
-		Token t;
+		error_at_expr(d, "not a function type\n");
+		return;
+	}
 
-		assert(f->type == D_FUNCDEF);
-		if (var->type->tag != T_FUNCTION)
+	p = fun_type->param_decls;
+	assert(p);			/* invariant enforced by syntax */
+	if (p->extra.e_decl->type->tag == T_VOID)
+	{
+		/* no other params should be there */
+		if (p->next)
 		{
-			error_at_expr(d, "not a function type\n");
-			continue;
+			error_at_expr(p->next, "void must be the only parameter\n");
 		}
-
-		p = fun_type->param_decls;
-		assert(p);			/* invariant enforced by syntax */
-		if (p->extra.e_decl->type->tag == T_VOID)
+		if (p->extra.e_decl->name)
 		{
-			/* no other params should be there */
-			if (p->next)
-			{
-				error_at_expr(p->next, "void must be the only parameter\n");
-			}
-			if (p->extra.e_decl->name)
-			{
-				error_at_expr(p, "void parameter should not have a name\n");
-			}
-			/* void means empty parameter list */
-			fun_type->param_decls = 0;
+			error_at_expr(p, "void parameter should not have a name\n");
 		}
-		foreach(p, fun_type->param_decls)
+		/* void means empty parameter list */
+		fun_type->param_decls = 0;
+	}
+	foreach(p, fun_type->param_decls)
+	{
+		/* check parameter has a name */
+		if (!p->extra.e_decl->name)
 		{
-			/* check parameter has a name */
-			if (!p->extra.e_decl->name)
-			{
-				error_at_expr(p, "function parameter must have a name\n");
-			}
+			error_at_expr(p, "function parameter must have a name\n");
 		}
-		/* prepend "SEQ_VARS *const _seq_vars" to parameter list */
-		t.str = NM_VARS_ARG;
-		t.line = d->line_num;
-		t.file = d->src_file;
-		p = decl_add_base_type(
-			decl_create(t),
-			/* HACK! act as if "SEQ_VARS *const" were an identifier */
-			mk_foreign_type(F_TYPENAME, "SEQ_VARS *const")
-		);
-		fun_type->param_decls = link_expr(p, fun_type->param_decls);
-		/* prepend "SS_ID _seq_ss" to parameter list*/
-		t.str = NM_SS;
-		t.line = d->line_num;
-		t.file = d->src_file;
-		p = decl_add_base_type(
-			decl_create(t),
-			mk_foreign_type(F_TYPENAME, "SS_ID")
-		);
-		fun_type->param_decls = link_expr(p, fun_type->param_decls);
-		prog->prog_defns = link_expr(prog->prog_defns, d);
 	}
+	/* prepend "SEQ_VARS *const _seq_vars" to parameter list */
+	t.str = NM_VARS_ARG;
+	t.line = d->line_num;
+	t.file = d->src_file;
+	p = decl_add_base_type(
+		decl_create(t),
+		/* HACK! act as if "SEQ_VARS *const" were an identifier */
+		mk_foreign_type(F_TYPENAME, "SEQ_VARS *const")
+	);
+	fun_type->param_decls = link_expr(p, fun_type->param_decls);
+	/* prepend "SS_ID _seq_ss" to parameter list*/
+	t.str = NM_SS;
+	t.line = d->line_num;
+	t.file = d->src_file;
+	p = decl_add_base_type(
+		decl_create(t),
+		mk_foreign_type(F_TYPENAME, "SS_ID")
+	);
+	fun_type->param_decls = link_expr(p, fun_type->param_decls);
 }
 
-static int analyse_defn(Expr *scope, Expr *parent_scope, void *parg)
+static void analyse_defns(Expr *defn_list, Expr *scope, Program *p)
 {
-	Program	*p = (Program *)parg;
-	Expr *defn_list;
-	VarList **pvar_list;
 	Expr *defn;
 
-	assert(scope);	/* precondition */
-
-#ifdef DEBUG
-	report("analyse_defn: scope=(%s:%s)\n",
-		expr_type_name(scope), scope->value);
-#endif
-
 	assert(is_scope(scope));				/* precondition */
-	assert(!parent_scope || is_scope(parent_scope));	/* precondition */
-
-	defn_list = defn_list_from_scope(scope);
-	pvar_list = pvar_list_from_scope(scope);
-
-	/* NOTE: We always need to allocate a var_list, even if there are no
-	   definitions on this level, so later on (see connect_variables below)
-	   we can traverse in the other direction to find the nearest enclosing
-	   scope. */
-	if (!*pvar_list)
-	{
-		*pvar_list = new(VarList);
-		(*pvar_list)->parent_scope = parent_scope;
-	}
-
 	foreach (defn, defn_list)
 	{
 		switch (defn->type)
@@ -203,6 +170,10 @@ static int analyse_defn(Expr *scope, Expr *parent_scope, void *parg)
 		case D_DECL:
 			analyse_declaration(p->sym_table, scope, defn);
 			break;
+		case D_FUNCDEF:
+			analyse_funcdef(defn);
+			analyse_declaration(p->sym_table, scope, defn->funcdef_decl);
+			break;
 		case D_ASSIGN:
 			analyse_assign(p->sym_table, p->chan_list, scope, defn);
 			break;
@@ -221,6 +192,43 @@ static int analyse_defn(Expr *scope, Expr *parent_scope, void *parg)
 			assert(impossible);
 		}
 	}
+}
+
+static int analyse_scope(Expr *scope, Expr *parent_scope, void *parg)
+{
+	Program	*p = (Program *)parg;
+	Expr *defn_list;
+	VarList **pvar_list;
+
+	assert(scope);	/* precondition */
+
+#ifdef DEBUG
+	report("analyse_defn: scope=(%s:%s)\n",
+		expr_type_name(scope), scope->value);
+#endif
+
+	assert(is_scope(scope));				/* precondition */
+	assert(!parent_scope || is_scope(parent_scope));	/* precondition */
+
+	defn_list = defn_list_from_scope(scope);
+	pvar_list = pvar_list_from_scope(scope);
+
+	/* NOTE: We always need to allocate a var_list, even if there are no
+	   definitions on this level, so later on (see connect_variables below)
+	   we can traverse in the other direction to find the nearest enclosing
+	   scope. */
+	if (!*pvar_list)
+	{
+		*pvar_list = new(VarList);
+		(*pvar_list)->parent_scope = parent_scope;
+	}
+
+	analyse_defns(defn_list, scope, p);
+	if (scope->type == D_PROG)
+	{
+		analyse_defns(scope->prog_xdefns, scope, p);
+	}
+
 	return TRUE; /* always descend into children */
 }
 
@@ -276,7 +284,7 @@ static void analyse_definitions(Program *p)
 	report("**begin** analyse definitions\n");
 #endif
 
-	traverse_expr_tree(p->prog, scope_mask, ~has_sub_scope_mask, 0, analyse_defn, p);
+	traverse_expr_tree(p->prog, scope_mask, ~has_sub_scope_mask, 0, analyse_scope, p);
 
 #ifdef DEBUG
 	report("**end** analyse definitions\n");
diff --git a/src/snc/analysis.h b/src/snc/analysis.h
index 6aa52879c7533e7abea15cd6ddba5412a0a00491..d111f1d957b0357beaee5eec8c2383d4bf35bd0c 100644
--- a/src/snc/analysis.h
+++ b/src/snc/analysis.h
@@ -39,7 +39,7 @@ void traverse_expr_tree(
 );
 
 VarList **pvar_list_from_scope(Expr *scope);
-#define var_list_from_scope(scope) *pvar_list_from_scope(scope)
+#define var_list_from_scope(scope) (*pvar_list_from_scope(scope))
 Expr *defn_list_from_scope(Expr *scope);
 
 Program *analyse_program(Expr *ep, Options options);
diff --git a/src/snc/gen_code.c b/src/snc/gen_code.c
index 19ea8d0b5ce21d97776546a57393680e02b7d8cc..5d1a09afda5004b202e7615b9c76c4a57ec3e7d6 100644
--- a/src/snc/gen_code.c
+++ b/src/snc/gen_code.c
@@ -22,9 +22,10 @@ in the file LICENSE that is included with this distribution.
 #include "gen_code.h"
 
 static void gen_main(char *prog_name);
-static void gen_user_var(Program *p);
-static void gen_global_c_code(Expr *global_c_list);
+static void gen_user_var(Expr *prog, uint opt_reent);
+static void gen_extra_c_code(Expr *extra_defns);
 static void gen_init_reg(char *prog_name);
+static void gen_func_decls(Expr *prog);
 
 static int assert_var_declared(Expr *ep, Expr *scope, void *parg)
 {
@@ -73,7 +74,7 @@ void generate_code(Program *p, const char *header_name)
 	else
 	{
 		/* Generate global, state set, and state variable declarations */
-		gen_user_var(p);
+		gen_user_var(p->prog, p->options.reent);
 	}
 
 	/* The usual C header file humdrum */
@@ -97,18 +98,21 @@ void generate_code(Program *p, const char *header_name)
 	if (!p->options.reent)
 	{
 		/* Generate global, state set, and state variable declarations */
-		gen_user_var(p);
+		gen_user_var(p->prog, p->options.reent);
 	}
 
+	/* Generate code for function definitions */
+	gen_func_decls(p->prog);
+
+	/* Output extra C code */
+	gen_extra_c_code(p->prog->prog_xdefns);
+
 	/* Generate code for each state set */
 	gen_ss_code(p->prog, p->options);
 
 	/* Generate tables */
 	gen_tables(p);
 
-	/* Output global C code */
-	gen_global_c_code(p->prog->prog_ccode);
-
 	/* Generate main function */
 	if (p->options.main) gen_main(p->name);
 
@@ -128,6 +132,26 @@ void gen_var_decl(Var *vp)
 	gen_type(vp->type, "", vp->name);
 }
 
+static void gen_func_decls(Expr *prog)
+{
+	Var	*vp;
+
+	assert(prog->type == D_PROG);
+	gen_code("\n/* Function declarations */\n");
+
+	/* function declarations are always global and static */
+	foreach (vp, var_list_from_scope(prog)->first)
+	{
+		if (vp->decl && vp->type->tag == T_FUNCTION)
+		{
+			gen_line_marker(vp->decl);
+			gen_code("static ");
+			gen_var_decl(vp);
+			gen_code(";\n");
+		}
+	}
+}
+
 /* Generate the UserVar struct containing all program variables with
    'infinite' (global) lifetime. These are: variables declared at the
    top-level, inside a state set, and inside a state. Note that state
@@ -135,12 +159,11 @@ void gen_var_decl(Var *vp)
    where they are declared, but still have global lifetime. To avoid
    name collisions, generate a nested struct for each state set, and
    for each state in a state set. */
-static void gen_user_var(Program *p)
+static void gen_user_var(Expr *prog, uint opt_reent)
 {
-	int	opt_reent = p->options.reent;
 	Var	*vp;
 	Expr	*sp, *ssp;
-	int	num_globals = 0;
+	uint	num_globals = 0;
 	uint	num_decls = 0;
 
 	gen_code("\n/* Variable declarations */\n");
@@ -150,7 +173,7 @@ static void gen_user_var(Program *p)
 		gen_code("struct %s {\n", NM_VARS);
 	}
 	/* Convert internal type to `C' type */
-	foreach (vp, p->prog->extra.e_prog->first)
+	foreach (vp, var_list_from_scope(prog)->first)
 	{
 		if (vp->decl && vp->type->tag != T_NONE && vp->type->tag != T_EVFLAG &&
 			vp->type->tag != T_FUNCTION)
@@ -168,7 +191,7 @@ static void gen_user_var(Program *p)
 	{
 		indent(1); gen_code("char _seq_dummy;\n");
 	}
-	foreach (ssp, p->prog->prog_statesets)
+	foreach (ssp, prog->prog_statesets)
 	{
 		int level = opt_reent;
 		int ss_empty = !ssp->extra.e_ss->var_list->first;
@@ -221,17 +244,6 @@ static void gen_user_var(Program *p)
 		}
 		gen_code("};\n");
 	}
-	/* function declarations are always global and static */
-	foreach (vp, p->prog->extra.e_prog->first)
-	{
-		if (vp->decl && vp->type->tag == T_FUNCTION)
-		{
-			gen_line_marker(vp->decl);
-			gen_code("static ");
-			gen_var_decl(vp);
-			gen_code(";\n");
-		}
-	}
 	gen_code("\n");
 }
 
@@ -259,19 +271,21 @@ void gen_defn_c_code(Expr *scope, int level)
 	}
 }
 
-/* Generate global C code following state sets */
-static void gen_global_c_code(Expr *global_c_list)
+/* Generate extra C code following state sets */
+static void gen_extra_c_code(Expr *extra_defns)
 {
 	Expr	*ep;
 
-	if (global_c_list != 0)
+	if (extra_defns != 0)
 	{
-		gen_code("\n/* Global C code */\n");
-		foreach (ep, global_c_list)
+		gen_code("\n/* Extra escaped C code */\n");
+		foreach (ep, extra_defns)
 		{
-			assert(ep->type == T_TEXT);
-			gen_line_marker(ep);
-			gen_code("%s\n", ep->value);
+			if (ep->type == T_TEXT)
+			{
+				gen_line_marker(ep);
+				gen_code("%s\n", ep->value);
+			}
 		}
 	}
 }
diff --git a/src/snc/gen_ss_code.c b/src/snc/gen_ss_code.c
index 41be7815635f29b9b8f3af0f928c860251f41f48..a6b096facc535c4e4f6a555a99f30e6a20c8f516 100644
--- a/src/snc/gen_ss_code.c
+++ b/src/snc/gen_ss_code.c
@@ -138,8 +138,14 @@ void gen_ss_code(Expr *prog, Options options)
 	if (prog->prog_exit)
 		gen_prog_entex_func(prog, "exit", NM_EXIT, gen_prog_exit_body);
 
+	gen_code("\n/****** Global function definitions ******/\n");
+
 	/* Generate function definitions */
-	foreach(fp, prog->prog_funcdefs)
+	foreach(fp, prog->prog_defns)
+	{
+		gen_funcdef(fp);
+	}
+	foreach(fp, prog->prog_xdefns)
 	{
 		gen_funcdef(fp);
 	}
@@ -908,12 +914,15 @@ static void gen_prog_exit_body(Expr *prog)
 
 static void gen_funcdef(Expr *fp)
 {
-	Var *vp = fp->funcdef_decl->extra.e_decl;
-
-	assert(fp->type == D_FUNCDEF);
-	gen_line_marker(vp->decl);
-	gen_code("static ");
-	gen_var_decl(vp);
-	gen_code("\n");
-	gen_block(fp->funcdef_block, C_FUNC, 0);
+	if (fp->type == D_FUNCDEF)
+	{
+		Var *vp = fp->funcdef_decl->extra.e_decl;
+
+		gen_code("\n");
+		gen_line_marker(vp->decl);
+		gen_code("static ");
+		gen_var_decl(vp);
+		gen_code("\n");
+		gen_block(fp->funcdef_block, C_FUNC, 0);
+	}
 }
diff --git a/src/snc/snl.lem b/src/snc/snl.lem
index f22d9f88248bbf7325b08d8e142f6fcd8ceff7d7..05cde3f5d26c913c67b27607f5692ea9714ef932 100644
--- a/src/snc/snl.lem
+++ b/src/snc/snl.lem
@@ -88,14 +88,13 @@ in the file LICENSE that is included with this distribution.
 program ::=
 	PROGRAM NAME(n)
 	program_param(pp)
-	global_defns(ds)
+	initial_defns(ds)
 	entry(en)
 	state_sets(ss)
 	exit(ex)
-        functions(fs)
-	c_codes(cc).
+        final_defns(fs).
 {
-	*presult =  expr(D_PROG, n, pp, ds, en, ss, ex, fs, cc);
+	*presult =  expr(D_PROG, n, pp, ds, en, ss, ex, fs);
 }
 
 program_param(p) ::= LPAREN string(x) RPAREN.	{ p = x; }
@@ -103,18 +102,27 @@ program_param(p) ::= .				{ p = 0; }
 
 // Definitions
 
-global_defns(p) ::= global_defns(xs) global_defn(x). {
+initial_defns(p) ::= initial_defns(xs) initial_defn(x). {
 	p = link_expr(xs, x);
 }
-global_defns(p) ::= .				{ p = 0; }
+initial_defns(p) ::= .				{ p = 0; }
+
+initial_defn(p) ::= assign(x).			{ p = x; }
+initial_defn(p) ::= monitor(x).			{ p = x; }
+initial_defn(p) ::= sync(x).			{ p = x; }
+initial_defn(p) ::= syncq(x).			{ p = x; }
+initial_defn(p) ::= declaration(x).		{ p = x; }
+initial_defn(p) ::= option(x).			{ p = x; }
+initial_defn(p) ::= c_code(x).			{ p = x; }
+initial_defn(p) ::= funcdef(x).			{ p = x; }
+
+final_defns(p) ::= final_defns(xs) final_defn(x). {
+	p = link_expr(xs, x);
+}
+final_defns(p) ::= .				{ p = 0; }
 
-global_defn(p) ::= assign(x).			{ p = x; }
-global_defn(p) ::= monitor(x).			{ p = x; }
-global_defn(p) ::= sync(x).			{ p = x; }
-global_defn(p) ::= syncq(x).			{ p = x; }
-global_defn(p) ::= declaration(x).		{ p = x; }
-global_defn(p) ::= option(x).			{ p = x; }
-global_defn(p) ::= c_code(x).			{ p = x; }
+final_defn(p) ::= c_code(x).			{ p = x; }
+final_defn(p) ::= funcdef(x).			{ p = x; }
 
 assign(p) ::= connect variable(v) to string(t) SEMICOLON. {
 	p = expr(D_ASSIGN, v, 0, t);
@@ -474,18 +482,12 @@ string(p) ::= STRCON(t).			{ p = expr(E_STRING, t); }
 
 member(p) ::= NAME(t).				{ p = expr(E_MEMBER, t); }
 
-// Functions
+// Function Definitions
 
-functions(p) ::= .					{ p = 0; }
-functions(p) ::= functions(fs) function(f).		{ p = link_expr(fs, f); }
-
-function(p) ::= basetype(t) declarator(d) block(b). {
+funcdef(p) ::= basetype(t) declarator(d) block(b). {
 	p = expr(D_FUNCDEF, token_from_expr(d), decl_add_base_type(d, t), b);
 }
 
 // Literal (C) code
 
-c_codes(p) ::= c_codes(xs) c_code(x).		{ p = link_expr(xs, x); }
-c_codes(p) ::= .				{ p = 0; }
-
 c_code(p) ::= CCODE(t). 			{ p = expr(T_TEXT, t); }
diff --git a/src/snc/types.h b/src/snc/types.h
index d9738e022ebd2deefa3005c79278010811f99d18..3eef333edff2a3c4e9f50d93c02b088b4b71fdae 100644
--- a/src/snc/types.h
+++ b/src/snc/types.h
@@ -274,7 +274,7 @@ enum expr_type			/* description [child expressions...] */
 	D_FUNCDEF,		/* function definition [decl,block] */
 	D_MONITOR,		/* monitor statement [subscr] */
 	D_OPTION,		/* option definition [] */
-	D_PROG,			/* whole program [param,defns,entry,statesets,exit,funcdefs,ccode] */
+	D_PROG,			/* whole program [param,defns,entry,statesets,exit,xdefns] */
 	D_SS,			/* state set statement [defns,states] */
 	D_STATE,		/* state statement [defns,entry,whens,exit] */
 	D_SYNC,			/* sync statement [subscr,evflag] */
@@ -348,8 +348,7 @@ STATIC_ASSERT(NUM_EXPR_TYPES <= 8*sizeof(TypeMask));
 #define prog_entry	children[2]
 #define prog_statesets	children[3]
 #define prog_exit	children[4]
-#define prog_funcdefs	children[5]
-#define prog_ccode	children[6]
+#define prog_xdefns	children[5]
 #define return_expr	children[0]
 #define select_left	children[0]
 #define select_right	children[1]
@@ -394,7 +393,7 @@ expr_type_info[]
 	{ "D_FUNCDEF",	2 },
 	{ "D_MONITOR",	1 },
 	{ "D_OPTION",	0 },
-	{ "D_PROG",	7 },
+	{ "D_PROG",	6 },
 	{ "D_SS",	2 },
 	{ "D_STATE",	4 },
 	{ "D_SYNC",	2 },