From 515d30e907298ed81c3f4e099f1c60bf6d368030 Mon Sep 17 00:00:00 2001
From: "benjamin.franksen" <benjamin.franksen@bessy.de>
Date: Fri, 12 Mar 2010 00:18:31 +0000
Subject: [PATCH] great re-structuring, finally fixed source location mess,
 removed last globals

---
 src/snc/Makefile                 |  39 +-
 src/snc/analysis.c               | 974 +++++++++++++++++++++++++++++++
 src/snc/analysis.h               |  30 +
 src/snc/{phase2.c => gen_code.c} | 315 ++--------
 src/snc/gen_code.h               |   8 +
 src/snc/gen_ss_code.c            |  90 +--
 src/snc/gen_ss_code.h            |   2 +-
 src/snc/gen_tables.c             | 140 ++---
 src/snc/gen_tables.h             |   4 +-
 src/snc/lexer.h                  |  22 +
 src/snc/parse.c                  | 774 +-----------------------
 src/snc/parse.h                  | 221 +------
 src/snc/phase2.h                 |  18 -
 src/snc/snc.y                    | 538 -----------------
 src/snc/snc_lex.l                | 278 ---------
 src/snc/snc_main.c               | 245 ++++----
 src/snc/snc_main.h               |  45 +-
 src/snc/snl.lem                  | 199 ++++---
 src/snc/snl.lt                   |   1 +
 src/snc/snl.re                   | 276 ++++-----
 src/snc/types.h                  | 240 ++++++++
 test/simple/sncExample.st        |  13 +
 22 files changed, 1865 insertions(+), 2607 deletions(-)
 create mode 100644 src/snc/analysis.c
 create mode 100644 src/snc/analysis.h
 rename src/snc/{phase2.c => gen_code.c} (56%)
 create mode 100644 src/snc/gen_code.h
 create mode 100644 src/snc/lexer.h
 delete mode 100644 src/snc/phase2.h
 delete mode 100644 src/snc/snc.y
 delete mode 100644 src/snc/snc_lex.l
 create mode 100644 src/snc/types.h

diff --git a/src/snc/Makefile b/src/snc/Makefile
index 0b0c92f5..4ee7230e 100644
--- a/src/snc/Makefile
+++ b/src/snc/Makefile
@@ -8,18 +8,34 @@ include $(TOP)/configure/CONFIG
 #USR_CPPFLAGS = -DDEBUG
 
 #  snc product
-PROD_HOST = snc
+PROD_HOST += snc
+
+# parser generator tool 
 PROD_HOST += lemon
 
 snc_LIBS += $(EPICS_BASE_IOC_LIBS)
 
-USR_CFLAGS += -DUSE_LEMON
-snc_SRCS += snl.c
-snc_SRCS += snl_lex.re
-snc_SRCS += snc_main.c parse.c phase2.c
-snc_SRCS += gen_ss_code.c gen_tables.c sncVersion.c
+#snc_SRCS += snl.re		# lexer spec
+#snc_SRCS += snl.lem		# parser spec
+
+snc_SRCS += snl.c		# generated by lemon
+snc_SRCS += lexer.c		# generated by re2c
+
+snc_SRCS += snc_main.c		# main program
+snc_SRCS += parse.c		# parse routines
+snc_SRCS += analysis.c		# analysis routines
+snc_SRCS += gen_code.c		# code generation
+snc_SRCS += gen_ss_code.c	# code generation (state sets)
+snc_SRCS += gen_tables.c	# code generation (tables)
+snc_SRCS += sncVersion.c	# version info
 
-lemon_SRCS = lemon.c
+ifdef LEXER_TEST
+PROD_HOST =
+TESTPROD_HOST = lexer
+USR_CFLAGS = -DTEST_LEXER
+endif
+
+lemon_SRCS = lemon.c		# parser generator
 
 LEMON = $(INSTALL_BIN)/lemon
 
@@ -29,11 +45,8 @@ include $(TOP)/configure/RULES
 
 #  How to generate the version file
 sncVersion.c: $(TOP)/configure/CONFIG
-	$(RM) $@
-	$(PERL) ../sncVersion.pl $(SEQ_VERSION) > $@
-
-clean::
-	@$(RM) snc.c snc_lex.c
+	$(PERL) ../sncVersion.pl $(SEQ_VERSION) > $@.tmp
+	$(MV) $@.tmp $@
 
 snl.c snl.h: snl.lem snl.lt $(LEMON)
 	$(LEMON) snl.lem
@@ -46,5 +59,5 @@ snl.c snl.h: snl.lem snl.lt $(LEMON)
 
 vpath %.re ..
 
-snl_lex.c: snl.re snl.h
+lexer.c: snl.re snl.h
 	re2c -o $@ $<
diff --git a/src/snc/analysis.c b/src/snc/analysis.c
new file mode 100644
index 00000000..2824eeac
--- /dev/null
+++ b/src/snc/analysis.c
@@ -0,0 +1,974 @@
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "types.h"
+#include "snc_main.h"
+#include "analysis.h"
+
+const int impossible = 0;
+
+static Options *analyse_options(Options *options, Expr *opt_list);
+static Scope *analyse_declarations(Expr *defn_list);
+static ChanList *analyse_assignments(Scope *scope, Expr *defn_list);
+static void analyse_monitors(Scope *scope, Expr *defn_list);
+static void analyse_syncs_and_syncqs(Scope *scope, Expr *defn_list);
+
+static int option_stmt(
+	struct options	*options,
+	char	*name,		/* "a", "r", ... */
+	char	*value		/* "+", "-" */
+);
+static void assign_subscr(
+	ChanList	*chan_list,
+	Expr		*dp,
+	Var		*vp,
+	char		*subscript,	/* subscript value or 0 */
+	char		*db_name
+);
+static void assign_single(
+	ChanList	*chan_list,
+	Expr		*dp,
+	Var		*vp,
+	char		*db_name
+);
+static void assign_list(
+	ChanList	*chan_list,
+	Expr		*dp,
+	Var		*vp,
+	Expr		*db_name_list
+);
+static void monitor_stmt(
+	Var		*vp,
+	Expr		*dp,
+	char		*subscript	/* element number or 0 */
+);
+static void sync_stmt(
+	Scope		*scope,
+	Expr		*dp,
+	char		*subscript,
+	char		*ef_name
+);
+static void syncq_stmt(
+	Scope		*scope,
+	Expr		*dp,
+	char		*subscript,
+	char		*ef_name,
+	char		*maxQueueSize
+);
+
+typedef struct connect_var_args {
+	Scope *scope;
+	int opt_warn;
+} connect_var_args;
+
+static Chan *build_channel(ChanList *chan_list, Var *vp);
+static void alloc_channel_lists(Chan *cp, int length);
+static void add_chan(ChanList *chan_list, Chan *cp);
+static void reconcile_variables(Scope *scope, int opt_warn, Expr *expr_list);
+static void reconcile_states(Expr *ss_list);
+static void connect_variable(Expr *ep, connect_var_args *args);
+static int db_queue_count(Scope *scope);
+static int db_chan_count(ChanList *chan_list);
+
+void analyse_program(Program *p, Options *os)
+{
+	Expr	*defn_list = p->global_defn_list;
+
+#ifdef	DEBUG
+	report("---- Analysis ----\n");
+#endif	/*DEBUG*/
+
+	p->options = analyse_options(os, defn_list);
+	p->global_scope = analyse_declarations(defn_list);
+	p->chan_list = analyse_assignments(p->global_scope, defn_list);
+	analyse_monitors(p->global_scope, defn_list);
+	analyse_syncs_and_syncqs(p->global_scope, defn_list);
+
+	/* Count number of db channels and state sets defined */
+	p->num_queues = db_queue_count(p->global_scope);
+	p->num_channels = db_chan_count(p->chan_list);
+	p->num_ss = expr_count(p->ss_list);
+
+	/* Reconcile all variable and tie each to the appropriate var struct */
+	reconcile_variables(p->global_scope, p->options->warn, p->ss_list);
+	reconcile_variables(p->global_scope, p->options->warn, p->entry_code_list);
+	reconcile_variables(p->global_scope, p->options->warn, p->exit_code_list);
+
+	/* reconcile all state names, including next state in transitions */
+	reconcile_states(p->ss_list);
+}
+
+static Options *analyse_options(Options *options, Expr *defn_list)
+{
+	Expr *def;
+
+	for (def = defn_list; def != 0; def = def->next)
+	{
+		if (def->type == E_OPTION)
+		{
+			char *name = def->value;
+			char *value = def->left->value;
+			assert(def->left->type == E_X);
+			if (!option_stmt(options, name, value))
+				report_at_expr(def, "warning: unknown option %s\n", name);
+		}
+	}
+	return options;
+}
+
+static Scope *analyse_declarations(Expr *defn_list)
+{
+	Expr *dp;
+	Var *vp, *vp2;
+	Scope *scope;
+
+#ifdef	DEBUG
+	report("-- Declarations --\n");
+#endif	/*DEBUG*/
+	scope = allocScope();
+	scope->var_list = allocVarList();
+	for (dp = defn_list; dp != 0; dp = dp->next)
+	{
+		if (dp->type != E_DECL)
+			continue;
+		vp = (Var *)dp->value;
+		assert(vp != 0);
+		vp->line_num = dp->line_num;
+		vp2 = find_var(scope, vp->name);
+		if (vp2 != 0)
+		{
+			report("%s:%d: ", dp->src_file, dp->line_num);
+			report("assign: variable %s already declared in line %d\n",
+			 vp->name, vp2->line_num);
+			continue;
+		}
+		add_var(scope, vp);
+	}
+	return scope;
+}
+
+static ChanList *analyse_assignments(Scope *scope, Expr *defn_list)
+{
+	Expr		*dp;
+	ChanList	*chan_list;
+
+#ifdef	DEBUG
+	report("-- Assignments --\n");
+#endif	/*DEBUG*/
+	chan_list = allocChanList();
+	for (dp = defn_list; dp != 0; dp = dp->next)
+	{
+		char *name;
+		Expr *pv_names;
+		Var *vp;
+
+		if (dp->type != E_ASSIGN)
+			continue;
+		name = dp->value;
+		pv_names = dp->right;
+
+		vp = find_var(scope, name);
+		if (vp == 0)
+		{
+			report("%s:%d: ", dp->src_file, dp->line_num);
+			report("assign: variable %s not declared\n", name);
+			continue;
+		}
+		if (dp->left != 0)
+		{
+			assign_subscr(chan_list, dp, vp, dp->left->value,
+				pv_names->value);
+		}
+		else if (dp->right->next == 0) {
+			assign_single(chan_list, dp, vp, pv_names->value);
+		}
+		else
+		{
+			assign_list(chan_list, dp, vp, pv_names);
+		}
+	}
+	return chan_list;
+}
+
+static void analyse_monitors(Scope *scope, Expr *defn_list)
+{
+	Expr *dp = defn_list;
+
+#ifdef	DEBUG
+	report("-- Monitors --\n");
+#endif	/*DEBUG*/
+	for (dp = defn_list; dp; dp = dp->next)
+	{
+		if (dp->type == E_MONITOR)
+		{
+			char *name = dp->value;
+			char *subscript = dp->left ? dp->left->value : 0;
+			Var *vp = find_var(scope, name);
+
+			if (vp == 0)
+			{
+				report("%s:%d: ", dp->src_file, dp->line_num);
+				report("assign: variable %s not declared\n", name);
+				continue;
+			}
+			monitor_stmt(vp, dp, subscript);
+		}
+	}
+}
+
+static void analyse_syncs_and_syncqs(Scope *scope, Expr *defn_list)
+{
+	Expr *dp = defn_list;
+
+#ifdef	DEBUG
+	report("-- Sync and SyncQ --\n");
+#endif	/*DEBUG*/
+	for (dp = defn_list; dp; dp = dp->next)
+	{
+		char *subscript = dp->left ? dp->left->value : 0;
+		char *ef_name;
+
+		if (dp->type == E_SYNC)
+		{
+			assert(dp->right);
+			assert(dp->right->type == E_X);
+			ef_name = dp->right->value;
+			sync_stmt(scope, dp, subscript, ef_name);
+		}
+		if (dp->type == E_SYNCQ)
+		{
+			char *maxQueueSize;
+			assert(dp->right);
+			assert(dp->right->type == E_X);
+			ef_name = dp->right->value;
+			maxQueueSize = dp->right->left ? dp->right->left->value : 0;
+			assert(maxQueueSize==0 || dp->right->left->type==E_CONST);
+			syncq_stmt(scope, dp, subscript, ef_name, maxQueueSize);
+		}
+	}
+}
+
+/* Option statement */
+static int option_stmt(
+	Options	*options,
+	char	*name,		/* "a", "r", ... */
+	char	*value		/* "+", "-" */
+)
+{
+	int optval = *value == '+';
+
+	assert(*value == '+' || *value == '-');
+	switch(*name)
+	{
+	    case 'a':
+		options->async = optval;
+		break;
+	    case 'c':
+		options->conn = optval;
+		break;
+	    case 'd':
+		options->debug = optval;
+		break;
+	    case 'e':
+		options->newef = optval;
+		break;
+	    case 'i':
+		options->init_reg = optval;
+		break;
+	    case 'l':
+		options->line = optval;
+		break;
+	    case 'm':
+		options->main = optval;
+		break;
+	    case 'r':
+		options->reent = optval;
+		break;
+	    case 'w':
+		options->warn = optval;
+		break;
+	    default:
+	        return FALSE;
+	}
+	return TRUE;
+}
+
+/* "Assign" statement: Assign a variable to a DB channel.
+ * Format: assign <variable> to <string;
+ * Note: Variable may be subscripted.
+ */
+static void assign_single(
+	ChanList	*chan_list,
+	Expr		*dp,
+	Var		*vp,
+	char		*db_name
+)
+{
+	Chan		*cp;
+	char		*name = vp->name;
+
+#ifdef	DEBUG
+	report("assign %s to \"%s\";\n", name, db_name);
+#endif	/*DEBUG*/
+
+	cp = vp->chan;
+	if (cp != 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: %s already assigned\n", name);
+		return;
+	}
+
+	/* Build structure for this channel */
+	cp = build_channel(chan_list, vp);
+
+	cp->db_name = db_name;	/* DB name */
+
+	/* The entire variable is assigned */
+	cp->count = vp->length1 * vp->length2;
+
+	return;
+}
+
+/* "Assign" statement: assign an array element to a DB channel.
+ * Format: assign <variable>[<subscr>] to <string>; */
+static void assign_subscr(
+	ChanList	*chan_list,
+	Expr		*dp,
+	Var		*vp,
+	char		*subscript,	/* subscript value or 0 */
+	char		*db_name
+)
+{
+	Chan		*cp;
+	char		*name = vp->name;
+	int		subNum;
+
+#ifdef	DEBUG
+	report("assign %s[%s] to \"%s\";\n", name, subscript, db_name);
+#endif	/*DEBUG*/
+
+	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: variable %s not an array\n", name);
+		return;
+	}
+
+	cp = vp->chan;
+	if (cp == 0)
+	{
+		/* Build structure for this channel */
+		cp = build_channel(chan_list, vp);
+	}
+	else if (cp->db_name != 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: array %s already assigned\n", name);
+		return;
+	}
+
+	subNum = atoi(subscript);
+	if (subNum < 0 || subNum >= vp->length1)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: subscript %s[%d] is out of range\n",
+		 name, subNum);
+		return;
+	}
+
+	if (cp->db_name_list == 0)
+		alloc_channel_lists(cp, vp->length1); /* allocate lists */
+	else if (cp->db_name_list[subNum] != 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: %s[%d] already assigned\n",
+		 name, subNum);
+		return;
+	}
+
+	cp->db_name_list[subNum] = db_name;
+	cp->count = vp->length2; /* could be a 2-dimensioned array */
+
+	return;
+}
+
+/* Assign statement: assign an array to multiple DB channels.
+ * Format: assign <variable> to { <string>, <string>, ... };
+ * Assignments for double dimensioned arrays:
+ * <var>[0][0] assigned to 1st db name,
+ * <var>[1][0] assigned to 2nd db name, etc.
+ * If db name list contains fewer names than the array dimension,
+ * the remaining elements receive 0 assignments.
+ */
+static void assign_list(
+	ChanList	*chan_list,
+	Expr		*dp,
+	Var		*vp,
+	Expr		*db_name_list
+)
+{
+	Chan		*cp;
+	int		elem_num;
+	char		*name = vp->name;
+
+#ifdef	DEBUG
+	report("assign %s to {", name);
+#endif	/*DEBUG*/
+
+	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: variable %s is not an array\n", name);
+		return;
+	}
+
+	cp = vp->chan;
+	if (cp != 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("assign: variable %s already assigned\n", name);
+		return;
+	}
+
+	/* Build a db structure for this variable */
+	cp = build_channel(chan_list, vp);
+
+	/* Allocate lists */
+	alloc_channel_lists(cp, vp->length1); /* allocate lists */
+
+	/* fill in the array of pv names */
+	for (elem_num = 0; elem_num < vp->length1; elem_num++)
+	{
+		if (db_name_list == 0)
+			break; /* end of list */
+
+#ifdef	DEBUG
+		report("\"%s\", ", db_name_list->value);
+#endif	/*DEBUG*/
+		cp->db_name_list[elem_num] = db_name_list->value; /* DB name */
+		cp->count = vp->length2;
+ 
+		db_name_list = db_name_list->next;
+	}
+#ifdef	DEBUG
+		report("};\n");
+#endif	/*DEBUG*/
+
+	return;
+}
+
+/* Build a channel structure for this variable */
+static Chan *build_channel(ChanList *chan_list, Var *vp)
+{
+	Chan		*cp;
+
+	cp = allocChan();
+	add_chan(chan_list, cp);		/* add to Chan list */
+
+	/* make connections between Var & Chan structures */
+	cp->var = vp;
+	vp->chan = cp;
+
+	/* Initialize the structure */
+	cp->db_name_list = 0;
+	cp->mon_flag_list = 0;
+	cp->ef_var_list = 0;
+	cp->ef_num_list = 0;
+	cp->num_elem = 0;
+	cp->mon_flag = 0;
+	cp->ef_var = 0;
+	cp->ef_num = 0;
+
+	return cp;
+}
+
+/* Allocate lists for assigning multiple pv's to a variable */
+static void alloc_channel_lists(Chan *cp, int length)
+{
+	/* allocate an array of pv names */
+	cp->db_name_list = (char **)calloc(sizeof(char **), length);
+
+	/* allocate an array for monitor flags */
+	cp->mon_flag_list = (int *)calloc(sizeof(int **), length);
+
+	/* allocate an array for event flag var ptrs */
+	cp->ef_var_list = (Var **)calloc(sizeof(Var **), length);
+
+	/* allocate an array for event flag numbers */
+	cp->ef_num_list = (int *)calloc(sizeof(int **), length);
+
+	cp->num_elem = length;
+}
+
+static void monitor_stmt(
+	Var		*vp,
+	Expr		*dp,
+	char		*subscript	/* element number or 0 */
+)
+{
+	Chan		*cp;
+	int		subNum;
+	char		*name = vp->name;
+
+#ifdef	DEBUG
+	report("monitor %s", name);
+	if (subscript != 0) report("[%s]", subscript);
+	report("\n");
+#endif	/*DEBUG*/
+
+	/* Find a channel assigned to this variable */
+	cp = vp->chan;
+	if (cp == 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("monitor: variable %s not assigned\n", name);
+		return;
+	}
+
+	if (subscript == 0)
+	{
+		if (cp->num_elem == 0)
+		{	/* monitor one channel for this variable */
+			cp->mon_flag = TRUE;
+			return;
+		}
+
+		/* else monitor all channels in db list */
+		for (subNum = 0; subNum < cp->num_elem; subNum++)
+		{	/* 1 pv per element of the array */
+			cp->mon_flag_list[subNum] = TRUE;
+		}
+		return;
+	}
+
+	/* subscript != 0 */
+	subNum = atoi(subscript);
+	if (subNum < 0 || subNum >= cp->num_elem)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("monitor: subscript of %s out of range\n", name);
+		return;
+	}
+
+	if (cp->num_elem == 0 || cp->db_name_list[subNum] == 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("monitor: %s[%d] not assigned\n",
+		 name, subNum);
+		return;
+	}
+
+	cp->mon_flag_list[subNum] = TRUE;
+	return;
+}
+
+static void sync_stmt(
+	Scope		*scope,
+	Expr		*dp,
+	char		*subscript,
+	char		*ef_name
+)
+{
+	Chan		*cp;
+	Var		*vp;
+	int		subNum;
+	char		*name = dp->value;
+
+#ifdef	DEBUG
+	report("sync %s%s%s%s to %s\n", name,
+	 subscript?"[":"", subscript?subscript:"", subscript?"]":"", ef_name);
+#endif	/*DEBUG*/
+
+	vp = find_var(scope, name);
+	if (vp == 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("sync: variable %s not declared\n", name);
+		return;
+	}
+
+	cp = vp->chan;
+	if (cp == 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("sync: variable %s not assigned\n", name);
+		return;
+	}
+
+	/* Find the event flag varible */
+	vp = find_var(scope, ef_name);
+	if (vp == 0 || vp->type != V_EVFLAG)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("sync: e-f variable %s not declared\n",
+		 ef_name);
+		return;
+	}
+
+	if (subscript == 0)
+	{	/* no subscript */
+		if (cp->db_name != 0)
+		{	/* 1 pv assigned to this variable */
+			cp->ef_var = vp;
+			return;
+		}
+
+		/* 1 pv per element in the array */
+		for (subNum = 0; subNum < cp->num_elem; subNum++)
+		{
+			cp->ef_var_list[subNum] = vp;
+		}
+		return;
+	}
+
+	/* subscript != 0 */
+	subNum = atoi(subscript);
+	if (subNum < 0 || subNum >= cp->num_elem)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("sync: subscript %s[%d] out of range\n",
+		 name, subNum);
+		return;
+	}
+	cp->ef_var_list[subNum] = vp; /* sync to a specific element of the array */
+
+	return;
+}
+
+static void syncq_stmt(
+	Scope		*scope,
+	Expr		*dp,
+	char		*subscript,
+	char		*ef_name,
+	char		*maxQueueSize
+)
+{
+	Chan		*cp;
+	Var		*vp;
+	Var		*efp;
+	int		subNum;
+	char		*name = dp->value;
+
+#ifdef	DEBUG
+	report("syncq_stmt: name=%s, subNum=%s, ef_name=%s, "
+	    "maxQueueSize=%s\n", name, subscript, ef_name, maxQueueSize);
+#endif	/*DEBUG*/
+
+	/* Find the variable and check it's assigned */
+	vp = find_var(scope, name);
+	if (vp == 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("syncQ: variable %s not declared\n", name);
+		return;
+	}
+
+	cp = vp->chan;
+	if (cp == 0)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("syncQ: variable %s not assigned\n", name);
+		return;
+	}
+
+	/* Check that the variable has not already been syncQ'd */
+	if (vp->queued)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("syncQ: variable %s already syncQ'd\n", name);
+		return;
+	}
+
+	/* Find the event flag variable */
+	efp = find_var(scope, ef_name);
+	if (efp == 0 || efp->type != V_EVFLAG)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("syncQ: e-f variable %s not declared\n", ef_name);
+		return;
+	}
+
+	/* Check that the event flag has not already been syncQ'd */
+	if (efp->queued)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("syncQ: e-f variable %s already syncQ'd\n", ef_name);
+		return;
+	}
+
+	/* Note queued (for both variable and event flag) and set the
+	   maximum queue size (0 means default) */
+	vp->queued = efp->queued = TRUE;
+	vp->maxQueueSize = (maxQueueSize == 0) ? 0 : atoi(maxQueueSize);
+
+	if (subscript == 0)
+	{	/* no subscript */
+		if (cp->db_name != 0)
+		{	/* 1 pv assigned to this variable */
+			cp->ef_var = efp;
+			return;
+		}
+
+		/* 1 pv per element in the array */
+		for (subNum = 0; subNum < cp->num_elem; subNum++)
+		{
+			cp->ef_var_list[subNum] = efp;
+		}
+		return;
+	}
+
+	/* subscript != 0 */
+	subNum = atoi(subscript);
+	if (subNum < 0 || subNum >= cp->num_elem)
+	{
+		report("%s:%d: ", dp->src_file, dp->line_num);
+		report("syncQ: subscript %s[%d] out of range\n",
+		 name, subNum);
+		return;
+	}
+	cp->ef_var_list[subNum] = efp; /* sync to a specific element of the array */
+}
+
+/* Add a channel to the channel linked list */
+static void add_chan(ChanList *chan_list, Chan *cp)
+{
+	if (chan_list->first == 0)
+		chan_list->first = cp;
+	else
+		chan_list->last->next = cp;
+	chan_list->last = cp;
+	cp->next = 0;
+}
+
+/* Add a variable to a scope; (append to the end of the list */
+void add_var(Scope *scope, Var *vp)
+{
+	VarList	*var_list = scope->var_list;
+
+	if (var_list->first == 0)
+		var_list->first = vp;
+	else
+		var_list->last->next = vp;
+	var_list->last = vp;
+	vp->next = 0;
+}
+
+/* Find a variable by name, given a scope; first searches the given
+   scope, then the parent scope, and so on. Returns a pointer to the
+   var struct or 0 if the variable is not found. */
+Var *find_var(Scope *scope, char *name)
+{
+	Var	*vp;
+
+	for ( ; scope != 0; scope = scope->next)
+	{
+		for (vp = scope->var_list->first; vp != 0; vp = vp->next)
+		{
+			if (strcmp(vp->name, name) == 0)
+				return vp;
+		}
+	}
+	return 0;
+}
+
+/* Count the number of linked expressions */
+int expr_count(Expr *ep)
+{
+	int		count;
+
+	for (count = 0; ep != 0; ep = ep->next)
+		count++;
+	return count;
+}
+
+/* Sets vp->queueIndex for each syncQ'd variable, & returns number of
+ * syncQ queues defined. 
+ */
+static int db_queue_count(Scope *scope)
+{
+	int		nqueue;
+	Var		*vp;
+
+	nqueue = 0;
+	for (vp = scope->var_list->first; vp != NULL; vp = vp->next)
+	{
+		if (vp->type != V_EVFLAG && vp->queued)
+		{
+			vp->queueIndex = nqueue;
+			nqueue++;
+		}
+	}
+
+	return nqueue;
+}
+
+/* Sets cp->index for each variable, & returns number of db channels defined. 
+ */
+static int db_chan_count(ChanList *chan_list)
+{
+	int	nchan;
+	Chan	*cp;
+
+	nchan = 0;
+	for (cp = chan_list->first; cp != NULL; cp = cp->next)
+	{
+		cp->index = nchan;
+		if (cp->num_elem == 0)
+			nchan += 1;
+		else
+			nchan += cp->num_elem; /* array with multiple channels */
+	}
+
+	return nchan;
+}
+
+static void reconcile_variables(Scope *scope, int opt_warn, Expr *expr_list)
+{
+	Expr *ep;
+	connect_var_args cv_args = { scope, opt_warn };
+
+	for (ep = expr_list; ep != 0; ep = ep->next)
+	{
+		traverse_expr_tree(ep, E_VAR, 0, (expr_fun*)connect_variable, &cv_args);
+	}
+}
+
+/* Traverse the expression tree, and call the supplied
+ * function whenever type = ep->type AND value matches ep->value.
+ * The condition value = 0 matches all.
+ * The function is called with the current ep and a supplied argument (argp) */
+void traverse_expr_tree(
+	Expr	    *ep,	/* ptr to start of expression */
+	int	    type,	/* to search for */
+	char	    *value,	/* with optional matching value */
+	expr_fun    *funcp,	/* function to call */
+	void	    *argp	/* ptr to argument to pass on to function */
+)
+{
+	Expr		*ep1;
+
+	if (ep == 0)
+		return;
+
+#if 0
+	if (printTree)
+		report("traverse_expr_tree: type=%s, value=%s\n",
+		 expr_type_names[ep->type], ep->value);
+#endif
+
+	/* Call the function? */
+	if ((ep->type == type) && (value == 0 || strcmp(ep->value, value) == 0) )
+	{
+		funcp(ep, argp);
+	}
+
+	/* Continue traversing the expression tree */
+	switch(ep->type)
+	{
+	case E_VAR:
+	case E_CONST:
+	case E_STRING:
+	case E_TEXT:
+	case E_BREAK:
+		break;
+
+	case E_PAREN:
+	case E_SS:
+	case E_STATE:
+	case E_FUNC:
+	case E_CMPND:
+	case E_STMT:
+	case E_ELSE:
+	case E_PRE:
+	case E_POST:
+		for (ep1 = ep->left; ep1 != 0;	ep1 = ep1->next)
+		{
+			traverse_expr_tree(ep1, type, value, funcp, argp);
+		}
+		break;
+
+	case E_DECL:
+	case E_WHEN:
+        case E_ENTRY:  /* E_ENTRY and E_EXIT only have expressions on RHS (->right) */
+        case E_EXIT:   /* but add them here incase ->left is used in future. */
+	case E_BINOP:
+	case E_TERNOP:
+	case E_SUBSCR:
+	case E_IF:
+	case E_WHILE:
+	case E_FOR:
+	case E_X:
+		for (ep1 = ep->left; ep1 != 0;	ep1 = ep1->next)
+		{
+			traverse_expr_tree(ep1, type, value, funcp, argp);
+		}
+		for (ep1 = ep->right; ep1 != 0;	ep1 = ep1->next)
+		{
+			traverse_expr_tree(ep1, type, value, funcp, argp);
+		}
+		break;
+
+	default:
+		report("traverse_expr_tree: type=%s ???\n", expr_type_names[ep->type]);
+	}
+}
+
+/* Connect a variable in an expression to the the Var structure */
+static void connect_variable(Expr *ep, connect_var_args *args)
+{
+	Scope *scope = args->scope;
+	int opt_warn = args->opt_warn;
+	Var *vp;
+
+	if (ep->type != E_VAR)
+		return;
+#ifdef	DEBUG
+	report("connect_variable: \"%s\", line %d\n", ep->value, ep->line_num);
+#endif	/*DEBUG*/
+	vp = find_var(scope, ep->value);
+#ifdef	DEBUG
+	report("\t \"%s\" was %s\n", ep->value, vp ? "found" : "not found" );
+#endif	/*DEBUG*/
+	if (vp == 0)
+	{	/* variable not declared; add it to the variable list */
+		if (opt_warn)
+			report(
+			 "Warning:  variable \"%s\" is used but not declared.\n",
+			 ep->value);
+		vp = allocVar();
+		add_var(scope, vp);
+		vp->name = ep->value;
+		vp->type = V_NONE; /* undeclared type */
+		vp->length1 = 1;
+		vp->length2 = 1;
+		vp->value = 0;
+	}
+	ep->left = (Expr *)vp; /* make connection */
+
+	return;
+} 
+
+/* Reconcile state names */
+static void reconcile_states(Expr *ss_list)
+{
+	Expr		*ssp, *sp, *sp1;
+
+	for (ssp = ss_list; ssp != 0; ssp = ssp->next)
+	{
+	    for (sp = ssp->left; sp != 0; sp = sp->next)
+	    {
+		/* Check for duplicate state names in this state set */
+		for (sp1 = sp->next; sp1 != 0; sp1 = sp1->next)
+		{
+			if (strcmp(sp->value, sp1->value) == 0)
+			{
+			    report(
+			       "State \"%s\" is duplicated in state set \"%s\"\n",
+			       sp->value, ssp->value);
+			}
+		}		
+	    }
+	}
+}
diff --git a/src/snc/analysis.h b/src/snc/analysis.h
new file mode 100644
index 00000000..0f1d5719
--- /dev/null
+++ b/src/snc/analysis.h
@@ -0,0 +1,30 @@
+#ifndef INCLanalysish
+#define INCLanalysish
+
+#include "types.h"
+
+void analyse_program(Program *p, Options *options);
+
+void add_var(
+	Scope *scope,		/* scope to add variable to */
+	Var *vp			/* variable to add */
+);
+
+Var *find_var(
+	Scope *scope,		/* scope where to first search for the variable */
+	char *name		/* variable name to find */
+);
+
+int expr_count(Expr*);
+
+typedef void expr_fun(Expr *, void *);
+
+void traverse_expr_tree(
+	Expr	    *ep,	/* ptr to start of expression */
+	int	    type,	/* to search for */
+	char	    *value,	/* with optional matching value */
+	expr_fun    *funcp,	/* function to call */
+	void	    *argp	/* ptr to argument to pass on to function */
+);
+
+#endif	/*INCLanalysish*/
diff --git a/src/snc/phase2.c b/src/snc/gen_code.c
similarity index 56%
rename from src/snc/phase2.c
rename to src/snc/gen_code.c
index 056741a5..fa584c1f 100644
--- a/src/snc/phase2.c
+++ b/src/snc/gen_code.c
@@ -3,8 +3,6 @@
 	Copyright, 1990, The Regents of the University of California.
 		 Los Alamos National Laboratory
 
- 	phase2.c,v 1.2 1995/06/27 15:25:52 wright Exp
-
 	DESCRIPTION: Phase 2 code generation routines for SNC.
 	Produces code and tables in C output file.
 	See also:  gen_ss_code.c and gen_tables.c
@@ -31,110 +29,80 @@
 17mar00,wfl	Added necessary includes for C main program.
 31mar00,wfl	Supported entry handler.
 ***************************************************************************/
-/*#define DEBUG 1*/
 
 #include	<stdio.h>
 #include	<stdlib.h>
 #include	<string.h>
 #include	<assert.h>
 
-#include	"parse.h"
-#include	"phase2.h"
+#include	"analysis.h"
 #include	"gen_ss_code.h"
 #include	"gen_tables.h"
 #include	"snc_main.h"
+#include	"gen_code.h"
 
 #ifndef TRUE
 #define TRUE    1
 #define FALSE   0
 #endif  /*TRUE*/
 
-static void gen_preamble(char *prog_name,
+static void gen_preamble(char *prog_name, Options *options,
 	int num_ss, int num_channels, int num_events, int num_queues);
 static void gen_opt_defn(int opt, char *defn_name);
-static void reconcile_variables(Scope *scope, Expr *expr_list);
-static void connect_variable(Expr *ep, Scope *scope);
-static void reconcile_states(Expr *ss_list);
-static void gen_var_decl(Scope *scope);
+static void gen_var_decl(Scope *scope, int opt_reent);
 static void gen_defn_c_code(Expr *defn_c_list);
 static void gen_global_c_code(Expr *global_c_list);
 static void gen_init_reg(char *prog_name);
 static int assign_ef_bits(Scope *scope, ChanList *chan_list);
 static void assign_delay_ids(Expr *ss_list);
 static void assign_next_delay_id(Expr *ep, int *delay_id);
-static int db_queue_count(Scope *scope);
-static int db_chan_count(ChanList *chan_list);
-
-/*+************************************************************************
-*  NAME: phase2
-*
-*  CALLING SEQUENCE
-*	type		argument	I/O	description
-*	---------------------------------------------------
-*
-*  RETURNS: n/a
-*
-*  FUNCTION: Generate C code from parsing lists.
-*-*************************************************************************/
-void phase2(Program *program)
-{
-	/* Count number of db channels and state sets defined */
-	program->num_queues = db_queue_count(program->global_scope);
-	program->num_channels = db_chan_count(program->chan_list);
-	program->num_ss = expr_count(program->ss_list);
-
-	/* Reconcile all variable and tie each to the appropriate VAR struct */
-	reconcile_variables(program->global_scope, program->ss_list);
-	reconcile_variables(program->global_scope, program->entry_code_list);
-	reconcile_variables(program->global_scope, program->exit_code_list);
-
-	/* reconcile all state names, including next state in transitions */
-	reconcile_states(program->ss_list);
 
+/* Generate C code from parse tree. */
+void generate_code(Program *p)
+{
 	/* Assign bits for event flags */
-	program->num_events = assign_ef_bits(program->global_scope, program->chan_list);
+	p->num_events = assign_ef_bits(p->global_scope, p->chan_list);
 
 #ifdef	DEBUG
 	fprintf(stderr, "gen_tables:\n");
-	fprintf(stderr, " num_channels = %d\n", program->num_channels);
-	fprintf(stderr, " num_events = %d\n", program->num_events);
-	fprintf(stderr, " num_queues = %d\n", program->num_queues);
-	fprintf(stderr, " num_ss = %d\n", program->num_ss);
+	fprintf(stderr, " num_channels = %d\n", p->num_channels);
+	fprintf(stderr, " num_events = %d\n", p->num_events);
+	fprintf(stderr, " num_queues = %d\n", p->num_queues);
+	fprintf(stderr, " num_ss = %d\n", p->num_ss);
 #endif	/*DEBUG*/
 
 	/* Assign delay id's */
-	assign_delay_ids(program->ss_list);
+	assign_delay_ids(p->ss_list);
 
 	/* Generate preamble code */
-	gen_preamble(program->prog_name, program->num_ss,
-		program->num_channels, program->num_events, program->num_queues);
+	gen_preamble(p->name, p->options, p->num_ss,
+		p->num_channels, p->num_events, p->num_queues);
 
 	/* Generate variable declarations */
-	gen_var_decl(program->global_scope);
+	gen_var_decl(p->global_scope, p->options->reent);
 
 	/* Generate definition C code */
-	gen_defn_c_code(program->global_defn_list);
+	gen_defn_c_code(p->global_defn_list);
 
 	/* Generate code for each state set */
-	gen_ss_code(program);
+	gen_ss_code(p);
 
 	/* Generate tables */
-	gen_tables(program);
+	gen_tables(p);
 
 	/* Output global C code */
-	gen_global_c_code(program->global_c_list);
+	gen_global_c_code(p->global_c_list);
 
 	/* Sequencer registration (if "init_register" option set) */
-	gen_init_reg(program->prog_name);
-
-	exit(0);
+	if (p->options->init_reg) {
+		gen_init_reg(p->name);
+	}
 }
+
 /* Generate preamble (includes, defines, etc.) */
-static void gen_preamble(char *prog_name,
+static void gen_preamble(char *prog_name, Options *options,
 	int num_ss, int num_channels, int num_events, int num_queues)
 {
-	Options *options = globals->options;
-
 	/* Program name (comment) */
 	printf("\n/* Program \"%s\" */\n", prog_name);
 
@@ -147,10 +115,15 @@ static void gen_preamble(char *prog_name,
 	printf("#define NUM_EVENTS %d\n", num_events);
 	printf("#define NUM_QUEUES %d\n", num_queues);
 
-	/* The following definition should be consistant with db_access.h */
+	/* The following definition should be consistent with db_access.h */
 	printf("\n");
 	printf("#define MAX_STRING_SIZE 40\n");
 
+	/* The following definition should be consistent with seq_if.c */
+	printf("\n");
+	printf("#define ASYNC %d\n", 1);
+	printf("#define SYNC %d\n", 2);
+
 	/* #define's for compiler options */
 	printf("\n");
 	gen_opt_defn(options->async, "ASYNC_OPT");
@@ -207,74 +180,8 @@ static void gen_opt_defn(int opt, char *defn_name)
  */
 int	printTree = FALSE; /* For debugging only */
 
-static void reconcile_variables(Scope *scope, Expr *expr_list)
-{
-	Expr			*ep;
-
-	for (ep = expr_list; ep != 0; ep = ep->next)
-	{
-		traverse_expr_tree(ep, E_VAR, 0, connect_variable, scope);
-	}
-}
-
-/* Connect a variable in an expression to the the Var structure */
-static void connect_variable(Expr *ep, Scope *scope)
-{
-	Var		*vp;
-
-	if (ep->type != E_VAR)
-		return;
-#ifdef	DEBUG
-	fprintf(stderr, "connect_variable: \"%s\", line %d\n", ep->value, ep->line_num);
-#endif	/*DEBUG*/
-	vp = find_var(scope, ep->value);
-#ifdef	DEBUG
-	fprintf(stderr, "\t \"%s\" was %s\n", ep->value, vp ? "found" : "not found" );
-#endif	/*DEBUG*/
-	if (vp == 0)
-	{	/* variable not declared; add it to the variable list */
-		if (globals->options->warn)
-			fprintf(stderr,
-			 "Warning:  variable \"%s\" is used but not declared.\n",
-			 ep->value);
-		vp = allocVar();
-		add_var(scope, vp);
-		vp->name = ep->value;
-		vp->type = V_NONE; /* undeclared type */
-		vp->length1 = 1;
-		vp->length2 = 1;
-		vp->value = 0;
-	}
-	ep->left = (Expr *)vp; /* make connection */
-
-	return;
-} 
-
-/* Reconcile state names */
-static void reconcile_states(Expr *ss_list)
-{
-	Expr		*ssp, *sp, *sp1;
-
-	for (ssp = ss_list; ssp != 0; ssp = ssp->next)
-	{
-	    for (sp = ssp->left; sp != 0; sp = sp->next)
-	    {
-		/* Check for duplicate state names in this state set */
-		for (sp1 = sp->next; sp1 != 0; sp1 = sp1->next)
-		{
-			if (strcmp(sp->value, sp1->value) == 0)
-			{
-			    fprintf(stderr,
-			       "State \"%s\" is duplicated in state set \"%s\"\n",
-			       sp->value, ssp->value);
-			}
-		}		
-	    }
-	}
-}
-
 /* Generate a C variable declaration for each variable declared in SNL */
-static void gen_var_decl(Scope *scope)
+static void gen_var_decl(Scope *scope, int opt_reent)
 {
 	Var		*vp;
 	char		*vstr;
@@ -283,7 +190,7 @@ static void gen_var_decl(Scope *scope)
 	printf("\n/* Variable declarations */\n");
 
 	/* Convert internal type to `C' type */
-	if (globals->options->reent)
+	if (opt_reent)
 		printf("struct UserVar {\n");
 	for (nv=0, vp = scope->var_list->first; vp != NULL; nv++, vp = vp->next)
 	{
@@ -333,7 +240,7 @@ static void gen_var_decl(Scope *scope)
 		if (vstr == NULL)
 			continue;
 
-		if (globals->options->reent)
+		if (opt_reent)
 			printf("\t");
 		else
 			printf("static ");
@@ -359,11 +266,11 @@ static void gen_var_decl(Scope *scope)
 
 		printf(";\n");
 	}
-	if (globals->options->reent)
+	if (opt_reent)
 		printf("};\n");
 
 	/* Avoid compilation warnings if not re-entrant */
-	if (!globals->options->reent)
+	if (!opt_reent)
 	{
 		printf("\n");
 		printf("/* Not used (avoids compilation warnings) */\n");
@@ -404,59 +311,18 @@ static void gen_global_c_code(Expr *global_c_list)
 	if (ep != NULL)
 	{
 		printf("\f/* Global C code */\n");
-		print_line_num(ep->line_num, ep->src_file);
 		for (; ep != NULL; ep = ep->next)
 		{
 			assert(ep->type == E_TEXT);
+			print_line_num(ep->line_num, ep->src_file);
 			printf("%s\n", ep->value);
 		}
 	}
 	return;
 }
 
-/* Sets cp->index for each variable, & returns number of db channels defined. 
- */
-static int db_chan_count(ChanList *chan_list)
-{
-	int	nchan;
-	Chan	*cp;
-
-	nchan = 0;
-	for (cp = chan_list->first; cp != NULL; cp = cp->next)
-	{
-		cp->index = nchan;
-		if (cp->num_elem == 0)
-			nchan += 1;
-		else
-			nchan += cp->num_elem; /* array with multiple channels */
-	}
-
-	return nchan;
-}
-
-/* Sets vp->queueIndex for each syncQ'd variable, & returns number of
- * syncQ queues defined. 
- */
-static int db_queue_count(Scope *scope)
-{
-	int		nqueue;
-	Var		*vp;
-
-	nqueue = 0;
-	for (vp = scope->var_list->first; vp != NULL; vp = vp->next)
-	{
-		if (vp->type != V_EVFLAG && vp->queued)
-		{
-			vp->queueIndex = nqueue;
-			nqueue++;
-		}
-	}
-
-	return nqueue;
-}
-
 /* Assign event bits to event flags and associate db channels with
- * event flags.
+ * event flags. Return number of event flags found.
  */
 static int assign_ef_bits(Scope *scope, ChanList *chan_list)
 {
@@ -477,7 +343,7 @@ static int assign_ef_bits(Scope *scope, ChanList *chan_list)
 			printf("#define %s\t%d\n", vp->name, num_events);
 		}
 	}
-			
+
 	/* Associate event flags with DB channels */
 	for (cp = chan_list->first; cp != NULL; cp = cp->next)
 	{
@@ -528,7 +394,7 @@ static void assign_delay_ids(Expr *ss_list)
 
 				/* traverse event expression only */
 				traverse_expr_tree(tp->left, E_FUNC, "delay",
-					assign_next_delay_id, &delay_id);
+				  (expr_fun*)assign_next_delay_id, &delay_id);
 			}
 		}
 	}
@@ -540,101 +406,12 @@ static void assign_next_delay_id(Expr *ep, int *delay_id)
 	*delay_id += 1;
 }
 
-/* Traverse the expression tree, and call the supplied
- * function whenever type = ep->type AND value matches ep->value.
- * The condition value = 0 matches all.
- * The function is called with the current ep and a supplied argument (argp) */
-void traverse_expr_tree(
-	Expr	    *ep,	/* ptr to start of expression */
-	int	    type,	/* to search for */
-	char	    *value,	/* with optional matching value */
-	expr_fun    *funcp,	/* function to call */
-	void	    *argp	/* ptr to argument to pass on to function */
-)
-{
-	Expr		*ep1;
-
-	if (ep == 0)
-		return;
-
-	if (printTree)
-		fprintf(stderr, "traverse_expr_tree: type=%s, value=%s\n",
-		 expr_type_names[ep->type], ep->value);
-
-	/* Call the function? */
-	if ((ep->type == type) && (value == 0 || strcmp(ep->value, value) == 0) )
-	{
-		funcp(ep, argp);
-	}
-
-	/* Continue traversing the expression tree */
-	switch(ep->type)
-	{
-	case E_VAR:
-	case E_CONST:
-	case E_STRING:
-	case E_TEXT:
-	case E_BREAK:
-		break;
-
-	case E_PAREN:
-	case E_SS:
-	case E_STATE:
-	case E_FUNC:
-	case E_CMPND:
-	case E_STMT:
-	case E_ELSE:
-	case E_PRE:
-	case E_POST:
-		for (ep1 = ep->left; ep1 != 0;	ep1 = ep1->next)
-		{
-			traverse_expr_tree(ep1, type, value, funcp, argp);
-		}
-		break;
-
-	case E_DECL:
-	case E_WHEN:
-        case E_ENTRY:  /* E_ENTRY and E_EXIT only have expressions on RHS (->right) */
-        case E_EXIT:   /* but add them here incase ->left is used in future. */
-	case E_BINOP:
-	case E_SUBSCR:
-	case E_IF:
-	case E_WHILE:
-	case E_FOR:
-	case E_X:
-		for (ep1 = ep->left; ep1 != 0;	ep1 = ep1->next)
-		{
-			traverse_expr_tree(ep1, type, value, funcp, argp);
-		}
-		for (ep1 = ep->right; ep1 != 0;	ep1 = ep1->next)
-		{
-			traverse_expr_tree(ep1, type, value, funcp, argp);
-		}
-		break;
-
-	default:
-		fprintf(stderr, "traverse_expr_tree: type=%d???\n", ep->type);
-	}
-}
-
 static void gen_init_reg(char *prog_name)
 {
-	if (globals->options->init_reg) {
-		printf("\n\n/* Register sequencer commands and program */\n");
-		printf("\nvoid %sRegistrar (void) {\n", prog_name);
-		printf("    seqRegisterSequencerCommands();\n");
-		printf("    seqRegisterSequencerProgram (&%s);\n", prog_name);
-		printf("}\n");
-		printf("epicsExportRegistrar(%sRegistrar);\n\n", prog_name);
-	}
-}
-
-/* Count the number of linked expressions */
-int expr_count(Expr *ep)
-{
-	int		count;
-
-	for (count = 0; ep != 0; ep = ep->next)
-		count++;
-	return count;
+	printf("\n\n/* Register sequencer commands and program */\n");
+	printf("\nvoid %sRegistrar (void) {\n", prog_name);
+	printf("    seqRegisterSequencerCommands();\n");
+	printf("    seqRegisterSequencerProgram (&%s);\n", prog_name);
+	printf("}\n");
+	printf("epicsExportRegistrar(%sRegistrar);\n\n", prog_name);
 }
diff --git a/src/snc/gen_code.h b/src/snc/gen_code.h
new file mode 100644
index 00000000..1e0ed485
--- /dev/null
+++ b/src/snc/gen_code.h
@@ -0,0 +1,8 @@
+#ifndef INCLgencodeh
+#define INCLgencodeh
+
+#include "types.h"
+
+void generate_code(Program *p);
+
+#endif	/*INCLgencodeh*/
diff --git a/src/snc/gen_ss_code.c b/src/snc/gen_ss_code.c
index bf963999..3609e688 100644
--- a/src/snc/gen_ss_code.c
+++ b/src/snc/gen_ss_code.c
@@ -31,7 +31,7 @@
 #include	<assert.h>
 
 #include	"parse.h"
-#include	"phase2.h"
+#include	"analysis.h"
 #include	"snc_main.h"
 
 #ifndef TRUE
@@ -66,7 +66,7 @@ static void gen_delay_func(Expr *sp, Expr *ssp);
 static void eval_delay(Expr *ep, Expr *sp);
 static void gen_action_func(Expr *sp, Expr *ssp);
 static void gen_event_func(Expr *sp, Expr *ssp);
-static void eval_expr(int stmt_type, Expr *ep, Expr *sp, int level);
+static void gen_expr(int stmt_type, Expr *ep, Expr *sp, int level);
 static void indent(int level);
 static void gen_ef_func(int stmt_type, Expr *ep, char *fname,
 	enum fcode func_code);
@@ -100,11 +100,15 @@ void print_loc(Expr *ep);
 #define	ENTRY_STMT	4
 #define	EXIT_STMT	5
 
+static int opt_reent;
+
 void gen_ss_code(Program *program)
 {
 	Expr			*ssp;
 	Expr			*sp;
 
+	opt_reent = program->options->reent;
+
 	/* Generate entry handler code */
 	gen_entry_handler(program->entry_code_list);
 
@@ -175,7 +179,7 @@ static void gen_entry_func(Expr *sp, Expr *ssp)
 			printf("/* Entry %d: */\n", ++entryI);
 			for (xp = ep->right; xp != NULL; xp = xp->next)
 			{
-				eval_expr(ACTION_STMT, xp, sp, 1);
+				gen_expr(ACTION_STMT, xp, sp, 1);
 			}
 		}
 	}
@@ -204,7 +208,7 @@ static void gen_exit_func(Expr *sp, Expr *ssp)
  			 printf("/* Exit %d: */\n", ++exitI);
 			 for (xp = ep->right; xp != NULL; xp = xp->next)
 			 {
-				eval_expr(ACTION_STMT, xp, sp, 1);
+				gen_expr(ACTION_STMT, xp, sp, 1);
 			 }
 		}
 	}
@@ -233,7 +237,7 @@ static void gen_delay_func(Expr *sp, Expr *ssp)
 	{
 		if ( tp->type == E_WHEN )
 		{
-			traverse_expr_tree(tp, E_FUNC, "delay", eval_delay, sp);
+			traverse_expr_tree(tp, E_FUNC, "delay", (expr_fun*)eval_delay, sp);
 		}
 	}
 	printf("}\n");
@@ -259,7 +263,7 @@ static void eval_delay(Expr *ep, Expr *sp)
 	printf("\tseq_delayInit(ssId, %d, (", delay_id);
 
 	/* Evaluate & generate the 3-rd parameter (an expression) */
-	eval_expr(EVENT_STMT, ep->left, sp, 0);
+	gen_expr(EVENT_STMT, ep->left, sp, 0);
 
 	/* Complete the function call */
 	printf("));\n");
@@ -309,7 +313,7 @@ static void gen_action_func(Expr *sp, Expr *ssp)
 			for (ap = tp->right; ap != NULL; ap = ap->next) 
 			{ 
 				/* Evaluate statements */ 
-				eval_expr(ACTION_STMT, ap, sp, 3); 
+				gen_expr(ACTION_STMT, ap, sp, 3); 
 			}
 
 			/* end of block */
@@ -350,7 +354,7 @@ static void gen_event_func(Expr *sp, Expr *ssp)
 			      printf("TRUE");
 			else
 			{
-			      eval_expr(EVENT_STMT, tp->left, sp, 0);
+			      gen_expr(EVENT_STMT, tp->left, sp, 0);
 			}
 			printf(")\n\t{\n");
 			/* index is the transition number (0, 1, ...) */
@@ -391,9 +395,8 @@ static int state_block_index_from_name(Expr *ssp, char *state_name)
 	return -1; /* State name non-existant */
 }
 
-/* Evaluate an expression.
-*/
-static void eval_expr(
+/* Recursively generate code for an expression (tree) */
+static void gen_expr(
 	int stmt_type,		/* EVENT_STMT, ACTION_STMT, or DELAY_STMT */
 	Expr *ep,		/* ptr to expression */
 	Expr *sp,		/* ptr to current State struct */
@@ -412,11 +415,11 @@ static void eval_expr(
 		if (stmt_type == ACTION_STMT) print_loc(ep->left);
 		indent(level);
 		printf("%s ",ep->value);
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		if (ep->right != 0)
 		{
 			printf(" = ");
-			eval_expr(stmt_type, ep->right, sp, 0);
+			gen_expr(stmt_type, ep->right, sp, 0);
 		}
 		printf(";\n");
 		break;
@@ -425,7 +428,7 @@ static void eval_expr(
 		printf("{\n");
 		for (epf = ep->left; epf != 0;	epf = epf->next)
 		{
-			eval_expr(stmt_type, epf, sp, level+1);
+			gen_expr(stmt_type, epf, sp, level+1);
 		}
 		indent(level);
 		printf("}\n");
@@ -433,7 +436,7 @@ static void eval_expr(
 	case E_STMT:
 		if (stmt_type == ACTION_STMT) print_loc(ep->left);
 		indent(level);
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		printf(";\n");
 		break;
 	case E_IF:
@@ -444,29 +447,29 @@ static void eval_expr(
 			printf("if (");
 		else
 			printf("while (");
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		printf(")\n");
 		epf = ep->right;
 		if (epf->type == E_CMPND)
-			eval_expr(stmt_type, ep->right, sp, level);
+			gen_expr(stmt_type, ep->right, sp, level);
 		else
-			eval_expr(stmt_type, ep->right, sp, level+1);
+			gen_expr(stmt_type, ep->right, sp, level+1);
 		break;
 	case E_FOR:
 		if (stmt_type == ACTION_STMT) print_loc(ep->left->left);
 		indent(level);
 		printf("for (");
-		eval_expr(stmt_type, ep->left->left, sp, 0);
+		gen_expr(stmt_type, ep->left->left, sp, 0);
 		printf("; ");
-		eval_expr(stmt_type, ep->left->right, sp, 0);
+		gen_expr(stmt_type, ep->left->right, sp, 0);
 		printf("; ");
-		eval_expr(stmt_type, ep->right->left, sp, 0);
+		gen_expr(stmt_type, ep->right->left, sp, 0);
 		printf(")\n");
 		epf = ep->right->right;
 		if (epf->type == E_CMPND)
-			eval_expr(stmt_type, epf, sp, level);
+			gen_expr(stmt_type, epf, sp, level);
 		else
-			eval_expr(stmt_type, epf, sp, level+1);
+			gen_expr(stmt_type, epf, sp, level+1);
 		break;
 	case E_ELSE:
 		if (stmt_type == ACTION_STMT) print_loc(ep->left);
@@ -475,16 +478,16 @@ static void eval_expr(
 		epf = ep->left;
 		/* Is it "else if" ? */
 		if (epf->type == E_IF || epf->type == E_CMPND)
-			eval_expr(stmt_type, ep->left, sp, level);
+			gen_expr(stmt_type, ep->left, sp, level);
 		else
-			eval_expr(stmt_type, ep->left, sp, level+1);
+			gen_expr(stmt_type, ep->left, sp, level+1);
 		break;
 	case E_VAR:
 #ifdef	DEBUG
 		fprintf(stderr, "E_VAR: %s\n", ep->value);
 		fprintf(stderr, "ep->left is %s\n",ep->left ? "non-null" : "null");
 #endif	/*DEBUG*/
-		if(globals->options->reent)
+		if(opt_reent)
 		{
 			/* Make variables point to allocated structure */
 			Var		*vp;
@@ -518,7 +521,7 @@ static void eval_expr(
 		{
 			if (nexprs > 0)
 				printf(", ");
-			eval_expr(stmt_type, epf, sp, 0);
+			gen_expr(stmt_type, epf, sp, 0);
 		}
 		printf(")");
 		break;
@@ -528,32 +531,39 @@ static void eval_expr(
 		{
 			if (nexprs > 0)
 				printf(", ");
-			eval_expr(stmt_type, epf, sp, 0);
+			gen_expr(stmt_type, epf, sp, 0);
 		}
 		break;
 #endif
+	case E_TERNOP:
+		gen_expr(stmt_type, ep->left, sp, 0);
+		printf(" %s ", ep->value);
+		gen_expr(stmt_type, ep->right->left, sp, 0);
+		printf(" %s ", ep->right->value);
+		gen_expr(stmt_type, ep->right->right, sp, 0);
+		break;
 	case E_BINOP:
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		printf(" %s ", ep->value);
-		eval_expr(stmt_type, ep->right, sp, 0);
+		gen_expr(stmt_type, ep->right, sp, 0);
 		break;
 	case E_PAREN:
 		printf("(");
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		printf(")");
 		break;
 	case E_PRE:
 		printf("%s", ep->value);
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		break;
 	case E_POST:
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		printf("%s", ep->value);
 		break;
 	case E_SUBSCR:
-		eval_expr(stmt_type, ep->left, sp, 0);
+		gen_expr(stmt_type, ep->left, sp, 0);
 		printf("[");
-		eval_expr(stmt_type, ep->right, sp, 0);
+		gen_expr(stmt_type, ep->right, sp, 0);
 		printf("]");
 		break;
 	case E_TEXT:
@@ -686,7 +696,7 @@ static int special_func(
 		for (ep1 = ep->left; ep1 != 0; ep1 = ep1->next)
 		{
 			printf(", ");
-			eval_expr(stmt_type, ep1, sp, 0);
+			gen_expr(stmt_type, ep1, sp, 0);
 		}
 		printf(")");
 		return TRUE;
@@ -823,7 +833,7 @@ static void gen_pv_func(
 	{	/* e.g. pvPut(xyz[i+2]); => seq_pvPut(ssId, 3 + (i+2)); */
 		printf(" + (");
 		/* evalute the subscript expression */
-		eval_expr(stmt_type, ep3, sp, 0);
+		gen_expr(stmt_type, ep3, sp, 0);
 		printf(")");
 	}
 
@@ -851,7 +861,7 @@ static void gen_pv_func(
 #endif
 
 		printf(", ");
-		eval_expr(stmt_type, ep1, sp, 0);
+		gen_expr(stmt_type, ep1, sp, 0);
 
 #if 0
 		/* Count parameters (makes use of knowledge that parameter
@@ -895,7 +905,7 @@ static void gen_entry_handler(Expr *expr_list)
 	printf("static void entry_handler(SS_ID ssId, struct UserVar *pVar)\n{\n");
 	for (ep = expr_list; ep != 0; ep = ep->next)
 	{
-		eval_expr(ENTRY_STMT, ep, NULL, 1);
+		gen_expr(ENTRY_STMT, ep, NULL, 1);
 	}
 	printf("}\n\n");
 }
@@ -909,7 +919,7 @@ static void gen_exit_handler(Expr *expr_list)
 	printf("static void exit_handler(SS_ID ssId, struct UserVar *pVar)\n{\n");
 	for (ep = expr_list; ep != 0; ep = ep->next)
 	{
-		eval_expr(EXIT_STMT, ep, NULL, 1);
+		gen_expr(EXIT_STMT, ep, NULL, 1);
 	}
 	printf("}\n\n");
 }
diff --git a/src/snc/gen_ss_code.h b/src/snc/gen_ss_code.h
index 7c97db29..9b012b2a 100644
--- a/src/snc/gen_ss_code.h
+++ b/src/snc/gen_ss_code.h
@@ -1,7 +1,7 @@
 #ifndef INCLgensscodeh
 #define INCLgensscodeh
 
-struct program;
+#include "types.h"
 
 void gen_ss_code(struct program *program);
 
diff --git a/src/snc/gen_tables.c b/src/snc/gen_tables.c
index 9cdaa009..169594dc 100644
--- a/src/snc/gen_tables.c
+++ b/src/snc/gen_tables.c
@@ -3,10 +3,7 @@
 	Copyright, 1990, The Regents of the University of California.
 		 Los Alamos National Laboratory
 
-	gen_tables.c,v 1.2 1995/06/27 15:25:45 wright Exp
-
 	DESCRIPTION: Generate tables for run-time sequencer.
-	See also:  phase2.c & gen_ss_code.c
 	ENVIRONMENT: UNIX
 	HISTORY:
 28apr92,ajk	Implemented new event flag mode.
@@ -35,8 +32,8 @@
 #include	<assert.h>
 
 #include	"seqCom.h"
-#include	"parse.h"
-#include	"phase2.h"
+#include	"analysis.h"
+#include	"gen_code.h"
 #include	"snc_main.h"
 
 typedef struct eval_event_mask_args {
@@ -45,13 +42,13 @@ typedef struct eval_event_mask_args {
 } eval_event_mask_args;
 
 static void encode_state_options(Expr *sp);
-static void gen_db_blocks(ChanList *chan_list, int num_events);
-static void fill_db_block(Chan *cp, int elem_num, int num_events);
+static void gen_db_blocks(ChanList *chan_list, int num_events, int opt_reent);
+static void fill_db_block(Chan *cp, int elem_num, int num_events, int opt_reent);
 static void gen_state_blocks(Expr *ss_list, int num_events, int num_channels);
 static void fill_state_block(Expr *sp, char *ss_name);
 static void gen_prog_params(char *prog_param);
-static void gen_prog_table(char *prog_name);
-static void encode_options(void);
+static void gen_prog_table(char *prog_name, Options *options);
+static void encode_options(Options *options);
 static void gen_ss_array(Expr *ss_list);
 static void eval_state_event_mask(Expr *sp, int num_events,
 	bitMask *event_words, int num_event_words);
@@ -60,46 +57,26 @@ static void eval_event_mask_subscr(Expr *ep, eval_event_mask_args *args);
 static int find_error_state(Expr *ssp);
 static char *db_type_str(int type);
 
-/*+************************************************************************
-*  NAME: gen_tables
-*
-*  CALLING SEQUENCE
-*	type		argument	I/O	description
-*	---------------------------------------------------
-*
-*  RETURNS: n/a
-*
-*  FUNCTION: Generate C code from tables.
-*-*************************************************************************/
-
-void gen_tables(Program *program)
+/* Generate all kinds of tables for a SNL program. */
+void gen_tables(Program *p)
 {
 	printf("\f/************************ Tables ***********************/\n");
 
-	/* Generate DB blocks */
-	gen_db_blocks(program->chan_list, program->num_events);
-
-	/* Generate State Blocks */
-	gen_state_blocks(program->ss_list, program->num_events, program->num_channels);
+	gen_db_blocks(p->chan_list, p->num_events, p->options->reent);
 
-	/* Generate State Set Blocks */
-	gen_ss_array(program->ss_list);
+	gen_state_blocks(p->ss_list, p->num_events, p->num_channels);
 
-	/* generate program parameter string */
-	gen_prog_params(program->prog_param);
+	gen_ss_array(p->ss_list);
 
-	/* Generate state program table */
-	gen_prog_table(program->prog_name);
+	gen_prog_params(p->param);
 
-	return;
+	gen_prog_table(p->name, p->options);
 }
+
 /* Generate database blocks with structure and data for each defined channel */
-static void gen_db_blocks(ChanList *chan_list, int num_events)
+static void gen_db_blocks(ChanList *chan_list, int num_events, int opt_reent)
 {
-	Chan		*cp;
-	int		nchan, elem_num;
-
-	nchan = 0;
+	Chan *cp;
 
 	if (chan_list->first)
 	{
@@ -107,23 +84,16 @@ static void gen_db_blocks(ChanList *chan_list, int num_events)
 		printf("static struct seqChan seqChan[NUM_CHANNELS] = {\n");
 		for (cp = chan_list->first; cp != NULL; cp = cp->next)
 		{
+			int n;
 #ifdef	DEBUG
 			fprintf(stderr, "gen_db_blocks: index=%d, num_elem=%d\n",
 				cp->index, cp->num_elem);
 #endif	/*DEBUG*/
+			int num_elem = cp->num_elem ? cp->num_elem : 1;
 
-			if (cp->num_elem == 0)
-			{	/* Variable assigned to single pv */
-				fill_db_block(cp, 0, num_events);
-				nchan++;
-			}
-			else
-			{	/* Variable assigned to multiple pv's */
-				for (elem_num = 0; elem_num<cp->num_elem; elem_num++)
-				{
-					fill_db_block(cp, elem_num, num_events);
-					nchan++;
-				}
+			for (n = 0; n < num_elem; n++)
+			{
+				fill_db_block(cp, n, num_events, opt_reent);
 			}
 		}
 		printf("};\n");
@@ -133,11 +103,10 @@ static void gen_db_blocks(ChanList *chan_list, int num_events)
 		printf("\n/* No Database Blocks, create 1 for ptr init. */\n");
 		printf("static struct seqChan seqChan[1];\n");
 	}
-	return;
 }
 
 /* Fill in a db block with data (all elements for "seqChan" struct) */
-static void fill_db_block(Chan *cp, int elem_num, int num_events)
+static void fill_db_block(Chan *cp, int elem_num, int num_events, int opt_reent)
 {
 	Var		*vp;
 	char		*suffix, elem_str[20], *db_name;
@@ -182,7 +151,7 @@ static void fill_db_block(Chan *cp, int elem_num, int num_events)
 
 	/* Ptr or offset to user variable */
 	printf("(void *)");
-	if (globals->options->reent)
+	if (opt_reent)
 		printf("OFFSET(struct UserVar, %s%s%s), ", vp->name, elem_str, suffix);
 	else
 		printf("&%s%s%s, ", vp->name, elem_str, suffix); /* variable ptr */
@@ -191,7 +160,7 @@ static void fill_db_block(Chan *cp, int elem_num, int num_events)
 	printf("\"%s%s\", ", vp->name, elem_str);
 
  	/* variable type */
-	printf("\n    \"%s\", ", db_type_str(vp->type) );
+	printf("\n    \"%s\", ", db_type_str(vp->type));
 
 	/* count for db requests */
 	printf("%d, ", cp->count);
@@ -212,8 +181,6 @@ static void fill_db_block(Chan *cp, int elem_num, int num_events)
 		printf("%d, %d, %d", vp->queued, vp->maxQueueSize, vp->queueIndex);
 
 	printf("},\n\n");
-
-	return;
 }
 
 /* Convert variable type to db type as a string */
@@ -276,7 +243,6 @@ static void gen_state_blocks(Expr *ss_list, int num_events, int num_channels)
 	}
 
 	free(event_mask);
-	return;
 }
 
 /* Fill in data for a state block (see seqState in seqCom.h) */
@@ -327,7 +293,6 @@ static void fill_state_block(Expr *sp, char *ss_name)
 	printf("\t/* state options */   ");
 	encode_state_options(sp);
 	printf("},\n\n");
-	return;
 }
 
 /* Writes the state option bitmask into a state block. At present this f is
@@ -347,8 +312,15 @@ static void encode_state_options(Expr *sp)
 	   check the option character is recognized and if so code it's bit mask */
 	for (ep = sp->right; ep != NULL; ep = ep->next )
 	{
-		char *plusminus = ep->left->value;
-		int opt_minus = plusminus[0] == '-';
+		char *plusminus;
+		int opt_minus;
+
+		if (ep->type != E_OPTION) {
+			continue;
+		}
+
+		plusminus = ep->left->value;
+		opt_minus = plusminus[0] == '-';
 
 		assert(ep->left->type == E_X);
 		for (pc = ep->value; *pc != '\0'; pc++)
@@ -389,29 +361,28 @@ static void encode_state_options(Expr *sp)
 			}
 			else
 			{
-				report_location(ep->src_file, ep->line_num);
-				report("unrecognized option in state %s: %s%c",
+				report_loc(ep->src_file, ep->line_num);
+				report("unrecognized option in state %s: %s%c\n",
 					sp->value, plusminus, *pc);
 			}
 
 			if ( duplicate )
 			{
-				report_location(ep->src_file, ep->line_num);
-				report("option already specified in state %s: %c",
+				report_loc(ep->src_file, ep->line_num);
+				report("option already specified in state %s: %c\n",
 					sp->value, *pc);
 			}
 			if ( contradictory )
 			{
-				report_location(ep->src_file, ep->line_num);
+				report_loc(ep->src_file, ep->line_num);
 				report("contradictory option or option out of "
-					"order %s%c in state %s",
+					"order %s%c in state %s\n",
 					plusminus, *pc, sp->value);
 			}
 
 		}
 	}
 	printf(")");
-	return;
 } 
 
 
@@ -424,7 +395,7 @@ static void gen_prog_params(char *prog_param)
 }
 
 /* Generate the structure with data for a state program table (SPROG) */
-static void gen_prog_table(char *prog_name)
+static void gen_prog_table(char *prog_name, Options *options)
 {
 	printf("\n/* State Program table (global) */\n");
 
@@ -442,7 +413,7 @@ static void gen_prog_table(char *prog_name)
 
 	printf("\t/* numSS */              NUM_SS,\n");	/* number of state sets */
 
-	if (globals->options->reent)
+	if (options->reent)
 		printf("\t/* user variable size */ sizeof(struct UserVar),\n");
 	else
 		printf("\t/* user variable size */ 0,\n");
@@ -452,35 +423,31 @@ static void gen_prog_table(char *prog_name)
 	printf("\t/* numEvents */          NUM_EVENTS,\n");	/* number event flags */
 
 	printf("\t/* encoded options */    ");
-	encode_options();
+	encode_options(options);
 
 	printf("\t/* entry handler */      (ENTRY_FUNC) entry_handler,\n");
 	printf("\t/* exit handler */       (EXIT_FUNC) exit_handler,\n");
 	printf("\t/* numQueues */          NUM_QUEUES,\n");	/* number of syncQ queues */
 
 	printf("};\n");
-
-	return;
 }
 
-static void encode_options(void)
+static void encode_options(Options *options)
 {
 	printf("(0");
-	if (globals->options->async)
+	if (options->async)
 		printf(" | OPT_ASYNC");
-	if (globals->options->conn)
+	if (options->conn)
 		printf(" | OPT_CONN");
-	if (globals->options->debug)
+	if (options->debug)
 		printf(" | OPT_DEBUG");
-	if (globals->options->newef)
+	if (options->newef)
 		printf(" | OPT_NEWEF");
-	if (globals->options->reent)
+	if (options->reent)
 		printf(" | OPT_REENT");
-	if (globals->options->main)
+	if (options->main)
 		printf(" | OPT_MAIN");
 	printf("),\n");
-
-	return;
 }
 
 /* Generate an array of state set blocks, one entry for each state set */
@@ -511,7 +478,6 @@ static void gen_ss_array(Expr *ss_list)
 
 	}
 	printf("};\n");
-	return;
 }
 
 /* Find the state named "error" in a state set */
@@ -553,10 +519,10 @@ static void eval_state_event_mask(Expr *sp, int num_events,
 			continue;
 
 		/* look for simple variables, e.g. "when(x > 0)" */
-		traverse_expr_tree(tp->left, E_VAR, 0, eval_event_mask, &args);
+		traverse_expr_tree(tp->left, E_VAR, 0, (expr_fun*)eval_event_mask, &args);
 
 		/* look for subscripted variables, e.g. "when(x[i] > 0)" */
-		traverse_expr_tree(tp->left, E_SUBSCR, 0, eval_event_mask_subscr, &args);
+		traverse_expr_tree(tp->left, E_SUBSCR, 0, (expr_fun*)eval_event_mask_subscr, &args);
 	}
 #ifdef	DEBUG
 	fprintf(stderr, "Event mask for state %s is", sp->value);
@@ -632,8 +598,6 @@ static void eval_event_mask(Expr *ep, eval_event_mask_args *args)
 			bitSet(event_words, cp->index + n + num_events + 1);
 		}
 	}
-
-	return;
 }
 
 /* Evaluate the event mask for a given transition (when() statement)
@@ -698,6 +662,4 @@ static void eval_event_mask_subscr(Expr *ep, eval_event_mask_args *args)
 	{
 		bitSet(event_words, cp->index + n + num_events + 1);
 	}
-
-	return;
 }
diff --git a/src/snc/gen_tables.h b/src/snc/gen_tables.h
index 26f912f8..585d2946 100644
--- a/src/snc/gen_tables.h
+++ b/src/snc/gen_tables.h
@@ -1,8 +1,8 @@
 #ifndef INCLgentablesh
 #define INCLgentablesh
 
-struct program;
+#include "types.h"
 
-void gen_tables(struct program *program);
+void gen_tables(Program *program);
 
 #endif	/*INCLgentablesh*/
diff --git a/src/snc/lexer.h b/src/snc/lexer.h
new file mode 100644
index 00000000..a7f437be
--- /dev/null
+++ b/src/snc/lexer.h
@@ -0,0 +1,22 @@
+#ifndef INCLlexerh
+#define INCLlexerh
+
+#include "types.h"
+
+Program *parse_program(const char *src_file);
+
+void parser(
+	void *yyp,		/* the parser */
+	int yymajor,		/* the major token code number */
+	Token yyminor,		/* the value for the token */
+	Program **presult	/* extra argument */
+);
+
+void *parserAlloc(void *(*mallocProc)(size_t));
+
+void parserFree(
+	void *p,		/* the parser to be deleted */
+	void (*freeProc)(void*)	/* function used to reclaim memory */
+);
+
+#endif	/*INCLlexerh*/
diff --git a/src/snc/parse.c b/src/snc/parse.c
index f7363dee..b243695b 100644
--- a/src/snc/parse.c
+++ b/src/snc/parse.c
@@ -1,13 +1,9 @@
-/*#define	DEBUG	1*/
 /**************************************************************************
 			GTA PROJECT   AT division
 	Copyright, 1990, The Regents of the University of California.
 		         Los Alamos National Laboratory
 
-< 	parse.c,v 1.3 1995/10/19 16:30:16 wright Exp
 	DESCRIPTION: Parsing support routines for state notation compiler.
-	 The 'yacc' parser calls these routines to build the tables
-	 and linked lists, which are then passed on to the phase 2 routines.
 
 	ENVIRONMENT: UNIX
 	HISTORY:
@@ -35,9 +31,10 @@
 #include	<assert.h>
 
 #define expr_type_GLOBAL
-#include	"parse.h"
+#include	"types.h"
 #undef expr_type_GLOBAL
-#include	"phase2.h"
+#include	"parse.h"
+#include	"gen_code.h"
 #include	"snc_main.h"
 
 #ifndef	TRUE
@@ -45,226 +42,34 @@
 #define	FALSE	0
 #endif	/*TRUE*/
 
-static Chan *build_channel(ChanList *chan_list, Var *vp);
-static void alloc_channel_lists(Chan *cp, int length);
-static void add_chan(ChanList *chan_list, Chan *cp);
-Scope *analyze_declarations(Expr *defn_list);
-ChanList *analyze_assignments(Scope *scope, Expr *defn_list);
-void analyze_monitors(Scope *scope, Expr *defn_list);
-void analyze_syncs_and_syncqs(Scope *scope, Expr *defn_list);
-
-static void assign_subscr(
-	ChanList	*chan_list,
-	Expr		*dp,
-	Var		*vp,
-	char		*subscript,	/* subscript value or NULL */
-	char		*db_name
-);
-static void assign_single(
-	ChanList	*chan_list,
-	Expr		*dp,
-	Var		*vp,
-	char		*db_name
-);
-void assign_list(
-	ChanList	*chan_list,
-	Expr		*dp,
-	Var		*vp,
-	Expr		*db_name_list
-);
-void monitor_stmt(
-	Var		*vp,
-	Expr		*dp,
-	char		*subscript	/* element number or NULL */
-);
-void sync_stmt(
-	Scope		*scope,
-	Expr		*dp,
-	char		*subscript,
-	char		*ef_name
-);
-void syncq_stmt(
-	Scope		*scope,
-	Expr		*dp,
-	char		*subscript,
-	char		*ef_name,
-	char		*maxQueueSize
-);
-
-/* Parsing whole program */
+/* Parsing a program */
 Program *program(
-	char *pname,
-	char *pparam,
-	Expr *defn_list,
-	Expr *entry_list,
-	Expr *prog_list,
-	Expr *exit_list,
-	Expr *c_list
+	char	*name,		/* program name */
+	char	*param,		/* program parameters */
+	Expr	*defn_list,	/* list of top-level definitions */
+	Expr	*entry_code,	/* global entry actions */
+	Expr	*ss_list,	/* state sets */
+	Expr	*exit_code,	/* global exit actions */
+	Expr	*c_code		/* global c code */
 )
 {
-	Program *program = allocProgram();
-
-	program->prog_name = pname;
-	program->prog_param = pparam;
-	program->global_defn_list = defn_list;
-	program->entry_code_list = entry_list;
-	program->ss_list = prog_list;
-	program->exit_code_list = exit_list;
-	program->global_c_list = c_list;
-
-#ifdef	DEBUG
-	fprintf(stderr, "---- Analysis ----\n");
-#endif	/*DEBUG*/
-	program->global_scope = analyze_declarations(defn_list);
-	program->chan_list = analyze_assignments(program->global_scope, defn_list);
-	analyze_monitors(program->global_scope, defn_list);
-	analyze_syncs_and_syncqs(program->global_scope, defn_list);
-
-#ifdef	DEBUG
-	fprintf(stderr, "---- Phase2 ----\n");
-#endif	/*DEBUG*/
-	phase2(program);
-
-	exit(0);
-}
-
-Scope *analyze_declarations(Expr *defn_list)
-{
-	Expr *dp;
-	Var *vp, *vp2;
-	Scope *scope;
-
-#ifdef	DEBUG
-	fprintf(stderr, "-- Declarations --\n");
-#endif	/*DEBUG*/
-	scope = allocScope();
-	scope->var_list = allocVarList();
-	for (dp = defn_list; dp != NULL; dp = dp->next)
-	{
-		if (dp->type != E_DECL)
-			continue;
-		vp = (Var *)dp->value;
-		assert(vp != NULL);
-		vp->line_num = dp->line_num;
-		vp2 = find_var(scope, vp->name);
-		if (vp2 != NULL)
-		{
-			fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-			fprintf(stderr, "assign: variable %s already declared in line %d\n",
-			 vp->name, vp2->line_num);
-			continue;
-		}
-		add_var(scope, vp);
-	}
-	return scope;
-}
-
-ChanList *analyze_assignments(Scope *scope, Expr *defn_list)
-{
-	Expr		*dp;
-	ChanList	*chan_list;
-
-#ifdef	DEBUG
-	fprintf(stderr, "-- Assignments --\n");
-#endif	/*DEBUG*/
-	chan_list = allocChanList();
-	for (dp = defn_list; dp != NULL; dp = dp->next)
-	{
-		char *name;
-		Expr *pv_names;
-		Var *vp;
-
-		if (dp->type != E_ASSIGN)
-			continue;
-		name = dp->value;
-		pv_names = dp->right;
-
-		vp = find_var(scope, name);
-		if (vp == NULL)
-		{
-			fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-			fprintf(stderr, "assign: variable %s not declared\n", name);
-			continue;
-		}
-		if (dp->left != NULL)
-		{
-			assign_subscr(chan_list, dp, vp, dp->left->value,
-				pv_names->value);
-		}
-		else if (dp->right->next == NULL) {
-			assign_single(chan_list, dp, vp, pv_names->value);
-		}
-		else
-		{
-			assign_list(chan_list, dp, vp, pv_names);
-		}
-	}
-	return chan_list;
-}
-
-void analyze_monitors(Scope *scope, Expr *defn_list)
-{
-	Expr *dp = defn_list;
-
-#ifdef	DEBUG
-	fprintf(stderr, "-- Monitors --\n");
-#endif	/*DEBUG*/
-	for (dp = defn_list; dp; dp = dp->next)
-	{
-		if (dp->type == E_MONITOR)
-		{
-			char *name = dp->value;
-			char *subscript = dp->left ? dp->left->value : 0;
-			Var *vp = find_var(scope, name);
+	Program *p = allocProgram();
 
-			if (vp == NULL)
-			{
-				fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-				fprintf(stderr, "assign: variable %s not declared\n", name);
-				continue;
-			}
-			monitor_stmt(vp, dp, subscript);
-		}
-	}
+	p->name = name;
+	p->param = param;
+	p->global_defn_list = defn_list;
+	p->entry_code_list = entry_code;
+	p->ss_list = ss_list;
+	p->exit_code_list = exit_code;
+	p->global_c_list = c_code;
+	return p;
 }
 
-void analyze_syncs_and_syncqs(Scope *scope, Expr *defn_list)
-{
-	Expr *dp = defn_list;
-
-#ifdef	DEBUG
-	fprintf(stderr, "-- Sync and SyncQ --\n");
-#endif	/*DEBUG*/
-	for (dp = defn_list; dp; dp = dp->next)
-	{
-		char *subscript = dp->left ? dp->left->value : 0;
-		char *ef_name;
-
-		if (dp->type == E_SYNC)
-		{
-			assert(dp->right);
-			assert(dp->right->type == E_X);
-			ef_name = dp->right->value;
-			sync_stmt(scope, dp, subscript, ef_name);
-		}
-		if (dp->type == E_SYNCQ)
-		{
-			char *maxQueueSize;
-			assert(dp->right);
-			assert(dp->right->type == E_X);
-			ef_name = dp->right->value;
-			maxQueueSize = dp->right->left ? dp->right->left->value : 0;
-			assert(maxQueueSize==NULL || dp->right->left->type==E_CONST);
-			syncq_stmt(scope, dp, subscript, ef_name, maxQueueSize);
-		}
-	}
-}
-
-/* Parsing a declaration */
+/* Parsing a variable declaration */
 Expr *decl(
 	int	type,		/* variable type (e.g. V_FLOAT) */
 	int	class,		/* variable class (e.g. VC_ARRAY) */
-	char	*name,		/* ptr to variable name */
+	Token	var,		/* variable name token */
 	char	*s_length1,	/* array lth (1st dim, arrays only) */
 	char	*s_length2,	/* array lth (2nd dim, [n]x[m] arrays only) */
 	char	*value		/* initial value or NULL */
@@ -287,539 +92,20 @@ Expr *decl(
 			length2 = 1;
 	}
 	vp = allocVar();
-	vp->name = name;
+	vp->name = var.str;
 	vp->class = class;
 	vp->type = type;
 	vp->length1 = length1;
 	vp->length2 = length2;
 	vp->value = value;
 	vp->chan = NULL;
-	return expr(E_DECL, (char *)vp, 0, 0);
-}
-
-/* Option statement */
-void option_stmt(
-	char	*option,	/* "a", "r", ... */
-	int	value		/* TRUE means +, FALSE means - */
-)
-{
-	Options *options = globals->options;
-	switch(*option)
-	{
-	    case 'a':
-		options->async = value;
-		break;
-	    case 'c':
-		options->conn = value;
-		break;
-	    case 'd':
-		options->debug = value;
-		break;
-	    case 'e':
-		options->newef = value;
-		break;
-	    case 'i':
-		options->init_reg = value;
-		break;
-	    case 'l':
-		options->line = value;
-		break;
-	    case 'm':
-		options->main = value;
-		break;
-	    case 'r':
-		options->reent = value;
-		break;
-	    case 'w':
-		options->warn = value;
-		break;
-	}
-	return;
-}
-
-/* "Assign" statement: Assign a variable to a DB channel.
- * Format: assign <variable> to <string;
- * Note: Variable may be subscripted.
- */
-static void assign_single(
-	ChanList	*chan_list,
-	Expr		*dp,
-	Var		*vp,
-	char		*db_name
-)
-{
-	Chan		*cp;
-	char		*name = vp->name;
-
-#ifdef	DEBUG
-	fprintf(stderr, "assign %s to \"%s\";\n", name, db_name);
-#endif	/*DEBUG*/
-
-	cp = vp->chan;
-	if (cp != NULL)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: %s already assigned\n", name);
-		return;
-	}
-
-	/* Build structure for this channel */
-	cp = build_channel(chan_list, vp);
-
-	cp->db_name = db_name;	/* DB name */
-
-	/* The entire variable is assigned */
-	cp->count = vp->length1 * vp->length2;
-
-	return;
-}
-
-/* "Assign" statement: assign an array element to a DB channel.
- * Format: assign <variable>[<subscr>] to <string>; */
-static void assign_subscr(
-	ChanList	*chan_list,
-	Expr		*dp,
-	Var		*vp,
-	char		*subscript,	/* subscript value or NULL */
-	char		*db_name
-)
-{
-	Chan		*cp;
-	char		*name = vp->name;
-	int		subNum;
-
-#ifdef	DEBUG
-	fprintf(stderr, "assign %s[%s] to \"%s\";\n", name, subscript, db_name);
-#endif	/*DEBUG*/
-
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: variable %s not an array\n", name);
-		return;
-	}
-
-	cp = vp->chan;
-	if (cp == NULL)
-	{
-		/* Build structure for this channel */
-		cp = build_channel(chan_list, vp);
-	}
-	else if (cp->db_name != NULL)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: array %s already assigned\n", name);
-		return;
-	}
-
-	subNum = atoi(subscript);
-	if (subNum < 0 || subNum >= vp->length1)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: subscript %s[%d] is out of range\n",
-		 name, subNum);
-		return;
-	}
-
-	if (cp->db_name_list == NULL)
-		alloc_channel_lists(cp, vp->length1); /* allocate lists */
-	else if (cp->db_name_list[subNum] != NULL)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: %s[%d] already assigned\n",
-		 name, subNum);
-		return;
-	}
-
-	cp->db_name_list[subNum] = db_name;
-	cp->count = vp->length2; /* could be a 2-dimensioned array */
-
-	return;
-}
-
-/* Assign statement: assign an array to multiple DB channels.
- * Format: assign <variable> to { <string>, <string>, ... };
- * Assignments for double dimensioned arrays:
- * <var>[0][0] assigned to 1st db name,
- * <var>[1][0] assigned to 2nd db name, etc.
- * If db name list contains fewer names than the array dimension,
- * the remaining elements receive NULL assignments.
- */
-void assign_list(
-	ChanList	*chan_list,
-	Expr		*dp,
-	Var		*vp,
-	Expr		*db_name_list
-)
-{
-	Chan		*cp;
-	int		elem_num;
-	char		*name = vp->name;
-
-#ifdef	DEBUG
-	fprintf(stderr, "assign %s to {", name);
-#endif	/*DEBUG*/
-
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: variable %s is not an array\n", name);
-		return;
-	}
-
-	cp = vp->chan;
-	if (cp != NULL)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "assign: variable %s already assigned\n", name);
-		return;
-	}
-
-	/* Build a db structure for this variable */
-	cp = build_channel(chan_list, vp);
-
-	/* Allocate lists */
-	alloc_channel_lists(cp, vp->length1); /* allocate lists */
-
-	/* fill in the array of pv names */
-	for (elem_num = 0; elem_num < vp->length1; elem_num++)
-	{
-		if (db_name_list == NULL)
-			break; /* end of list */
-
-#ifdef	DEBUG
-		fprintf(stderr, "\"%s\", ", db_name_list->value);
-#endif	/*DEBUG*/
-		cp->db_name_list[elem_num] = db_name_list->value; /* DB name */
-		cp->count = vp->length2;
- 
-		db_name_list = db_name_list->next;
-	}
-#ifdef	DEBUG
-		fprintf(stderr, "};\n");
-#endif	/*DEBUG*/
-
-	return;
-}
-
-/* Build a channel structure for this variable */
-static Chan *build_channel(ChanList *chan_list, Var *vp)
-{
-	Chan		*cp;
-
-	cp = allocChan();
-	add_chan(chan_list, cp);		/* add to Chan list */
-
-	/* make connections between Var & Chan structures */
-	cp->var = vp;
-	vp->chan = cp;
-
-	/* Initialize the structure */
-	cp->db_name_list = 0;
-	cp->mon_flag_list = 0;
-	cp->ef_var_list = 0;
-	cp->ef_num_list = 0;
-	cp->num_elem = 0;
-	cp->mon_flag = 0;
-	cp->ef_var = 0;
-	cp->ef_num = 0;
-
-	return cp;
-}
-
-/* Allocate lists for assigning multiple pv's to a variable */
-static void alloc_channel_lists(Chan *cp, int length)
-{
-	/* allocate an array of pv names */
-	cp->db_name_list = (char **)calloc(sizeof(char **), length);
-
-	/* allocate an array for monitor flags */
-	cp->mon_flag_list = (int *)calloc(sizeof(int **), length);
-
-	/* allocate an array for event flag var ptrs */
-	cp->ef_var_list = (Var **)calloc(sizeof(Var **), length);
-
-	/* allocate an array for event flag numbers */
-	cp->ef_num_list = (int *)calloc(sizeof(int **), length);
-
-	cp->num_elem = length;
-}
-
-void monitor_stmt(
-	Var		*vp,
-	Expr		*dp,
-	char		*subscript	/* element number or NULL */
-)
-{
-	Chan		*cp;
-	int		subNum;
-	char		*name = vp->name;
-
-#ifdef	DEBUG
-	fprintf(stderr, "monitor %s", name);
-	if (subscript != NULL) fprintf(stderr, "[%s]", subscript);
-	fprintf(stderr, "\n");
-#endif	/*DEBUG*/
-
-	/* Find a channel assigned to this variable */
-	cp = vp->chan;
-	if (cp == 0)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "monitor: variable %s not assigned\n", name);
-		return;
-	}
-
-	if (subscript == NULL)
-	{
-		if (cp->num_elem == 0)
-		{	/* monitor one channel for this variable */
-			cp->mon_flag = TRUE;
-			return;
-		}
-
-		/* else monitor all channels in db list */
-		for (subNum = 0; subNum < cp->num_elem; subNum++)
-		{	/* 1 pv per element of the array */
-			cp->mon_flag_list[subNum] = TRUE;
-		}
-		return;
-	}
-
-	/* subscript != NULL */
-	subNum = atoi(subscript);
-	if (subNum < 0 || subNum >= cp->num_elem)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "monitor: subscript of %s out of range\n", name);
-		return;
-	}
-
-	if (cp->num_elem == 0 || cp->db_name_list[subNum] == NULL)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "monitor: %s[%d] not assigned\n",
-		 name, subNum);
-		return;
-	}
-
-	cp->mon_flag_list[subNum] = TRUE;
-	return;
-}
-
-void sync_stmt(
-	Scope		*scope,
-	Expr		*dp,
-	char		*subscript,
-	char		*ef_name
-)
-{
-	Chan		*cp;
-	Var		*vp;
-	int		subNum;
-	char		*name = dp->value;
-
-#ifdef	DEBUG
-	fprintf(stderr, "sync %s%s%s%s to %s\n", name,
-	 subscript?"[":"", subscript?subscript:"", subscript?"]":"", ef_name);
-#endif	/*DEBUG*/
-
-	vp = find_var(scope, name);
-	if (vp == 0)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "sync: variable %s not declared\n", name);
-		return;
-	}
-
-	cp = vp->chan;
-	if (cp == 0)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "sync: variable %s not assigned\n", name);
-		return;
-	}
-
-	/* Find the event flag varible */
-	vp = find_var(scope, ef_name);
-	if (vp == 0 || vp->type != V_EVFLAG)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "sync: e-f variable %s not declared\n",
-		 ef_name);
-		return;
-	}
-
-	if (subscript == NULL)
-	{	/* no subscript */
-		if (cp->db_name != NULL)
-		{	/* 1 pv assigned to this variable */
-			cp->ef_var = vp;
-			return;
-		}
-
-		/* 1 pv per element in the array */
-		for (subNum = 0; subNum < cp->num_elem; subNum++)
-		{
-			cp->ef_var_list[subNum] = vp;
-		}
-		return;
-	}
-
-	/* subscript != NULL */
-	subNum = atoi(subscript);
-	if (subNum < 0 || subNum >= cp->num_elem)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "sync: subscript %s[%d] out of range\n",
-		 name, subNum);
-		return;
-	}
-	cp->ef_var_list[subNum] = vp; /* sync to a specific element of the array */
-
-	return;
-}
-
-void syncq_stmt(
-	Scope		*scope,
-	Expr		*dp,
-	char		*subscript,
-	char		*ef_name,
-	char		*maxQueueSize
-)
-{
-	Chan		*cp;
-	Var		*vp;
-	Var		*efp;
-	int		subNum;
-	char		*name = dp->value;
-
-#ifdef	DEBUG
-	fprintf(stderr, "syncq_stmt: name=%s, subNum=%s, ef_name=%s, "
-	    "maxQueueSize=%s\n", name, subscript, ef_name, maxQueueSize);
-#endif	/*DEBUG*/
-
-	/* Find the variable and check it's assigned */
-	vp = find_var(scope, name);
-	if (vp == 0)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "syncQ: variable %s not declared\n", name);
-		return;
-	}
-
-	cp = vp->chan;
-	if (cp == 0)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "syncQ: variable %s not assigned\n", name);
-		return;
-	}
-
-	/* Check that the variable has not already been syncQ'd */
-	if (vp->queued)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "syncQ: variable %s already syncQ'd\n", name);
-		return;
-	}
-
-	/* Find the event flag variable */
-	efp = find_var(scope, ef_name);
-	if (efp == 0 || efp->type != V_EVFLAG)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "syncQ: e-f variable %s not declared\n", ef_name);
-		return;
-	}
-
-	/* Check that the event flag has not already been syncQ'd */
-	if (efp->queued)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "syncQ: e-f variable %s already syncQ'd\n", ef_name);
-		return;
-	}
-
-	/* Note queued (for both variable and event flag) and set the
-	   maximum queue size (0 means default) */
-	vp->queued = efp->queued = TRUE;
-	vp->maxQueueSize = (maxQueueSize == NULL) ? 0 : atoi(maxQueueSize);
-
-	if (subscript == NULL)
-	{	/* no subscript */
-		if (cp->db_name != NULL)
-		{	/* 1 pv assigned to this variable */
-			cp->ef_var = efp;
-			return;
-		}
-
-		/* 1 pv per element in the array */
-		for (subNum = 0; subNum < cp->num_elem; subNum++)
-		{
-			cp->ef_var_list[subNum] = efp;
-		}
-		return;
-	}
-
-	/* subscript != NULL */
-	subNum = atoi(subscript);
-	if (subNum < 0 || subNum >= cp->num_elem)
-	{
-		fprintf(stderr, "%s:%d: ", dp->src_file, dp->line_num);
-		fprintf(stderr, "syncQ: subscript %s[%d] out of range\n",
-		 name, subNum);
-		return;
-	}
-	cp->ef_var_list[subNum] = efp; /* sync to a specific element of the array */
-}
-
-/* Add a variable to a scope; (append to the end of the list */
-void add_var(Scope *scope, Var *vp)
-{
-	VarList	*var_list = scope->var_list;
-
-	if (var_list->first == NULL)
-		var_list->first = vp;
-	else
-		var_list->last->next = vp;
-	var_list->last = vp;
-	vp->next = NULL;
-}
-
-/* Find a variable by name, given a scope; first searches the given
-   scope, then the parent scope, and so on. Returns a pointer to the
-   var struct or NULL if the variable is not found. */
-Var *find_var(Scope *scope, char *name)
-{
-	Var	*vp;
-
-	for ( ; scope != NULL; scope = scope->next)
-	{
-		for (vp = scope->var_list->first; vp != NULL; vp = vp->next)
-		{
-			if (strcmp(vp->name, name) == 0)
-				return vp;
-		}
-	}
-	return NULL;
-}
-
-/* Add a channel to the channel linked list */
-static void add_chan(ChanList *chan_list, Chan *cp)
-{
-	if (chan_list->first == NULL)
-		chan_list->first = cp;
-	else
-		chan_list->last->next = cp;
-	chan_list->last = cp;
-	cp->next = NULL;
+	return expr(E_DECL, tok((char*)vp), 0, 0);
 }
 
 /* Expr is the generic syntax tree node. It is formed by a type  */
 Expr *expr(
 	int	type,		/* E_BINOP, E_ASGNOP, etc */
-	char	*value,		/* "==", "+=", var name, constant, etc. */	
+	Token	value,		/* "==", "+=", var name, constant, etc. */	
 	Expr	*left,		/* LH side */
 	Expr	*right		/* RH side */
 )
@@ -831,7 +117,7 @@ Expr *expr(
 #ifdef	DEBUG
 	if (type == E_DECL)
 	{
-		Var	*vp = (Var*)value;
+		Var	*vp = (Var*)value.str;
 
 		fprintf(stderr,
 		 "expr: ep=%p, type=%s, value="
@@ -844,17 +130,17 @@ Expr *expr(
         else
 		fprintf(stderr,
 		 "expr: ep=%p, type=%s, value=\"%s\", left=%p, right=%p\n",
-		 ep, expr_type_names[type], value, left, right);
+		 ep, expr_type_names[type], value.str, left, right);
 #endif	/*DEBUG*/
 	/* Fill in the structure */
 	ep->next = 0;
 	ep->last = ep;
 	ep->type = type;
-	ep->value = value;
+	ep->value = value.str;
 	ep->left = left;
 	ep->right = right;
-	ep->line_num = globals->prev_line_num;
-	ep->src_file = globals->src_file;
+	ep->line_num = value.line;
+	ep->src_file = value.file;
 
 	return ep;
 }
diff --git a/src/snc/parse.h b/src/snc/parse.h
index 86f4de93..1ab550a0 100644
--- a/src/snc/parse.h
+++ b/src/snc/parse.h
@@ -3,7 +3,6 @@
 	Copyright, 1989-93, The Regents of the University of California.
 		         Los Alamos National Laboratory
 
- 	parse.h,v 1.2 1995/06/27 15:25:50 wright Exp
 	DESCRIPTION: Structures for parsing the state notation language.
 	ENVIRONMENT: UNIX
 	HISTORY:
@@ -21,231 +20,31 @@
 #ifndef INCLparseh
 #define INCLparseh
 
-/* Data for these blocks are generated by the parsing routines for each
-** state set.  The tables are then used to generate the run-time C code
-** for the sequencer.  This decouples the parsing implementation from
-** the run-time code implementation.
-*/
-
-struct	scope
-{
-	struct	var_list *var_list;
-	struct	scope *next;
-};
-typedef struct	scope Scope;
-
-struct	expression			/* Expression block */
-{
-	struct	expression *next;	/* link to next expression */
-	struct	expression *last;	/* link to last in list */
-	struct	expression *left;	/* ptr to left expression */
-	struct	expression *right;	/* ptr to right expression */
-	int	type;			/* expression type (E_*) */
-	char	*value;			/* operator or value string */
-	int	line_num;		/* line number */
-	char	*src_file;		/* effective source file */
-};
-typedef	struct	expression Expr;
-
-struct	variable			/* Variable or function definition */
-{
-	struct	variable *next;		/* link to next item in list */
-	char	*name;			/* variable name */
-	char	*value;			/* initial value or NULL */
-	int	type;			/* var type */
-	int	class;			/* simple, array, or pointer */
-	int	length1;		/* 1st dim. array lth (default=1) */
-	int	length2;		/* 2nd dim. array lth (default=1) */
-	int	ef_num;			/* bit number if this is an event flag */
-	struct	db_chan *chan;		/* ptr to channel struct if assigned */
-	int	queued;			/* whether queued via syncQ */
-	int	maxQueueSize;		/* max syncQ queue size */
-	int	queueIndex;		/* index in syncQ queue array */
-	int	line_num;		/* line number */
-};
-typedef	struct	variable Var;
-
-struct	db_chan				/* DB channel assignment info */
-{
-	struct	db_chan *next;		/* link to next item in list */
-	char	*db_name;		/* database name (assign all to 1 pv) */
-	char	**db_name_list;		/* list of db names (assign each to a pv) */
-	int	num_elem;		/* number of elements assigned in db_name_list */
-	Var	*var;			/* ptr to variable definition */
-	int	count;			/* count for db access */
-	int	mon_flag;		/* TRUE if channel is "monitored" */
-	int	*mon_flag_list;		/* ptr to list of monitor flags */
-	Var	*ef_var;		/* ptr to event flag variable for sync */
-	Var	**ef_var_list;		/* ptr to list of event flag variables */
-	int	ef_num;			/* event flag number */
-	int	*ef_num_list;		/* list of event flag numbers */
-	int	index;			/* index in database channel array (seqChan) */
-};
-typedef	struct	db_chan Chan;
-/* Note: Only one of db_name or db_name_list can have a non-zero value */
-
-struct chan_list
-{
-	Chan	*first, *last;
-};
-typedef struct	chan_list ChanList;
-
-struct var_list
-{
-	Var	*first, *last;
-};
-typedef struct	var_list VarList;
-
-struct program				/* result of parsing */
-{
-	char	*prog_name;		/* ptr to program name (string) */
-	char	*prog_param;		/* parameter string for program stmt */
-	Expr	*global_defn_list;	/* global definition list */
-	Expr	*ss_list;		/* state set list */
-	Expr	*entry_code_list;	/* entry code list */
-	Expr	*exit_code_list;	/* exit code list */
-	Scope	*global_scope;		/* global scope */
-	ChanList *chan_list;		/* channel list */
-	Expr	*global_c_list;		/* global C code following state program */
-	int	num_channels;		/* number of db channels */
-	int	num_events;		/* number of event flags */
-	int	num_queues;		/* number of syncQ queues */
-	int	num_ss;			/* number of state sets */
-};
-typedef struct program Program;
-
-/* Allocation 'functions' */
-#define	allocExpr()		(Expr *)calloc(1, sizeof(Expr))
-#define	allocVar()		(Var *)calloc(1, sizeof(Var))
-#define	allocChan()		(Chan *)calloc(1, sizeof(Chan))
-#define	allocVarList()		(VarList *)calloc(1, sizeof(VarList))
-#define	allocChanList()		(ChanList *)calloc(1, sizeof(ChanList))
-#define	allocScope()		(Scope *)calloc(1, sizeof(Scope))
-#define	allocProgram()		(Program *)calloc(1, sizeof(Program))
-
-/* Variable types */
-#define	V_NONE		0		/* not defined */
-#define	V_CHAR		1		/* char */
-#define	V_SHORT		2		/* short */
-#define	V_INT		3		/* int */
-#define	V_LONG		4		/* long */
-#define	V_FLOAT		5		/* float */
-#define	V_DOUBLE	6		/* double */
-#define	V_STRING	7		/* strings (array of char) */
-#define	V_EVFLAG	8		/* event flag */
-#define	V_FUNC		9		/* function (not a variable) */
-#define	V_UCHAR		11		/* unsigned char */
-#define	V_USHORT	12		/* unsigned short */
-#define	V_UINT		13		/* unsigned int */
-#define	V_ULONG		14		/* unsigned long */
-
-/* Variable classes */
-#define	VC_SIMPLE	0		/* simple (un-dimensioned) variable */
-#define	VC_ARRAY1	1		/* single dim. array */
-#define	VC_ARRAY2	2		/* multiple dim. array */
-#define	VC_POINTER	3		/* pointer */
-#define	VC_ARRAYP	4		/* array of pointers */
-
-/* Expression types */
-enum expr_type {
-	E_CONST,		/* numeric constant */
-	E_STRING,		/* ptr to string constant */
-	E_VAR,			/* variable */
-	E_PAREN,		/* parenthesis around an expression */
-	E_FUNC,			/* function */
-	E_SUBSCR,		/* subscript: expr[expr] */
-	E_POST,			/* unary postfix operator: expr OP */
-	E_PRE,			/* unary prefix operator: OP expr */
-	E_BINOP,		/* binary operator: expr OP expr */
-	E_TERNOP,		/* ternary operator: expr OP expr OP expr */
-	E_TEXT,			/* C code or other text to be inserted */
-	E_STMT,			/* simple statement */
-	E_CMPND,		/* begin compound statement: {...} */
-	E_IF,			/* if statement */
-	E_ELSE,			/* else statement */
-	E_WHILE,		/* while statement */
-	E_SS,			/* state set statement */
-	E_STATE,		/* state statement */
-	E_WHEN,			/* when statement */
-	E_FOR,			/* for statement */
-	E_X,			/* eXpansion (e.g. for(;;) */
-	E_BREAK,		/* break stmt */
-	E_DECL,			/* declaration statement */
-	E_ENTRY,		/* entry statement */
-	E_EXIT,			/* exit statement */
-	E_OPTION,		/* state option statement */
-	E_ASSIGN,		/* assign statement */
-	E_MONITOR,		/* monitor statement */
-	E_SYNC,			/* sync statement */
-	E_SYNCQ			/* syncq statement */
-};
-typedef enum expr_type ExprType;
-
-#ifdef expr_type_GLOBAL
-const char *expr_type_names[] =
-{
-	"E_CONST",
-	"E_STRING",
-	"E_VAR",	
-	"E_PAREN",
-	"E_FUNC",	
-	"E_SUBSCR",
-	"E_POST",	
-	"E_PRE",	
-	"E_BINOP",
-	"E_TERNOP",
-	"E_TEXT",	
-	"E_STMT",	
-	"E_CMPND",
-	"E_IF",	
-	"E_ELSE",	
-	"E_WHILE",
-	"E_SS",	
-	"E_STATE",
-	"E_WHEN",	
-	"E_FOR",	
-	"E_X",	
-	"E_BREAK",
-	"E_DECL",	
-	"E_ENTRY",
-	"E_EXIT",	
-	"E_OPTION",
-	"E_ASSIGN",
-	"E_MONITOR",
-	"E_SYNC",
-	"E_SYNCQ"
-};
-#else
-extern const char *expr_type_names[];
-#endif
+#include "types.h"
 
 Program *program(
-	char *pname,
-	char *pparam,
-	Expr *defn_list,
-	Expr *entry_list,
-	Expr *prog_list,
-	Expr *exit_list,
-	Expr *c_list
+	char	*name,		/* program name */
+	char	*param,		/* program parameters */
+	Expr	*defn_list,	/* list of top-level definitions */
+	Expr	*entry_code,	/* global entry actions */
+	Expr	*ss_list,	/* state sets */
+	Expr	*exit_code,	/* global exit actions */
+	Expr	*c_code		/* global c code */
 );
 Expr *expr(
 	int	type,		/* E_BINOP, E_ASGNOP, etc */
-	char	*value,		/* "==", "+=", var name, constant, etc. */
+	Token	tok,		/* "==", "+=", var name, constant, etc. */
 	Expr	*left,		/* LH side */
 	Expr	*right		/* RH side */
 );
 Expr *decl(
 	int	type,		/* variable type (e.g. V_FLOAT) */
 	int	class,		/* variable class (e.g. VC_ARRAY) */
-	char	*name,		/* ptr to variable name */
+	Token	var,		/* variable name token */
 	char	*s_length1,	/* array lth (1st dim, arrays only) */
 	char	*s_length2,	/* array lth (2nd dim, [n]x[m] arrays only) */
 	char	*value		/* initial value or NULL */
 );
-void option_stmt(
-	char	*option,	/* "a", "r", ... */
-	int	value		/* TRUE means +, FALSE means - */
-);
 void add_var(
 	Scope *scope,		/* scope to add variable to */
 	Var *vp			/* variable to add */
diff --git a/src/snc/phase2.h b/src/snc/phase2.h
deleted file mode 100644
index bfdb3d94..00000000
--- a/src/snc/phase2.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef INCLphase2h
-#define INCLphase2h
-
-void phase2(Program *program);
-
-int expr_count(Expr*);
-
-typedef void expr_fun(Expr *, void *);
-
-void traverse_expr_tree(
-	Expr	    *ep,	/* ptr to start of expression */
-	int	    type,	/* to search for */
-	char	    *value,	/* with optional matching value */
-	expr_fun    *funcp,	/* function to call */
-	void	    *argp	/* ptr to argument to pass on to function */
-);
-
-#endif	/*INCLphase2h*/
diff --git a/src/snc/snc.y b/src/snc/snc.y
deleted file mode 100644
index 007facaf..00000000
--- a/src/snc/snc.y
+++ /dev/null
@@ -1,538 +0,0 @@
-%{
-/**************************************************************************
-			GTA PROJECT   AT division
-	Copyright, 1990, The Regents of the University of California.
-		         Los Alamos National Laboratory
-	snc.y,v 1.2 1995/06/27 15:26:07 wright Exp
-	ENVIRONMENT: UNIX
-	HISTORY:
-20nov91,ajk	Added new "option" statement.
-08nov93,ajk	Implemented additional declarations (see VC_CLASS in parse.h).
-08nov93,ajk	Implemented assignment of array elements to pv's.
-02may93,ajk	Removed "parameter" definition for functions, and added "%prec"
-		qualifications to some "expr" definitions.
-31may94,ajk	Changed method for handling global C code.
-20jul95,ajk	Added "unsigned" types (see UNSIGNED token).
-11jul96,ajk	Added character constants (CHAR_CONST).
-08aug96,wfl	Added new "syncQ" statement.
-23jun97,wfl	Permitted pre-processor "#" lines between states. 
-13jan98,wfl     Added "down a level" handling of compound expressions
-09jun98,wfl     Permitted pre-processor "#" lines between state-sets
-07sep99,wfl	Supported ternary operator;
-		Supported local declarations (not yet finished).
-22sep99,grw     Supported entry and exit actions; supported state options.
-18feb00,wfl     More partial support for local declarations (still not done).
-31mar00,wfl	Supported entry handler; made 'to' consistently optional.
-***************************************************************************/
-/*	SNC - State Notation Compiler.
- *	The general structure of a state program is:
- *		program-name
- *		declarations
- *		ss  { state { event { action ...} new-state } ... } ...
- *
- *	The following yacc definitions call the various parsing routines, which
- *	are coded in the file "parse.c".  Their major action is to build
- *	a structure for each SNL component (state, event, action, etc.) and
- *	build linked lists from these structures.  The linked lists have a
- *	hierarchical structure corresponding to the SNL block structure.
- *	For instance, a "state" structure is linked to a chain of "event",
- *	structures, which are, in turn, linked to a chain of "action"
- *	structures.
- *	The lexical analyser (see snc_lex.l) reads the input
- *	stream and passes tokens to the yacc-generated code.  The snc_lex
- *	and parsing routines may also pass data elements that take on one
- *	of the types defined under the %union definition.
- *
- */
-#include	<stdio.h>
-#include	<ctype.h>
-#include	"parse.h"
-#include	"snc_main.h"
-
-#ifndef	TRUE
-#define	TRUE	1
-#define	FALSE	0
-#endif
-
-static void pp_code(char *line, char *fname);
-%}
-
-%start	state_program
-
-%union
-{
-	int	ival;
-	char	*str;
-	Expr	*pexpr;
-}
-%token	<str>	STATE STATE_SET
-%token	<str>	INTNUM FPNUM NAME
-%token	<str>	DEBUG_PRINT
-%token	PROGRAM ENTRY EXIT L_OPTION
-%token	R_SQ_BRACKET L_SQ_BRACKET
-%token	BAD_CHAR L_BRACKET R_BRACKET
-%token	QUESTION COLON SEMI_COLON EQUAL
-%token	L_PAREN R_PAREN PERIOD POINTER COMMA OR AND
-%token	MONITOR ASSIGN TO WHEN
-%token	UNSIGNED CHAR SHORT INT LONG FLOAT DOUBLE STRING_DECL
-%token	EVFLAG SYNC SYNCQ
-%token	ASTERISK AMPERSAND
-%token	AUTO_INCR AUTO_DECR
-%token	PLUS MINUS SLASH GT GE EQ LE LT NE NOT BIT_OR BIT_XOR
-%token	L_SHIFT R_SHIFT COMPLEMENT MODULO OPTION
-%token	PLUS_EQUAL MINUS_EQUAL MULT_EQUAL DIV_EQUAL AND_EQUAL OR_EQUAL
-%token	MODULO_EQUAL LEFT_EQUAL RIGHT_EQUAL XOR_EQUAL
-%token	<str>	STRING
-%token	<str>	C_STMT
-%token	IF ELSE WHILE FOR BREAK
-%token	PP_SYMBOL CR
-%type	<ival>	type
-%type	<str>	program_name program_param
-%type	<str>	subscript number
-%type	<str>	binop asgnop unop
-%type	<pexpr> global_entry_code global_exit_code
-%type	<pexpr> global_c definitions defn_stmt
-%type	<pexpr> assign_stmt monitor_stmt decl_stmt sync_stmt syncq_stmt
-%type	<pexpr> optional_subscript syncq_size
-%type	<pexpr> state_set_list state_set state_list state
-%type	<pexpr> transition_list transition state_option_value
-%type	<pexpr> expr compound_expr assign_list bracked_expr
-%type	<pexpr> statement stmt_list compound_stmt if_stmt else_stmt while_stmt
-%type	<pexpr> for_stmt escaped_c_list
-%type	<pexpr> state_option_list state_option
-%type	<pexpr> condition_list
-%type	<pexpr> entry_list exit_list entry exit
-/* precedence rules for expr evaluation */
-
-%right	EQUAL COMMA
-%left	QUESTION COLON	/* ### check this is correct */
-%left	OR AND
-%left	GT GE EQ NE LE LT
-%left	PLUS MINUS
-%left	ASTERISK SLASH
-%left	NOT UOP	/* unary operators: e.g. -x */
-%left	SUBSCRIPT
-
-%%	/* Begin rules */
-
-state_program 	/* define a state program */
-:	pp_codes	/* $1 */
-	program_name		/* $2 */
-	program_param		/* $3 */
-	definitions		/* $4 */
-	global_entry_code	/* $5 */
-	state_set_list		/* $6 */
-	global_exit_code	/* $7 */
-	pp_codes	/* $8 */
-	global_c		/* $9 */
-{
-	program($2,$3,$4,$5,$6,$7,$9);
-}
-;
-
-program_name 	/* program name */
-:	PROGRAM NAME			{ $$ = $2; }
-;
-
-program_param
-:					{ $$ = ""; }
-|	L_PAREN STRING R_PAREN		{ $$ = $2; }
-
-definitions 	/* definitions block */
-:	defn_stmt			{ $$ = $1; }
-|	definitions defn_stmt		{ $$ = link_expr($1, $2); }
-;
-
-defn_stmt	/* individual definitions for SNL (preceeds state sets) */
-:	assign_stmt			{ $$ = $1; }
-|	monitor_stmt			{ $$ = $1; }
-|	decl_stmt			{ $$ = $1; }
-|	sync_stmt			{ $$ = $1; }
-|	syncq_stmt			{ $$ = $1; }
-|	option_stmt			{ $$ = 0; }
-|	escaped_c_list			{ $$ = $1; }
-|	pp_code				{ $$ = 0; }
-|	error { snc_err("definitions/declarations"); }
-;
-
-assign_stmt	/* assign <var name> to <db name>; */
-:	ASSIGN NAME to STRING SEMI_COLON
-{
-	$$ = expression(E_ASSIGN, $2, 0, expression(E_STRING, $4, 0, 0));
-	/* assign_single($2, $4); */
-}
-|	ASSIGN NAME to subscript STRING SEMI_COLON
-{		/* assign <var name>[<n>] [to] <db name>; */
-	$$ = expression(E_ASSIGN, $2,
-			expression(E_CONST, $4, 0, 0),
-			expression(E_STRING, $5, 0, 0));
-	/* assign_single($2, $4); */
-}
-		/* assign <var name> [to] {<db name>, ... }; */
-|	ASSIGN NAME to L_BRACKET assign_list R_BRACKET SEMI_COLON
-{
-	$$ = expression(E_ASSIGN, $2, 0, $5);
-	/* assign_list($2, $5); */
-}
-;
-
-assign_list	/* {"<db name>", .... } */ 
-:	STRING				{ $$ = expression(E_STRING, $1, 0, 0); }
-|	assign_list COMMA STRING
-			{ $$ = link_expr($1, expression(E_STRING, $3, 0, 0)); }
-;
-
-to		/* "to" */
-:	/* optional */
-|	TO;
-;
-
-monitor_stmt	/* variable to be monitored; delta is optional */
-:	MONITOR NAME optional_subscript SEMI_COLON
-{
-	$$ = expression(E_MONITOR, $2, $3, 0);
-	/* monitor_stmt($2, $3); */
-}
-;
-
-sync_stmt	/* sync <variable> <event flag> */
-:	SYNC NAME optional_subscript to NAME SEMI_COLON
-{
-	$$ = expression(E_SYNC, $2, $3, expression(E_X, $5, 0, 0));
-	/* sync_stmt($2, $3, $5); */
-}
-;
-
-syncq_stmt	/* syncQ <variable> [[subscript]] to <event flag> [<max queue size>] */
-:	SYNCQ NAME optional_subscript to NAME syncq_size SEMI_COLON
-{
-	$$ = expression(E_SYNCQ, $2, $3, expression(E_X, $5, $6, 0));
-	/* syncq_stmt($2, $3, $5, $6); */
-}
-;
-
-syncq_size
-:				{ $$ = 0; }
-|	INTNUM			{ $$ = expression(E_CONST, $1, 0, 0); }
-;
-
-optional_subscript
-:					{ $$ = 0; }
-|	subscript			{ $$ = expression(E_CONST, $1, 0, 0); }
-;
-
-subscript	/* e.g. [10] */
-:	L_SQ_BRACKET INTNUM R_SQ_BRACKET	{ $$ = $2; }
-;
-
-decl_stmt	/* variable declarations (e.g. float x[20];)
-		 * declaration(type, class, name, <1-st dim>, <2-nd dim>, value) */
-:	type NAME SEMI_COLON
-		{ $$ = declaration($1, VC_SIMPLE,  $2,  NULL, NULL, NULL); }
-
-|	type NAME EQUAL number SEMI_COLON
-		{ $$ = declaration($1, VC_SIMPLE,  $2,  NULL, NULL, $4  ); }
-
-|	type NAME subscript SEMI_COLON
-		{ $$ = declaration($1, VC_ARRAY1,  $2,  $3,   NULL, NULL); }
-
-|	type NAME subscript subscript SEMI_COLON
-		{ $$ = declaration($1, VC_ARRAY2,  $2,  $3,   $4,   NULL); }
-
-|	type ASTERISK NAME SEMI_COLON
-		{ $$ = declaration($1, VC_POINTER, $3,  NULL, NULL, NULL); }
-
-|	type ASTERISK NAME subscript SEMI_COLON
-		{ $$ = declaration($1, VC_ARRAYP,  $3,  $4,   NULL, NULL); }
-;
-
-/* local_decl_stmt */	/* local variable declarations (not yet arrays... but easy
-		   to add); not added to SNC's tables; treated as though
-		   in escaped C code */
-		/* ### this is not working yet; don't use it */
-/* :	type NAME SEMI_COLON
-		{ $$ = expression(E_TEXT, $2, 0, 0); }
-|	type NAME EQUAL number SEMI_COLON
-		{ $$ = expression(E_TEXT, $2, expression(E_CONST, $4, 0, 0), 0); }
-; */
-
-number
-:	INTNUM		{ $$ = $1; }
-|	FPNUM		{ $$ = $1; }
-;
-
-type		/* types for variables defined in SNL */
-:	CHAR		{ $$ = V_CHAR; }
-|	SHORT		{ $$ = V_SHORT; }
-|	INT		{ $$ = V_INT; }
-|	LONG		{ $$ = V_LONG; }
-|	UNSIGNED CHAR	{ $$ = V_UCHAR; }
-|	UNSIGNED SHORT	{ $$ = V_USHORT; }
-|	UNSIGNED INT	{ $$ = V_UINT; }
-|	UNSIGNED LONG	{ $$ = V_ULONG; }
-|	FLOAT		{ $$ = V_FLOAT; }
-|	DOUBLE		{ $$ = V_DOUBLE; }
-|	STRING_DECL	{ $$ = V_STRING; }
-|	EVFLAG		{ $$ = V_EVFLAG; }
-|	error { snc_err("type specifier"); }
-;
-
-option_stmt	/* option +/-<option>;  e.g. option +a; */
-:	OPTION PLUS NAME SEMI_COLON	{ option_stmt($3, TRUE); }
-|	OPTION MINUS NAME SEMI_COLON	{ option_stmt($3, FALSE); }
-;
-
-global_entry_code
-:						{ $$ = 0; }
-|	ENTRY L_BRACKET stmt_list R_BRACKET	{ $$ = $3; }
-;
-
-global_exit_code
-:						{ $$ = 0; }
-|	EXIT L_BRACKET stmt_list R_BRACKET	{ $$ = $3; }
-;
-
-state_set_list 	/* a program body is one or more state sets */
-:	state_set			{ $$ = $1; }
-|	state_set_list state_set	{ $$ = link_expr($1, $2); }
-;
-
-state_set 	/* define a state set */
-:	STATE_SET NAME L_BRACKET state_list R_BRACKET
-					{ $$ = expression(E_SS, $2, $4, 0); }
-|	pp_code				{ $$ = 0; }
-|	error				{ snc_err("state set"); }
-;
-
-state_list /* define a state set body (one or more states) */
-:	state				{ $$ = $1; }
-|	state_list state		{ $$ = link_expr($1, $2); }
-|	error				{ snc_err("state list"); }
-;
-
-state	/* a block that defines a single state */
-: 	STATE NAME L_BRACKET state_option_list condition_list R_BRACKET
-			{ $$ = expression(E_STATE, $2, $5, $4); }
-|	pp_code				{ $$ = 0; }
-|	error				{ snc_err("state block"); }
-;
-
-state_option_list /* A list of options for a single state */
-:	/* Optional */			{ $$ = NULL; }
-|	state_option			{ $$ = $1; }
-|	state_option_list state_option	{ $$ = link_expr($1, $2); }
-|	error				{ snc_err("state option list"); }
-;
-
-state_option /* An option for a state */
-:	OPTION state_option_value NAME SEMI_COLON
-		{ $$ = expression(E_OPTION,$3,$2,0); }
-		/* $$ = expression(E_OPTION,"stateoption",$3,"+"); */
-		/* $$ = expression(E_OPTION,"stateoption",$3,"-"); */
-|	error	{ snc_err("state option specifier"); }
-;
-
-state_option_value
-:	PLUS	{ $$ = expression(E_X, "+", 0, 0); }
-|	MINUS	{ $$ = expression(E_X, "-", 0, 0); }
-
-condition_list /* Conditions and resulting actions */
-:	entry_list transition_list exit_list
-				{ $$ = link_expr( link_expr($1,$2), $3 ); }
-|	error			{ snc_err("state condition list"); }
-;
-
-entry_list
-:	/* optional */		{ $$ = NULL; }
-|	entry			{ $$ = $1; }
-|	entry_list entry	{ $$ = link_expr( $1, $2 ); }
-;
-
-exit_list
-:	/* optional */		{ $$ = NULL; }
-|	exit			{ $$ = $1; }
-|	exit_list exit		{ $$ = link_expr( $1, $2 ); }
-;
-
-entry	/* On entry to a state, do this */
-:	ENTRY L_BRACKET stmt_list R_BRACKET
-				{ $$ = expression( E_ENTRY, "entry", 0, $3 ); } 
-|	error			{ snc_err("entry block"); }
-;
-
-exit	/* On exit from a state, do this */
-:	EXIT L_BRACKET stmt_list R_BRACKET
-				{ $$ = expression( E_EXIT, "exit", 0, $3 ); } 
-|	error			{ snc_err("exit block"); }
-;
-
-transition_list	/* all transitions for one state */
-:	transition			{ $$ = $1; }
-|	transition_list transition	{ $$ = link_expr($1, $2); }
-|	error				{ snc_err("when transition list"); }
-;
-
-transition /* define a transition condition and action */
-:	WHEN L_PAREN expr R_PAREN L_BRACKET stmt_list R_BRACKET STATE NAME
-					{ $$ = expression(E_WHEN, $9, $3, $6); }
-/* |	local_decl_stmt			{ $$ = $1; } */
-|	pp_code				{ $$ = 0; }
-|	error				{ snc_err("when transition block"); }
-;
-
-expr	/* general expr: e.g. (-b+2*a/(c+d)) != 0 || (func1(x,y) < 5.0) */
-	/* Expr *expression(int type, char *value, Expr *left, Expr *right) */
-:	compound_expr			{ $$ = expression(E_COMMA, "", $1, 0); }
-|	expr binop expr %prec UOP	{ $$ = expression(E_BINOP, $2, $1, $3); }
-|	expr asgnop expr		{ $$ = expression(E_ASGNOP, $2, $1, $3); }
-|	unop expr  %prec UOP		{ $$ = expression(E_UNOP, $1, $2, 0); }
-|	AUTO_INCR expr  %prec UOP	{ $$ = expression(E_PRE, "++", $2, 0); }
-|	AUTO_DECR expr  %prec UOP	{ $$ = expression(E_PRE, "--", $2, 0); }
-|	expr AUTO_INCR  %prec UOP	{ $$ = expression(E_POST, "++", $1, 0); }
-|	expr AUTO_DECR  %prec UOP	{ $$ = expression(E_POST, "--", $1, 0); }
-|	STRING				{ $$ = expression(E_STRING, $1, 0, 0); }
-|	number				{ $$ = expression(E_CONST, $1, 0, 0); }
-|	NAME				{ $$ = expression(E_VAR, $1, 0, 0); }
-|	NAME L_PAREN expr R_PAREN	{ $$ = expression(E_FUNC, $1, $3, 0); }
-|	EXIT L_PAREN expr R_PAREN	{ $$ = expression(E_FUNC, "exit", $3, 0); }
-|	L_PAREN expr R_PAREN		{ $$ = expression(E_PAREN, "", $2, 0); }
-|	expr bracked_expr %prec SUBSCRIPT { $$ = expression(E_SUBSCR, "", $1, $2); }
-|	/* empty */			{ $$ = 0; }
-;
-
-compound_expr
-:	expr COMMA expr			{ $$ = link_expr($1, $3); }
-|	compound_expr COMMA expr	{ $$ = link_expr($1, $3); }
-;
-
-bracked_expr	/* e.g. [k-1] */
-:	L_SQ_BRACKET expr R_SQ_BRACKET	{ $$ = $2; }
-;
-
-unop	/* Unary operators */
-:	PLUS		{ $$ = "+"; }
-|	MINUS		{ $$ = "-"; }
-|	ASTERISK	{ $$ = "*"; }
-|	AMPERSAND	{ $$ = "&"; }
-|	NOT		{ $$ = "!"; }
-|	COMPLEMENT	{ $$ = "~"; }
-;
-
-binop	/* Binary operators */
-:	MINUS		{ $$ = "-"; }
-|	PLUS		{ $$ = "+"; }
-|	ASTERISK	{ $$ = "*"; }
-|	SLASH 		{ $$ = "/"; }
-|	GT		{ $$ = ">"; }
-|	GE		{ $$ = ">="; }
-|	EQ		{ $$ = "=="; }
-|	NE		{ $$ = "!="; }
-|	LE		{ $$ = "<="; }
-|	LT		{ $$ = "<"; }
-|	OR		{ $$ = "||"; }
-|	AND		{ $$ = "&&"; }
-|	L_SHIFT		{ $$ = "<<"; }
-|	R_SHIFT		{ $$ = ">>"; }
-|	BIT_OR		{ $$ = "|"; }
-|	BIT_XOR		{ $$ = "^"; }
-|	AMPERSAND	{ $$ = "&"; }
-|	MODULO		{ $$ = "%"; }
-|	QUESTION	{ $$ = "?"; }	/* fudges ternary operator */
-|	COLON		{ $$ = ":"; }	/* fudges ternary operator */
-|	PERIOD		{ $$ = "."; }	/* fudges structure elements */
-|	POINTER		{ $$ = "->"; }	/* fudges ptr to structure elements */
-;
-
-asgnop	/* Assignment operators */
-:	EQUAL		{ $$ = "="; }
-|	PLUS_EQUAL	{ $$ = "+="; }
-|	MINUS_EQUAL	{ $$ = "-="; }
-|	AND_EQUAL	{ $$ = "&="; }
-|	OR_EQUAL	{ $$ = "|="; }
-|	DIV_EQUAL	{ $$ = "/="; }
-|	MULT_EQUAL	{ $$ = "*="; }
-|	MODULO_EQUAL	{ $$ = "%="; }
-|	LEFT_EQUAL	{ $$ = "<<="; }
-|	RIGHT_EQUAL	{ $$ = ">>="; }
-|	XOR_EQUAL	{ $$ = "^="; }
-;
-
-compound_stmt		/* compound statement e.g. { ...; ...; ...; } */
-:	L_BRACKET stmt_list R_BRACKET { $$ = expression(E_CMPND, "",$2, 0); }
-|	error { snc_err("action statements"); }	
-;
-
-stmt_list
-:	statement		{ $$ = $1; }
-|	stmt_list statement	{ $$ = link_expr($1, $2); }
-|	/* empty */		{ $$ = 0; }
-;
-
-statement
-:	compound_stmt			{ $$ = $1; }
-|	expr SEMI_COLON			{ $$ = expression(E_STMT, "", $1, 0); }
-|	BREAK SEMI_COLON		{ $$ = expression(E_BREAK, "", 0, 0); }
-|	if_stmt				{ $$ = $1; }
-|	else_stmt			{ $$ = $1; }
-|	while_stmt			{ $$ = $1; }
-|	for_stmt			{ $$ = $1; }
-|	C_STMT				{ $$ = expression(E_TEXT, $1, 0, 0); }
-|	pp_code				{ $$ = 0; }
-/* |	error 				{ snc_err("action statement"); } */
-;
-
-if_stmt
-:	IF L_PAREN expr R_PAREN statement { $$ = expression(E_IF, "", $3, $5); }
-;
-
-else_stmt
-:	ELSE statement			{ $$ = expression(E_ELSE, "", $2, 0); }
-;
-
-while_stmt
-:	WHILE L_PAREN expr R_PAREN statement { $$ = expression(E_WHILE, "", $3, $5); }
-;
-
-for_stmt
-:	FOR L_PAREN expr SEMI_COLON expr SEMI_COLON expr R_PAREN statement
-	{ $$ = expression(E_FOR, "", expression(E_X, "", $3, $5),
-				expression(E_X, "", $7, $9) ); }
-;
-
-pp_codes	/* zero or more pp_code */
-:	pp_codes pp_code
-|	/* optional */
-;
-
-pp_code		/* pre-processor code (e.g. # 1 "test.st") */
-:	PP_SYMBOL INTNUM STRING CR	{ pp_code($2, $3); }
-|	PP_SYMBOL INTNUM CR		{ pp_code($2, 0); }
-|	PP_SYMBOL STRING CR		{ /* Silently consume #pragma lines */ }
-;
-
-global_c
-:	/* optional */		{ $$ = 0; }
-|	escaped_c_list		{ $$ = $1; }
-
-escaped_c_list
-:	C_STMT			{ $$ = expression(E_TEXT, $1, 0, 0); }
-|	escaped_c_list C_STMT	{ $$ = link_expr($1, expression(E_TEXT, $2, 0, 0)); }
-;
-%%
-#include	"snc_lex.c"
-
-static int yyparse (void);
-
-/* yyparse() is static, so we create global access to it */
-void compile (void)
-{
-	yyparse ();
-}
-
-/* Interpret pre-processor code */
-static void pp_code(char *line, char *fname)
-{
-	globals->line_num = atoi(line);
-	if (fname != 0)
-		globals->src_file = fname;
-}
diff --git a/src/snc/snc_lex.l b/src/snc/snc_lex.l
deleted file mode 100644
index 5dcb6be2..00000000
--- a/src/snc/snc_lex.l
+++ /dev/null
@@ -1,278 +0,0 @@
-%{
-/**************************************************************************
-			GTA PROJECT   AT division
-	Copyright, 1990, The Regents of the University of California.
-		         Los Alamos National Laboratory
-
-	snc_lex.l,v 1.2 1995/06/27 15:26:09 wright Exp
-	ENVIRONMENT: UNIX
-	HISTORY:
-20nov91,ajk	Added OPTION token.
-15jan92,ajk	Fixed to allow "!" as a unary operator.
-17Jul92,rcz	changed warn_flag to warn_opt
-17Jul92,rcz	Ported ajk version from lanl
-04apr93,ajk	Increased STR_BFR_SIZE from 30000 to 300000
-19nov93,ajk	Added definitions for octal and hex numbers.
-19nov93,ajk	Removed optional "-" from definition of FPNUM.  This was
-		causing problems with statements like "k-1".
-27man94,ajk	Implemented dynamic allocation of strings, thus eliminating
-		huge string buffer.
-31may94,ajk	Changed handling of escaped C code.
-17feb95,ajk	Removed includes "parse.h" & "snc.h", because this module
-		now gets included in snc.y.
-20jul95,ajk	Added unsigned types.
-11jul96,ajk	Added character constants
-08aug96,wfl	Added SYNCQ token.
-23jun97,wfl	Added ^L as white-space char; permitted '"x" "y"' syntax.
-01oct98,wfl     Replaced FPNUM with version from Sun lex manual ("E" support)
-7sep99,wfl	Added QUESTION token (for ternary operator).
-22sep99,grw     Supported ENTRY token (for entry action).
-06mar00,wfl	Supported ASYNC and STNC tokens (avoids need for #define).
-***************************************************************************/
-/* Lexical analyzer for State Notation Compiler (snc).
- *
- * This routine recognizes State Notation Language (SNL) syntax,
- * and passes tokens to yacc().
- * All C code is passed through as a stream, without conversion.
- * Hence, the C compiler may find errors not reported by SNC.
- * Comments are recognized as part of the syntax.
- */
-
-#include	<string.h>
-#include	<unistd.h>
-#include	<stdlib.h>
-#include	"snc_main.h"
-#ifdef USE_LEMON
-#include	"token.h"
-#include	"snl.h"
-#endif
-
-#ifndef	TRUE
-#define	TRUE	1
-#define	FALSE	0
-#endif
-
-#ifdef	DEBUG
-#define	RETURN(param) {\
-	fprintf(stderr, "return(" #param ")\n");\
-	globals->prev_line_num = tok_line_num;\
-	tok_line_num = globals->line_num;\
-	return(param);\
-	}
-#else
-#define	RETURN(param) {\
-	globals->prev_line_num = tok_line_num;\
-	tok_line_num = globals->line_num;\
-	return(param);\
-	}
-#endif
-
-#define	STR_BFR_SIZE	1000
-
-static char		strBfr[STR_BFR_SIZE];	/* holding place for strings */
-static char		*pStr;			/* current ptr to strBfr */
-
-%}
-
-/* Start conditions (SNL, C code, comment, string, pre-processor, pre-proc. string) */
-%Start	SNL C_CODE COMMENT STR PP PP_SP PP_STR PP_END
-
-OCT	[0-7]
-DEC	[0-9]
-LET	[a-zA-Z_]
-HEX	[a-fA-F0-9]
-EXP	[DEde][+-]?{DEC}+
-FS	[fFlL]
-IS	[uUlL]*
-ESC	\\([abfnrtv?'"\\]|"x"{HEX}+|{OCT}+)
-
-NAME	{LET}({LET}|{DEC})*
-HEXNUM	0[xX]{HEX}+{IS}?
-OCTNUM	0{OCT}+{IS}?
-DECNUM	{DEC}+{IS}?
-CHRCON	'({ESC}|[^\n\\'])*'
-
-INTNUM	{HEXNUM}|{OCTNUM}|{DECNUM}|{CHRCON}
-FPNUM	{DEC}+{EXP}{FS}?|{DEC}*\.{DEC}+{EXP}?{FS}?|{DEC}+\.{DEC}*{EXP}?{FS}?
-/*
-FPNUM	{DEC}+({EXP})?|{DEC}+\.{DEC}*({EXP})?|{DEC}*\.{DEC}+({EXP})?
-*/
-
-%% /* Begin rules */
-
-<C_CODE>\n {
-		globals->line_num++;
-}
-<C_CODE>"}%" {
-		BEGIN SNL;
-}
-<C_CODE>([^}\n]|[}][^%])* {
-		globals->c_line_num = globals->line_num;
-		yylval.str = strdup((char*)yytext);
-		RETURN(C_STMT);
-}
-
-<COMMENT>\n	globals->line_num++;
-<COMMENT>"*/"	BEGIN SNL;
-<COMMENT>.	;
-
-<STR>"\\\"" {
-		*pStr++ = yytext[0];
-		*pStr++ = yytext[1];
-}
-<STR>\"[\n\t\ ]*\" /* ignored */ ;
-<STR>\"	 {
-		*pStr++ = 0;
-		yylval.str = strdup(strBfr);
-		BEGIN SNL;
-		RETURN(STRING);
-}
-<STR>.		{ *pStr++ = yytext[0]; }
-<STR>\n	{
-		*pStr++ = '?';
-		if (globals->options->warn) {
-			parse_error("warning: newline in string");
-		}
-		globals->line_num++;
-}
-
-<PP>[\t\ ]+	;
-<PP>{DEC}+ {
-		globals->line_num = atoi((char*)yytext) - 1;
-		pStr = strBfr;
-		BEGIN PP_SP;
-}
-<PP>.		BEGIN PP_END;
-<PP_SP>[\t\ ]+	;
-<PP_SP>\" {
-		pStr = strBfr;
-		BEGIN PP_STR;
-}
-<PP_SP>.	BEGIN PP_END;
-<PP_STR>\" {	/* done scanning the string */
-		*pStr++ = 0;
-		if (strcmp(strBfr,globals->src_file) != 0) {
-			globals->src_file = strdup(strBfr);
-		}
-		BEGIN PP_END;
-}
-<PP_STR>.	{ *pStr++ = yytext[0]; }
-<PP_STR>\n	{ *pStr++ = '?'; globals->line_num++; }
-<PP_END>.*	;
-<PP_END>\n	{ globals->line_num++; BEGIN SNL; }
-
-<SNL>\n		{ globals->line_num++; }
-<SNL>"%{"	BEGIN C_CODE;
-<SNL>"%%".* {
-		globals->c_line_num = globals->line_num;
-		yylval.str = strdup((char*)yytext+2);
-		RETURN(C_STMT);
-}
-<SNL>^# {
-		BEGIN PP;
-}
-<SNL>"/*"	BEGIN COMMENT;
-<SNL>\"		{ pStr = strBfr; BEGIN STR; }
-<SNL>"ss"	RETURN(STATE_SET);
-<SNL>"state"	RETURN(STATE);
-<SNL>"when"	RETURN(WHEN);
-<SNL>"monitor"	RETURN(MONITOR);
-<SNL>"assign"	RETURN(ASSIGN);
-<SNL>"unsigned"	RETURN(UNSIGNED);
-<SNL>"char"	RETURN(CHAR);
-<SNL>"short"	RETURN(SHORT);
-<SNL>"int"	RETURN(INT);
-<SNL>"long"	RETURN(LONG);
-<SNL>"float"	RETURN(FLOAT);
-<SNL>"double"	RETURN(DOUBLE);
-<SNL>"string"	RETURN(STRING_DECL);
-<SNL>"to"	RETURN(TO);
-<SNL>"program"	RETURN(PROGRAM);
-<SNL>"option"	RETURN(OPTION);
-<SNL>"debug"	RETURN(DEBUG_PRINT);
-<SNL>"evflag"	RETURN(EVFLAG);
-<SNL>"sync"	RETURN(SYNC);
-<SNL>"syncQ"	RETURN(SYNCQ);
-<SNL>"if"	RETURN(IF);
-<SNL>"else"	RETURN(ELSE);
-<SNL>"while"	RETURN(WHILE);
-<SNL>"for"	RETURN(FOR);
-<SNL>"break"	RETURN(BREAK);
-<SNL>"exit"	RETURN(EXIT);
-<SNL>"entry"	RETURN(ENTRY);
-<SNL>"TRUE" {
-		yylval.str = "1";
-		RETURN(INTNUM);
-}
-<SNL>"FALSE" {
-		yylval.str = "0";
-		RETURN(INTNUM);
-}
-<SNL>"ASYNC" {
-		yylval.str = "1";
-		RETURN(INTNUM);
-}
-<SNL>"SYNC" {
-		yylval.str = "2";
-		RETURN(INTNUM);
-}
-<SNL>{NAME} {
-		yylval.str = strdup((char *)yytext);
-		RETURN(NAME);
-}
-<SNL>"++"	RETURN(AUTO_INCR);
-<SNL>"--"	RETURN(AUTO_DECR);
-<SNL>"||"	RETURN(OR);
-<SNL>"<<="	RETURN(LEFT_EQUAL);
-<SNL>">>="	RETURN(RIGHT_EQUAL);
-<SNL>"&&"	RETURN(AND);
-<SNL>">>"	RETURN(R_SHIFT);
-<SNL>">="	RETURN(GE);
-<SNL>"=="	RETURN(EQ);
-<SNL>"+="	RETURN(PLUS_EQUAL);
-<SNL>"-="	RETURN(MINUS_EQUAL);
-<SNL>"*="	RETURN(MULT_EQUAL);
-<SNL>"/="	RETURN(DIV_EQUAL);
-<SNL>"&="	RETURN(AND_EQUAL);
-<SNL>"|="	RETURN(OR_EQUAL);
-<SNL>"!="	RETURN(NE);
-<SNL>"<<"	RETURN(L_SHIFT);
-<SNL>"<="	RETURN(LE);
-<SNL>"%="	RETURN(MODULO_EQUAL);
-<SNL>"^="	RETURN(XOR_EQUAL);
-<SNL>"->"	RETURN(POINTER);
-<SNL>"+"	RETURN(PLUS);
-<SNL>"-"	RETURN(MINUS);
-<SNL>"!"	RETURN(NOT);
-<SNL>"/"	RETURN(SLASH);
-<SNL>"<"	RETURN(LT);
-<SNL>">"	RETURN(GT);
-<SNL>"|"	RETURN(BIT_OR);
-<SNL>"^"	RETURN(BIT_XOR);
-<SNL>"~"	RETURN(COMPLEMENT);
-<SNL>"%"	RETURN(MODULO);
-<SNL>"="	RETURN(EQUAL);
-<SNL>"&"	RETURN(AMPERSAND);
-<SNL>"*"	RETURN(ASTERISK);
-<SNL>"{"	RETURN(L_BRACKET);
-<SNL>"}"	RETURN(R_BRACKET);
-<SNL>"["	RETURN(L_SQ_BRACKET);
-<SNL>"]"	RETURN(R_SQ_BRACKET);
-<SNL>"?"	RETURN(QUESTION);
-<SNL>":"	RETURN(COLON);
-<SNL>";"	RETURN(SEMI_COLON);
-<SNL>"."	RETURN(PERIOD);
-<SNL>"("	RETURN(L_PAREN);
-<SNL>")"	RETURN(R_PAREN);
-<SNL>","	RETURN(COMMA);
-<SNL>{INTNUM} {
-		yylval.str = strdup((char *)yytext);
-		RETURN(INTNUM);
-}
-<SNL>{FPNUM} {
-		yylval.str = strdup((char *)yytext);
-		RETURN(FPNUM);
-}
-<SNL>[\f\t\ ]*	/* no action */ ;
-<SNL>.		RETURN(BAD_CHAR);
-.|\n		{ globals->line_num = 1; BEGIN SNL; yyless(0); }
diff --git a/src/snc/snc_main.c b/src/snc/snc_main.c
index fa59964e..f1a2fc0b 100644
--- a/src/snc/snc_main.c
+++ b/src/snc/snc_main.c
@@ -30,6 +30,10 @@
 #include	<string.h>
 #include	<stdarg.h>
 
+#include	"types.h"
+#include	"lexer.h"
+#include	"analysis.h"
+#include	"gen_code.h"
 #include	"snc_main.h"
 
 #ifndef	TRUE
@@ -37,49 +41,38 @@
 #define	FALSE 0
 #endif
 
-extern char	*sncVersion;	/* snc version and date created */
+extern char *sncVersion;	/* snc version and date created */
 
-extern void compile(void);	/* defined in snl.re */
-
-static Options	default_options =
-{
-	FALSE,	/* async */
-	TRUE,	/* conn */
-	FALSE,	/* debug */
-	TRUE,	/* newef */
-	TRUE,	/* init_reg */
-	TRUE,	/* line */
-	FALSE,	/* main */
-	FALSE,	/* reent */
-	TRUE	/* warn */
-};
-
-static Globals	default_globals =
+static Options options =
 {
-	0,0,0,&default_options
+	FALSE,		/* async */
+	TRUE,		/* conn */
+	FALSE,		/* debug */
+	TRUE,		/* newef */
+	TRUE,		/* init_reg */
+	TRUE,		/* line */
+	FALSE,		/* main */
+	FALSE,		/* reent */
+	TRUE		/* warn */
 };
 
-Globals *globals = &default_globals;
+static char *in_file;	/* input file name */
+static char *out_file;	/* output file name */
 
-static char	in_file[200];	/* input file name */
-static char	out_file[200];	/* output file name */
-
-static void get_args(int argc, char *argv[]);
-static void get_options(char *s);
-static void get_in_file(char *s);
-static void get_out_file(char *s);
+static void parse_args(int argc, char *argv[]);
+static void parse_option(char *s);
 static void print_usage(void);
 
 /* The streams stdin and stdout are redirected to files named in the
    command parameters.  This accomodates the use by lex of stdin for input
-   and permits printf() to be used for output.
-*/
+   and permits printf() to be used for output. */
 int main(int argc, char *argv[])
 {
 	FILE	*infp, *outfp;
+	Program	*prg;
 
 	/* Get command arguments */
-	get_args(argc, argv);
+	parse_args(argc, argv);
 
 	/* Redirect input stream from specified file */
 	infp = freopen(in_file, "r", stdin);
@@ -97,26 +90,23 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	/* src_file is used to mark the output file for snc & cc errors */
-	globals->src_file = in_file;
-
 	/* Use line buffered output */
 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
 	setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 
 	printf("/* %s: %s */\n", sncVersion, in_file);
 
-	compile();
+	prg = parse_program(in_file);
+	analyse_program(prg, &options);
+	generate_code(prg);
 
-        return 0; /* never reached */
+	exit(0);
 }
 
-/* If "*.s" is input file then "*.c" is the output file.  Otherwise,
-   ".c" is appended to the input file to form the output file name.
-   Sets the globals in_file[] and out_file[]. */
-static void get_args(int argc, char *argv[])
+/* Initialize options, in_file, and out_file from arguments. */
+static void parse_args(int argc, char *argv[])
 {
-	char	*s;
+	int i;
 
 	if (argc < 2)
 	{
@@ -124,179 +114,154 @@ static void get_args(int argc, char *argv[])
 		exit(1);
 	}
 
-	strcpy(in_file,"");
-	strcpy(out_file,"");
-
-	for (argc--, argv++; argc > 0; argc--, argv++)
+	for (i=1; i<argc; i++)
 	{
-		s = *argv;
-		if (*s != '+' && *s != '-')
+		char *s = argv[i];
+
+		if (strcmp(s,"-o") == 0)
 		{
-			get_in_file(s);
+			if (i+1 == argc)
+			{
+				report("missing filename after option -o\n");
+				print_usage();
+				exit(1);
+			}
+			else
+			{
+				i++;
+				out_file = argv[i];
+				continue;
+			}
 		}
-		else if (*s == '-' && *(s+1) == 'o')
+		else if (s[0] != '+' && s[0] != '-')
 		{
-			argc--; argv++; s = *argv;
-			get_out_file(s);
+			in_file = s;
+			continue;
 		}
 		else
 		{
-			get_options(s);
+			parse_option(s);
 		}
 	}
 
-	if (strcmp(in_file,"") == 0)
+	if (!in_file)
 	{
+		report("no input file argument given\n");
 		print_usage();
 		exit(1);
 	}
+
+	if (!out_file)	/* no -o option given */
+	{
+		int l = strlen(in_file);
+		char *ext = strrchr(in_file, '.');
+
+		if (ext && strcmp(ext,".st") == 0)
+		{
+			out_file = (char*)malloc(l);
+			strcpy(out_file, in_file);
+			strcpy(out_file+(ext-in_file), ".c\n");
+		}
+		else
+		{
+			out_file = (char*)malloc(l+3);
+			sprintf(out_file, "%s.c", in_file);
+		}
+	}
 }
 
-static void get_options(char *s)
+static void parse_option(char *s)
 {
 	int		opt_val;
-	Options		*opt = globals->options;
 
 	opt_val = (*s == '+');
 
 	switch (s[1])
 	{
 	case 'a':
-		opt->async = opt_val;
+		options.async = opt_val;
 		break;
 	case 'c':
-		opt->conn = opt_val;
+		options.conn = opt_val;
 		break;
 	case 'd':
-		opt->debug = opt_val;
+		options.debug = opt_val;
 		break;
 	case 'e':
-		opt->newef = opt_val;
+		options.newef = opt_val;
 		break;
 	case 'i':
-		opt->init_reg = opt_val;
+		options.init_reg = opt_val;
 		break;
 	case 'l':
-		opt->line = opt_val;
+		options.line = opt_val;
 		break;
 	case 'm':
-		opt->main = opt_val;
+		options.main = opt_val;
 		break;
 	case 'r':
-		opt->reent = opt_val;
+		options.reent = opt_val;
 		break;
 	case 'w':
-		opt->warn = opt_val;
+		options.warn = opt_val;
 		break;
 	default:
-		report("unknown option ignored: \"%s\"", s);
+		report("unknown option ignored: '%s'\n", s);
 		break;
 	}
 }
 
-static void get_in_file(char *s)
-{				
-	int		ls;
-
-	if (strcmp(in_file,"") != 0)
-	{
-		print_usage();
-		exit(1);
-	}
-
-	ls = strlen (s);
-	strcpy (in_file, s);
-
-	if (strcmp(out_file,"") != 0)
-	{
-		return;
-	}
-
-	strcpy (out_file, s);
-	if ( strcmp (&in_file[ls-3], ".st") == 0 )
-	{
-		out_file[ls-2] = 'c';
-		out_file[ls-1] = 0;
-	}
-	else if (in_file[ls-2] == '.')
-	{	/* change suffix to 'c' */
-		out_file[ls -1] = 'c';
-	}
-	else
-	{	/* append ".c" */
-		out_file[ls] = '.';
-		out_file[ls+1] = 'c';
-		out_file[ls+2] = 0;
-	}
-}
-
-static void get_out_file(char *s)
-{
-	if (s == NULL)
-	{
-		print_usage();
-		exit(1);
-	}
-	
-	strcpy(out_file,s);
-}
-
 static void print_usage(void)
 {
-	report("%s", sncVersion);
-	report("usage: snc <options> <infile>");
-	report("options:");
-	report("  -o <outfile> - override name of output file");
-	report("  +a           - do asynchronous pvGet");
-	report("  -c           - don't wait for all connects");
-	report("  +d           - turn on debug run-time option");
-	report("  -e           - don't use new event flag mode");
-	report("  -l           - suppress line numbering");
-	report("  +m           - generate main program");
-	report("  -i           - don't register commands/programs");
-	report("  +r           - make reentrant at run-time");
-	report("  -w           - suppress compiler warnings");
-	report("example:\n snc +a -c vacuum.st");
+	report("%s\n", sncVersion);
+	report("usage: snc <options> <infile>\n");
+	report("options:\n");
+	report("  -o <outfile> - override name of output file\n");
+	report("  +a           - do asynchronous pvGet\n");
+	report("  -c           - don't wait for all connects\n");
+	report("  +d           - turn on debug run-time option\n");
+	report("  -e           - don't use new event flag mode\n");
+	report("  -l           - suppress line numbering\n");
+	report("  +m           - generate main program\n");
+	report("  -i           - don't register commands/programs\n");
+	report("  +r           - make reentrant at run-time\n");
+	report("  -w           - suppress compiler warnings\n");
+	report("example:\n snc +a -c vacuum.st\n");
 }
 
 void print_line_num(int line_num, char *src_file)
 {
-	if (globals->options->line)
+	if (options.line)
 		printf("# line %d \"%s\"\n", line_num, src_file);
 }
 
 /* Errors and warnings */
 
-void parse_error(const char *format, ...)
+void report_loc(const char *src_file, int line_num)
+{
+	fprintf(stderr, "%s:%d: ", src_file, line_num);
+}
+
+void report_at(const char *src_file, int line_num, const char *format, ...)
 {
 	va_list args;
 
-	report_location(globals->src_file, globals->line_num);
+	report_loc(src_file, line_num);
 
 	va_start(args, format);
 	vfprintf(stderr, format, args);
 	va_end(args);
-
-	fprintf(stderr, "\n");
 }
 
-void report_location(const char *src_file, int line_num)
-{
-	fprintf(stderr, "%s:%d: ", src_file, line_num);
-}
-
-void report_with_location(
-	const char *src_file, int line_num, const char *format, ...)
+void report_at_expr(Expr *ep, const char *format, ...)
 {
 	va_list args;
 
-	report_location(src_file, line_num);
+	report_loc(ep->src_file, ep->line_num);
 
 	va_start(args, format);
 	vfprintf(stderr, format, args);
 	va_end(args);
-
-	fprintf(stderr, "\n");
 }
 
 void report(const char *format, ...)
@@ -306,6 +271,4 @@ void report(const char *format, ...)
 	va_start(args, format);
 	vfprintf(stderr, format, args);
 	va_end(args);
-
-	fprintf(stderr, "\n");
 }
diff --git a/src/snc/snc_main.h b/src/snc/snc_main.h
index 44580948..b2ba6e30 100644
--- a/src/snc/snc_main.h
+++ b/src/snc/snc_main.h
@@ -1,47 +1,24 @@
 #ifndef INCLsncmainh
 #define INCLsncmainh
 
-struct options			/* compile & run-time options */
-{
-	int	async;		/* do pvGet() asynchronously */
-	int	conn;		/* wait for all conns to complete */
-	int	debug;		/* run-time debug */
-	int	newef;		/* new event flag mode */
-	int	init_reg;	/* register commands/programs */
-	int	line;		/* line numbering */
-	int	main;		/* main program */
-	int	reent;		/* reentrant at run-time */
-	int	warn;		/* compiler warnings */
-};
-typedef struct options Options;
-
-struct globals
-{
-	char	*src_file;	/* current source file name */
-	int	line_num;	/* current line number */
-	int	prev_line_num;	/* line number for previous token */
-	Options *options;	/* compile & run-time options */
-};
-typedef struct globals Globals;
-
-extern Globals *globals;
-
-/* append '# <line_num> "<src_file>"\n' to output */
+/* Export various reporting and printing procedures. */
 
+/* append '# <line_num> "<src_file>"\n' to output (if not disabled by cmd-line option) */
 void print_line_num(int line_num, char *src_file);
 
 /* Error and warning message support */
 
-/* this uses the global location information which is valid only during the
-   parsing stage */
-void parse_error(const char *format, ...);
+/* just the location info */
+void report_loc(const char *src_file, int line_num);
 
-/* just the location info, no newline */
-void report_location(const char *src_file, int line_num);
+/* location plus message */
+void report_at(const char *src_file, int line_num, const char *format, ...);
 
-/* these both add a trailing newline */
-void report_with_location(
-	const char *src_file, int line_num, const char *format, ...);
+/* with location from this expression */
+struct expression;
+void report_at_expr(struct expression *ep, const char *format, ...);
+
+/* message only */
 void report(const char *format, ...);
 
 #endif	/*INCLsncmainh*/
diff --git a/src/snc/snl.lem b/src/snc/snl.lem
index f0f69b49..a77e283b 100644
--- a/src/snc/snl.lem
+++ b/src/snc/snl.lem
@@ -7,19 +7,22 @@
 #include "snc_main.h"
 }
 
+%extra_argument { Program **presult }
+
 %name parser
 
 %parse_failure {
-	parse_error("giving up");
+	report("parser giving up\n");
 	exit(1);
 }
 
 %syntax_error {
-	parse_error("syntax error");
+	report_at(TOKEN.file, TOKEN.line,
+        	"syntax error near token '%s'\n", TOKEN.str);
 	exit(1);
 }
 
-%token_type { char* }
+%token_type { Token }
 %default_type { Expr* }
 
 /* Standard C operator table
@@ -73,16 +76,16 @@ program ::=
 	global_exit_code(ex)
 	c_codes(cc).
 {
-	program(pn,pp,ds,en,ss,ex,cc);
+	*presult = program(pn,pp,ds,en,ss,ex,cc);
 }
 
 %type program_name {char*}
-program_name(p) ::= PROGRAM NAME(n).	{ p = n; }
+program_name(p) ::= PROGRAM NAME(t).	{ p = t.str; }
 
 %type program_param {char*}
 program_param(p) ::=
-	LPAREN STRCON(x) RPAREN.	{ p = x; }
-program_param(p) ::= .			{ p = 0; }
+	LPAREN STRCON(t) RPAREN.	{ p = t.str; }
+program_param(p) ::= .			{ p = ""; }
 
 definitions(p) ::= definitions(xs) definition(x). {
 	p = link_expr(xs, x);
@@ -94,7 +97,7 @@ definition(p) ::= monitor(x).		{ p = x; }
 definition(p) ::= sync(x).		{ p = x; }
 definition(p) ::= syncq(x).		{ p = x; }
 definition(p) ::= decl(x).		{ p = x; }
-definition(p) ::= option.		{ p = 0; }
+definition(p) ::= option(x).		{ p = x; }
 definition(p) ::= c_code(x).		{ p = x; }
 
 assign(p) ::= ASSIGN NAME(v) to string(t) SEMICOLON. {
@@ -135,23 +138,23 @@ to ::= .
 opt_subscript(p) ::= subscript(s).	{ p = expr(E_CONST, s, 0, 0); }
 opt_subscript(p) ::= .			{ p = 0; }
 
-%type subscript {char*}
+%type subscript {Token}
 subscript(p) ::= LBRACKET INTCON(n) RBRACKET. { p = n; }
 
 decl(p) ::= type(t) NAME(v) SEMICOLON.
-		{ p = decl(t, VC_SIMPLE,  v, NULL, NULL, NULL); }
+		{ p = decl(t, VC_SIMPLE,  v, 0,  0,  0); }
 decl(p) ::= type(t) NAME(v) EQUAL number(n) SEMICOLON.
-		{ p = decl(t, VC_SIMPLE,  v, NULL, NULL, n); }
+		{ p = decl(t, VC_SIMPLE,  v, 0,  0, n.str); }
 decl(p) ::= type(t) NAME(v) subscript(s) SEMICOLON.
-		{ p = decl(t, VC_ARRAY1,  v, s,    NULL, NULL); }
+		{ p = decl(t, VC_ARRAY1,  v, s.str,  0,  0); }
 decl(p) ::= type(t) NAME(v) subscript(s1) subscript(s2) SEMICOLON.
-		{ p = decl(t, VC_ARRAY2,  v, s1,   s2,   NULL); }
+		{ p = decl(t, VC_ARRAY2,  v, s1.str, s2.str, 0); }
 decl(p) ::= type(t) ASTERISK NAME(v) SEMICOLON.
-		{ p = decl(t, VC_POINTER, v, NULL, NULL, NULL); }
+		{ p = decl(t, VC_POINTER, v, 0, 0, 0); }
 decl(p) ::= type(t) ASTERISK NAME(v) subscript(s) SEMICOLON.
-		{ p = decl(t, VC_ARRAYP,  v, s,    NULL, NULL); }
+		{ p = decl(t, VC_ARRAYP,  v, s.str,  0,  0); }
 
-%type number {char*}
+%type number {Token}
 number(p) ::= INTCON(x).			{ p = x; }
 number(p) ::= FPCON(x).				{ p = x; }
 
@@ -169,8 +172,11 @@ type(p) ::= DOUBLE.				{ p = V_DOUBLE;	}
 type(p) ::= STRING.				{ p = V_STRING;	}
 type(p) ::= EVFLAG.				{ p = V_EVFLAG;	}
 
-option ::= OPTION ADD NAME(n) SEMICOLON.	{ option_stmt(n, 1); }
-option ::= OPTION SUB NAME(n) SEMICOLON.	{ option_stmt(n, 0); }
+option(p) ::= OPTION option_value(v) NAME(n) SEMICOLON.
+						{ p = expr(E_OPTION, n, v, 0); }
+
+option_value(p) ::= ADD(t).			{ p = expr(E_X, t, 0, 0); }
+option_value(p) ::= SUB(t).			{ p = expr(E_X, t, 0, 0); }
 
 // State sets and states
 
@@ -190,18 +196,21 @@ state_set(p) ::= SS NAME(n) LBRACE states(xs) RBRACE. {
 states(p) ::= states(xs) state(x).		{ p = link_expr(xs, x); }
 states(p) ::= state(x).				{ p = x; }
 
-state(p) ::= STATE NAME(n) LBRACE state_options(os) state_blocks(xs) RBRACE.
-						{ p = expr(E_STATE, n, xs, os); }
-
-state_options(p) ::= state_options(xs) state_option(x).
-						{ p = link_expr(xs, x); }
-state_options(p) ::= .				{ p = 0; }
+state(p) ::= STATE NAME(n) LBRACE state_definitions(ds) state_blocks(xs) RBRACE.
+						{ p = expr(E_STATE, n, xs, ds); }
 
-state_option(p) ::= OPTION state_option_value(v) NAME(n) SEMICOLON.
-						{ p = expr(E_OPTION, n, v, 0); }
+state_definitions(p) ::= state_definitions(xs) state_definition(x). {
+	p = link_expr(xs, x);
+}
+state_definitions(p) ::= .			{ p = 0; }
 
-state_option_value(p) ::= ADD.			{ p = expr(E_X, "+", 0, 0); }
-state_option_value(p) ::= SUB.			{ p = expr(E_X, "-", 0, 0); }
+// state_definition(p) ::= assign(x).		{ p = x; }
+// state_definition(p) ::= monitor(x).		{ p = x; }
+// state_definition(p) ::= sync(x).		{ p = x; }
+// state_definition(p) ::= syncq(x).		{ p = x; }
+// state_definition(p) ::= decl(x).		{ p = x; }
+state_definition(p) ::= option(x).		{ p = x; }
+state_definition(p) ::= c_code(x).		{ p = x; }
 
 state_blocks(p) ::= entries(xs) transitions(ts) exits(ys).
 						{ p = link_expr(link_expr(xs, ts), ys); }
@@ -209,12 +218,12 @@ state_blocks(p) ::= entries(xs) transitions(ts) exits(ys).
 entries(p) ::= entries(xs) entry(x).		{ p = link_expr(xs, x); }
 entries(p) ::= .				{ p = 0; }
 
-entry(p) ::= ENTRY block(xs).			{  p = expr(E_ENTRY, "", 0, xs); }
+entry(p) ::= ENTRY(t) block(xs).		{ p = expr(E_ENTRY, t, 0, xs); }
 
 exits(p) ::= exits(xs) exit(x).			{ p = link_expr(xs, x); }
 exits(p) ::= .					{ p = 0; }
 
-exit(p) ::= EXIT block(xs).			{  p = expr(E_EXIT, "", 0, xs); }
+exit(p) ::= EXIT(t) block(xs).			{ p = expr(E_EXIT, t, 0, xs); }
 
 transitions(p) ::= transitions(xs) transition(x). { p = link_expr(xs, x); }
 transitions(p) ::= transition(x).		{ p = x; }
@@ -229,23 +238,23 @@ block(p) ::= LBRACE statements(xs) RBRACE.	{ p = xs; }
 statements(p) ::= statements(xs) statement(x).	{ p = link_expr(xs, x); }
 statements(p) ::= .				{ p = 0; }
 
-statement(p) ::= BREAK SEMICOLON.		{ p = expr(E_BREAK, "", 0, 0); }
+statement(p) ::= BREAK(t) SEMICOLON.		{ p = expr(E_BREAK, t, 0, 0); }
 statement(p) ::= c_code(x).			{ p = x; }
-statement(p) ::= block(xs).			{ p = expr(E_CMPND, "",xs, 0); }
-statement(p) ::= IF LPAREN expr(c) RPAREN statement(x).
-						{ p = expr(E_IF, "", c, x); }
-statement(p) ::= ELSE statement(x).		{ p = expr(E_ELSE, "", x, 0); }
-statement(p) ::= WHILE LPAREN expr(c) RPAREN statement(x).
-						{ p = expr(E_WHILE, "", c, x); }
+statement(p) ::= LBRACE(t) statements(xs) RBRACE. { p = expr(E_CMPND, t, xs, 0); }
+statement(p) ::= IF(t) LPAREN expr(c) RPAREN statement(x).
+						{ p = expr(E_IF, t, c, x); }
+statement(p) ::= ELSE(t) statement(x).		{ p = expr(E_ELSE, t, x, 0); }
+statement(p) ::= WHILE(t) LPAREN expr(c) RPAREN statement(x).
+						{ p = expr(E_WHILE, t, c, x); }
 statement(p) ::= for_statement(x).		{ p = x; }
-statement(p) ::= opt_expr(x) SEMICOLON.		{ p = expr(E_STMT, "", x, 0); }
+statement(p) ::= opt_expr(x) SEMICOLON(t).	{ p = expr(E_STMT, t, x, 0); }
 
 for_statement(p) ::=
-	FOR LPAREN
-		exprs(init) SEMICOLON opt_expr(cond) SEMICOLON exprs(iter)
-	RPAREN statement(x).			{ p = expr(E_FOR, "",
-							expr(E_X, "", init, cond),
-							expr(E_X, "", iter, x));
+	FOR(for) LPAREN
+		exprs(init) SEMICOLON(sem1) opt_expr(cond) SEMICOLON(sem2) exprs(iter)
+	RPAREN statement(x).			{ p = expr(E_FOR, for,
+							expr(E_X, sem1, init, cond),
+							expr(E_X, sem2, iter, x));
 						}
 
 // Expressions
@@ -256,69 +265,69 @@ expr(p) ::= string(x).				{ p = x; }
 expr(p) ::= NAME(v).				{ p = expr(E_VAR, v, 0, 0); }
 
 // Parenthesized
-expr(p) ::= LPAREN expr(x) RPAREN.		{ p = expr(E_PAREN, "", x, 0); }
+expr(p) ::= LPAREN(t) expr(x) RPAREN.		{ p = expr(E_PAREN, t, x, 0); }
 
 // Primary Expression and Unary Postfix Operators
-expr(p) ::= NAME(f) LPAREN exprs(xs) RPAREN. [POST]
-						{ p = expr(E_FUNC,  f, xs, 0); }
-expr(p) ::= EXIT LPAREN exprs(xs) RPAREN. [POST]{ p = expr(E_FUNC, "exit", xs, 0); }
-expr(p) ::= expr(x) LBRACKET expr(y) RBRACKET. [POST]
-						{ p = expr(E_SUBSCR, "",   x, y); }
-expr(p) ::= expr(x) PERIOD  expr(y).	[POST]	{ p = expr(E_BINOP,  "." , x, y); }
-expr(p) ::= expr(x) POINTER expr(y).	[POST]	{ p = expr(E_BINOP,  "->", x, y); }
-expr(p) ::= expr(x) INCR.		[POST]	{ p = expr(E_POST,   "++", x, 0); }
-expr(p) ::= expr(x) DECR.		[POST]	{ p = expr(E_POST,   "--", x, 0); }
+expr(p) ::= NAME(t) LPAREN exprs(xs) RPAREN. [POST]
+						{ p = expr(E_FUNC, t, xs, 0); }
+expr(p) ::= EXIT(t) LPAREN exprs(xs) RPAREN. [POST] { p = expr(E_FUNC, t, xs, 0); }
+expr(p) ::= expr(x) LBRACKET(t) expr(y) RBRACKET. [POST]
+						{ p = expr(E_SUBSCR, t, x, y); }
+expr(p) ::= expr(x) PERIOD(t)  expr(y).	[POST]	{ p = expr(E_BINOP,  t, x, y); }
+expr(p) ::= expr(x) POINTER(t) expr(y).	[POST]	{ p = expr(E_BINOP,  t, x, y); }
+expr(p) ::= expr(x) INCR(t).		[POST]	{ p = expr(E_POST,   t, x, 0); }
+expr(p) ::= expr(x) DECR(t).		[POST]	{ p = expr(E_POST,   t, x, 0); }
 
 // Unary Prefix Operators
-expr(p) ::= ADD	expr(x). [PRE]			{ p = expr(E_PRE, "+",  x, 0); }
-expr(p) ::= SUB	expr(x). [PRE]			{ p = expr(E_PRE, "-",  x, 0); }
-expr(p) ::= ASTERISK	expr(x). [PRE]		{ p = expr(E_PRE, "*",  x, 0); }
-expr(p) ::= AMPERSAND	expr(x). [PRE]		{ p = expr(E_PRE, "&",  x, 0); }
-expr(p) ::= NOT		expr(x). [PRE]		{ p = expr(E_PRE, "!",  x, 0); }
-expr(p) ::= TILDE	expr(x). [PRE]		{ p = expr(E_PRE, "~",  x, 0); }
-expr(p) ::= INCR	expr(x). [PRE]		{ p = expr(E_PRE, "++", x, 0); }
-expr(p) ::= DECR	expr(x). [PRE]		{ p = expr(E_PRE, "--", x, 0); }
+expr(p) ::= ADD(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= SUB(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= ASTERISK(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= AMPERSAND(t)expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= NOT(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= TILDE(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= INCR(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
+expr(p) ::= DECR(t)	expr(x). [PRE]		{ p = expr(E_PRE, t, x, 0); }
 
 // Binary Operators, left-to-right
-expr(p) ::= expr(x) SUB	expr(y).		{ p = expr(E_BINOP, "-",  x, y); }
-expr(p) ::= expr(x) ADD		expr(y).	{ p = expr(E_BINOP, "+",  x, y); }
-expr(p) ::= expr(x) ASTERISK	expr(y).	{ p = expr(E_BINOP, "*",  x, y); }
-expr(p) ::= expr(x) SLASH	expr(y).	{ p = expr(E_BINOP, "/",  x, y); }
-expr(p) ::= expr(x) GT		expr(y).	{ p = expr(E_BINOP, ">",  x, y); }
-expr(p) ::= expr(x) GE		expr(y).	{ p = expr(E_BINOP, ">=", x, y); }
-expr(p) ::= expr(x) EQ		expr(y).	{ p = expr(E_BINOP, "==", x, y); }
-expr(p) ::= expr(x) NE		expr(y).	{ p = expr(E_BINOP, "!=", x, y); }
-expr(p) ::= expr(x) LE		expr(y).	{ p = expr(E_BINOP, "<=", x, y); }
-expr(p) ::= expr(x) LT		expr(y).	{ p = expr(E_BINOP, "<" , x, y); }
-expr(p) ::= expr(x) OROR	expr(y).	{ p = expr(E_BINOP, "||", x, y); }
-expr(p) ::= expr(x) ANDAND	expr(y).	{ p = expr(E_BINOP, "&&", x, y); }
-expr(p) ::= expr(x) LSHIFT	expr(y).	{ p = expr(E_BINOP, "<<", x, y); }
-expr(p) ::= expr(x) RSHIFT	expr(y).	{ p = expr(E_BINOP, ">>", x, y); }
-expr(p) ::= expr(x) VBAR	expr(y).	{ p = expr(E_BINOP, "|",  x, y); }
-expr(p) ::= expr(x) CARET	expr(y).	{ p = expr(E_BINOP, "^",  x, y); }
-expr(p) ::= expr(x) AMPERSAND	expr(y).	{ p = expr(E_BINOP, "&",  x, y); }
-expr(p) ::= expr(x) MOD		expr(y).	{ p = expr(E_BINOP, "%",  x, y); }
+expr(p) ::= expr(x) SUB(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) ADD(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) ASTERISK(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) SLASH(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) GT(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) GE(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) EQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) NE(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) LE(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) LT(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) OROR(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) ANDAND(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) LSHIFT(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) RSHIFT(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) VBAR(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) CARET(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) AMPERSAND(t) expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) MOD(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
 
 // Ternary Operator, right-to-left
-expr(p) ::= expr(x) QUESTION expr(y) COLON expr(z). {
-	p = expr(E_TERNOP, "?", x, expr(E_X, ":", y, z));
+expr(p) ::= expr(x) QUESTION(t1) expr(y) COLON(t2) expr(z). {
+	p = expr(E_TERNOP, t1, x, expr(E_X, t2, y, z));
 }
 
 // Assignment Operators, right-to-left
-expr(p) ::= expr(x) EQUAL	expr(y).	{ p = expr(E_BINOP, "="  , x, y); }
-expr(p) ::= expr(x) ADDEQ	expr(y).	{ p = expr(E_BINOP, "+=" , x, y); }
-expr(p) ::= expr(x) SUBEQ	expr(y).	{ p = expr(E_BINOP, "-=" , x, y); }
-expr(p) ::= expr(x) ANDEQ	expr(y).	{ p = expr(E_BINOP, "&=" , x, y); }
-expr(p) ::= expr(x) OREQ	expr(y).	{ p = expr(E_BINOP, "|=" , x, y); }
-expr(p) ::= expr(x) DIVEQ	expr(y).	{ p = expr(E_BINOP, "/=" , x, y); }
-expr(p) ::= expr(x) MULEQ	expr(y).	{ p = expr(E_BINOP, "*=" , x, y); }
-expr(p) ::= expr(x) MODEQ 	expr(y).	{ p = expr(E_BINOP, "%=" , x, y); }
-expr(p) ::= expr(x) LSHEQ	expr(y).	{ p = expr(E_BINOP, "<<=", x, y); }
-expr(p) ::= expr(x) RSHEQ	expr(y).	{ p = expr(E_BINOP, ">>=", x, y); }
-expr(p) ::= expr(x) XOREQ	expr(y).	{ p = expr(E_BINOP, "^=" , x, y); }
+expr(p) ::= expr(x) EQUAL(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) ADDEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) SUBEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) ANDEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) OREQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) DIVEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) MULEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) MODEQ(t) 	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) LSHEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) RSHEQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
+expr(p) ::= expr(x) XOREQ(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
 
 // Comma, left-to-right, not supported
-// expr(p) ::= expr(x) COMMA	expr(y).	{ p = expr(E_BINOP, "," ,  x, y); }
+// expr(p) ::= expr(x) COMMA(t)	expr(y).	{ p = expr(E_BINOP, t, x, y); }
 
 opt_expr(p) ::= expr(x).			{ p = x; }
 opt_expr(p) ::= .				{ p = 0; }
@@ -327,11 +336,11 @@ exprs(p) ::= exprs(xs) COMMA expr(x).		{ p = link_expr(xs, x); }
 exprs(p) ::= expr(x).				{ p = x; }
 exprs(p) ::= .					{ p = 0; }
 
-string(p) ::= STRCON(x).			{ p = expr(E_STRING, x, 0, 0); }
+string(p) ::= STRCON(t).			{ p = expr(E_STRING, t, 0, 0); }
 
 // 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(x). 			{ p = expr(E_TEXT, x, 0, 0); }
+c_code(p) ::= CCODE(t). 			{ p = expr(E_TEXT, t, 0, 0); }
diff --git a/src/snc/snl.lt b/src/snc/snl.lt
index 7ee649b7..64bb42e0 100644
--- a/src/snc/snl.lt
+++ b/src/snc/snl.lt
@@ -309,6 +309,7 @@ static void yy_destructor(
 %%
     default:  break;   /* If no destructor action specified: do nothing */
   }
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
 
 /*
diff --git a/src/snc/snl.re b/src/snc/snl.re
index 30f7eab7..6bc9cf45 100644
--- a/src/snc/snl.re
+++ b/src/snc/snl.re
@@ -6,6 +6,7 @@
 
 #include "snl.h"
 #include "snc_main.h"
+#include "lexer.h"
 
 #define	EOI		0
 
@@ -21,13 +22,16 @@ typedef unsigned char uchar;
 #define	YYFILL			cursor = fill(s, cursor);
 #define	YYDEBUG(state, current) fprintf(stderr, "state = %d, current = %c\n", state, current);
 
-#define	RET(i)			{s->cur = cursor; return i;}
+#define	RET(i,r) {\
+	s->cur = cursor;\
+	t->str = r;\
+	return i;\
+}
 
 typedef struct Scanner {
 	int	fd;	/* file descriptor */
 	uchar	*bot;	/* pointer to bottom (start) of buffer */
 	uchar	*tok;	/* pointer to start of current token */
-	uchar	*end;	/* pointer to end of token (or 0, then use cur) */
 	uchar	*ptr;	/* marker for backtracking (always > tok) */
 	uchar	*cur;	/* saved scan position between calls to scan() */
 	uchar	*lim;	/* pointer to one position after last read char */
@@ -41,7 +45,7 @@ static void scan_report(Scanner *s, const char *format, ...)
 {
 	va_list args;
 
-	report_location(s->file, s->line);
+	report_loc(s->file, s->line);
 	va_start(args, format);
 	vfprintf(stderr, format, args);
 	va_end(args);
@@ -106,6 +110,22 @@ static uchar *fill(Scanner *s, uchar *cursor) {
 	return cursor;
 }
 
+/* alias strdup_from_to: duplicate string from start to (exclusive) stop */
+char *strdupft(uchar *start, uchar *stop) {
+	char *result;
+	char c = *stop;
+	*stop = 0;
+	result = strdup((char*)start);
+	*stop = c;
+#if 0
+	int len = stop - start;
+	result = malloc(len + 1);
+	memcpy(result, start, len);
+	result[len] = 0;
+#endif
+	return result;
+}
+
 /*!re2c
 	re2c:yyfill:parameter	= 0;
 
@@ -121,17 +141,18 @@ static uchar *fill(Scanner *s, uchar *cursor) {
 	ESC	= [\\] ([abfnrtv?'"\\] | "x" HEX+ | OCT+);
 */
 
-static int scan(Scanner *s) {
+static int scan(Scanner *s, Token *t) {
 	uchar *cursor = s->cur;
 	uchar *str_end = 0;
 
-        s->end = 0;
 snl:
+	t->line = s->line;
+	t->file = s->file;
 	s->tok = cursor;
 
 /*!re2c
 	"\n"		{
-				if(cursor == s->eof) RET(EOI);
+				if(cursor == s->eof) RET(EOI,0);
 				s->line++;
 				goto snl;
 			}
@@ -150,92 +171,92 @@ snl:
 			}
 	("%%" .*)	{
 				s->tok += 2;
-				RET(CCODE);
+				RET(CCODE, strdupft(s->tok, cursor));
 			}
-	"assign"	{ RET(ASSIGN); }
-	"break"		{ RET(BREAK); }
-	"char"		{ RET(CHAR); }
-	"double"	{ RET(DOUBLE); }
-	"else"		{ RET(ELSE); }
-	"entry"		{ RET(ENTRY); }
-	"evflag"	{ RET(EVFLAG); }
-	"exit"		{ RET(EXIT); }
-	"float"		{ RET(FLOAT); }
-	"for"		{ RET(FOR); }
-	"if"		{ RET(IF); }
-	"int"		{ RET(INT); }
-	"long"		{ RET(LONG); }
-	"monitor"	{ RET(MONITOR); }
-	"option"	{ RET(OPTION); }
-	"program"	{ RET(PROGRAM); }
-	"short"		{ RET(SHORT); }
-	"ss"		{ RET(SS); }
-	"state"		{ RET(STATE); }
-	"string"	{ RET(STRING); }
-	"syncQ"		{ RET(SYNCQ); }
-	"sync"		{ RET(SYNC); }
-	"to"		{ RET(TO); }
-	"unsigned"	{ RET(UNSIGNED); }
-	"when"		{ RET(WHEN); }
-	"while"		{ RET(WHILE); }
-	"TRUE"		{ RET(INTCON); }
-	"FALSE"		{ RET(INTCON); }
-	"ASYNC"		{ RET(INTCON); }
-	"SYNC"		{ RET(INTCON); }
-	LET (LET|DEC)*	{ RET(NAME); }
+	"assign"	{ RET(ASSIGN,	"assign"); }
+	"break"		{ RET(BREAK,	"break"); }
+	"char"		{ RET(CHAR,	"char"); }
+	"double"	{ RET(DOUBLE,	"double"); }
+	"else"		{ RET(ELSE,	"else"); }
+	"entry"		{ RET(ENTRY,	"entry"); }
+	"evflag"	{ RET(EVFLAG,	"evflag"); }
+	"exit"		{ RET(EXIT,	"exit"); }
+	"float"		{ RET(FLOAT,	"float"); }
+	"for"		{ RET(FOR,	"for"); }
+	"if"		{ RET(IF,	"if"); }
+	"int"		{ RET(INT,	"int"); }
+	"long"		{ RET(LONG,	"long"); }
+	"monitor"	{ RET(MONITOR,	"monitor"); }
+	"option"	{ RET(OPTION,	"option"); }
+	"program"	{ RET(PROGRAM,	"program"); }
+	"short"		{ RET(SHORT,	"short"); }
+	"ss"		{ RET(SS,	"ss"); }
+	"state"		{ RET(STATE,	"state"); }
+	"string"	{ RET(STRING,	"string"); }
+	"syncQ"		{ RET(SYNCQ,	"syncQ"); }
+	"sync"		{ RET(SYNC,	"sync"); }
+	"to"		{ RET(TO,	"to"); }
+	"unsigned"	{ RET(UNSIGNED,	"unsigned"); }
+	"when"		{ RET(WHEN,	"when"); }
+	"while"		{ RET(WHILE,	"while"); }
+	"TRUE"		{ RET(INTCON,	"TRUE"); }
+	"FALSE"		{ RET(INTCON,	"FALSE"); }
+	"ASYNC"		{ RET(INTCON,	"ASYNC"); }
+	"SYNC"		{ RET(INTCON,	"SYNC"); }
+	LET (LET|DEC)*	{ RET(NAME, strdupft(s->tok, cursor)); }
 	("0" [xX] HEX+ IS?) | ("0" DEC+ IS?) | (DEC+ IS?) | (['] (ESC|ANY\[\n\\'])* ['])
-			{ RET(INTCON); }
+			{ RET(INTCON, strdupft(s->tok, cursor)); }
 
 	(DEC+ EXP FS?) | (DEC* "." DEC+ EXP? FS?) | (DEC+ "." DEC* EXP? FS?)
-			{ RET(FPCON); }
-
-	">>="		{ RET(RSHEQ); }
-	"<<="		{ RET(LSHEQ); }
-	"+="		{ RET(ADDEQ); }
-	"-="		{ RET(SUBEQ); }
-	"*="		{ RET(MULEQ); }
-	"/="		{ RET(DIVEQ); }
-	"%="		{ RET(MODEQ); }
-	"&="		{ RET(ANDEQ); }
-	"^="		{ RET(XOREQ); }
-	"|="		{ RET(OREQ); }
-	">>"		{ RET(RSHIFT); }
-	"<<"		{ RET(LSHIFT); }
-	"++"		{ RET(INCR); }
-	"--"		{ RET(DECR); }
-	"->"		{ RET(POINTER); }
-	"&&"		{ RET(ANDAND); }
-	"||"		{ RET(OROR); }
-	"<="		{ RET(LE); }
-	">="		{ RET(GE); }
-	"=="		{ RET(EQ); }
-	"!="		{ RET(NE); }
-	";"		{ RET(SEMICOLON); }
-	"{"		{ RET(LBRACE); }
-	"}"		{ RET(RBRACE); }
-	","		{ RET(COMMA); }
-	":"		{ RET(COLON); }
-	"="		{ RET(EQUAL); }
-	"("		{ RET(LPAREN); }
-	")"		{ RET(RPAREN); }
-	"["		{ RET(LBRACKET); }
-	"]"		{ RET(RBRACKET); }
-	"."		{ RET(PERIOD); }
-	"&"		{ RET(AMPERSAND); }
-	"!"		{ RET(NOT); }
-	"~"		{ RET(TILDE); }
-	"-"		{ RET(SUB); }
-	"+"		{ RET(ADD); }
-	"*"		{ RET(ASTERISK); }
-	"/"		{ RET(SLASH); }
-	"%"		{ RET(MOD); }
-	"<"		{ RET(LT); }
-	">"		{ RET(GT); }
-	"^"		{ RET(CARET); }
-	"|"		{ RET(VBAR); }
-	"?"		{ RET(QUESTION); }
+			{ RET(FPCON, strdupft(s->tok, cursor)); }
+
+	">>="		{ RET(RSHEQ,	">>="); }
+	"<<="		{ RET(LSHEQ,	"<<="); }
+	"+="		{ RET(ADDEQ,	"+="); }
+	"-="		{ RET(SUBEQ,	"-="); }
+	"*="		{ RET(MULEQ,	"*="); }
+	"/="		{ RET(DIVEQ,	"/="); }
+	"%="		{ RET(MODEQ,	"%="); }
+	"&="		{ RET(ANDEQ,	"&="); }
+	"^="		{ RET(XOREQ,	"^="); }
+	"|="		{ RET(OREQ,	"|="); }
+	">>"		{ RET(RSHIFT,	">>"); }
+	"<<"		{ RET(LSHIFT,	"<<"); }
+	"++"		{ RET(INCR,	"++"); }
+	"--"		{ RET(DECR,	"--"); }
+	"->"		{ RET(POINTER,	"->"); }
+	"&&"		{ RET(ANDAND,	"&&"); }
+	"||"		{ RET(OROR,	"||"); }
+	"<="		{ RET(LE,	"<="); }
+	">="		{ RET(GE,	">="); }
+	"=="		{ RET(EQ,	"=="); }
+	"!="		{ RET(NE,	"!="); }
+	";"		{ RET(SEMICOLON,";"); }
+	"{"		{ RET(LBRACE,	"{"); }
+	"}"		{ RET(RBRACE,	"}"); }
+	","		{ RET(COMMA,	","); }
+	":"		{ RET(COLON,	":"); }
+	"="		{ RET(EQUAL,	"="); }
+	"("		{ RET(LPAREN,	"("); }
+	")"		{ RET(RPAREN,	")"); }
+	"["		{ RET(LBRACKET,	"["); }
+	"]"		{ RET(RBRACKET,	"]"); }
+	"."		{ RET(PERIOD,	"."); }
+	"&"		{ RET(AMPERSAND,"&"); }
+	"!"		{ RET(NOT,	"!"); }
+	"~"		{ RET(TILDE,	"~"); }
+	"-"		{ RET(SUB,	"-"); }
+	"+"		{ RET(ADD,	"+"); }
+	"*"		{ RET(ASTERISK,	"*"); }
+	"/"		{ RET(SLASH,	"/"); }
+	"%"		{ RET(MOD,	"%"); }
+	"<"		{ RET(LT,	"<"); }
+	">"		{ RET(GT,	">"); }
+	"^"		{ RET(CARET,	"^"); }
+	"|"		{ RET(VBAR,	"|"); }
+	"?"		{ RET(QUESTION,	"?"); }
 	[ \t\v\f]+	{ goto snl; }
-	ANY		{ scan_report(s, "invalid character\n"); RET(EOI); }
+	ANY		{ scan_report(s, "invalid character\n"); RET(EOI,0); }
 */
 
 string_const:
@@ -246,7 +267,7 @@ string_const:
 				str_end = cursor - 1;
 				goto string_cat;
 			}
-	ANY		{ scan_report(s, "invalid character in string constant\n"); RET(EOI); }
+	ANY		{ scan_report(s, "invalid character in string constant\n"); RET(EOI,0); }
 */
 
 string_cat:
@@ -254,9 +275,8 @@ string_cat:
 	SPC+		{ goto string_cat; }
 	"\n"		{
 				if (cursor == s->eof) {
-					s->end = str_end;
 					cursor -= 1;
-					RET(STRCON);
+					RET(STRCON, strdupft(s->tok, str_end));
 				}
 				s->line++;
 				goto string_cat;
@@ -268,9 +288,8 @@ string_cat:
 				goto string_const;
 			}
 	ANY		{
-				s->end = str_end;
 				cursor -= 1;
-				RET(STRCON);
+				RET(STRCON, strdupft(s->tok, str_end));
 			}
 */
 
@@ -299,9 +318,8 @@ line_marker_str:
 			}
 	"\n"		{
 				if (cursor == s->eof) {
-					s->end = str_end;
 					cursor -= 1;
-					RET(STRCON);
+					goto snl;
 				}
 				s->line++;
 				goto string_cat;
@@ -322,7 +340,7 @@ comment:
 	"\n"		{
 				if (cursor == s->eof) {
 					scan_report(s, "at eof: unterminated comment\n");
-					RET(EOI);
+					RET(EOI,0);
 				}
 				s->tok = cursor;
 				s->line++;
@@ -333,14 +351,13 @@ comment:
 c_code:
 /*!re2c
 	"}%"		{
-				s->end = cursor - 2;
-				RET(CCODE);
+				RET(CCODE, strdupft(s->tok, cursor - 2));
 			}
 	.		{ goto c_code; }
 	"\n"		{
 				if (cursor == s->eof) {
 					scan_report(s, "at eof: unterminated literal c-code section\n");
-					RET(EOI);
+					RET(EOI,0);
 				}
 				s->line++;
 				goto c_code;
@@ -349,59 +366,50 @@ c_code:
 }
 
 #ifdef TEST_LEXER
+void report_loc(const char *f, int l) {
+	fprintf(stderr, "%s:%d: ", f, l);
+}
+
 int main() {
 	Scanner s;
-	int t;
-	memset((char*) &s, 0, sizeof(s));
-	s.fd = 0;
+	int		tt;	/* token type */
+	Token		tv;	/* token value */
+
+	bzero(&s, sizeof(s));
+
 	s.cur = fill(&s, s.cur);
 	s.line = 1;
-	while( (t = scan(&s)) != EOI) {
-		if (!s.end) s.end = s.cur;
-		printf("%s:%d: %2d\t£%.*s£\n", s.file, s.line, t, s.end - s.tok, s.tok);
+
+	while( (tt = scan(&s, &tv)) != EOI) {
+		printf("%s:%d: %2d\t$%s$\n", tv.file, tv.line, tt, tv.str);
 	}
-	close(s.fd);
+	return 0;
 }
 #else
 
-extern void parser(
-	void *yyp,		/* the parser */
-	int yymajor,		/* the major token code number */
-	char *yyminor		/* the value for the token */
-);
-extern void *parserAlloc(void *(*mallocProc)(size_t));
-void parserFree(
-	void *p,		/* the parser to be deleted */
-	void (*freeProc)(void*)	/* function used to reclaim memory */
-);
-
-void compile(void)
+Program *parse_program(const char *src_file)
 {
-	Scanner s;
-	int t;
-	char *x;
+	Scanner		s;
+	int		tt;	/* token type */
+	Token		tv;	/* token value */
+        Program		*result; /* result of parsing */
 
 	bzero(&s, sizeof(s));
-	s.cur = fill(&s, s.cur); /* otherwise scanner crashes in debug mode */
+	s.file = strdup(src_file);
 	s.line = 1;
 
 	void *pParser = parserAlloc(malloc);
 	do
 	{
-		globals->prev_line_num = s.line;
-		t = scan(&s);
-		globals->src_file = s.file;
-		globals->line_num = s.line;
-
-		if (!s.end) s.end = s.cur;
-		scan_report(&s,"%2d\t£%.*s£\n", t, s.end - s.tok, s.tok);
-		x = malloc(s.end - s.tok + 1);
-		memcpy(x,s.tok,s.end - s.tok);
-		x[s.end - s.tok] = 0;
-		parser(pParser, t, x);
+		tt = scan(&s, &tv);
+#ifdef	DEBUG
+		report_at(tv.file, tv.line, &s,"%2d\t$%s$\n", tt, tv.str);
+#endif
+		parser(pParser, tt, tv, &result);
 	}
-	while (t);
+	while (tt);
 	parserFree(pParser, free);
+	return result;
 }
 
-#endif
+#endif /* TEST_LEXER */
diff --git a/src/snc/types.h b/src/snc/types.h
new file mode 100644
index 00000000..e0db6993
--- /dev/null
+++ b/src/snc/types.h
@@ -0,0 +1,240 @@
+#ifndef INCLtypesh
+#define INCLtypesh
+
+#ifndef TRUE
+#define TRUE	1
+#define FALSE	0
+#endif
+
+typedef struct options		Options;
+typedef struct token		Token;
+typedef struct scope		Scope;
+typedef struct program		Program;
+typedef struct channel		Chan;
+typedef struct expression	Expr;
+typedef struct variable		Var;
+typedef struct chan_list	ChanList;
+typedef struct var_list		VarList;
+
+typedef enum var_type		VarType;
+typedef enum var_class		VarClass;
+typedef enum expr_type		ExprType;
+
+struct options			/* compile & run-time options */
+{
+	int	async;		/* do pvGet() asynchronously */
+	int	conn;		/* wait for all conns to complete */
+	int	debug;		/* run-time debug */
+	int	newef;		/* new event flag mode */
+	int	init_reg;	/* register commands/programs */
+	int	line;		/* line numbering */
+	int	main;		/* main program */
+	int	reent;		/* reentrant at run-time */
+	int	warn;		/* compiler warnings */
+};
+
+struct token
+{
+	char	*str;
+	char	*file;
+	int	line;
+};
+
+#define tok(s)	(Token){s,0,0}
+
+struct	scope
+{
+	VarList	*var_list;
+	Scope	*next;
+};
+
+struct	expression			/* Expression block */
+{
+	Expr	*next;			/* link to next expression */
+	Expr	*last;			/* link to last in list */
+	Expr	*left;			/* ptr to left expression */
+	Expr	*right;			/* ptr to right expression */
+	int	type;			/* expression type (E_*) */
+	char	*value;			/* operator or value string */
+	int	line_num;		/* effective line number */
+	char	*src_file;		/* effective source file */
+	Scope	*scope;			/* local definitions */
+};
+
+struct	variable			/* Variable or function definition */
+{
+	struct	variable *next;		/* link to next item in list */
+	char	*name;			/* variable name */
+	char	*value;			/* initial value or NULL */
+	int	type;			/* var type */
+	int	class;			/* simple, array, or pointer */
+	int	length1;		/* 1st dim. array lth (default=1) */
+	int	length2;		/* 2nd dim. array lth (default=1) */
+	int	ef_num;			/* bit number if this is an event flag */
+	struct	channel *chan;		/* ptr to channel struct if assigned */
+	int	queued;			/* whether queued via syncQ */
+	int	maxQueueSize;		/* max syncQ queue size */
+	int	queueIndex;		/* index in syncQ queue array */
+	int	line_num;		/* line number */
+};
+
+struct	channel				/* DB channel assignment info */
+{
+	struct	channel *next;		/* link to next item in list */
+	char	*db_name;		/* database name (assign all to 1 pv) */
+	char	**db_name_list;		/* list of db names (assign each to a pv) */
+	int	num_elem;		/* number of elements assigned in db_name_list */
+	Var	*var;			/* ptr to variable definition */
+	int	count;			/* count for db access */
+	int	mon_flag;		/* TRUE if channel is "monitored" */
+	int	*mon_flag_list;		/* ptr to list of monitor flags */
+	Var	*ef_var;		/* ptr to event flag variable for sync */
+	Var	**ef_var_list;		/* ptr to list of event flag variables */
+	int	ef_num;			/* event flag number */
+	int	*ef_num_list;		/* list of event flag numbers */
+	int	index;			/* index in database channel array (seqChan) */
+};
+/* Note: Only one of db_name or db_name_list can have a non-zero value */
+
+struct chan_list
+{
+	Chan	*first, *last;
+};
+
+struct var_list
+{
+	Var	*first, *last;
+};
+
+struct program				/* result of parsing an SNL program */
+{
+	/* parser generates these */
+	char	*name;			/* ptr to program name (string) */
+	char	*param;			/* parameter string for program stmt */
+	Expr	*global_defn_list;	/* global definition list */
+	Expr	*ss_list;		/* state set list */
+	Expr	*entry_code_list;	/* entry code list */
+	Expr	*exit_code_list;	/* exit code list */
+	Expr	*global_c_list;		/* global C code following state program */
+
+	/* these get added by later stages */
+	Options *options;		/* program options, from source or command line */
+	Scope	*global_scope;		/* global scope */
+	ChanList *chan_list;		/* channel list */
+	int	num_channels;		/* number of db channels */
+	int	num_events;		/* number of event flags */
+	int	num_queues;		/* number of syncQ queues */
+	int	num_ss;			/* number of state sets */
+};
+
+/* Allocation 'functions' */
+#define	allocExpr()		(Expr *)calloc(1, sizeof(Expr))
+#define	allocVar()		(Var *)calloc(1, sizeof(Var))
+#define	allocChan()		(Chan *)calloc(1, sizeof(Chan))
+#define	allocVarList()		(VarList *)calloc(1, sizeof(VarList))
+#define	allocChanList()		(ChanList *)calloc(1, sizeof(ChanList))
+#define	allocScope()		(Scope *)calloc(1, sizeof(Scope))
+#define	allocProgram()		(Program *)calloc(1, sizeof(Program))
+
+/* Variable types */
+enum var_type
+{
+	V_NONE,			/* not defined */
+	V_CHAR,			/* char */
+	V_SHORT,		/* short */
+	V_INT,			/* int */
+	V_LONG,			/* long */
+	V_FLOAT,		/* float */
+	V_DOUBLE,		/* double */
+	V_STRING,		/* strings (array of char) */
+	V_EVFLAG,		/* event flag */
+	V_UCHAR,		/* unsigned char */
+	V_USHORT,		/* unsigned short */
+	V_UINT,			/* unsigned int */
+	V_ULONG			/* unsigned long */
+};
+
+/* Variable classes */
+enum var_class
+{
+	VC_SIMPLE,		/* simple (un-dimensioned) variable */
+	VC_ARRAY1,		/* single dim. array */
+	VC_ARRAY2,		/* multiple dim. array */
+	VC_POINTER,		/* pointer */
+	VC_ARRAYP		/* array of pointers */
+};
+
+/* Expression types */
+enum expr_type
+{
+	E_CONST,		/* numeric constant */
+	E_STRING,		/* ptr to string constant */
+	E_VAR,			/* variable */
+	E_PAREN,		/* parenthesis around an expression */
+	E_FUNC,			/* function */
+	E_SUBSCR,		/* subscript: expr[expr] */
+	E_POST,			/* unary postfix operator: expr OP */
+	E_PRE,			/* unary prefix operator: OP expr */
+	E_BINOP,		/* binary operator: expr OP expr */
+	E_TERNOP,		/* ternary operator: expr OP expr OP expr */
+	E_TEXT,			/* C code or other text to be inserted */
+	E_STMT,			/* simple statement */
+	E_CMPND,		/* begin compound statement: {...} */
+	E_IF,			/* if statement */
+	E_ELSE,			/* else statement */
+	E_WHILE,		/* while statement */
+	E_SS,			/* state set statement */
+	E_STATE,		/* state statement */
+	E_WHEN,			/* when statement */
+	E_FOR,			/* for statement */
+	E_X,			/* eXpansion (e.g. for(;;) */
+	E_BREAK,		/* break stmt */
+	E_DECL,			/* declaration statement */
+	E_ENTRY,		/* entry statement */
+	E_EXIT,			/* exit statement */
+	E_OPTION,		/* state option statement */
+	E_ASSIGN,		/* assign statement */
+	E_MONITOR,		/* monitor statement */
+	E_SYNC,			/* sync statement */
+	E_SYNCQ			/* syncq statement */
+};
+
+#ifdef expr_type_GLOBAL
+const char *expr_type_names[] =
+{
+	"E_CONST",
+	"E_STRING",
+	"E_VAR",
+	"E_PAREN",
+	"E_FUNC",
+	"E_SUBSCR",
+	"E_POST",
+	"E_PRE",
+	"E_BINOP",
+	"E_TERNOP",
+	"E_TEXT",
+	"E_STMT",
+	"E_CMPND",
+	"E_IF",
+	"E_ELSE",
+	"E_WHILE",
+	"E_SS",
+	"E_STATE",
+	"E_WHEN",
+	"E_FOR",
+	"E_X",
+	"E_BREAK",
+	"E_DECL",
+	"E_ENTRY",
+	"E_EXIT",
+	"E_OPTION",
+	"E_ASSIGN",
+	"E_MONITOR",
+	"E_SYNC",
+	"E_SYNCQ"
+};
+#else
+extern const char *expr_type_names[];
+#endif
+
+#endif	/*INCLtypesh*/
diff --git a/test/simple/sncExample.st b/test/simple/sncExample.st
index fdde6966..56807d1f 100644
--- a/test/simple/sncExample.st
+++ b/test/simple/sncExample.st
@@ -4,6 +4,8 @@ float v;
 assign v to "{user}:xxxExample";
 monitor v;
 
+evflag tick;
+
 ss ss1
 {
 	state low
@@ -25,5 +27,16 @@ ss ss1
 	    when(delay(.1))
 	    {
 	    } state high
+        when (efTestAndClear(tick)) {
+            printf("tick!");
+        } state high
 	}
 }
+
+ss ss2 {
+    state it {
+        when (delay(10)) {
+            efSet(tick);
+        } state it
+    }
+}
-- 
GitLab